HOWTO · Git

Git 푸시 --force-with-lease 대 Git 푸시 --force

이 기사에서는 git push --force-with-lease 및 git push --force 명령의 차이점에 대해 설명합니다.

이 페이지의 내용

리베이스나 amend로 이미 공개한 커밋을 변경하면, 원격 브랜치가 로컬 브랜치에서 더 이상 fast-forward되지 않아 일반 push가 거부될 수 있습니다. git push --force와 git push --force-with-lease는 모두 원격 브랜치의 끝 커밋을 바꿀 수 있습니다. 차이는 업데이트 전에 Git이 예상한 원격 값을 확인하는지 여부입니다. 의도적으로 이력을 다시 쓸 때는 lease 방식을 우선 사용하고, push가 거부되면 원격 브랜치를 살펴보고 변경 사항을 조정하세요.

git push --force의 작동 방식

일반 push는 브랜치를 앞으로 이동시키는 업데이트만 허용해 원격 커밋을 보호합니다. git push --force는 push 대상 ref에 적용되는 이 보호를 해제합니다. 지정한 커밋으로 원격 브랜치를 설정하므로, 원격 브랜치에서 일부 커밋이 보이지 않게 될 수 있습니다. 동료가 push한 작업을 아직 반영하지 않았다면, 그 작업은 브랜치에서 도달할 수 없는 상태가 될 수 있습니다.

이 명령의 적용 범위는 대상에 따라 정해집니다. 예를 들어 git push --force origin feature는 origin의 feature 브랜치를 대상으로 합니다. 브랜치 이름을 명확히 지정하지 않으면 영향을 받는 ref를 알아보기 어려울 수 있습니다. 브랜치 이력을 바꾸는 것이 의도된 일이고 해당 브랜치를 사용하는 사람들과 조율한 경우에만 force push를 사용하세요. force push는 병합 충돌을 만들거나 원격 커밋을 대신 합쳐 주지 않습니다.

git push --force-with-lease의 작동 방식

git push --force-with-lease origin feature도 fast-forward가 아닌 업데이트를 허용하지만, 먼저 원격 브랜치에 예상한 값이 아직 있는지 확인합니다. 일반적인 형태에서 Git은 origin/feature와 같은 로컬 원격 추적 ref를 기준으로 예상값을 정합니다. 서버의 브랜치 값이 다르면 이를 덮어쓰는 대신 업데이트를 거부합니다.

이 확인은 유용하지만, 다른 사람이 내가 보지 못한 작업을 push하지 않았다는 증거는 아닙니다. 마지막으로 검토한 뒤 백그라운드 fetch가 origin/feature를 갱신했다면, 기본 lease는 새로 가져온 값을 기준으로 이력을 다시 쓰는 업데이트를 허용할 수 있습니다. 예상 객체 ID를 명시하면 비교 대상을 분명히 지정할 수 있습니다. 예: git push --force-with-lease=refs/heads/feature:<expected-object-id> origin HEAD:refs/heads/feature. 팀 작업 절차에 따라 예상값을 확보하고 검토하세요. 그 값이 무엇을 가리키는지 확인하지 않은 채 ID를 복사하지 마세요.

이력을 다시 쓴 뒤 --force-with-lease 사용하기

공유 브랜치가 A---B---C였고, 동료가 C 위에 D를 추가한 동안 내가 로컬 작업을 리베이스해 A---B---C'를 만들었다고 가정해 봅시다. 이제 로컬의 C'와 원격의 D는 서로 다른 끝 커밋을 가리킵니다. 예상한 원격 상태가 여전히 C일 때 lease는 D를 알아차리지 못한 채 덮어쓰는 일을 막기 위한 장치입니다.

먼저 브랜치를 살펴보고 원격의 최신 상태를 가져오세요. 그런 다음 동료의 커밋을 다시 쓴 이력에 포함할지 결정합니다. 가져온 브랜치 위로 작업을 리베이스하거나, 팀과 다른 통합 방법을 조율할 수 있습니다. 이력을 조정하고 검토한 다음 lease를 사용해 의도한 결과를 push하세요. lease가 push를 거부하면 다시 fetch하고 살펴보세요. 곧바로 --force로 재시도하지 마세요.

다음 독립 실행형 예제는 로컬 브랜치를 만들고 임시 bare 저장소에 게시한 뒤, 브랜치 끝을 amend하고 lease를 사용해 업데이트합니다.

set -e
root="$(mktemp -d)"
trap 'rm -rf "$root"' EXIT

git init --bare "$root/remote.git" >/dev/null 2>&1
git init -b feature "$root/work" >/dev/null 2>&1
cd "$root/work"
git config user.name "Example Developer"
git config user.email "developer@example.com"
printf 'first version\n' > README.md
git add README.md
git commit -m "Add first version" >/dev/null 2>&1
git remote add origin "$root/remote.git"
git push -u origin feature >/dev/null 2>&1
git commit --amend -m "Rewrite first version" >/dev/null 2>&1
git push --force-with-lease origin feature >/dev/null 2>&1

경로는 임시로 생성되며 스크립트가 종료될 때 테스트용 저장소를 삭제합니다. 실제 저장소에서는 공유 이력을 바꾸기 전에 커밋을 확인하고 동료들과 조율하세요.

force push 옵션을 안전하게 선택하기

협업자가 없는 개인 브랜치라면 원격 브랜치 끝을 바꾸려는 것이 의도된 경우 직접 force push를 사용할 수 있습니다. 공유 브랜치에서는 예상한 원격 상태를 검토하고 이력 변경을 조율한 뒤 --force-with-lease를 선택하세요. 공유 브랜치의 이력을 다시 쓰지 않아도 된다면 pull request나 다른 검토 절차를 우선 고려하세요.

원격과 브랜치를 명확히 지정하고, 결정하기 전에 fetch한 다음 push 전에 커밋 그래프를 검토하세요. lease 거부는 안전을 위한 신호입니다. 로컬 브랜치와 fetch한 원격 브랜치를 비교하고 필요한 커밋을 보존한 뒤, 각 커밋을 어떻게 반영할지 결정하고 나서 재시도하세요. 정기적으로 동기화하면 예상치 못한 상황을 줄일 수 있지만, push할 이력을 검토하는 일을 대신하지는 않습니다.

커밋 손실 복구 또는 예방하기

force push로 브랜치 끝의 커밋이 사라졌다면 정리 작업을 더 하지 말고 남아 있는 참조를 찾아보세요. 로컬 클론의 git reflog에서 최근 브랜치 위치를 확인할 수 있습니다. 동료의 클론, 원격 백업 또는 호스팅 제공자의 복구 기능에도 해당 커밋이 남아 있을 수 있습니다. 커밋을 찾았다면 복원하거나 통합하는 방법을 결정하기 전에 그 커밋을 가리키는 브랜치를 만드세요. reflog 항목은 만료되고 로컬에만 있으므로 복구를 보장할 수는 없습니다.

손실을 예방하려면 공유 브랜치의 이력을 다시 쓸 수 있는 사람을 정하고, 업데이트 전에 동료들에게 알리며, 검토를 위해 이력 변경을 보존해야 할 때는 기준이 되는 참조를 남겨 두세요. lease는 우발적인 덮어쓰기의 한 유형을 줄여 주고, 명확한 조율과 검증된 복구 지점은 lease가 감지하지 못하는 위험에 대비하도록 돕습니다.

FAQ

git push --force와 git push --force-with-lease의 차이는 무엇인가요? 전자는 현재 원격 ref 값을 확인하지 않고 교체합니다. 후자는 예상값을 확인하고 원격 값이 일치하지 않으면 업데이트를 거부합니다.

git push --force를 사용해도 되는 경우는 언제인가요? 대상 브랜치 끝을 바꾸려는 것이 의도된 일이고, 어떤 커밋이 브랜치에서 사라질 수 있는지 이해하며, 영향을 받는 동료들과 조율한 경우에만 사용하세요. 공유 작업에서는 lease를 우선 사용하고 예상 상태를 확인하세요.

공유 브랜치에서 force push를 하면 위험한가요? 브랜치에서 커밋이 보이지 않게 되고 동료의 작업에 지장을 줄 수 있습니다. lease는 원격 값이 예상값과 다를 때 도움이 되지만, 검토하지 않은 fetch로 기본 예상값이 바뀔 수 있습니다.

충돌이나 예상치 못한 상황을 줄이려면 어떻게 해야 하나요? 원격을 fetch하고 확인한 뒤, 필요한 경우 동료의 커밋을 다시 쓴 이력에 통합하세요. 계획을 알리고 공유 변경에는 검토 절차를 활용하세요.

force push를 되돌릴 수 있나요? 자동으로 되돌리는 방법은 없습니다. reflog, 다른 클론 또는 제공자의 복구 기능에서 이전 커밋을 찾을 수 있다면 참조를 만든 뒤 복원 방법을 조율할 수 있습니다. 복구 가능 여부는 해당 커밋을 가리키는 참조가 남아 있는지에 따라 달라집니다.