reset・revert・reflogの実習
한국어 원문으로 표시합니다.
목표
reset 세 모드, amend, revert, reflog 를 각각 독립된 저장소에서 실행해 결과를 비교하고, 상황별로 무엇을 써야 하는지 치트시트로 정리합니다. 산출물은 /root/gitx2/ 아래에 둡니다.
왜 중요한가
되돌리기 사고의 대부분은 명령을 몰라서가 아니라, 그 명령이 무엇까지 덮어쓰는지 모르고 실행해서 생깁니다. --soft 는 잃는 것이 없고, 기본값 --mixed 는 스테이징 상태만 잃으며, --hard 는 커밋되지 않은 모든 변경을 잃습니다. 위험도는 명령 이름이 아니라 "이 명령이 커밋되지 않은 변경을 덮어쓰는가"로 매겨야 합니다. 그리고 두 번째 축이 있습니다. 커밋이 이미 다른 사람의 저장소에 있다면 그 커밋을 없애는 모든 방법은 남의 이력을 깨뜨립니다. 그때는 이력을 고치는 대신 덧붙이는 것이 답입니다. 이 실습은 그 차이를 말이 아니라 커밋 개수와 파일 존재 여부로 확인시켜 줍니다.
단계
전역 git 신원이 없습니다. 저장소를 만들 때마다 로컬 user.email / user.name 을 설정해야 커밋이 됩니다.
/root/gitx2/mkrepo.sh를 만들고chmod +x합니다. 첫 인자($1)로 받은 경로에(없으면 만들고) 저장소를 초기화하고, 브랜치는main, 커밋 5개를 만듭니다. n번째 커밋은fn.txt(f1.txt … f5.txt)를 추가하고 제목은c1…c5입니다. 채점기는 임시 디렉터리에 이 스크립트를 실행해 확인하므로, 경로를 하드코딩하지 말고 반드시"$1"을 쓰세요./root/gitx2/amend에 스크립트로 저장소를 만들고, 마지막 커밋의 제목만c5 fixed로 바꿉니다. 커밋 수는 5개 그대로여야 하고, reflog 에 amend 기록이 남아야 하며, 바뀌기 전 해시와 현재 해시는 달라야 합니다./root/gitx2/soft에 저장소를 만들고 커밋 하나를 되돌립니다. 결과: 커밋 4개,f5.txt가 인덱스에 스테이징된 상태, 작업 트리에도f5.txt존재./root/gitx2/mixed에 저장소를 만들고 커밋 하나를 되돌립니다. 결과: 커밋 4개,f5.txt가 스테이징돼 있지 않고, 작업 트리에는 남아 있어야 합니다(git status --porcelain에서??또는M)./root/gitx2/hard에 저장소를 만들고 커밋 하나를 되돌립니다. 결과: 커밋 4개,f5.txt가 사라지고,f4.txt는 남아 있으며, 작업 트리가 완전히 깨끗해야 합니다./root/gitx2/revert에 저장소를 만들고c3커밋의 변경만 상쇄합니다. 결과: 커밋 6개, 제목이Revert로 시작하는 커밋 존재, 원래의c3커밋도 이력에 그대로 남아 있을 것,f3.txt는 사라지고f1/f2/f4/f5.txt는 남아 있을 것./root/gitx2/reflog에 저장소를 만듭니다. 되돌리기 전에 현재 HEAD 해시를/root/gitx2/before.txt에 저장합니다(파일에는 해시 문자열만 있어야 합니다). 그다음 커밋 2개를 강제로 날렸다가, 참조 로그를 보고 원래 위치로 복구합니다. 결과: HEAD 가 기록해 둔 해시와 같고 커밋은 5개, reflog 에 reset 기록이 남아 있어야 합니다./root/gitx2/undo.md에 치트시트를 씁니다. 본문에--soft,--mixed,--hard,revert,reflog가 모두 등장해야 하고, 아래 세 줄이 있어야 합니다.pushed=— 이미 푸시해서 다른 사람이 받아 간 커밋을 되돌릴 때 쓸 명령 (한 단어)staging_only=— 스테이징만 풀고 파일은 남기는 reset 옵션worktree_wiped=— 커밋되지 않은 변경까지 날리는 reset 옵션
참고
- 스크립트 뼈대:
mkdir -p "$1"→git -C "$1" init -q -b main→git -C "$1" config user.email ...→ 반복문으로 파일 생성·git add·git commit -m "c$i". - 해시 저장:
git rev-parse HEAD > /root/gitx2/before.txt로 하면 해시만 들어갑니다.git log출력을 그대로 넣으면 형식 검사에서 걸립니다. - 잃어버린 커밋 찾기:
git reflog에서HEAD@{1}같은 표기를 쓰거나 왼쪽에 보이는 해시를 그대로 씁니다. - 흔한 실수 1: 3~5단계를 같은 저장소에서 이어서 하는 것. 각 단계는 별도 디렉터리에서 깨끗한 상태로 시작해야 합니다.
- 흔한 실수 2: 6단계에서
git reset을 쓰는 것. 커밋 수가 줄어들면 실패합니다. revert 는 과거를 지우지 않고 반대 커밋을 하나 더 쌓습니다. git revert는 편집기를 열 수 있습니다.--no-edit를 붙이면 그대로 진행됩니다.
저장소 생성 스크립트 만들기
/root/gitx2/mkrepo.sh 를 만들고 chmod +x 합니다. 첫 인자($1)로 받은 경로에(없으면 만들고) 저장소를 초기화하고, 브랜치는 main, 커밋 5개를 만듭니다. n번째 커밋은 fn.txt(f1.txt … f5.txt)를 추가하고 제목은 c1 … c5 입니다. 채점기는 임시 디렉터리에 이 스크립트를 실행해 확인하므로, 경로를 하드코딩하지 말고 반드시 "$1" 을 쓰세요.
/root/gitx2/mkrepo.sh 는 첫 인자로 받은 경로에 저장소를 새로 만듭니다. 경로가 아직 없을 수도 있으니 먼저 만들어야 하고, 전역 신원이 없으므로 저장소마다 로컬 신원을 설정해야 커밋이 됩니다. chmod +x 를 잊지 마세요.
마지막 커밋 메시지 고치기
/root/gitx2/amend 에 스크립트로 저장소를 만들고, 마지막 커밋의 제목만 c5 fixed 로 바꿉니다. 커밋 수는 5개 그대로여야 하고, reflog 에 amend 기록이 남아야 하며, 바뀌기 전 해시와 현재 해시는 달라야 합니다.
/root/gitx2/amend 에 저장소를 찍어 내고 마지막 커밋의 제목만 바꿉니다. amend 는 커밋 수를 늘리지 않지만 새 커밋 객체를 만들기 때문에 해시가 달라지고, 이전 해시는 reflog 에 남습니다.
커밋만 풀고 스테이징은 남기기
/root/gitx2/soft 에 저장소를 만들고 커밋 하나를 되돌립니다. 결과: 커밋 4개, f5.txt 가 인덱스에 스테이징된 상태, 작업 트리에도 f5.txt 존재.
/root/gitx2/soft 에서 커밋 하나를 되돌리되 변경 내용이 인덱스에 그대로 남아야 합니다. 세 모드 중 잃는 것이 아무것도 없는 모드입니다.
인덱스까지 되돌리기
/root/gitx2/mixed 에 저장소를 만들고 커밋 하나를 되돌립니다. 결과: 커밋 4개, f5.txt 가 스테이징돼 있지 않고, 작업 트리에는 남아 있어야 합니다(git status --porcelain 에서 ?? 또는 M).
/root/gitx2/mixed 에서 커밋을 되돌리되 스테이징은 풀리고 파일은 작업 트리에 남아야 합니다. 옵션을 붙이지 않았을 때의 기본 동작이 바로 이것입니다.
작업 트리까지 되돌리기
/root/gitx2/hard 에 저장소를 만들고 커밋 하나를 되돌립니다. 결과: 커밋 4개, f5.txt 가 사라지고, f4.txt 는 남아 있으며, 작업 트리가 완전히 깨끗해야 합니다.
/root/gitx2/hard 에서 커밋과 함께 파일도 사라져야 합니다. 커밋되지 않은 변경을 덮어쓰는 유일한 모드이므로 실행 전에 항상 한 번 더 생각해야 합니다.
이력을 남기며 되돌리기
/root/gitx2/revert 에 저장소를 만들고 c3 커밋의 변경만 상쇄합니다. 결과: 커밋 6개, 제목이 Revert 로 시작하는 커밋 존재, 원래의 c3 커밋도 이력에 그대로 남아 있을 것, f3.txt 는 사라지고 f1/f2/f4/f5.txt 는 남아 있을 것.
/root/gitx2/revert 에서 중간 커밋 하나의 변경만 상쇄합니다. 이력이 줄어들면 안 되고 오히려 커밋이 하나 늘어야 합니다. 이미 다른 사람에게 간 커밋에는 이 방법만 안전합니다.
잃어버린 커밋 되찾기
/root/gitx2/reflog 에 저장소를 만듭니다. 되돌리기 전에 현재 HEAD 해시를 /root/gitx2/before.txt 에 저장합니다(파일에는 해시 문자열만 있어야 합니다). 그다음 커밋 2개를 강제로 날렸다가, 참조 로그를 보고 원래 위치로 복구합니다. 결과: HEAD 가 기록해 둔 해시와 같고 커밋은 5개, reflog 에 reset 기록이 남아 있어야 합니다.
/root/gitx2/reflog 에서 되돌리기 전 해시를 먼저 파일에 적어 두고, 일부러 커밋을 날린 뒤 참조 로그를 보고 그 위치로 되돌아옵니다. before.txt 에는 해시 문자열만 있어야 합니다.
상황별 치트시트 정리
/root/gitx2/undo.md 에 치트시트를 씁니다. 본문에 --soft, --mixed, --hard, revert, reflog 가 모두 등장해야 하고, 아래 세 줄이 있어야 합니다.
pushed=— 이미 푸시해서 다른 사람이 받아 간 커밋을 되돌릴 때 쓸 명령 (한 단어)staging_only=— 스테이징만 풀고 파일은 남기는 reset 옵션worktree_wiped=— 커밋되지 않은 변경까지 날리는 reset 옵션
/root/gitx2/undo.md 에 세 모드와 revert, reflog 를 모두 언급하고 pushed= / staging_only= / worktree_wiped= 세 줄로 상황별 정답을 적습니다. 이미 푸시한 커밋에는 이력을 고치는 명령을 쓰지 않습니다.