Git Reset 과 Reflog 마스터하기

GitBeginner
지금 연습하기

소개

Git 시간 여행자 여러분, 환영합니다! 오늘은 저장소의 히스토리를 전례 없는 수준으로 제어할 수 있게 해주는 두 가지 강력한 기능인 git resetgit reflog를 살펴보겠습니다. 이 도구들은 Git 타임머신의 고급 제어 장치와 같아서, 프로젝트의 서로 다른 상태 사이를 이동하거나 심지어 "잃어버린" 작업까지 복구할 수 있게 해줍니다.

git reset 명령어는 변경 사항 취소, 파일 스테이징 해제, 커밋 히스토리 재작성 등 다양한 용도로 사용되는 다재다능한 도구입니다. 하지만 강력한 힘에는 큰 책임이 따르는 법이며, 초보자에게 git reset은 다소 위협적일 수 있습니다. 바로 이때 git reflog가 등장합니다. 이는 안전망과 같아서 브랜치 끝 (branch tips) 과 같은 저장소 참조 (refs) 에 발생한 모든 변경 사항을 기록하므로, 아무리 극단적인 리셋을 했더라도 다시 복구할 수 있도록 도와줍니다.

이 실습에서는 다음 내용을 다룹니다:

  1. Soft Reset: 작업 디렉토리나 스테이징 영역을 변경하지 않고 HEAD 위치만 이동하기
  2. Mixed Reset: 작업 디렉토리의 수정 사항은 유지하면서 스테이징만 해제하기
  3. Hard Reset: 모든 변경 사항을 완전히 삭제하기
  4. Reflog 를 사용하여 "파괴적인" 작업으로부터 복구하기
  5. 시간 기반 리셋: 특정 시점의 상태로 저장소 되돌리기

이 실습을 마칠 때쯤이면 이러한 강력한 Git 기능들을 안전하고 효과적으로 사용하는 방법을 확실히 이해하게 될 것입니다. 이제 필요할 때 언제든 이전 상태로 돌아갈 수 있다는 자신감을 가지고 저장소 히스토리를 자유롭게 다뤄보세요.

그럼 이제 git resetreflog를 마스터하러 떠나볼까요!

이 과정은 단계별 안내를 통해 학습과 실습을 돕는 가이드 랩 (Guided Lab) 입니다. 각 단계를 주의 깊게 따라가며 직접 경험을 쌓아보세요. 통계에 따르면 이 과정은 초급 수준이며, 98%의 수강생이 완료했습니다. 또한 학습자들로부터 100%의 긍정적인 평가를 받았습니다.

작업 공간 설정하기

리셋과 리플로그를 시작하기 전에, 실험해 볼 수 있는 몇 개의 커밋이 포함된 작업 공간을 만들어 보겠습니다. 새 디렉토리를 만들고 Git 저장소를 초기화한 다음, 여러 번의 커밋을 통해 파일을 추가하겠습니다.

터미널을 열고 다음 명령어들을 입력하세요:

cd ~/project
mkdir git-reset-lab
cd git-reset-lab
git init

이제 다음 명령어들을 터미널에 복사하여 붙여넣어 파일들을 생성하고 일련의 커밋을 만듭니다:

echo "## Git Reset and Reflog Lab" > README.md
git add README.md
git commit -m "Initial commit"

echo "function add(a, b) { return a + b; }" > math.js
git add math.js
git commit -m "Add addition function"

echo "function subtract(a, b) { return a - b; }" >> math.js
git add math.js
git commit -m "Add subtraction function"

echo "function multiply(a, b) { return a * b; }" >> math.js
git add math.js
git commit -m "Add multiplication function"

방금 수행한 작업의 내용은 다음과 같습니다:

  1. README 파일을 생성하고 첫 번째 커밋을 만들었습니다.
  2. 덧셈 함수가 포함된 JavaScript 파일을 생성하고 커밋했습니다.
  3. 같은 파일에 뺄셈 함수를 추가하고 커밋했습니다.
  4. 마지막으로 곱셈 함수를 추가하고 커밋했습니다.

이제 실험해 볼 수 있는 히스토리가 쌓인 저장소가 준비되었습니다!

Soft Reset: HEAD 이동하기

가장 먼저 살펴볼 리셋 유형은 "Soft" 리셋입니다. Soft 리셋은 HEAD(및 현재 브랜치) 를 다른 커밋으로 이동시키지만, 스테이징 영역이나 작업 디렉토리는 변경하지 않습니다. 이는 몇 개의 커밋을 "취소"하고 싶지만, 해당 변경 사항들을 그대로 유지하여 새로운 커밋으로 묶고 싶을 때 유용합니다.

Soft 리셋을 시도해 봅시다:

git reset --soft HEAD~2

이 명령어는 HEAD 를 두 단계 전 커밋 ("Add subtraction function" 이전 커밋) 으로 되돌립니다. ~2는 "현재 HEAD 로부터 두 단계 전 커밋"을 의미합니다. ~N 형식을 사용하여 N단계 전으로 돌아갈 수 있습니다.

이제 git status를 실행해 보면, "Add subtraction function"과 "Add multiplication function" 커밋에서 발생했던 변경 사항들이 한꺼번에 스테이징되어 있는 것을 볼 수 있습니다. 작업 디렉토리의 파일들은 전혀 변하지 않았습니다. 두 커밋의 모든 작업 내용이 이제 하나의 새로운 커밋으로 묶일 준비가 된 상태입니다.

이 방식은 최근의 여러 커밋을 하나로 합치는 "스쿼시 (squash)" 작업을 할 때 매우 유용합니다. 몇 단계 전으로 Soft 리셋을 한 뒤, 모든 변경 사항을 포함하여 새로운 커밋 메시지로 커밋하면 됩니다.

이제 이 변경 사항들을 새로운 메시지로 다시 커밋해 보겠습니다:

git commit -m "Add subtraction and multiplication functions"

주의할 점은, Soft 리셋이 변경 사항을 삭제하지 않으므로 일반적으로 안전하지만 히스토리를 재작성한다는 사실입니다. 이미 원격 저장소에 푸시된 커밋을 리셋했다면 원격 브랜치를 업데이트하기 위해 강제 푸시 (force push) 가 필요하며, 이는 협업자들에게 문제를 일으킬 수 있습니다. 공유된 히스토리를 수정하기 전에는 항상 팀원들과 소통하세요!

Mixed Reset: 스테이징 해제하기

다음으로 살펴볼 리셋 유형은 "Mixed" 리셋입니다. 이는 플래그를 지정하지 않았을 때 git reset의 기본 동작 모드입니다. Mixed 리셋은 HEAD 를 이동시키고 스테이징 영역을 그에 맞게 업데이트하지만, 작업 디렉토리는 건드리지 않습니다.

변경 사항을 만들고 스테이징해 보겠습니다:

echo "function divide(a, b) { return a / b; }" >> math.js
git add math.js

이제 마음이 바뀌어서 이 변경 사항을 아직 스테이징하고 싶지 않다고 가정해 봅시다. 이때 Mixed 리셋을 사용할 수 있습니다:

git reset HEAD

이 명령어는 스테이징을 해제하지만 작업 디렉토리의 변경 사항은 그대로 유지합니다. 지금 git status를 실행해 보면 math.js가 수정되었지만 스테이징되지는 않은 상태임을 확인할 수 있습니다.

Mixed 리셋은 변경 사항을 스테이징했지만 아직 커밋할 준비가 되지 않았다고 판단될 때 유용합니다. 스테이징을 하기 전에 코드를 다시 검토하거나 추가 수정을 하고 싶을 때 사용하세요.

Soft 리셋과 달리 Mixed 리셋은 스테이징 영역을 변경한다는 점을 기억하세요. 하지만 작업 디렉토리의 결과물은 삭제하지 않으므로 여전히 안전한 편에 속합니다.

Hard Reset: 변경 사항 폐기하기

세 번째이자 가장 극단적인 리셋 유형은 "Hard" 리셋입니다. Hard 리셋은 HEAD 를 이동시키고, 스테이징 영역을 업데이트하며, 작업 디렉토리까지 대상 커밋과 일치하도록 업데이트합니다. 즉, 리셋하려는 커밋 이후의 모든 변경 사항을 완전히 삭제합니다.

Hard 리셋을 시도해 봅시다:

git add math.js
git commit -m "Add division function"
git status
git reset --hard HEAD~1

위 과정은 나눗셈 함수를 스테이징하고 커밋한 뒤, 바로 이전 커밋으로 Hard 리셋을 수행하여 마지막 커밋을 "취소"하고 변경 사항을 완전히 버리는 과정입니다.

이제 math.js 파일을 확인해 보면 나눗셈 함수가 사라진 것을 볼 수 있습니다. 마치 코드를 작성한 적이 없는 것처럼 말이죠.

Hard 리셋은 강력하지만 위험합니다. 작업을 완전히 폐기하고 이전 상태에서 새로 시작하고 싶을 때 유용하지만, 변경 사항이 영구적으로 삭제될 수 있으므로 매우 주의해서 사용해야 합니다.

Hard 리셋을 실행하기 전에는 항상 올바른 커밋으로 리셋하는지 다시 한번 확인하세요. 확신이 서지 않는다면 Soft 나 Mixed 리셋을 사용하거나, 실험을 시작하기 전에 새 브랜치를 만들어 두는 것이 안전합니다.

Reflog 를 사용하여 손실된 커밋 복구하기

만약 나눗셈 함수를 삭제한 것이 실수였다는 것을 깨달았다면 어떻게 해야 할까요? 바로 이때 git reflog가 구원투수로 등장합니다. Reflog 는 로컬 저장소에서 HEAD 가 머물렀던 모든 위치의 기록입니다. 리셋과 같이 히스토리를 재작성하는 명령까지도 모두 기록하는 "슈퍼 히스토리"라고 할 수 있습니다.

Reflog 를 확인해 봅시다:

git reflog

리셋을 포함하여 최근에 수행한 모든 작업 목록이 표시될 것입니다. 각 항목에는 HEAD@{n} 형태의 식별자가 붙어 있습니다.

손실된 커밋을 복구하려면 Hard 리셋을 수행하기 전의 상태로 다시 리셋하면 됩니다:

git reset --hard HEAD@{1}

이 명령어는 마지막 작업 (여기서는 Hard 리셋) 을 수행하기 직전의 HEAD 상태로 되돌립니다.

이제 math.js를 확인해 보세요. 나눗셈 함수가 돌아온 것을 확인할 수 있습니다!

cat math.js
function add(a, b) { return a + b; }
function subtract(a, b) { return a - b; }
function multiply(a, b) { return a * b; }
function divide(a, b) { return a / b; }

Reflog 는 거의 모든 Git 사고로부터 복구할 수 있게 해주는 강력한 안전망입니다. 하지만 이 기록은 본인의 컴퓨터에만 로컬로 저장되며 일시적 (보통 30 일에서 90 일 동안 유지) 이라는 점을 명심하세요. 정기적인 백업이나 원격 저장소 푸시를 대신할 수는 없습니다.

시간 기반 리셋

Git 은 특정 시점의 상태로 저장소를 리셋하는 기능도 제공합니다. 저장소가 원하는 상태였던 대략적인 시간을 기억하고 있을 때 유용합니다.

시간 기반 리셋을 시도해 봅시다:

git reset --hard master@{"1 hour ago"}

이 명령어는 저장소를 1 시간 전의 상태로 되돌립니다. "yesterday", "2 days ago", "3 minutes ago" 등 다양한 시간 표현을 사용할 수 있습니다.

시간 기반 리셋은 특정 커밋으로 리셋하는 것보다 정밀도가 떨어질 수 있으므로 주의해야 합니다. 리셋 후에는 항상 저장소 상태를 확인하여 의도한 지점으로 돌아왔는지 확인하세요.

결과가 예상과 다르다면 언제든지 Reflog 를 사용하여 시간 기반 리셋을 취소할 수 있다는 점을 잊지 마세요.

요약

축하합니다, Git 시간의 지배자님! Git 에서 가장 강력하면서도 주의가 필요한 명령어들을 마스터하셨습니다. 오늘 배운 핵심 개념들을 정리해 보겠습니다:

  1. Soft Reset: 스테이징 영역이나 작업 디렉토리를 변경하지 않고 HEAD 만 이동합니다. 커밋 합치기 (Squashing) 에 유용합니다.
  2. Mixed Reset: HEAD 를 이동하고 스테이징 영역을 업데이트하지만, 작업 디렉토리는 유지합니다. 스테이징 해제에 적합합니다.
  3. Hard Reset: HEAD, 스테이징 영역, 작업 디렉토리를 모두 업데이트합니다. 강력하지만 파괴적일 수 있습니다.
  4. Reflog: HEAD 의 모든 변경 사항을 기록하는 안전망으로, 거의 모든 Git 실수로부터 복구할 수 있게 해줍니다.
  5. 시간 기반 리셋: 특정 시점의 상태로 저장소를 되돌릴 수 있게 해줍니다.

강력한 힘에는 큰 책임이 따릅니다. 이러한 명령어들은 저장소 히스토리를 완벽하게 제어할 수 있게 해주지만, 부주의하게 사용하면 위험할 수 있습니다. 리셋, 특히 Hard 리셋을 수행하기 전에는 항상 두 번 확인하고, 문제가 생겼을 때는 Reflog 가 여러분의 친구라는 사실을 기억하세요.

앞으로의 Git 여정에서 이 명령어들이 익숙해질 때까지 안전한 환경에서 충분히 연습해 보세요. 올바르게 사용한다면 여러분의 Git 워크플로우를 획기적으로 향상시켜 줄 강력한 도구가 될 것입니다.

즐거운 리셋 되시길 바라며, 여러분의 Git 히스토리가 항상 깔끔하고 의미 있게 유지되기를 바랍니다!