restore - 삭제된 파일 찾아 복구하기, 저장한 파일 커밋하지 않고 변경점 버리기

김동규·2023년 4월 23일
0

Git

목록 보기
2/15

삭제한 파일 복구하기

작업 중에 파일을 삭제했는데 나중에 그 파일이 필요해지는 경우가 있습니다. 다행히 git을 이용하면 삭제한 파일을 복구할 수 있습니다.

파일을 삭제하고 아직 커밋하지 않은 경우

아직 커밋하기 전이라면 index에 기록이 저장된 상태이므로 git status 명령을 통해서 간단하게 파일 경로를 확인할 수 있습니다.

이제 restore 명령을 통해 해당 파일 경로를 지정하면 간단하게 파일을 되살릴 수 있습니다.

git restore <filename>

파일을 삭제하고 아직 커밋은 안했는데 add까지 진행한 경우

이 경우에도 굳이 커밋까지 진행할 필요 없이 restore 명령에서 제공하는 옵션만으로 해결할 수 있습니다.

git restore --staged --worktree <filename>

위의 명령에서

  • --staged는 add 명령을 통해 index에 추가된 스냅샷을 제거하는 옵션입니다.
  • --worktree는 우리가 현재 작업 중인 working directory를 파일 복구장소로 지정하는 옵션입니다.

즉, 위의 명령어를 두 줄로 풀어쓰면 다음과 같습니다.

/* 
* 아래 명령으로 스냅샷이 index에서 삭제됩니다. 
* 그러나 아직 우리의 working directory에서는 파일이 보이지 않습니다.
*/
git restore --staged src/dummy.md

/* 
* 파일 탐색기까지 복구하려면 다음 명령을 한번 더 입력해야 합니다. 축약된 명령이 더 간편합니다.
*/
git restore src/dummy.md

파일을 삭제하고 커밋까지 진행한 경우

파일을 삭제하고 커밋까지 진행했다면 파일을 복구하기 위해 두 가지 정보가 필요합니다.

  1. 소스로 사용할(파일이 존재했던) 커밋 위치
  2. 이름을 포함한 파일 경로

case 1: 파일 경로도 자세히 기억이 안나고 어떤 커밋에 파일이 있었는지도 모르는 경우

최악의 상황을 가정해 파일을 삭제한 게 일주일 전이고 파일 경로도 정확하게 떠오르지 않는다고 해봅시다.

그래도 커밋 메세지를 보고 필요한 커밋을 알아볼 수 있다면, 아직 git은 당신을 도울 수 있습니다. 먼저 다음 명령을 통해 지금까지 파일이 삭제된 커밋 목록을 확인해봅시다.

/* --diff-filter=D는 파일이 삭제된 커밋만을 탐색하는 옵션입니다. */
git log --diff-filter=D

로그를 확인해보니 당신이 찾고 있는 파일을 삭제한 커밋은 세 번째 커밋인 6e914bc...이었습니다. 이제 이 커밋을 통해 삭제된 파일의 정확한 이름과 경로를 확인해봅시다.

/* hash값이 유일하다면 git은 4자리까지 줄여써도 여전히 커밋을 알아볼 수 있습니다. */
git show 6e914bc

diff 행을 보면 삭제된 파일의 경로가 나와있습니다. (a, b는 비교를 위한 표시이므로 무시합니다.)

  1. 파일이 있었던 커밋은 6e914bc보다 한 커밋 위다.
  2. 삭제된 파일의 이름과 경로는 src/dummy.md이다.

이제 필요한 두 가지 정보를 모두 얻었습니다. 현재 위치에 파일을 복구해봅시다.

/* ^는 해당 커밋의 부모커밋을 뜻합니다. */
git restore --source=6e914bc^ src/dummy.md

case 2: 파일 경로는 기억하는데 어떤 커밋이었는지 모르겠습니다.

git log에 옵션을 주어 해당 파일이 변경된 커밋만 필터링할 수 있습니다.

/* -- 뒤에 한 칸 띄워주세요 */
git log -- src/dummy.md

case 3: 파일 경로를 알고 지금 막 삭제한 파일을 커밋한 참입니다.

restore 명령을 사용하기 최선의 상황입니다. 최신 상태의 파일은 지금 HEAD의 한 커밋 위에 있습니다.

git restore --source=HEAD^ src/dummy.md

!주의하기: reset --hard를 추천하지 않는 이유

git reset --hard명령의 위험성에 대해 잘 모르고 쓴다면 난처한 상황에 처할 수 있기 때문입니다.

  1. 나는 파일만 복구하고 싶었는데 같은 커밋에 반영한 다른 변경사항들까지 롤백될 수 있습니다.
  2. 이미 푸시한 커밋이 reset --hard의 명령 대상에 포함되어 있다면 히스토리가 달라져서 리모트 레포에 더 이상 푸시할 수 없게 됩니다.

둘 다 해결방법은 있지만 특히 2번은 git push --force명령을 통해 문제를 팀 전체로 확산시킬 가능성이 있는 상황입니다.

그보다는 명령에 영향 받는 커밋과 대상을 최소화하여 restore명령을 활용하는 편이 더 낫습니다.

reset명령에 대해서는 다음 기회에 자세히 다루겠습니다.

!주의하기: 나는 삭제하지 않았는데 git은 삭제했다고 알고 있을 때가 있습니다.

파일의 삭제, 이동을 git에게 정확하게 알려주기

저장한 파일 커밋하지 않고 변경점 버리기

git의 관점에서 이 상황은 상단의 '파일을 삭제했지만 아직 커밋하지 않은 경우'와 같습니다.

git add명령을 입력했는지 아닌지에 따라 아래 두 명령 중에서 골라쓰면 됩니다.

/* add하지 않은 경우 */
git restore <filename>

/* add한 경우 */
git restore --staged --worktree <filename>

TMI

restore 명령의 상세

여기까지 오면 눈치채셨겠지만 git restore는 원본 소스와 현재 working directory를 비교하여 지정된 대상을 기준이 되는 원본 소스의 상태로 복구하는 명령입니다.

원본 소스가 주어지지 않았을 때는 현재 HEAD 위치(일반적으로, 현재 브랜치의 가장 최근 커밋입니다.)를 default로 참고하도록 설정되어 있습니다.

/* 현재 브랜치의 HEAD위치 (최신 커밋)을 기준으로 filename의 상태를 복구한다. */
git restore <filename>

git checkout과의 관계

사실 위의 작업은 모두 git checkout명령을 통해서도 가능합니다.

그러나 git checkout명령어가 하는 일이 지나치게 광범위하고 많아졌기 때문에, git의 버전이 올라가며 같은 일을 하지만 보다 한정적인 용도를 가지는 작은 명령어들이 추가되었습니다. git restore도 그런 명령들 중 하나입니다.

profile
공식문서를 사랑하는 프론트엔드 주니어 개발자

0개의 댓글

관련 채용 정보