마루옵스서버 · 네트워크 · AI 기술 노트

소개문의

[Git·GitOps 07] 되돌리기 전에 고르는 명령: restore·reset·revert

키보드와 마우스가 놓인 작업대

참고 사진 · 키보드와 마우스가 놓인 작업대 · 사진: Jeff Sheldon ugmonk / 원본 / CC0 · 목록용 크기 조정

“취소하고 싶다”는 말만으로는 Git 명령을 고르기 어렵습니다. 아직 커밋하지 않은 파일을 돌릴지, 커밋을 다시 나눌지, 이미 공유한 변경을 상쇄할지부터 구분해야 해요. 대상이 다르면 같은 되돌리기라도 이력과 파일에 미치는 영향이 달라집니다.

연습은 폐기해도 되는 저장소에서 진행합니다. 특히 restore로 미커밋 변경을 버리거나 reset --hard를 실행하면 Git이 복구할 자료를 가지고 있지 않을 수 있습니다. 실행 전 status, diff, diff --staged를 확인합니다.

Git·GitOps 전체 연재 · 07 / 24

이 글의 목차

add만 취소하려면 restore –staged

git status --short
git diff --staged -- README.md
git restore --staged -- README.md
git diff -- README.md

커밋이 이미 하나 이상 있는 저장소에서 실행합니다. --staged는 기본적으로 HEAD 내용을 인덱스에 복원합니다. 작업 트리의 편집 내용은 남으므로 파일을 다시 고쳐서 스테이징할 수 있습니다.

반대로 아래 명령은 인덱스의 내용으로 작업 파일을 덮어씁니다. 버려도 되는 수정일 때만 사용합니다. --staged가 빠졌다는 차이가 중요합니다.

# Discards unstaged edits in this tracked file.
git diff -- README.md
git restore -- README.md

인덱스에 다른 내용이 있다면 HEAD가 아니라 그 인덱스 내용이 돌아옵니다. HEAD를 명시적으로 기준으로 삼으려면 --source=HEAD를 지정합니다. 소스와 목적지를 구분해 생각하면 옵션을 외우기 쉬워요.

내 로컬 커밋을 다시 나누려면 reset

아직 공유하지 않은 마지막 커밋을 다시 작성할 때 reset --soft HEAD~1을 사용할 수 있습니다. 현재 브랜치 위치를 부모로 이동하고 인덱스와 작업 트리는 유지합니다. 커밋이 두 개 이상이고, 다른 사람이 해당 커밋을 기반으로 작업하지 않는 상황을 전제로 합니다.

git status --short
git branch safety/before-reset
git reset --soft HEAD~1
git diff --staged
git commit -m "Rewrite the local change description"

안전 브랜치는 기존 커밋을 가리키는 이름입니다. 추적하지 않은 파일이나 커밋하지 않은 변경까지 보관하지는 않습니다. 필요한 미커밋 작업은 먼저 커밋하거나 별도 백업합니다.

모드인덱스작업 트리
--soft유지유지
--mixed·기본값대상 커밋으로 변경유지
--hard대상 커밋으로 변경대상 커밋으로 변경

이 표는 경로를 지정하지 않고 커밋으로 reset하는 경우입니다. --hard는 추적 파일의 미커밋 작업을 버리고, 추적 파일을 쓰는 데 방해되는 미추적 파일·폴더도 제거할 수 있습니다. “깨끗하게 만들기”용 기본 명령으로 사용하지 않습니다.

공유한 변경은 revert로 상쇄한다

이미 main에 합쳐서 푸시한 일반 커밋을 되돌리려면, 그 변경을 상쇄하는 새 커밋을 추가하는 revert를 우선 검토합니다. 기존 기록을 지우지 않아 다른 사람도 정상적인 푸시와 fetch로 따라올 수 있습니다.

git status --porcelain
git log --oneline -5
# Replace BAD_COMMIT with the non-merge commit to undo.
git revert BAD_COMMIT
# Run the project tests, then push the new revert commit.

다른 수정이 겹쳤다면 revert도 충돌할 수 있습니다. 해결 후 git add와 git revert --continue를 사용하거나 git revert --abort로 취소합니다. 병합 커밋의 revert에는 주 부모를 정하는 -m과 이후 재병합 영향이 있으므로 일반 커밋 예제를 그대로 적용하지 않습니다.

브랜치 위치를 잃었을 때의 reflog

git reflog --date=iso -15
# After inspecting the desired commit ID:
git branch rescue/work RECOVER_COMMIT

RECOVER_COMMIT은 실제 확인한 커밋 해시로 바꿉니다. reflog는 로컬 참조가 이동한 기록이며 원격 서버 전체의 감사 로그가 아닙니다. 만료나 객체 정리가 진행되면 찾을 수 없는 기록도 있고, 한 번도 커밋하거나 저장하지 않은 편집 내용의 복구를 보장하지 않습니다.

정확한 동작은 git restore, git reset, git revert, git reflog에서 확인할 수 있습니다. 되돌린 다음에는 파일뿐 아니라 테스트 결과까지 확인해야 변경을 마쳤다고 볼 수 있습니다.

이전 글 · [Git·GitOps 06] 이력 읽는 법: 커밋 그래프·HEAD·diff·bisect · 다음 글 · [Git·GitOps 08] 브랜치 만들고 합치기: switch·merge와 fast-forward · 연재 목록과 예제 파일

댓글

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다

닉네임·이메일·댓글 내용·IP 주소·브라우저 정보는 댓글 게시 및 관리에 사용됩니다. 이메일과 접속 정보는 공개 댓글에 표시하지 않습니다. 개인정보 요청은 운영자 이메일로 보내 주세요. 개인정보처리방침