안녕하세요!
이어서 Git의 브랜치에 관한 포스팅입니다.
지난 포스팅에서 브랜치를 이용해서 커밋 사이를 이동해봤습니다.
이번 포스팅은 이슈를 해결해보는 포스팅입니다.
작업 중인 프로젝트가 있습니다.
그리고, iss53이라는 이슈가 발생해서 브랜치를 새로 만들고 해결하려 합니다.
그런데 이슈를 해결하는 중 우선순위가 높은 더 큰 이슈가 발생한 경우 입니다.
먼저 이슈 해결을 위한 브랜치를 생성합니다.
-b
옵션을 넣어주면 브랜치를 생성하고, checkout 하게 됩니다.
$ git checkout -b iss53
만약 이슈 해결중에 배포중인 사이트에 문제가 생겨 우선순위 높은 이슈가 생겼다면 어떻게 해야할까요?
배포중인 브랜치로 돌아가려면 그냥 master브랜치로 체크아웃 하면 됩니다.
iss53 브랜치의 이슈 해결은 나중에 다시 할 수 있습니다.
체크아웃 하기전에 iss53의 브랜치를 커밋하는 것을 잊지 말아야 합니다.
아직 커밋하지 않은 파일이 Checkout할 브랜치와 충돌이 나면 브랜치를 변경할 수 없습니다.
$ git checkout master
이 때 워킹 디렉터리는 53번 이슈를 시작하기 이전 모습으로 되돌려지기 때문에 새로운 문제에 집중할 수 있는 환경이 만들어집니다. Git은 자동으로 워킹 디렉터리에 파일들을 추가하고 지우고, 수정해서 Checkout한 브랜치의 마지막 스냅샷으로 되돌려 놓는다는 점이 중요합니다.
원점으로 돌아왔습니다.
급한 문제를 해결하기위해 hotfix라는 브랜치를 만들고 새로운 이슈를 해결할 때까지 사용합니다.
$ git checkout -b hotfix
master브랜치에서 새로운 브랜치 hotfix를 만들어 checkout했습니다. 그러면 master브랜치가 있던C2
커밋을 기점으로 hotfix라는 브랜치가 하나 더 생깁니다.
이슈를 해결했다면 master브랜치에 합쳐야 합니다.
$ git checkout master
$ git merge hotfix
Updating f42c576..3a0874c
Fast-forward
index.html | 2 ++
1 file changed, 2 insertions(+)
master브랜치로 체크아웃하고 hotfix브랜치를 master에 Merge합니다.
Fast-forward
는 뭘까요
위 명령어를 실행했을 때 실제로 Merge는 일어나진 않았습니다.
hotfix는 master브랜치보다 이 후의 커밋을 가리키고 있었습니다.
두 브랜치를 합친다면 결국 hotfix가 될겁니다. Merge할 필요가 없기 때문에 그저 master브랜치를 hotfix브랜치와 같은 곳으로 이동시키는 것입니다.
Fast-forward
후의 모습입니다.
두 브랜치가 같은 커밋을 가리키고있고 이슈도 해결했기 때문에 더 이상 hotfix브랜치는 필요 없습니다.
$ git branch -d hotfix
hotfix브랜치를 삭제합니다.
iss53브랜치로 돌아가 이슈를 계속 해결합니다.
$ git checkout iss53
이슈를 해결하고 commit합니다.
$ git commit -a -m "resolve an issue53"
master브랜치로 이동해 iss53브랜치를 merge해보겠습니다.
$ git checkout master
$ git merge iss53
Merge made by the 'recursive' strategy.
README | 1 +
1 file changed, 1 insertion(+)
아까 hotfix를 merge할 때와는 다른 메세지가 출력됩니다.
현재 브랜치가 가리키는 커밋이 Merge할 브랜치의 조상이 아닙니다. 따라서 Fast-forward가 적용되지 않습니다.
이 때의 공통조상은 C2가 되고 각 브랜치가 가리키는 커밋 두 개와 공통 조상 하나를 이용해 3-way Merge
를 합니다.
단순히 브랜치 포인터를 최신 커밋으로 옮기는 Fast-forward
와는 다릅니다.
Fast-forward
와 비교한다면 master브랜치가 바로 iss53으로 옮겨갈 수 없습니다.
따라서 별도의 커밋을 생성하고 master브랜치는 그 커밋을 가리키도록 이동하게 됩니다.
그래서 이런 커밋은 부모가 여러개이며 Merge Commit
이라고 부릅니다.
Git은 Merge하는데 필요한 최적의 공통 조상을 자동으로 찾습니다. 이런 기능이 Git이 다른 VCS들보다 나은 점입니다. CVS나 Subversion 같은 VCS는 개발자가 직접 공통조상을 찾아야 합니다.
Git은 다른 VCS보다 Merge가 쉽습니다.
이제 더이상 필요없어진 iss53 브랜치도 삭제합니다.
$ git branch -d iss53
3-way Merge
가 실패하는 경우가 있습니다. 두 브랜치에서 같은 파일을 동시에 수정하고 Merge하려고 하면 Conflict
가 발생합니다
실패하게되면 당연히 새로운 커밋도 생기지 않죠
Git을 사용하다가 가장 자주 만나는 문제이기도 합니다.
$ git merge iss53
Auto-merging index.html
CONFLICT (content): Merge conflict in index.html
Automatic merge failed; fix conflicts and then commit the result.
git status
명령을 이용해 어떤 파일을 Merge할 수 없었는지 확인해야 합니다.$ git status
On branch master
You have unmerged paths.
(fix conflicts and run "git commit")
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: index.html
no changes added to commit (use "git add" and/or "git commit -a")
Unmerged paths
부분에 both modified
를 보면 index.html
에 충돌이 발생했다는 것을 알 수 있습니다.
<<<<<<< HEAD:index.html
<div id="footer">contact : email.support@github.com</div>
=======
<div id="footer">
please contact us at support@github.com
</div>
>>>>>>> iss53:index.html
이런 식으로 윗 부분은 HEAD포인터가 가르키고 있는 master브랜치, 아랫 부분은 iss53브랜치가 가리키는 내용입니다.
이 부분을 수동으로 해결하고 git add
명령으로 다시 Git에 저장하면 됩니다.
$ git status
On branch master
All conflicts fixed but you are still merging.
(use "git commit" to conclude merge)
Changes to be committed:
modified: index.html
충돌을 해결하고 Staging Area에 저장 됐는지 확인됐습니다. git commit명령으로 Merge한 것을 커밋합니다.
Merge tool
을 이용하는 방법도 있다고 하는데 나중에 시간이 된다면 알아봐야겠습니다.
git branch
를 아무런 옵션 없이 실행하면 브랜치의 목록을 보여줍니다.
$ git branch
iss53
* master
testing
* 기호가 붙은 master브랜치는 현재 Checkout해서 작업하는 브랜치입니다.
git branch -v
명령어로 브랜치마다 마지막 커밋 메세지도 함께 보여줍니다.
$ git branch -v
iss53 93b412c fix javascript issue
* master 7a98805 Merge branch 'iss53'
testing 782fd34 add scott to the author list in the readmes
git branch --merged
옵션을 넣으면 Merge된 브랜치를 필터링해서 보여줍니다.
$ git branch --merged
iss53
* master
이 붙어있지 않은 iss53브랜치는 삭제해도 됩니다. 이미 다른 브랜치와 Merge했기 때문입니다.
git branch --no-merged
는 현재 Checkout한 브랜치에서 Merge하지 않은 브랜치를 보여줍니다.
$ git branch --no-merged
testing
삭제할 때 유의해야합니다. Merge하지 않은 커밋을 담고있는 testing브랜치는 git branch -d
명령어로 삭제되지 않습니다.
만약 강제로 삭제하려면 -D
옵션을 넣어줍니다.
여기까지 이번 포스팅을 마치겠습니다.
아직 까지 Github에 연결해서 사용하지않고 로컬에서만 git을 사용했습니다.
다음 시간에 이어서 Rebase
에 대해서 알아보겠습니다.
깔끔하네요 잘봤습니다!