main
브랜치에서 새로운 기능 개발을 위해 feature
브랜치를 팠다.
개발을 하다 보니 main
에 새로운 기능에 대한 커밋이 추가 됐고 feature
에서도 해당 기능이 필요하다고 판단해 feature
에서 git rebase main
을 사용했다.
그리고 개발을 하다가 git push
를 하면! 원격 저장소에서 볼 수 있는 엉망진창이 된 그래프… 예상했던 결과는 이게 아니었는데… 어디서부터 어떻게 잘못된 것이고 어떻게 해야 되는 걸까?
우선 Rebase기능에 대해 알아보자.
위와 같이 main
에 A
와 B
두 커밋이 존재하는 상황이다.
새로운 기능 개발을 위해 feature
를 생성했고, C
라는 새로운 커밋을 feature
에 추가했다.
그 사이 remote/main
에는 feature
에서 필요로 하는 기능을 담은 커밋 D
가 다른 사람에 의해 추가되었고 git checkout
후 git pull
을 통해 로컬에 있는 main
을 위의 사진과 같은 상태로 만들었다.
git checkout feature
를 한 후 git rebase main
을 한 결과는 이렇게 될 것이다. 기존 feature
에 존재하던 C
커밋이 C'
커밋으로 대체됐다. C
와 C'
은 내용은 동일한 커밋이다.
하지만 만약 feature
에서 C
커밋을 만든 후 git push
를 진행했다면 얘기가 조금 달라진다.
C
를 만들고 remote/feature
와 동기화 시켰기 때문에 git rebase
후 git push
명령어를 통해 remote/feature
와 동기화를 시킨다면 B
에서 분기되어 나오는 두 가지 feature
브랜치 때문에 충돌이 발생하고 따라서 충돌을 해결하기 위한 머지 커밋 M
이 하나 추가된다.
결국 우리가 원했던 아래와 같은 모양의 remote/feature
가 아닌 위와 같은 remote/feature
가 된다.
설명을 위해 글이 길어졌지만 사실 해결법은 간단하다. remote/feature
는 우리가 원하는 브랜치가 아니므로 git rebase main
후 feature
를 git push -f
를 통해 remote/feature
와 동기화 시키면 우리가 원하던 remote/feature
를 만들 수 있다. 심지어 C
와 C'
은 내용이 동일하니 삭제되는 수정사항도 없을 것이다.
새로운 기능 개발을 하다가 git rebase
를 사용했다면 git push -f
를 사용하면 된다. 물론 이건 git rebase
를 하기 전에 remote
에 git push
를 한 적이 있을 때에 한정되는 얘기이다. 없다면 원하던 브랜치 모양 그대로 유지될 것이다.
주의할 점이 있는데 feature
와 같이 개인이 개발하기 위해 만들어져 있는 브랜치를 git push -f
하는 것은 문제가 되지 않지만 main
과 같이 같이 작업을 하고 있는 브랜치가 있다면 정말 git push -f
가 꼭 필요한지, 필요하다면 결과가 어떻게 될지 확실히 알 때만 사용하는 것이 좋을 것이다.