팀프로젝트를 진행하다보면 git 에서 여러 에러를 발생할 수 있다.
내가 이번에 만난 에러는 다음과 같다.
상황을 조금 구체적으로 설명하자면,
default 브랜치인 "develop"과 각자 기능을 담당하는 feature/n 브랜치가 존재한다.
나는 feature/8 를 사용 중이었고, commit을 모두 마친 후 PR을 요청했다.
그래서 그동안 팀원들이 바꾼 develop 브랜치의 코드를 업데이트 하기 위해
git pull origin develop을 했다.
그런데
POST git-upload-pack (323 bytes)
POST git-upload-pack (943 bytes)
POST git-upload-pack (gzip 2543 to 1322 bytes) remote: Total 228 (delta 84),
reused 217 (delta 76),
pack-reused 0 From https://github.com/Homeat/Server * branch develop -> FETCH_HEAD 1fe1f65..70c7b21 develop -> origin/develop
hint: You have divergent branches and need to specify how to reconcile them.
hint: You can do so by running one of the following commands sometime before
hint: your next pull: hint: hint: git config pull.rebase false # merge
hint: git config pull.rebase true # rebase
hint: git config pull.ff only # fast-forward only hint:
hint: You can replace "git config" with "git config --global" to set a default hint: preference for all repositories.
You can also pass --rebase, --no-rebase, hint: or --ff-only on the command line to override the configured default per hint: invocation. Need to specify how to reconcile divergent branches.
어후.. 끔찍하다.. 이게 무슨 말인지 이해는 안된다.
사실 이전에 git 충돌 때문에 이 문제를 포기했던 적이 있다.. 같이 공부하던 친구도 pull 을 하려는 브랜치에 굴복(?)당하는 건 싫다고 해서 어째저째 하다가 어영부영 넘어갔던 거 같다.. 그 땐 fetch 진행 후, merge를 rebase로 진행했던 것 같다.
이 때는 git에 대해 조금 더 공부하려고 했으나 프로젝트 진행이 급하기 때문에 잠시 보류해두었다.
근데, 이제 어느 정도 프로젝트 구현은 마무리가 되어가고 깃에 대한 기록을 남기기 위해 작성한다.
위 문제 원인은 로컬 브랜치와 remote 원격 브랜치 사이에 변경 사항 충돌 때문에 발생한다.
그래서 이 문제를 해결하기 위한 방법은 3가지가 있다고 친절히 힌트를 주고 있다.
1. git config pull.rebase false
2. git config pull.rebase true
3. git config pull.ff only
우선, 위 3가지 방법을 알아보기 전에
git pull에 대해서 알아야 한다.
git pull (origin ~~~)은 두 단계를 포함하고 있다.
- git fetch (origin ~~~) 리모트 저장소(origin ~~~)에서 변경사항을 가져온다.
- git merge (origin ~~~) 변경 사항을 현재 작업 중인 브랜치에 병합한다.
그럼 이제, 위의 3가지 방법을 알아보자
git config pull.rebase false
이 옵션은 git pull이 fetch 이후 merge를 실행하도록 설정한다. 즉, git pull을 실행하면 원격(remote) 브랜치의 변경 사항을 가져와서 현재(local) 브랜치에 병합한다.
병합(merge)는 두 브랜치의 변경 사항을 모두 포함하는 새로운 커밋을 생성한다. 이 새로운 커밋에는 병합된 두 브랜치의 커밋이 부모로 설정된다. 이렇게 하면 두 브랜치에서 독립적으로 이루어진 작업을 모두 유지하면서 한 브랜치로 합칠 수 있다.
하지만, 이 방식은 여러 사람이 동시에 작업을 진행할 때 복잡한 커밋 히스토리를 만들 수 있다. 그 이유는 병합 과정에서 새로운 커밋이 생성되기 때문이다. 또한, 병합 과정에서 충돌이 발생할 수 있으며, 이 충돌은 수동으로 해결해야 한다.
따라서, 병합은 작업 내용을 명확하게 구분하고 싶을 때 유용하다. 하지만, 커밋 히스토리를 간결하게 유지하고 싶다면, rebase 옵션을 고려해 보는 것이 좋다.
친구와 함께 팀 프로젝트를 하고 있다고 생각해보세요.
당신과 친구는 각각 자신의 부분을 작성하고, 이후에 모두 합쳐서 최종 보고서를 만들어야 합니다.
이 때, 각자가 작성한 부분을 그대로 모아서 하나의 보고서를 만드는 것이 'merge' 방식입니다.
각자 작성한 부분이 그대로 보존되지만, 적절한 순서나 흐름을 만들기 위해 추가적인 편집이 필요할 수 있습니다.
git config pull.rebase true
이 옵션은 fetch 이후 'rebase'를 실행하도록 git pull 옵션을 설정한다. 따라서, git pull을 실행하면 local(현재) 브랜치의 변경 사항이 임시적으로 "저장"되고, remote(원격) 브랜치의 최신 변경 사항으로 local 브랜치가 업데이트 된다. 그 다음, 앞서 "저장"했던 local 브랜치의 변경 사항이 다시 적용된다.
이 과정을 통해, 여러 사람이 동시에 작업을 진행하더라도 각자의 작업이 순차적으로 이루어진 것처럼 보이게 된다. 이는 커밋 히스토리를 깔끔하게 유지할 수 있게 해주며, 코드 변경 사항 추적에 있어서 혼란을 줄여 준다.
하지만 주의할 점이 있다. rebase는 기본적으로 기존의 커밋 히스토리를 변경한다. 따라서, 이미 원격 저장소에 push한 커밋을 rebase를 통해 변경하는 것은 다른 사람들과의 작업에 혼란을 줄 수 있다. 그러므로, 원격 저장소에 push한 커밋은 가능한 변경하지 않는 것이 좋다.
또한, rebase를 사용하면 병합된 커밋이 생성되지 않는다. 이는 각 브랜치에서의 작업이 병합으로 인해 '섞이지' 않게 되므로, 각 브랜치에서 어떤 작업이 이루어졌는지 더 명확하게 파악할 수 있다는 장점이 있다.
같은 팀 프로젝트 상황에서, 이번에는 당신이 친구의 부분을 먼저 읽고, 그 내용에 맞춰서 자신의 부분을 이어서 작성한다고 생각해보세요.
이렇게 하면, 친구의 부분이 바뀌더라도 그 변경 사항을 빠르게 반영하고, 자신의 부분을 순차적으로 이어서 작성할 수 있습니다.
이것이 'rebase' 방식입니다.
git config pull.ff only
이 옵션은 git pull이 Fast-forward 방식만을 사용하도록 설정한다. Fast-forward는 현재(local) 브랜치가 가리키는 커밋이 원격(remote) 브랜치가 가리키는 커밋의 직접적인 선행 커밋일 때만 적용 가능한 방식이다.
Fast-forward 방식을 사용하면, 현재 브랜치의 포인터만 원격 브랜치가 가리키는 커밋으로 이동시키고, 별도의 병합 커밋을 생성하지 않는다. 이렇게 하면 커밋 히스토리가 선형적으로 유지되고, 병합으로 인한 혼란을 방지할 수 있다.
하지만, 현재 브랜치에서 새로운 커밋이 추가되었거나, 원격 브랜치의 커밋이 현재 브랜치의 선행 커밋이 아닌 경우에는 Fast-forward가 불가능하다. 이런 경우에는 병합(merge)나 리베이스(rebase)를 사용해야 한다.
따라서, 'git config pull.ff only' 옵션은 협업 환경에서 커밋 히스토리를 깔끔하게 유지하고 싶을 때 유용하다. 하지만, 이 옵션을 사용할 때는 현재 브랜치의 변경 사항을 자주 원격 저장소에 푸시하거나, 원격 브랜치의 변경 사항을 자주 가져와야 한다는 점을 유의해야 한다.
이렇게 설명만으로는 이해가 되지 않을 수 있다.
이번에는 당신이 친구의 부분을 기다리지 않고 먼저 보고서를 작성했다고 생각해봅시다.
그리고 친구가 자신의 부분을 완성하면, 그 부분을 당신이 이미 작성한 부분 뒤에 바로 이어붙입니다.
이 경우, 당신이 작성한 부분을 다시 수정하거나 조정할 필요 없이, 친구의 부분을 그대로 추가할 수 있습니다.
이것이 'fast-forward' 방식입니다.
위의 방법으로 git 충돌 문제를 해결할 수 있다고 한다.
나는
git fetch origin
git merge origin/develop
이렇게 문제를 해결했다. 그래서 리모트 브랜치와 내 작업 브랜치를 합쳐서 변경 사항을 수동으로 작업한 후에
PR을 해보니 충돌이 해결됐다.