작업 중에 파일을 삭제했는데 나중에 그 파일이 필요해지는 경우가 있습니다. 다행히 git을 이용하면 삭제한 파일을 복구할 수 있습니다.
아직 커밋하기 전이라면 index에 기록이 저장된 상태이므로 git status 명령을 통해서 간단하게 파일 경로를 확인할 수 있습니다.
이제 restore 명령을 통해 해당 파일 경로를 지정하면 간단하게 파일을 되살릴 수 있습니다.
git restore <filename>
이 경우에도 굳이 커밋까지 진행할 필요 없이 restore 명령에서 제공하는 옵션만으로 해결할 수 있습니다.
git restore --staged --worktree <filename>
위의 명령에서
즉, 위의 명령어를 두 줄로 풀어쓰면 다음과 같습니다.
/*
* 아래 명령으로 스냅샷이 index에서 삭제됩니다.
* 그러나 아직 우리의 working directory에서는 파일이 보이지 않습니다.
*/
git restore --staged src/dummy.md
/*
* 파일 탐색기까지 복구하려면 다음 명령을 한번 더 입력해야 합니다. 축약된 명령이 더 간편합니다.
*/
git restore src/dummy.md
파일을 삭제하고 커밋까지 진행했다면 파일을 복구하기 위해 두 가지 정보가 필요합니다.
최악의 상황을 가정해 파일을 삭제한 게 일주일 전이고 파일 경로도 정확하게 떠오르지 않는다고 해봅시다.
그래도 커밋 메세지를 보고 필요한 커밋을 알아볼 수 있다면, 아직 git은 당신을 도울 수 있습니다. 먼저 다음 명령을 통해 지금까지 파일이 삭제된 커밋 목록을 확인해봅시다.
/* --diff-filter=D는 파일이 삭제된 커밋만을 탐색하는 옵션입니다. */
git log --diff-filter=D
로그를 확인해보니 당신이 찾고 있는 파일을 삭제한 커밋은 세 번째 커밋인 6e914bc...이었습니다. 이제 이 커밋을 통해 삭제된 파일의 정확한 이름과 경로를 확인해봅시다.
/* hash값이 유일하다면 git은 4자리까지 줄여써도 여전히 커밋을 알아볼 수 있습니다. */
git show 6e914bc
diff 행을 보면 삭제된 파일의 경로가 나와있습니다. (a, b는 비교를 위한 표시이므로 무시합니다.)
이제 필요한 두 가지 정보를 모두 얻었습니다. 현재 위치에 파일을 복구해봅시다.
/* ^는 해당 커밋의 부모커밋을 뜻합니다. */
git restore --source=6e914bc^ src/dummy.md
git log에 옵션을 주어 해당 파일이 변경된 커밋만 필터링할 수 있습니다.
/* -- 뒤에 한 칸 띄워주세요 */
git log -- src/dummy.md
restore 명령을 사용하기 최선의 상황입니다. 최신 상태의 파일은 지금 HEAD의 한 커밋 위에 있습니다.
git restore --source=HEAD^ src/dummy.md
git reset --hard명령의 위험성에 대해 잘 모르고 쓴다면 난처한 상황에 처할 수 있기 때문입니다.
둘 다 해결방법은 있지만 특히 2번은 git push --force명령을 통해 문제를 팀 전체로 확산시킬 가능성이 있는 상황입니다.
그보다는 명령에 영향 받는 커밋과 대상을 최소화하여 restore명령을 활용하는 편이 더 낫습니다.
reset명령에 대해서는 다음 기회에 자세히 다루겠습니다.
git의 관점에서 이 상황은 상단의 '파일을 삭제했지만 아직 커밋하지 않은 경우'와 같습니다.
git add명령을 입력했는지 아닌지에 따라 아래 두 명령 중에서 골라쓰면 됩니다.
/* add하지 않은 경우 */
git restore <filename>
/* add한 경우 */
git restore --staged --worktree <filename>
여기까지 오면 눈치채셨겠지만 git restore는 원본 소스와 현재 working directory를 비교하여 지정된 대상을 기준이 되는 원본 소스의 상태로 복구하는 명령입니다.
원본 소스가 주어지지 않았을 때는 현재 HEAD 위치(일반적으로, 현재 브랜치의 가장 최근 커밋입니다.)를 default로 참고하도록 설정되어 있습니다.
/* 현재 브랜치의 HEAD위치 (최신 커밋)을 기준으로 filename의 상태를 복구한다. */
git restore <filename>
사실 위의 작업은 모두 git checkout명령을 통해서도 가능합니다.
그러나 git checkout명령어가 하는 일이 지나치게 광범위하고 많아졌기 때문에, git의 버전이 올라가며 같은 일을 하지만 보다 한정적인 용도를 가지는 작은 명령어들이 추가되었습니다. git restore도 그런 명령들 중 하나입니다.