GitHub를 혼자 사용하다 보니 브랜치를 사용할 일이 없었지만, 협업을 위해 꼭 필요한 기능이기에 전부터 꼭 공부하고 싶던 내용이다.
GitHub에서 master
였던 기본 브랜치의 이름을 바뀐다는 이야기는 들은 적이 있다. 그 이후 다른 변화가 없길래 잊고 있었는데 이번에 브랜치를 공부하기 위해 만든 레파지토리의 기본 브랜치 이름이 main
으로 설정되어 있어서 신기했다.
그러다 깃의 히스토리를 삭제할 일이 있어서 삭제 후 init
을 했더니 기본 브랜치의 이름이 다시 master
로 바뀌어 있었다. 이유를 찾아보니 내 맥북에 설치된 로컬 git은 아직 기본 브랜치의 이름이 master
로 생성되는 것이었다.
Git 2.28부터는 git config --global init.defaultBranch <name>
으로 기본 브랜치의 이름을 설정할 수 있어서 내 로컬 git도 main
으로 설정해놓았다.
IT 역사의 꽤 특별한 한순간을 함께한 것 같아 기쁘다.
$ git branch <branchname> // 브랜치 만들기
$ git branch // 브랜치 목록 전체 확인
$ 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 reset --hard HEAD~ // 마지막으로 진행했던 명령 취소
진행했던 명령을 취소하는 명령어이다. 옵션에는 --hard
말고 --soft
도 있다. 정확한 사용법은 좀 더 공부해봐야 할 것 같다.
merge
와rebase
는 통합 브랜치에 토픽 브랜치를 통합하고자 하는 목적은 같으나, 그 특징은 약간 다릅니다.
merge
: 변경 내용의 이력이 모두 그대로 남아 있기 때문에 이력이 복잡해짐.rebase
: 이력은 단순해지지만, 원래의 커밋 이력이 변경됨. 정확한 이력을 남겨야 할 필요가 있면 사용하면 안 됨.
merge
와rebase
는 팀 운용 방침에 따라 구별해 쓸 수 있습니다.
토픽 브랜치에 통합 브랜치의 최신 코드를 적용할 경우에는rebase
를 사용,
통합 브랜치에 토픽 브랜치를 불러올 경우에는 우선rebase
를 한 후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 병합'이라고 합니다.
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
)브랜치로 확장되니 개념이 확실히 복잡하고 이해하기 어렵기는 하다. 반복해서 공부해야 할 것 같다.
init
만 하면 .git
폴더가 생성되고 버전 관리를 할 수 있었다. (얼마나 필요할지는 모르겠지만) 혼자 작업을 하는데 버전 관리가 필요할 경우, GitHub에 업로드 하지 않고 git을 사용해도 될 것 같다.git init
이 무한히 될 것 같다. 하지만 git init
이 된 폴더 안의 폴더에 git init
을 한 경우, 상위 폴더에서 git add
를 하려고 하자 warning 메시지가 떴다. 이중으로 버전을 관리하는 것이 일반적인 일은 아닌가 보다.stash
실제로 사용해보기^
실사용 예시 찾아보기 (브랜치 병합에서 원본이 여럿 있는 경우 몇 번째 원본인지를 지정할 수 있습니다.)git reset
사용하는 방법 (7.7 Git 도구 - Reset 명확히 알고 가기 - Git Book)