[7] Git Branch

SeoChanhee·2020년 10월 13일
0

브랜치 (Branch)

GitHub를 혼자 사용하다 보니 브랜치를 사용할 일이 없었지만, 협업을 위해 꼭 필요한 기능이기에 전부터 꼭 공부하고 싶던 내용이다.

master 브랜치 (main 브랜치)

GitHub에서 master였던 기본 브랜치의 이름을 바뀐다는 이야기는 들은 적이 있다. 그 이후 다른 변화가 없길래 잊고 있었는데 이번에 브랜치를 공부하기 위해 만든 레파지토리의 기본 브랜치 이름이 main으로 설정되어 있어서 신기했다.
그러다 깃의 히스토리를 삭제할 일이 있어서 삭제 후 init을 했더니 기본 브랜치의 이름이 다시 master로 바뀌어 있었다. 이유를 찾아보니 내 맥북에 설치된 로컬 git은 아직 기본 브랜치의 이름이 master로 생성되는 것이었다.
Git 2.28부터는 git config --global init.defaultBranch <name>으로 기본 브랜치의 이름을 설정할 수 있어서 내 로컬 git도 main으로 설정해놓았다.
IT 역사의 꽤 특별한 한순간을 함께한 것 같아 기쁘다.

참고: Git의 기본 브랜치를 master에서 main으로 변경하기 - Outsider's Dev Story

git branch

$ git branch <branchname> // 브랜치 만들기
$ git branch // 브랜치 목록 전체 확인

git checkout

$ git checkout <branch> // 브랜치 전환하기
$ git checkout -b <branch> // 브랜치 작성 및 브랜치 전환
$ git branch -d <branchname> // 브랜치 삭제

여기서 HEAD라는 개념이 등장한다. HEAD란 현재 체크아웃된 커밋, 즉 현재 작업중인 커밋을 말한다. HEAD는 항상 작업트리의 가장 최근 커밋을 가리킨다.
stash라는 개념도 등장하는데 이것을 통해 깃을 쉽게 사용한다는 얘기를 주워들은 적이 있다. 나중에 사용해봐야겠다.

커밋을 지정할 때, ~^을 사용하여 현재 커밋으로부터 특정 커밋의 위치를 가리킬 수 있습니다. 이때 자주 사용하는 것이 'HEAD' 로서, ~와 숫자를 'HEAD' 뒤에 붙여 몇 세대 앞의 커밋을 가리킬 수 있습니다.
^은 브랜치 병합에서 원본이 여럿 있는 경우 몇 번째 원본인지를 지정할 수 있습니다.
~는 실습에서 몇 번 사용해봐서 이해했는데 ^는 사용해본 적이 없다.

발전편을 공부하며 브랜치 사용을 하다 보니 checkout 명령어를 쓸 일이 많아져서 checkout 명령어를 단축어 'co'로 지정했다. (git config --global alias.co checkout)
단축어도 .gitconfig 파일에서 확인 및 수정이 가능하다.

참고: [git] git - HEAD (브랜치 이동하기) - ChanHee

git reset

$ git reset --hard HEAD~ // 마지막으로 진행했던 명령 취소

진행했던 명령을 취소하는 명령어이다. 옵션에는 --hard 말고 --soft도 있다. 정확한 사용법은 좀 더 공부해봐야 할 것 같다.

브랜치 통합하기

mergerebase는 통합 브랜치에 토픽 브랜치를 통합하고자 하는 목적은 같으나, 그 특징은 약간 다릅니다.

  • merge : 변경 내용의 이력이 모두 그대로 남아 있기 때문에 이력이 복잡해짐.
  • rebase : 이력은 단순해지지만, 원래의 커밋 이력이 변경됨. 정확한 이력을 남겨야 할 필요가 있면 사용하면 안 됨.

mergerebase는 팀 운용 방침에 따라 구별해 쓸 수 있습니다.
토픽 브랜치에 통합 브랜치의 최신 코드를 적용할 경우에는 rebase를 사용,
통합 브랜치에 토픽 브랜치를 불러올 경우에는 우선 rebase를 한 후 merge

git merge

$ git merge <commit> // 브랜치 병합하기

master 브랜치에 issue1를 넣기 위해서는 우선 master 브랜치에 HEAD가 위치하게 만들어야 한다. 그다음 git merge issue1라는 명령어를 사용하면 된다.
이렇게 하면 master 브랜치가 가리키는 커밋이 issue1과 같은 위치로 한다. 이런 방식의 병합을 'fast-forward (빨리감기) 병합'이라고 한다고 한다.

  • <commit>에 브랜치 이름을 넣으면 가장 최근 커밋이 병합이 되는 것으로 보인다. 최근 커밋을 사용하고 싶지 않은 경우, 과거 커밋 코드의 앞 7자리를 넣어도 된다.

브랜치를 merge로 병합할 때 충돌이 발생하는 것을 해결하는 방법과 push한 내용이 충돌이 발생하는 것을 해결하는 방법이 매우 비슷하고 편리하다.

충돌이 있는 부분에 Git이 자동으로 위와 같이 충돌 정보를 포함하여 파일 내용을 변경합니다. 이 내용을 통해 어떤 브랜치에서 어떤 부분이 충돌되었는지 확인할 수 있습니다. 충돌이 일어난 부분은 이렇게 일일이 확인해서 수정해 주어야 합니다.
이번 병합은 충돌 부분을 수정했기 때문에 그 변화를 기록하는 병합 커밋이 새로 생성되었습니다. 그리고 'master' 브랜치의 시작('HEAD')이 그 위치로 이동해 있는 것을 확인할 수 있습니다. 아래와 같은 방식을 'non fast-forward 병합'이라고 합니다.

git rebase

  • issue3 브랜치로 전환하여 main 브랜치에 rebase 를 실행한다. (git rebase main)
  • 충돌이 난 파일 내용을 적절히 처리한다.
  • rebase 의 경우 충돌 부분을 수정한 후에는 commit이 아니라 rebase 명령에 --continue 옵션을 지정하여 실행해야 한다. (git rebase --continue)
  • rebase 자체를 취소하려면 --abort 옵션을 지정하면 된다.
  • rebase만 실행한 경우에는 issue3 브랜치가 main 브랜치의 앞쪽으로 위치가 옮겨졌을 뿐 main 브랜치는 아직 issue3의 변경 사항이 적용되지 못한 상태로 뒤에 남겨져 있다.
  • main 브랜치로 전환하여 issue3 브랜치의 변경 사항을 모두 병합하면 된다. (git merge issue3)


마침

브랜치로 확장되니 개념이 확실히 복잡하고 이해하기 어렵기는 하다. 반복해서 공부해야 할 것 같다.

  • 공부하면서 가장 신기했던 것은 git을 꼭 GitHub에 올려서 사용할 필요가 없다는 것이다. 어느 폴더든 init만 하면 .git 폴더가 생성되고 버전 관리를 할 수 있었다. (얼마나 필요할지는 모르겠지만) 혼자 작업을 하는데 버전 관리가 필요할 경우, GitHub에 업로드 하지 않고 git을 사용해도 될 것 같다.
  • 사실상 조건만 갖춰지면 git init이 무한히 될 것 같다. 하지만 git init이 된 폴더 안의 폴더에 git init을 한 경우, 상위 폴더에서 git add를 하려고 하자 warning 메시지가 떴다. 이중으로 버전을 관리하는 것이 일반적인 일은 아닌가 보다.

더 공부할 내용

  1. stash 실제로 사용해보기
  2. ^ 실사용 예시 찾아보기 (브랜치 병합에서 원본이 여럿 있는 경우 몇 번째 원본인지를 지정할 수 있습니다.)
  3. git reset 사용하는 방법 (7.7 Git 도구 - Reset 명확히 알고 가기 - Git Book)
  4. fast-foward 병합과 non-fast-foward 병합이란?


출처: 누구나 쉽게 이해할 수 있는 Git 입문 (발전편)

0개의 댓글