git pull 사용법과 주의사항

git pull 사용법과 주의사항

팀 프로젝트를 하다 보면 동료가 올린 코드를 내 로컬에 반영해야 하는 상황이 자주 생기는데요. 이때 사용하는 명령어가 바로 git pull입니다. git pull은 원격 저장소(remote repository)의 최신 변경분을 가져와서 현재 브랜치에 합치는 과정을 한 번에 처리해줍니다.

git fetch + git merge

git pull은 사실 두 가지 명령어를 연달아 실행하는 것과 같습니다.

$ git fetch origin
$ git merge origin/main

먼저 git fetch로 원격 저장소의 변경 내용을 로컬로 가져오고, 그 다음 git merge로 현재 브랜치에 합칩니다. 이 두 단계를 git pull 하나로 줄일 수 있다는 게 핵심이에요.

$ git pull origin main

이 명령어는 origin이라는 원격 저장소의 main 브랜치에서 변경분을 가져와서 현재 브랜치에 병합합니다.

기본 사용법

가장 흔하게 쓰이는 형태는 인자 없이 git pull만 실행하는 것입니다.

$ git pull

이렇게 하면 현재 브랜치가 추적(tracking)하고 있는 원격 브랜치에서 변경분을 가져와서 병합합니다. 보통 git clone으로 저장소를 복제하거나 git push에서 -u 옵션으로 트래킹을 설정해놓으면, 따로 인자를 넘기지 않아도 됩니다.

원격 저장소와 브랜치를 명시하고 싶다면 이렇게 씁니다.

$ git pull <원격저장소명> <브랜치명>

예를 들어, origindevelop 브랜치에서 코드를 당겨오려면 다음과 같습니다.

$ git pull origin develop

merge vs. rebase

git pull은 기본적으로 fetch 후에 merge를 수행하는데요. merge 대신 rebase를 사용하고 싶다면 --rebase 옵션을 추가합니다.

$ git pull --rebase origin main

merge와 rebase의 가장 큰 차이를 간단히 설명하면, merge는 두 브랜치의 변경 이력을 합치면서 별도의 “병합 커밋(merge commit)“을 만들고, rebase는 내 커밋들을 원격 브랜치의 최신 커밋 위에 다시 쌓아 올려서 마치 처음부터 그 위에서 작업한 것처럼 이력을 깔끔하게 만들어 줍니다.

# merge 방식 (기본값) - 병합 커밋이 생김
$ git pull origin main

# rebase 방식 - 커밋 이력이 깔끔해짐
$ git pull --rebase origin main

어떤 방식이 나은지는 팀의 컨벤션에 따라 다릅니다. 이력의 맥락을 보존하고 싶다면 merge가 낫고, 커밋 그래프를 깔끔하게 유지하고 싶다면 rebase가 유리합니다.

매번 --rebase 옵션을 붙이기 귀찮다면 git config로 기본 동작을 rebase로 바꿀 수도 있습니다.

$ git config --global pull.rebase true

이렇게 설정하면 git pull만 실행해도 자동으로 rebase가 적용됩니다.

충돌 해결

git pull을 실행했을 때 원격 변경분과 내 로컬 변경분이 같은 파일의 같은 부분을 수정했다면 충돌(conflict)이 발생합니다.

$ git pull origin main
Auto-merging src/app.js
CONFLICT (content): Merge conflict in src/app.js
Automatic merge failed; fix conflicts and then commit the result.

이런 경우에는 Git이 충돌이 발생한 파일에 다음과 같은 표시를 남겨 줍니다.

function getGreeting() {
<<<<<<< HEAD
  return "안녕하세요";
=======
  return "반갑습니다";
>>>>>>> origin/main
}

<<<<<<< HEAD======= 사이가 내 변경 내용이고, =======>>>>>>> origin/main 사이가 원격 저장소의 변경 내용입니다. 원하는 쪽을 선택하거나 양쪽을 적절히 합친 뒤에 충돌 표시(<<<<<<<, =======, >>>>>>>)를 지워줍니다.

그런 다음 해당 파일을 스테이징하고 커밋하면 충돌 해결이 완료됩니다.

$ git add src/app.js
$ git commit -m "merge 충돌 해결"

만약 rebase 중에 충돌이 발생했다면 충돌을 해결한 후 git rebase --continue로 진행합니다.

$ git add src/app.js
$ git rebase --continue

로컬 변경 내용이 있을 때

로컬에서 아직 커밋하지 않은 변경 내용이 있는 상태에서 git pull을 시도하면, Git이 변경 내용이 덮어씌워질 수 있다며 거부하는 경우가 있습니다.

$ git pull
error: Your local changes to the following files would be overwritten by merge:
        src/app.js
Please commit your changes or stash them before you merge.

이럴 때는 두 가지 방법이 있습니다.

첫째, 작업 내용을 git commit으로 커밋한 뒤 pull합니다.

$ git commit -a -m "작업 중인 변경 사항 저장"
$ git pull

둘째, 작업 내용을 git stash로 임시 저장한 뒤 pull하고, 다시 꺼냅니다.

$ git stash
$ git pull
$ git stash pop

커밋을 남기기엔 아직 작업이 덜 끝났을 때는 stash 방식이 편합니다.

자주 겪는 실수

git pull을 사용하다 보면 흔히 겪는 실수가 있는데요.

첫 번째로 많은 분들이 브랜치를 확인하지 않고 pull하는 실수를 합니다. feature 브랜치에서 작업하고 있는데 무심코 git pull origin main을 실행하면, main 브랜치의 변경분이 feature 브랜치에 병합돼버립니다. pull하기 전에 git statusgit branch로 현재 브랜치를 꼭 확인하세요.

두 번째로 pull과 push의 순서를 혼동하는 경우가 있습니다. 원격에 이미 다른 사람이 푸시한 내용이 있는데 내가 먼저 push하려고 하면 거부됩니다. 이런 상황에서는 먼저 git pull로 원격 변경분을 가져온 뒤에 push해야 합니다.

$ git pull origin main
$ git push origin main

마치며

git pull은 팀 작업에서 매일같이 사용하는 기본 명령어입니다. 이 글에서 다룬 merge와 rebase 방식의 차이를 이해하고 상황에 맞게 사용하면, 불필요한 충돌이나 꼬인 이력 때문에 고생하는 일이 줄어들 것입니다.

git fetchgit merge에 대해서도 각각 자세히 다루고 있으니 함께 읽어보시면 도움이 될 거예요.

더 자세한 내용은 Git 공식 문서를 참고하세요.

This work is licensed under CC BY 4.0 CC BY

Discord