Original article: Git Push to Remote Branch – How to Push a Local Branch to Origin

git push는 로컬 브랜치(local branch)를 원격 저장소(remote repository)로 푸시할 때 사용하는 기본 명령어입니다.

git push 명령어는 다양한 옵션과 매개변수를 가지고 있습니다. 이 기사에서는 그 중 자주 사용하는 옵션과 매개변수에 대해 설명합니다.

Git 로컬 브랜치를 원격 저장소로 푸시하기

기본 git push 명령어를 실행하면 Git는 푸시 동작을 행할 원격 저장소와 푸시할 로컬 브랜치의 두 매개변수를 기본값으로 설정합니다.

명령어의 기본 문법은 다음과 같습니다.

예시:

$ git push <remote> <branch>

사용자가 이 두 매개변수를 지정하지 않는다면 Git는 기본적으로 origin을 원격 저장소로, 현재 작업하고 있는 브랜치를 푸시할 브랜치로 지정합니다.

현재 작업 중인 브랜치가 main인 경우, git push 명령어는 두 개의 기본 매개변수를 제공하기 때문에 git push origin main과 동일하게 실행됩니다.

다음 예시에서는 origin은 GitHub 원격 저장소이고, 현재 작업 중인 브랜치는 main입니다.

(main)$ git remote -v 
origin  git@github.com:johnmosesman/burner-repo.git (fetch)
origin  git@github.com:johnmosesman/burner-repo.git (push)

(main)$ git push
Enumerating objects: 4, done.
Counting objects: 100% (4/4), done.
Delta compression using up to 16 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 274 bytes | 274.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To github.com:johnmosesman/burner-repo.git
   b7f661f..ab77dd6  main -> main

출력에서 로컬 main 브랜치가 원격 main 브랜치로 푸시된 것을 확인할 수 있습니다.

To github.com:johnmosesman/burner-repo.git
   b7f661f..ab77dd6  main -> main

Git 브랜치를 강제로 푸시(force push)하기

일반적으로 사용자는 원격 브랜치에 푸시하고 해당 커밋 기록에 변경 이력을 추가합니다.

하지만 간혹 브랜치 커밋 기록을 강제로 덮어써야 하는 경우가 있습니다.

강제 푸시를 실행하는 이유는 몇 가지가 있습니다.

첫 번째 이유는 오류를 수정하기 위해서입니다. 하지만 이 같은 이유라면 일반적으로 revert 멍령어를 사용해 변경 사항을 되돌리는 새 커밋을 생성하는 것이 더 나은 방법입니다.

두 번째 더 일반적인 시나리오는 커밋 기록을 변경하는 rebase와 같은 작업이 실행된 이후입니다:

내부적으로 Git은 새로운 커밋을 생성하고 지정된 브랜치에 변경 이력을 적용해 [rebase]를 실행합니다. 여기서 유념할 점은 동일한 브랜치인 것 같아 보이지만 rebase전과 후의 브랜치는 완전히 다른(새로운) 커밋으로 구성된다는 것입니다.

rebase완전히 새로운 커밋을 생성합니다.

즉, 로컬에서만 rebase가 실행된 브랜치를 푸시하려고 하면 원격 저장소에서 커밋 기록이 변경되었다는 것을 인식하고 로컬과 원격 저장소의 커밋 기록이 일치할 때까지 푸시하지 못하게 합니다.

(my-feature)$ git push
To github.com:johnmosesman/burner-repo.git
 ! [rejected]        my-feature -> my-feature (non-fast-forward)
error: failed to push some refs to 'git@github.com:johnmosesman/burner-repo.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

git pull를 실행해 변경이력을 병합할 수 있지만, 원격 저장소를 강제로 덮어쓰려면 푸시 명령어에 --force 플래그를 추가합니다.

(my-feature)$ git push --force origin my-feature
Enumerating objects: 1, done.
Counting objects: 100% (1/1), done.
Writing objects: 100% (1/1), 184 bytes | 184.00 KiB/s, done.
Total 1 (delta 0), reused 0 (delta 0)
To github.com:johnmosesman/burner-repo.git
 + edb64e2...52f54da my-feature -> my-feature (forced update)

(참고: --force대신 약자인 -f를 사용할 수 있습니다)

강제 푸시는 원격 저장소를 완전히 바꿔버리고 손상시킬 수 있는 작업이기 때문에 확실한 경우에만 사용하는 걸 권장합니다.

--force-with-lease 옵션 사용하기

때로는 자신 이외의 사람이 브랜치에 기여하지 않은 경우에만 강제 푸시를 실행하고 싶을 수도 있습니다.

다른 사람이 브랜치에 기여하고 원격 저장소로 푸시한 후 기존 작업자가 강제 푸시를 실행하면 다른 사람의 작업 내용을 덮어쓰게 됩니다.

이런 상황을 방지하려면 --force-with-lease 옵션을 사용합니다.

설명서에 따르면:

세부 정보를 지정하지 않은 채로 --force-with-lease를 실행하면 모든 원격 참조(remote Refs 레퍼런스)들은 보호됩니다. 여기서 말하는 원격 참조란 리모트 트래킹 브랜치(remote-tracking branch)의 소스와 동일하도록 맞춰서 업데이트 되는 참조를 뜻합니다.

즉, Git에게 이 브랜치가 마지막으로 봤을 때와 동일한 경우에만 강제로 업데이트하도록 지시하는 것입니다.

다른 사람과 같은 브랜치에서 협업하는 경우, 다른 사용자가 변경한 내용이 손실되지 않도록 --force를 사용하지 않거나 최소한 --force-with-lease를 사용하는 것이 좋습니다.

Git 로컬 브랜치를 다른 이름의 원격 브랜치로 푸시하기

일반적으로 로컬 브랜치를 같은 이름의 원격 브랜치에 푸시하지만, 그렇지 않은 경우도 있습니다.

다른 이름의 원격 브랜치로 푸시하려면 푸시할 로컬 브랜치와 원격 브랜치의 이름을 콜론(:)으로 구분하여 지정합니다.

예를 들어 로컬 브랜치 some-branch를 원격 브랜치 my-feature로 푸시하고 싶다면:

(some-branch)$ git push origin some-branch:my-feature
Total 0 (delta 0), reused 0 (delta 0)
To github.com:johnmosesman/burner-repo.git
 + 728f0df...8bf04ea some-branch -> my-feature

모든 로컬 브랜치를 원격 저장소로 푸시하기

모든 로컬 브랜치를 원격 저장소로 푸시할 필요는 없지만, 그럴 경우 --all 플래그를 명령어에 추가해야 합니다:

(main)$ git branch
* main
  my-feature

(main)$ git push --all
...
To github.com:johnmosesman/burner-repo.git
   b7f661f..6e36148  main -> main
 * [new branch]      my-feature -> my-feature

결론

git push 명령어는 자주 사용하는 명령어이며, 같이 사용할 수 있는 옵션이 매우 다양합니다. 유용한 옵션에 대해서 알고 싶으시다면 설명서 (영문)를 읽어보시기 바랍니다.

이 튜토리얼이 마음에 드셨다면, 제 트위터 계정사이트를 통해 이런 주제에 대한 글을 확인할 수 있습니다.