본문 바로가기
개발/트러블슈팅

Git restore와 reset 비교: 수정 파일과 스테이징 되돌리기

by char_lie 2026. 9. 12.
반응형

Git restore와 reset이 작업 파일과 스테이징 영역에 미치는 차이를 비교한 표지

 

git restore를 실행했는데 마지막 커밋 내용으로 돌아가지 않는 경우가 있다. 기본 복원 원본이 마지막 커밋인 HEAD가 아니라 스테이징 영역인 인덱스이기 때문이다.

커밋에 넣을 대상만 빼려면 git restore --staged를 사용한다. 작업 파일의 수정까지 없애는 동작과 구분해야 한다. 경로를 지정한 git reset HEAD -- 파일도 인덱스를 HEAD 내용으로 돌리지만 작업 파일은 유지한다.

HEAD·인덱스·작업 파일을 다르게 만들기

HEAD는 현재 커밋, 인덱스는 다음 커밋에 들어갈 내용, 작업 트리는 디스크에서 편집하는 파일이다. 같은 파일이 세 위치에서 서로 다른 내용을 가질 수 있다.

다음 코드는 Git 2.55.0과 Bash에서 검증했다. 별도 임시 저장소를 만들며, 이후 블록은 같은 터미널에서 순서대로 실행한다. 마지막 예제는 커밋하지 않은 수정을 없애므로 실제 작업 저장소에 그대로 실행하지 않는다.

restore_demo="$(mktemp -d)"
cd "$restore_demo"
git init -q

printf 'A\n' > note.txt
git add note.txt
git -c user.name=Demo -c user.email=demo@example.invalid commit -qm base

printf 'B\n' > note.txt
git add note.txt
printf 'C\n' > note.txt

git show HEAD:note.txt  # A: 마지막 커밋
git show :note.txt      # B: 인덱스
cat note.txt           # C: 작업 파일

처음 커밋에는 A를 저장했다. B를 작성해 git add한 뒤 파일만 C로 바꿨으므로, 지금 커밋하면 B가 들어간다. git diff는 B와 C, git diff --cached는 A와 B의 차이를 보여준다.

기본 restore는 인덱스에서 작업 파일로 복원한다

git restore -- note.txt
git show HEAD:note.txt  # A
git show :note.txt      # B
cat note.txt           # B

작업 파일의 C가 B로 바뀌었다. 스테이징해 둔 B는 그대로다. 기본 git restore -- 파일은 인덱스를 바꾸거나 커밋을 이동하지 않는다. 아직 add하지 않은 수정 C가 사라진다는 점이 중요하다.

파일 경로 앞의 --는 뒤 인수를 옵션이 아닌 경로로 구분한다. 예제처럼 대상 파일을 명시하면 작업 범위도 확인하기 쉽다.

다시 작업 파일만 C로 만든 뒤 스테이징을 해제해 보자.

printf 'C\n' > note.txt
git restore --staged -- note.txt
git show HEAD:note.txt  # A
git show :note.txt      # A
cat note.txt           # C

--staged만 지정하면 복원 대상은 인덱스이고, 기본 원본은 HEAD다. 따라서 B 대신 A가 스테이징되지만 작업 파일의 C는 유지된다. 기존 추적 파일이기 때문에 파일 자체를 추적에서 제외한 것이 아니다.

경로를 지정한 reset과 비교하기

먼저 인덱스 B와 작업 파일 C를 다시 만든다. 이번에는 경로를 지정한 reset을 실행한다.

printf 'B\n' > note.txt
git add note.txt
printf 'C\n' > note.txt

git reset -q HEAD -- note.txt
git show HEAD:note.txt  # A
git show :note.txt      # A
cat note.txt           # C

이 형태의 결과는 앞의 git restore --staged -- note.txt와 같다. HEAD의 파일 내용을 인덱스로 가져오며, 작업 파일은 바꾸지 않고 현재 브랜치의 커밋도 이동하지 않는다.

명령 형태 복원 원본 바뀌는 곳
git restore -- note.txt 인덱스 작업 파일
git restore --staged -- note.txt HEAD 인덱스
git reset HEAD -- note.txt HEAD 인덱스
git restore --source=HEAD --staged --worktree -- note.txt HEAD 인덱스와 작업 파일

여기서 비교한 것은 경로를 지정한 reset이다. 커밋을 대상으로 브랜치를 옮기는 git reset --soft나 git reset --hard와 같은 동작으로 묶으면 안 된다. 파일의 스테이징 해제에 커밋 이동을 끌어들일 필요는 없다.

수정까지 버릴 때는 원본과 대상을 모두 적기

다음 명령은 예제 파일의 인덱스와 작업 파일을 모두 HEAD의 A로 바꾼다. 앞에서 남겨 둔 작업 파일 C도 사라진다.

git restore --source=HEAD --staged --worktree -- note.txt
git show HEAD:note.txt  # A
git show :note.txt      # A
cat note.txt           # A
git status --short     # 출력 없음

저장소에 아직 커밋이 없으면 HEAD를 복원 원본으로 쓸 수 없다. 또한 이 예제는 충돌이 없는 기존 추적 파일을 대상으로 하며, 미추적 파일 전체를 정리하는 명령을 설명한 것이 아니다.

실행 전에는 git diff와 git diff --cached로 버릴 수정이 어느 쪽에 있는지 확인한다. 커밋 후보만 되돌릴 때는 --staged, 작업 파일도 되돌릴 때는 복원 원본과 --worktree를 함께 확인하면 된다. add와 commit이 내용을 어디에 저장하는지는 Git 명령어의 내부 동작에서 이어서 볼 수 있다.

반응형

댓글