Git에서 로컬 및 원격 커밋을 안전하게 되돌리는 방법

reset, revert, reflog, force-with-lease를 사용하여 작업 손실이나 공유 브랜치 손상 없이 Git 커밋을 안전하게 되돌리는 방법

Git에서 로컬 및 원격 커밋을 안전하게 되돌리는 방법

Git 커밋을 되돌리는 것은 쉽습니다. 올바른 것을 되돌리면서 작업을 잃지 않고 브랜치의 다른 사람들을 놀라게 하지 않는 것이 판단이 필요한 부분입니다.

첫 번째 질문은 "어떤 명령을 실행해야 하나?"가 아닙니다. "이 커밋을 누가 보았는가?"입니다. 커밋이 노트북에만 존재한다면 보통 git reset이나 git commit --amend로 다시 쓸 수 있습니다. 커밋이 이미 다른 사람들이 사용하는 브랜치에 푸시되었다면 git revert를 사용하는 것이 좋습니다. 이렇게 하면 기록이 그대로 유지되고 잘못된 변경을 되돌리는 새 커밋이 생성됩니다.

기록을 건드리기 전에 현재 상태의 스냅샷을 빠르게 찍으세요:

git status
git branch backup-before-undo
git log --oneline --decorate -5

임시 브랜치는 저렴한 보험입니다. 너무 많이 리셋하거나 마음이 바뀌어도 이전 커밋에 이름이 남아 있습니다.

커밋이 푸시되지 않은 경우

푸시하지 않은 로컬 커밋의 경우 git reset이 일반적으로 가장 깔끔한 도구입니다. 브랜치 포인터를 뒤로 이동시킵니다. 선택한 모드에 따라 파일에 어떤 일이 발생하는지 결정됩니다.

커밋 메시지가 잘못되었거나 작은 파일 하나를 잊어버린 경우 --soft를 사용하세요:

git reset --soft HEAD~1

마지막 커밋은 사라지지만 변경 사항은 스테이징된 상태로 유지됩니다. 누락된 파일을 추가하고 다시 커밋할 수 있습니다:

git add missing-file.yml
git commit -m "배포 설정 업데이트"

변경 사항을 작업 트리에 언스테이징된 상태로 되돌리려면 기본 혼합 리셋을 사용하세요:

git reset HEAD~1

이것은 일상적인 "이 커밋을 취소하지만 내 편집 내용은 유지" 명령입니다. 하나의 커밋이 실제로 두 개의 작은 커밋이 되어야 할 때나 실제 코드와 함께 디버깅 출력문을 커밋했을 때 유용합니다.

로컬 변경 사항을 정말로 버리려는 경우에만 --hard를 사용하세요:

git reset --hard HEAD~1

이것은 추적된 파일을 이전 커밋으로 재설정합니다. 당신이 의도했는지 정중하게 묻지 않습니다. 추적된 파일에 커밋되지 않은 작업이 있으면 작업 트리에서 사라질 수 있습니다. 먼저 git status를 확인하고, 다시 가져오고 싶은 것은 스태시하거나 브랜치를 만드세요.

가장 최근 로컬 커밋의 작은 수정에는 git commit --amend가 리셋보다 더 나은 경우가 많습니다:

git add corrected-file.js
git commit --amend

이것은 마지막 커밋을 새 커밋으로 대체합니다. 같은 규칙이 적용됩니다: 푸시하기 전에는 자유롭게 수정하고, 푸시 후에는 조심하세요.

커밋이 이미 푸시된 경우

공유 브랜치에서는 기록을 다시 써야 할 강력한 이유가 없는 한 git revert를 사용하세요. Revert는 반대 패치를 적용하는 새 커밋을 만듭니다.

git revert a1b2c3d

이 명령은 생성된 메시지와 함께 편집기를 엽니다. 저장하면 Git이 새 커밋을 만듭니다. 원래 커밋은 기록에 남아 있으며, 이는 main, master, develop, 릴리스 브랜치 및 팀원이 풀했을 수 있는 모든 브랜치에서 정확히 원하는 것입니다.

여러 개의 연속된 커밋을 되돌려야 하는 경우 한 번에 스테이징된 배치로 수행할 수 있습니다:

git revert --no-commit HEAD~3..HEAD
git status
git commit -m "최근 배포 변경 사항 되돌리기"

범위를 주의 깊게 읽으세요. HEAD~3..HEADHEAD~3 자체를 포함하지 않고 마지막 세 개의 커밋을 의미합니다. 확실하지 않으면 먼저 커밋을 나열하세요:

git log --oneline HEAD~3..HEAD

병합 커밋은 추가 결정이 하나 더 필요합니다. 병합에는 둘 이상의 부모가 있으므로 Git은 어느 쪽을 메인라인으로 처리해야 하는지 알아야 합니다:

git revert -m 1 <merge-commit-sha>

대부분의 팀은 대상 브랜치에서 기능 브랜치 병합을 되돌릴 때 -m 1을 사용하지만, 맹목적으로 실행하지 마세요. git show --summary <sha>로 병합 커밋을 확인하고 부모 순서를 확인하세요.

잘못된 것을 푸시했고 제거해야 하는 경우

때로는 revert만으로 충분하지 않습니다. 비밀, 거대한 바이너리 또는 개인 고객 데이터를 푸시했다면 revert는 최신 트리에서만 제거합니다. 민감한 내용은 여전히 기록에 존재합니다. 이것은 Git 정리 문제가 아니라 사고 대응 문제가 됩니다.

비밀의 경우 먼저 자격 증명을 교체하세요. 그런 다음 git filter-repo, BFG Repo-Cleaner 또는 호스트별 비밀 제거 프로세스와 같은 적절한 기록 재작성 도구를 사용하여 기록에서 데이터를 제거하세요. 저장소 소유자와 조정하고, 액세스 권한이 있는 사람이 제거하기 전에 잘못된 커밋을 가져갔을 수 있다고 가정하세요.

자신의 기능 브랜치에서 일반적인 잘못된 커밋의 경우 원격 브랜치를 다시 쓰는 것이 허용될 수 있습니다. 로컬에서 리셋한 다음 리스와 함께 강제 푸시하세요:

git reset --hard HEAD~1
git push --force-with-lease origin my-feature-branch

--force-with-lease는 마지막 페치 이후 다른 사람이 새 작업을 푸시한 경우 원격 업데이트를 거부하기 때문에 더 안전한 형태입니다. 여전히 강제 푸시입니다. 여전히 브랜치를 다시 씁니다. 개인 또는 조정된 기능 브랜치에서 사용하고, 공유 브랜치에서 무심코 사용하지 마세요.

강제 푸시 전에 좋은 습관은:

git fetch origin
git log --oneline --left-right --graph origin/my-feature-branch...my-feature-branch

이것은 원격에만 존재하는 것과 로컬에만 존재하는 것을 보여줍니다. 왼쪽에 다른 사람의 커밋이 있으면 멈추고 그들과 상의하세요.

reflog로 복구하기

git reflog는 많은 나쁜 오후를 구해주는 명령입니다. 로컬 HEAD와 브랜치 참조가 최근에 가리켰던 위치를 기록합니다. 잘못된 위치로 리셋했거나, 브랜치를 삭제했거나, 잘못된 커밋을 수정했다면 reflog는 종종 이전 커밋 SHA를 알고 있습니다.

git reflog

다음과 같은 내용이 보일 수 있습니다:

7cc8a91 HEAD@{0}: reset: moving to HEAD~1
2b41f0d HEAD@{1}: commit: deploy 단계에 재시도 추가

이전 커밋을 복구하려면 그 위치에 브랜치를 만드세요:

git branch recovered-deploy-work 2b41f0d

즉시 다른 하드 리셋을 실행하는 대신 브랜치를 만드는 것을 선호합니다. 안정적인 핸들을 제공하고 복구된 작업을 침착하게 검사할 수 있습니다:

git show recovered-deploy-work
git switch recovered-deploy-work

Reflog는 로컬입니다. 팀원의 reflog에는 당신이 잃어버린 로컬 커밋이 포함되지 않으며, 원격 호스트는 동일한 복구 경로를 노출하지 않을 수 있습니다. 또한 Git의 가비지 컬렉션 설정에 따라 시간이 지나면 정리되므로, 아카이브 저장소가 아닌 최근 안전망으로 취급하세요.

실용적인 결정 가이드

너무 일찍 커밋했고 푸시하지 않은 경우 git reset --soft HEAD~1 또는 git reset HEAD~1을 사용하세요.

잘못된 파일을 커밋했고 편집 내용을 로컬에서 제거하려는 경우 git status를 확인한 후에만 git reset --hard HEAD~1을 사용하세요.

잘못된 커밋이 이미 공유 브랜치에 있는 경우 git revert <sha>를 사용하세요.

기능 브랜치가 원격에 있지만 당신만 사용하는 경우 git resetgit push --force-with-lease가 일반적으로 허용됩니다.

커밋에 비밀 또는 민감한 데이터가 포함된 경우 revert에 의존하지 마세요. 비밀을 교체하고, 적절한 도구로 기록을 다시 쓰고, 정리를 조정하세요.

가장 안전한 Git 되돌리기 워크플로는 지루합니다: 먼저 검사하고, 백업 브랜치를 만들고, 커밋이 공유되었는지에 따라 명령을 선택하고, 자신의 복구 시도에서 복구해야 할 때 reflog를 사용하세요.