잘못된 커밋·push 되돌리기
git revert reset 차이를 외우는 대신 '지금 어디까지 퍼졌는가' 한 가지로 고르는 판단표와, restore·reset·revert·reflog를 언제 쓰고 언제 쓰면 안 되는지 정리합니다.
Git에서 되돌리는 명령은 여러 개지만, 고르는 기준은 하나입니다. "이 실수가 지금 어디까지 퍼졌는가." 내 작업 폴더에만 있는지, 커밋했지만 아직 push 전인지, 이미 push했는지, 남이 벌써 받아 갔는지에 따라 쓸 수 있는 명령이 달라집니다.
이 글은 그 판단표를 먼저 세우고, restore·reset·revert·reflog 를 각각 언제 쓰고 언제 쓰면 안 되는지 정리합니다. 커밋과 PR을 만드는 평소 조작은 Git 조작 자동화에 있습니다.
핵심 요약
- 명령을 외우지 말고 "퍼진 범위"를 먼저 확인합니다. 범위가 명령을 정합니다.
- push 전이라면 이력을 고쳐도 됩니다. push 후에는 새 커밋으로 되돌리는 방법만 안전합니다.
reset --hard와 force push는 무언가를 확실히 없애는 명령입니다. 없어지는 대상이 무엇인지 먼저 말할 수 있어야 실행합니다.- 비밀값이 올라갔을 때는 이력 정리보다 키 폐기가 먼저입니다.
- 충돌 화면에서 한쪽을 기계적으로 수락하면 남의 작업이 오류 없이 사라집니다.
어디까지 퍼졌는지로 고른다
| 퍼진 범위 | 상황 예 | 쓸 명령 | 하면 안 되는 것 |
|---|---|---|---|
| 작업 디렉터리만 | 엉뚱한 파일을 고쳤다 | git restore <파일>, 스테이징했다면 git restore --staged <파일> | 확인 없이 전체에 적용 |
| 커밋했지만 push 전 | 메시지나 포함 파일이 틀렸다 | git commit --amend, git reset --soft HEAD~1 | 이미 push한 커밋에 같은 명령 적용 |
| 내 작업 브랜치에 push, 리뷰 전 | 커밋을 정리하고 싶다 | 되도록 새 커밋으로 수정. 꼭 필요하면 내 브랜치에만 --force-with-lease | 공유 브랜치에 force push |
| main에 머지됨 | 머지된 PR이 기능을 깨뜨렸다 | git revert 로 반대 변경 커밋 후 평소처럼 PR | main에 reset·force push |
| 비밀값이 push됨 | 키가 든 파일이 올라갔다 | 키 폐기·재발급 먼저, 그다음 제거 커밋 | 파일만 지우고 끝내기 |
이 표를 팀 문서에 그대로 옮겨 두면, 사고가 난 사람이 당황한 상태에서 검색하지 않고 한 줄을 짚을 수 있습니다.
작업 디렉터리만 바뀌었을 때 — restore
아직 커밋하지 않은 편집을 버리는 명령입니다.
git restore src/app.js # 마지막 커밋 상태로 파일을 되돌린다
git restore --staged src/app.js # 스테이징만 취소하고 편집은 남긴다첫 번째 명령은 그 파일의 저장하지 않은 편집 내용을 완전히 버립니다. 커밋도 스태시도 없었다면 Git 어디에도 남지 않아 되찾을 수 없습니다. 실행 전에 git diff 로 무엇이 사라지는지 한 번 보는 습관을 권합니다.
두 번째 명령은 안전합니다. 스테이징 영역에서만 빼기 때문에 편집한 내용은 그대로 있습니다. "실수로 git add . 를 해서 .env 까지 올라갈 뻔했다" 같은 상황에 씁니다.
커밋했지만 push 전 — reset의 세 가지 모드
reset 은 브랜치가 가리키는 위치를 뒤로 옮기는 명령입니다. 옮기면서 작업 내용을 어디까지 남기느냐가 세 모드의 차이입니다.
| 모드 | 커밋 | 스테이징 영역 | 작업 파일 |
|---|---|---|---|
--soft | 치워짐 | 변경 내용이 남음 | 그대로 |
--mixed(기본) | 치워짐 | 비워짐 | 그대로 |
--hard | 치워짐 | 비워짐 | 마지막 지점 상태로 덮어씀 |
git reset --soft HEAD~1 # 커밋만 취소, 변경은 스테이징에 남아 바로 다시 커밋 가능
git reset HEAD~1 # 커밋 취소, 변경은 파일에 남고 스테이징만 해제--soft 가 가장 자주 쓰입니다. 커밋 하나를 잘못 묶었을 때 이 명령으로 풀고 둘로 나눠 다시 커밋하면 됩니다. 메시지만 고칠 때는 git commit --amend 한 줄이 더 간단합니다.
--hard 는 다릅니다.
git reset --hard HEAD~1이 명령은 마지막 커밋과 함께, 커밋하지 않은 모든 편집을 지웁니다. 사라지는 것이 두 종류라는 점이 중요합니다. 커밋된 내용은 뒤에서 볼 reflog 로 되찾을 수 있지만, 커밋하지 않은 편집은 어디에도 기록이 없어 복구 불가입니다. 그래서 --hard 를 쓸 상황이라면 먼저 git stash 로 현재 편집을 대피시키거나, 임시 커밋을 하나 만들어 두는 편이 안전합니다.
그리고 이 세 모드 모두 push 전에만 쓰는 명령입니다. push한 커밋을 reset으로 치우면 내 이력과 원격 이력이 어긋나고, 그 상태를 맞추려면 force push밖에 남지 않습니다.
이미 push했을 때 — revert
revert 는 커밋을 지우지 않습니다. 그 커밋이 한 일의 반대 변경을 담은 새 커밋을 하나 더 쌓습니다.
git revert <되돌릴 커밋 해시>이력이 늘어나는 것이 단점처럼 보이지만, 공유된 브랜치에서는 이것이 장점입니다. 남의 로컬에 있는 커밋은 그대로 두고 앞쪽에 한 줄을 더 얹는 방식이라, 다른 사람은 평소처럼 pull만 하면 됩니다. GitHub PR 화면의 되돌리기 버튼도 같은 일을 하고, 결과를 PR로 만들어 주므로 리뷰 기록까지 남습니다.
revert도 충돌이 날 수 있습니다. 되돌릴 커밋 이후에 같은 자리를 누군가 또 고쳤다면, Git은 반대 변경을 어디에 적용할지 몰라 멈춥니다. 이때는 평소 충돌과 똑같이 해소하면 되고, 중간에 그만두려면 git revert --abort 로 되돌리기 전 상태로 돌아갑니다. 이 명령은 revert 작업만 취소하므로 원래 이력에는 영향이 없습니다.
머지 커밋을 되돌릴 때는 어느 쪽 변경을 반대로 적용할지 지정해야 합니다. squash merge로 통일한 팀이라면 PR 하나가 커밋 하나여서 이 고민이 없어집니다. 이 선택을 왜 팀 차원에서 통일하는지는 팀 Git·GitHub 협업 규칙에서 다룹니다.
공유 브랜치의 force push가 왜 남의 작업을 지우나
force push는 "원격의 이력을 내 이력으로 덮어쓴다"는 명령입니다. 상황을 순서대로 보면 왜 위험한지 분명해집니다.
동료가 오후에 커밋 세 개를 공유 브랜치에 올렸습니다. 나는 오전에 받아 둔 상태에서 작업했으니 내 로컬에는 그 세 개가 없습니다. 이 상태에서 내가 이력을 정리하고 force push하면, 원격의 브랜치 끝은 내 로컬 상태가 됩니다. 동료의 커밋 세 개는 어느 브랜치도 가리키지 않는 상태가 되어 목록에서 사라집니다. 동료의 PC에는 아직 남아 있지만, 동료가 그 사실을 모르고 pull하거나 다시 clone하면 그대로 없어집니다.
그래서 두 가지를 씁니다. 첫째, 공유 브랜치에는 force push 금지를 보호 규칙으로 걸어 둡니다. 조심하겠다는 약속보다 플랫폼의 거부가 확실합니다. 둘째, 내 개인 브랜치에서 꼭 이력을 고쳐야 할 때는 --force 대신 --force-with-lease 를 씁니다.
git push --force-with-lease origin feature/my-branch이 옵션은 "내가 마지막으로 본 원격 상태와 지금 원격 상태가 같을 때만 덮어쓴다"는 조건을 붙입니다. 그동안 누군가 무언가를 올렸다면 push가 거부되므로, 모르고 남의 커밋을 날리는 일을 막아 줍니다.
비밀값을 올렸다면 키 폐기가 먼저인 이유
파일을 지우고 이력까지 깨끗하게 정리하면 해결된 것처럼 보이지만, 그 사이에 값은 이미 여러 곳에 복제돼 있습니다. 다른 사람이 pull한 로컬 리포지터리, CI 실행 로그, 플랫폼의 캐시와 PR 화면, 알림 메일 본문까지 남을 수 있습니다. 이력을 지운다고 이 복제본들이 함께 사라지지는 않습니다.
그래서 순서를 고정합니다.
- 노출된 키를 즉시 폐기하고 새로 발급합니다. 이 단계만으로 노출의 피해가 끊깁니다.
- 리포지터리에서 파일을 제거하는 커밋을 만들고
.gitignore에 해당 경로를 추가합니다. - 새 키를 리포지터리가 아닌 환경 변수나 비밀 관리 도구에 넣습니다.
- 이력 재작성이 필요한지는 관리자가 판단합니다. 이력을 다시 쓰면 팀 전원이 다시 clone해야 하므로 영향이 큽니다.
팀에서는 이 순서를 사고 대응표에 "알릴 사람"까지 포함해 적어 둡니다. 혼자 조용히 처리하려다 폐기 단계를 건너뛰는 것이 가장 흔한 실수입니다. 이 대응 순서를 팀이 같은 기준으로 공유하는 실습은 1일 과정에서 다룹니다.
충돌 화면에서 조용히 사라지는 변경
충돌은 두 사람이 같은 자리를 서로 다른 의도로 고쳤다는 신호입니다. 에디터가 보여 주는 "현재 변경 수락"이나 "들어오는 변경 수락" 버튼은 편리하지만, 기계적으로 누르면 한쪽 의도가 통째로 버려집니다.
이 유실이 위험한 이유는 아무 오류도 나지 않는다는 점입니다. 문법이 맞고 테스트가 통과하면 그대로 머지되고, 몇 주 뒤에 "내가 고친 문장이 왜 원래대로 돌아가 있지"라는 질문으로 발견됩니다.
그래서 세 가지를 습관으로 둡니다. 충돌 해소는 코드 선택이 아니라 의도 합치기라고 보고 두 변경을 모두 살리는 결과를 직접 만듭니다. 해소한 뒤에는 원래 작성자 양쪽에게 결과를 확인받습니다. 그리고 JSON이나 목록 데이터처럼 구조가 있는 파일은 해소 후 반드시 검사 스크립트를 한 번 돌립니다. 배열 끝에 항목을 동시에 추가하는 충돌은 쉼표 하나가 빠져 파일이 깨지기 쉽습니다.
git status # 아직 해소되지 않은 파일 목록 확인
git diff --check # 충돌 표시가 남아 있는지 확인충돌 자체를 줄이는 쪽이 더 효과적입니다. 작업 시작 전 pull, 짧게 사는 브랜치, 같은 파일을 만질 때 미리 알리기, 정렬 규칙이 있는 데이터는 끝이 아니라 정해진 위치에 추가하기 정도로 대부분 줄어듭니다.
reflog로 되찾는 절차
reflog 는 내 로컬에서 HEAD가 지나온 위치를 시간순으로 적어 둔 기록입니다. 브랜치에서 떨어져 나간 커밋도 여기에는 남아 있어서, reset으로 치운 커밋을 되찾을 수 있습니다.
git reflog
# a1b2c3d HEAD@{0}: reset: moving to HEAD~1
# e4f5g6h HEAD@{1}: commit: feat: 공지 목록 정렬 추가 ← 되찾고 싶은 지점되돌아갈 지점을 찾았으면 그 위치에 브랜치를 새로 만듭니다. 현재 브랜치를 바로 옮기는 대신 새 브랜치를 만드는 쪽이 안전합니다. 잘못 짚었을 때 지금 상태를 잃지 않습니다.
git switch -c rescue e4f5g6h내용을 확인한 뒤 필요한 커밋만 원래 브랜치로 가져오면 됩니다. 두 가지 한계는 알아 둡니다. reflog는 내 로컬 기록이라 다른 PC에서 일어난 일은 없고, 기본 보존 기간이 지나면 정리됩니다. 그리고 앞서 말한 대로 커밋하지 않은 편집은 reflog에도 없습니다. 이것이 "일단 커밋은 자주"라는 조언의 실질적인 이유입니다.
자주 겪는 문제
| 상황 | 하기 쉬운 선택 | 안전한 선택 |
|---|---|---|
| push한 커밋을 지우고 싶다 | reset 후 force push | git revert 로 새 커밋 |
| 커밋을 잘못 묶었다 | reset --hard 로 전부 지우고 다시 | reset --soft 로 풀고 나눠 커밋 |
| 브랜치가 원격과 어긋난다 | --force 로 덮어쓰기 | 원격을 받아 합치거나 --force-with-lease |
| 키가 올라갔다 | 파일 삭제 커밋 | 키 폐기·재발급 먼저 |
| 충돌이 났다 | 한쪽 수락 버튼 | 두 의도를 합친 뒤 검사 실행 |
| 커밋을 날렸다 | 포기하고 다시 작업 | git reflog 로 지점 찾아 새 브랜치 |
정리
- 명령을 고르기 전에 "어디까지 퍼졌는가"를 한 번 확인합니다. 그 답이 명령을 정합니다.
- push 전이라면
restore·amend·reset --soft, push 후라면revert입니다. reset --hard와 force push는 무엇이 사라지는지 말할 수 있을 때만 실행합니다.- 비밀값은 키 폐기가 먼저, 이력 정리는 나중입니다.
- 이런 판단을 팀 전체가 같은 표로 공유하는 방법은 팀 Git·GitHub 협업 규칙에 있고, Claude Code가 파괴적 명령을 실행하지 못하게 막는 설정은 권한 설정과 하네스 엔지니어링 예시에서 다룹니다.
- 사고를 교실에서 먼저 내 보고 수습 절차를 팀 문서로 만들어 가는 실습은 기업 교육 1일 과정에 있습니다.
자주 묻는 질문
이 주제를 실습으로 다루는 교육
- B-9 팀 Git·GitHub 운용 실전브랜치 전략·PR 규칙·충돌 해결·잘못된 push 수습·Claude Code 공유 설정을 조별로 실제로과정 보기
- Claude Code 엔지니어 교육반나절 4시간부터 1일·회차제까지, 작동하는 산출물을 수료 기준으로과정 보기
우리 팀에 맞는 과정이 무엇인지 모르겠다면 커리큘럼 찾기로 4문항만 답하거나, 무료 상담 신청을 남겨 주세요.