개발자 A의 이야기

개발자 A는 자신의 feature branch에서 열심히 작업을 했습니다. 이 feature branch는 구현이 마쳐지지 않아, 아직 merge 할 수 없습니다. 그런데 어느 날 feature branch의 GitHub pull request가 close 되어 있습니다. git history를 확인해보니, develop merge 된 것으로 보입니다! 그런데 정작 branch의 수정 사항들이 모두 반영되지는 않아 더욱 혼란스럽습니다. 어떤 일이 생긴 것일까요?

개발자 B의 이야기

개발자 B는 새로운 구현에 앞서, 참고 용도로 개발자 A의 branch에 checkout을 했습니다. 코드를 보던 와중, 아주 간단한 수정을 해야 하는 것이 문득 떠올랐습니다. 코드를 수정해 commit을 하고 나서야, branch를 따로 만들지 않은 것이 생각났습니다. git reset --soft ~ git stash ~ git branch ~ git pop ~ git commit ~ git merge ~ git push를 하는 것은 아무래도 번거롭습니다. 아직 push를 하지 않은 상태로, 방금의 local commit을 develop merge 해봅니다. 앗, conflict가 났습니다. 개발자 A branch가 아직 작업 중이라는 것을 생각하면 당연합니다. 방금 local commit의 수정 사항만 stage 하고 commit 합니다. branch를 별도로 만들어 merge 한 것과 동일한 결과가 된 듯하니, develop branch를 push 합니다.

git remote의 이야기

  • develop branch의 가장 최근 commit hash는 bba72b입니다.
  • 개발자 A branch의 가장 최근 commit hash는 3c90cf입니다.
  • develop branch에 개발자 B의 merge commit이 push 되었습니다.
  • 개발자 B merge commit의 parent commit은 bba72b, 3c90cf입니다.
  • 개발자 A branch가 develop merge 된 것으로 보이니, pull request를 close 합니다.

git history는 Directed Acyclic Graph 형태로 구성되며, 연속된 두 commit은 parent-child가 됩니다. 모든 commit은 자신의 branch에서 자신 이전의 latest commit이 parent commit입니다. inital commit의 경우, 이전 commit이 존재하지 않으므로 parent commit이 없습니다. merge commit의 경우, 두 branch 각각의 latest commit이 동시에 parent commit이 됩니다. 앞선 이야기에서의 git history는 아래와 같습니다.

git-history

git history는 수정 사항이 아닌 DAG를 바탕으로 관리되기 때문에, 개발자 B의 commit은 개발자 A feature branch의 merge로 인식되는 것입니다.

문제 해결

git merge는 commit 단위가 아닌 branch 단위로 생각해야 합니다. 그러나 실수로 merge commit 내에서 추가적인 수정을 하는 일은 누구에게나 생길 수 있습니다. merge conflict가 발생한 경우에는 특히 그렇습니다. GitHub 등 managed service를 이용하는 경우, master/develop branch를 protected branch로 지정하고 branch restriction을 설정하면 이를 방지할 수 있습니다. branch restriction으로 pull request를 강제하는 경우, remote branch 사이의 merge만 허용되어 merge commit 내에서의 임의 수정이 불가능합니다.