출처: GIT CLI - 협업 by 이고잉, 생활코딩, CC BY
아래 사진처럼 원격 저장소에 work.txt 파일이 푸시된 상태라고 해보자.
그리고 a라는 사람이 work.txt 파일을 아래와 같이 수정하고 work 2a
라는 버전을 원격 저장소에 푸시까지 했다고 가정해보자.
이번에는 b라는 사람이 work.txt 파일의 동일한 위치를 수정한 뒤에 커밋, 푸시를 시도했다고 해보자. 그러면 당연하게도 아래와 같은 에러가 발생한다! 이 에러는 로컬에서 push를 하기 전에 원격 저장소의 변경 사항을 먼저 pull 하라고 알려주고 있다.
pull을 하면 같은 파일의 같은 위치를 수정했기 때문에 충돌이 발생하며, 이 부분은 mergetool을 사용하거나, 텍스트 에디터에서 직접 수정할 수 있다.
아래처럼 충돌이 발생한 work.txt 파일을 수정한 뒤에 커밋을 해주면 정상적으로 병합이 된다. 병합에 의해 생긴 이 버전은 work 2a
와 work 2b
둘 모두를 공통의 조상으로 갖는 버전이다.
이제 b가 푸시까지 하면, 지역 저장소와 원격 저장소 모두 동일한 상태의 버전을 갖게 된다.
이번에는 a가 pull을 통해 원격 저장소와 로컬 상태를 동기화 시키면, 결국 a와 b는 동일한 버전을 갖게 된다.
여기서 얻을 수 있는 교훈은 다른 사람과 협업할 때 commit, push, pull을 최대한 자주 해서 원격 저장소와 로컬 저장소가 항상 최신 상태로 동기화 되어 있을 수 있도록 노력해야 한다는 것이다.
우리는 이제까지 협업을 위해, 로컬 저장소에서 pull → commit → push 하는 과정을 거쳤다. 그런데 여기서 pull 대신에 fetch와 merge 명령을 같이 사용할 수도 있다.
git pull = git fetch + git merge FETCH_HEAD
우선 a라는 사람이 work.txt 파일을 수정하고 work 3a
라는 커밋 메시지를 남겼다고 해보자. 아래 커밋 로그와 git status
결과를 보면, 깃은 현재 내 브랜치가 origin/master 보다 1 커밋 앞서 있기 때문에, 이 변경 사항을 원격 저장소에 반영하려면 push를 해야 한다고 알려주고 있다.
push를 한 뒤에 커밋 로그를 확인해보면, 이제 원격 저장소와 로컬 저장소의 브랜치가 같은 버전을 가리키게 된다.
이제 b라는 사람이 pull 명령 대신에 원격 저장소를 fetch 했다고 해보자. 그러면 원격 저장소의 work.txt 파일 내용은 아직 로컬에 반영되지 않았고, 커밋 로그에서도 로컬의 HEAD 포인터가 원격 저장소보다 1 커밋 뒤쳐져 있다는 걸 알 수 있다.
따라서 동기화를 시켜주려면, git merge origin/master
또는 git merge FETCH_HEAD
명령으로 원격 저장소의 브랜치와 로컬 저장소의 브랜치를 병합시켜줘야 한다.
이처럼 git fetch
는 원격 저장소의 상태만 로컬에 업로드 하기 때문에 git merge origin/master
명령으로 병합까지 해줘야, 비로소 로컬 저장소의 HEAD도 원격 저장소와 같은 버전을 가리키게 된다. 그런데 매번 origin/master 처럼 병합할 브랜치를 알아내는 게 번거롭기 때문에 FETCH_HEAD 포인터를 사용한다. 이 포인터는 원격 저장소가 가장 최근에 로컬 저장소에 패치시킨 버전의 브랜치를 가리키고 있다. 즉, 지금 예제에서는 origin/master
브랜치가 FETCH_HEAD가 가리키는 브랜치인 것이다. 이것과 병합을 하면 결국에는 pull과 같은 효과를 볼 수 있다!