[Git] 브랜치 이해하고 활용하기

브랜치 이해하고 활용하기

기본적으로는 하나의 main 브랜치에서 모든 작업이 수행된다. 그러나 프로젝트 규모가 커지고, 버전 관리가 복잡해지며 곧 여러 브랜치 운영이 필요한 순간이 다가온다. Git 에서 브랜치는 매우 중요한 부분이며, 아래 내용을 기본으로 익혀야 기업이 요구하는 다양한 브랜치 전략을 수행할 수 있다.

  • 새로운 브랜치 생성
  • 브랜치 간의 변경 사항 합치기
  • 충돌 다루기
  • 브랜치 삭제하기
  • 브랜치명 변경하기
  • 릴리즈 브랜치 다루기

브랜치란?

Git 에서 브랜치는 작업의 이력의 갈래이다. Git 은 모든 것을 브랜치로 관리하며, 직관적으로는 방향성 비순환 그래프(Directed Acyclic Graph, DAG) 라고 설명할 수 있다.

한 개 브랜치로만 형상관리를 한다면? 이 같은 단방향 이력 관리만으로는 기능 추가, 리팩터링, 버그 수정과 같은 다양한 요구 사항을 만족시킬 수 없다. 그래서 브랜치는 필수적이라 할 수 있다.

자세한 내용은 git branch -h 옵션을 사용하면 모두 확인할 수 있다.

$ git branch -h
usage: git branch [<options>] [-r | -a] [--merged | --no-merged]
   or: git branch [<options>] [-l] [-f] <branch-name> [<start-point>]
   or: git branch [<options>] [-r] (-d | -D) <branch-name>...
   or: git branch [<options>] (-m | -M) [<old-branch>] <new-branch>
   or: git branch [<options>] (-c | -C) [<old-branch>] <new-branch>
   or: git branch [<options>] [-r | -a] [--points-at]
   or: git branch [<options>] [-r | -a] [--format]

Generic options
    -v, --verbose         show hash and subject, give twice for upstream branch
    -q, --quiet           suppress informational messages
    -t, --track           set up tracking mode (see git-pull(1))
    -u, --set-upstream-to <upstream>
                          change the upstream info
    --unset-upstream      Unset the upstream info
    --color[=<when>]      use colored output
    -r, --remotes         act on remote-tracking branches
    --contains <commit>   print only branches that contain the commit
    --no-contains <commit>
                          print only branches that don't contain the commit
    --abbrev[=<n>]        use <n> digits to display SHA-1s

Specific git-branch actions:
    -a, --all             list both remote-tracking and local branches
    -d, --delete          delete fully merged branch
    -D                    delete branch (even if not merged)
    -m, --move            move/rename a branch and its reflog
    -M                    move/rename a branch, even if target exists
    -c, --copy            copy a branch and its reflog
    -C                    copy a branch, even if target exists
    -l, --list            list branch names
    --create-reflog       create the branch's reflog
    --edit-description    edit the description for the branch
    -f, --force           force creation, move/rename, deletion
    --merged <commit>     print only branches that are merged
    --no-merged <commit>  print only branches that are not merged
    --column[=<style>]    list branches in columns
    --sort <key>          field name to sort on
    --points-at <object>  print only branches of the object
    -i, --ignore-case     sorting and filtering are case insensitive
    --format <format>     format to use for the output

새로운 브랜치 생성하기

git branch 명령을 사용하면 현재 작업 중인 브랜치 앞에 * 가 표시되며 녹색으로 나타난다. git branch [새로운 브랜치 명] 을 통해 새로운 브랜치를 만들 수 있고, git branch -m [브랜치 명] [변경할 브랜치 명] 으로 이름을 바꿀 수도 있다.

또한, git checkout [변경할 브랜치] 를 사용해 작업할 브랜치를 변경할 수 있다.

wch18735@DESKTOP MINGW64 ~/Desktop/WCH/Github/[REPO] GitFirst (master)
$ git branch
  RB_1.0.1
* master

wch18735@DESKTOP MINGW64 ~/Desktop/WCH/Github/[REPO] GitFirst (master)
$ git checkout RB_1.0.1
Switched to branch 'RB_1.0.1'

wch18735@DESKTOP MINGW64 ~/Desktop/WCH/Github/[REPO] GitFirst (RB_1.0.1)
$ git branch
* RB_1.0.1
  master

현재 브랜치가 여러 개 있는 상황이라면? git checkout -b [생성할 브랜치] [기존 브랜치] 명령으로 특정 브랜치에서 분기시킬 수 있다.

## 브랜치 간의 변경 사항 합치기

각 브랜치는 저자오를 구성하는 데 매우 중요한 요소이나, 브랜치 간의 변경 사항을 공유하고 합칠 필요도 있다. 이런 경우를 브랜치 병합이라 한다. 병합 방법은 대표적으로 아래 3가지가 있다.

  • 바로 합치기(Straight Merge): 하나의 브랜치와 다른 브랜치의 변경 이력 전체를 합치는 방법
  • 커밋 합치기(Squashed Commit): 한 브랜치의 이력을 압축하여 다른 브랜치의 최신 커밋 하나로 만드는 방법
  • 선택하여 합치기(Cherry-picking): 다른 브랜치에서 하나의 커밋을 가져와 현재 브랜치에 적용하는 방법

바로 합치기

먼저 바로 합치는 경우부터 확인해보자. 아래와 같이 두 브랜치가 있다.

$ git branch
  alternate
* master

현재 마스터 브랜치로 alternate 브랜치를 합치고 싶다면 현재 브랜치에서 다음과 같이 git merge [병합 대상 브랜치] 명령어를 입력한다.

$ git merge alternate
Updating c57865d..cf1fc94
Fast-forward
 alternate.txt | 1 +
 1 file changed, 1 insertion(+)
 create mode 100644 alternate.txt

위 명령어를 입력하면 alternate 브랜치 변경 내용이 master 브랜치에 합쳐졌다.

커밋 합치기

개발할 기능이나 수정할 변경 사항에 따라 브랜치를 생성하는 것도 Git 에서 브랜치를 사용하는 방법 중 하나다. 새로운 기능이나 버그를 수정했다면 변경 사항을 다시 합칠 수 있도록 커밋 합치기를 사용한다.

이 때, 브랜치 하나의 변경 이력을 아축해 다른 브랜치에 하나의 커밋으로 만들어 적용한다. 이러한 커밋 합치기를 할 때는 압축 대상인 모든 커밋 이력이 독자적으로 유지되어야 한다는 것이다. 브랜치에ㅓ 변경한 내용들이 합쳐질 내용과 충돌하는 부분 없이 하나의 변경 사항으로 볼 수 있다면, 커밋 합치기를 사용할 수 있는 후보다.

특히, 이것저것 실험한 후 마지막 결과만을 적용하고 싶을 때 유용하게 사용할 수 있다. 마스터 브랜치로 이동한 뒤 git merge --squash [대상 브랜치] 명령을 입력하면 변경 내역이 합쳐진다. 하지만 단순 merge 와 다르게 commit 은 되지 않고, 변경 내역만 스테이징 영역에 남는다.

$ git merge --squash contact
Updating cf1fc94..34184f6
Fast-forward
Squash commit -- not updating HEAD
 checkout.txt | 2 ++
 1 file changed, 2 insertions(+)
 create mode 100644 checkout.txt

변경 영역만 스테이징된 것을 아래와 같이 확인할 수 있다. 이제 모든 변경 사항의 결과만을 가져왔다. 마지막은 git commit 을 통해 한 개의 commit 으로 기록하는 것이다.

$ git status
On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        new file:   checkout.txt

선택하여 합치기

지금까지는 변경된 모든 내용 전체를 반영하는 방법을 알아보았다. 그러나 때로는 브랜치 간에 전체를 합치는 대신 오직 하나 또는 몇 개의 커밋만 합칠 필요가 있다. 대표적으로 브랜치들 사이에 수정된 버그나 새로 추가한 클래스를 공유하는 경우가 있다.

wch18735@DESKTOP-NA583NG MINGW64 ~/Desktop/WCH/GitHub/[REPO] GitFirst (contact)
$ git commit -m "cherry-pick"
[contact 88f062a] cherry-pick
 1 file changed, 1 insertion(+), 1 deletion(-)

wch18735@DESKTOP-NA583NG MINGW64 ~/Desktop/WCH/GitHub/[REPO] GitFirst (contact)
$ git checkout master
Switched to branch 'master'

wch18735@DESKTOP-NA583NG MINGW64 ~/Desktop/WCH/GitHub/[REPO] GitFirst (master)
$ git cherry-pick 88f062a
[master 54e5956] cherry-pick
 Date: Tue Jul 19 00:31:53 2022 +0900
 1 file changed, 1 insertion(+), 1 deletion(-)

위 예시처럼 변경사항이 저장된 88f062a 커밋을 master 브랜치에서 불러온다. 지금은 한 개에서만 수행했지만 여러 커밋들을 동시에 가져올 수 있으며 방법은 git cherry-pick [commit hash] ... [commit hash] 와 같이 커밋 해시를 나열해주면 된다.

git cherry-pick 은 선택한 커밋의 변경 사항을 가지고 새로운 커밋을 생성하는데, 선택하려는 커밋이 여러 개인 경우 변경 사항만 가져와 반영하는 것도 가능하다. 이는 git cherry-pick -n 을 사용해 커밋하지 않게 할 수 있다. 이 매개변수를 이용하면 여러 커밋들을 가져온 후 한 번에 반영할 수 있다.

끝으로 cherry-pick 도중 에러가 발생했을 때에는 두 가지 옵션이 있다.

  • git cherry-pick --continue : conflict 가 발생한 파일을 수정한 후 다시 진행
  • git cherry-pick --abort : cherry-pick 중단

충돌 다루기

두 개의 다른 브랜치에서 동일한 파일을 다르게 편집한 후 합치려고 할 때, Git 은 이를 충돌로 판단해 실행을 멈추고 사용자가 수정하도록 한다.

hello.txt 를 만들고 브랜치를 분기한 후 서로 다른 내용을 기입했다. 그리고 양쪽에 커밋을 수행한 뒤 master 브랜치에서 merge 를 진행하면 아래와 같은 에러를 확인할 수 있다.

$ git merge contact
Auto-merging hello.txt
CONFLICT (content): Merge conflict in hello.txt
Automatic merge failed; fix conflicts and then commit the result.

충돌이 난 부분을 확인하기 위해 hello.txt 를 열어보면 아래와 같은 내용을 확인할 수 있다.

$ vim hello.txt

hello.txt
<<<<<<< HEAD
modified in master
=======
modified in contact branch
>>>>>>> contact

<<<<<<< 뒤에 나오는 부분은 현재 브랜치 코드, >>>>>>> 뒤에 나오는 부분은 다른 브랜치의 코드이다. 합칠 내용이 간단하다면 충돌이 발생한 부분을 직접 수정한다. 복잡한 내용인 경우 코드를 비교하면서 합칠 수 있는 도구를 사용한다. git mergetool 명령어로 합치기 도구를 실행할 수 있다.

끝으로 변경된 사항을 add 한 뒤 commit 을 수행한다. 그러면 아래와 같이 MERGING 과정이 종료된다.

wch18735@DESKTOP-NA583NG MINGW64 ~/Desktop/WCH/GitHub/[REPO] GitFirst (master|MERGING)
$ git add .

wch18735@DESKTOP-NA583NG MINGW64 ~/Desktop/WCH/GitHub/[REPO] GitFirst (master|MERGING)
$ git commit -m "merged"
[master e9d64c1] merged

wch18735@DESKTOP-NA583NG MINGW64 ~/Desktop/WCH/GitHub/[REPO] GitFirst (master)

Updated:

Leave a comment