git restore
는 작업 디렉토리의 파일을 이전 상태로 복원하거나, 스테이징 영역에서 변경을 취소할 때 사용됩니다. 주로 변경된 파일을 이전 상태로 되돌리는 데에 사용됩니다.
git restore [파일명]
# 최신 커밋 상태로 복원
불필요한 수정이나 변경 사항이 발생했을 경우, 최신 커밋 상태로 되돌릴 수 있습니다. git restore
명령어를 사용하면 아직 커밋되지 않은 변경 사항은 모두 사라지므로, 변경 사항을 유지하려면 먼저 커밋을 해야 합니다.
git restore --source HEAD~1
# HEAD의 이전 커밋(HEAD~1, 바로 직전의 커밋)의 상태로 특정 파일을 복원합니다
git restore --source HEAD [파일명]
# HEAD의 상태로 특정 파일을 복원합니다
git restore --source [커밋 해시] [파일명]
# 특정 파일을 특정 커밋의 상태로 복원합니다
특정 커밋의 파일 상태로 현재 작업 중인 파일을 복원할 수 있습니다.
git restore --staged [파일명]
# 스테이징 영역의 변경 사항 취소(Unstage)합니다
스테이징 영역에서 선택한 파일의 변경을 취소하고, 해당 파일을 unstaged 상태로 되돌립니다.
git reset
은 작업 디렉토리를 특정 커밋 상태로 되돌리는 git 명령어입니다. 이 명령어는 이전 커밋으로 되돌아가거나, 작업 디렉토리나 스테이징 영역을 초기화하고자 할 때 사용됩니다.
git reset --soft [커밋 해시]
# HEAD는 계속 현재 브랜치를 가리키고 있고, 현재 브랜치가 가리키는 커밋을 바꾼다.
git reset --soft
명령어는 HEAD만 이동시키고, 인덱스(Staging Area)와 워크스페이스는 변경하지 않습니다. 즉, 이전 커밋의 변경 사항을 워크스페이스에 적용하지 않고 HEAD만 이동시켜 이전 커밋 버전으로 되돌아갈 수 있습니다. 인덱스에는 해당 커밋 이후로 추가된 변경 사항들은 그대로 남아있게 됩니다.
git reset --mixed [커밋 해시]
# HEAD를 특정 커밋으로 이동시키고, 해당 커밋 이후의 변경 사항들은 스테이징 영역에서 제거됩니다.
git reset --mixed
는 HEAD를 특정 커밋으로 이동시키며, 스테이징 영역(인덱스)은 이전 커밋의 상태로 초기화됩니다. 그러나 워크스페이스는 변경되지 않으며, 해당 커밋 이후의 변경 이력은 모두 제거됩니다. (reset
명령을 실행할 때 아무 옵션도 주지 않으면 기본적으로 --mixed
옵션으로 동작한다.)
위의 다이어그램을 보고 어떤 일이 일어날지 한 번 더 생각해보자. 가리키는 대상을 가장 최근의
커밋
으로 되돌리는 것은 같다. 그러고 나서 Staging Area 를 비우기까지 한다.git commit
명령도 되돌리고git add
명령까지 되돌리는 것이다.
git reset --hard [커밋 해시]
# HEAD를 특정 커밋으로 이동시키며, 해당 커밋 이후의 모든 변경 사항을 스테이징 영역과 작업 디렉토리에서 제거합니다.
git reset --hard
명령어는 HEAD 포인터를 이동시키고 인덱스(Staging Area)와 워크스페이스를 모두 지정된 커밋 버전으로 업데이트합니다. 만약 커밋한 적 없다면 Git이 덮어쓴 데이터는 복원할 수 없습니다.
reset
명령은 정해진 순서대로 세 개의 트리를 덮어써 나가다가 옵션에 따라 지정한 곳에서 멈춘다.
1. HEAD가 가리키는 브랜치를 옮긴다. (--soft
옵션이 붙으면 여기까지)
2. index를 HEAD가 가리키는 상태로 만든다. (--hard
옵션이 붙지 않았으면 여기까지)
3. 워킹 디렉토리를 index의 상태로 만든다.
git reset file.txt
예를 들어, git restore file.txt
명령을 실행한다고 가정할 때, 이는 커밋의 해시 값이나 브랜치, --soft
나 --hard
표기가 없는 git reset --mixed HEAD file.txt
의 축약형입니다. 즉, file.txt
파일을 HEAD에서 Index로 복사합니다.
1. HEAD의 브랜치를 옮긴다. (건너뜀)
git revert
명령어는 특정 커밋의 변경 사항을 되돌리는 데 사용됩니다. 이는 새로운 커밋을 생성하여 원하는 커밋의 변경 사항을 되돌리면서 기존의 커밋 히스토리를 변경하지 않습니다.reset
은 HEAD의 위치를 바꿔 히스토리를 직접 변경하는 반면에 revert
는 커밋의 내용을 되돌리는 커밋을 새로 만듭니다.git revert
명령어는 충돌을 일으킬 수 있습니다. 충돌이 발생하면 직접 해결해야 합니다.git revert [커밋 해시]
# 특정 커밋의 변경 사항을 취소하고 새로운 커밋을 생성합니다.
# 히스토리는 변경됩니다.
git revert --no-commit [커밋 해시]
# 특정 커밋의 변경 사항을 취소하지만 새로운 커밋을 생성하지 않습니다.
# 히스토리는 변경되지 않습니다.
--no-commit
옵션을 추가하면, revert한 결과를 stage 상태로만 유지하고 commit하지 않습니다.git revert [커밋 해시]..[커밋 해시]
# 특정 범위의 커밋을 되돌리고 새로운 커밋을 생성합니다.
5번 커밋에서 2번 커밋으로 revert를 해보겠습니다.
revert중 충돌이 발생했다는 메시지가 출력됩니다.
git revert c1a4d66
자동 병합: 1.txt
충돌 (내용): 1.txt에 병합 충돌
error: 다음을 되돌릴(revert) 수 없습니다: c1a4d66... 2번
힌트: After resolving the conflicts, mark them with
힌트: "git add/rm <pathspec>", then run
힌트: "git revert --continue".
힌트: You can instead skip this commit with "git revert --skip".
힌트: To abort and get back to the state before "git revert",
힌트: run "git revert --abort".
충돌이 발생하는 이유는 5번 커밋에는 이미 2번 커밋 이후의 변경 사항이 포함되기 때문에 충돌이 발생합니다.
2번 커밋으로 돌아가고 싶었지만, 충돌의 흔적을 보면 수신 변경 사항에 1번
텍스트만 남아 있습니다. 2번 커밋의 내용까지 있어야 할 것 같았지만, revert
는 "커밋을 없던 일로 해줄테니 다시 커밋해" 라는 명령어입니다. 즉, 2번 커밋으로 되돌아가는 것이 아니라, 2번 커밋 자체를 취소한다는 의미입니다. 그래서 2번 커밋이 사라져 1번 텍스트만 남게 됩니다.
git add
를 사용해 스테이징 영역에 추가합니다.git revert --continue
를 사용해 revert 작업을 진행합니다.git revert
명령어를 사용하여 충돌을 해결하고 새로운 커밋을 생성하면, 현재의 HEAD는 새로 만들어진 커밋을 가리키게 됩니다. 따라서 현재 HEAD는 2번째 커밋을 기반으로 충돌을 해결하고 새로운 커밋을 생성하였습니다. 충돌이 발생하지 않도록 revert를 진행하려면 순서대로 진행해야 합니다. 예를 들어, 5번 커밋에서 2번 커밋까지 순차적으로 revert하면 충돌이 발생하지 않습니다.
충돌을 발생시키지 않고 이전 커밋으로 되돌아가려면 순서대로 진행해야 합니다. 그러나 많은 수의 커밋을 되돌리려면 git revert [커밋 해시]..[커밋 해시]
명령어를 사용할 수 있습니다.
git revert a226818..39f0a39 # 2번 커밋 .. 4번 커밋
git revert a226818..39f0a39
와 같이 범위를 지정하여 revert를 실행하면, 범위의 시작 커밋(2번)은 포함되지 않습니다. 즉, git revert a226818..39f0a39
는 실제로 3번과 4번 커밋에 대한 변경 사항을 취소합니다. 따라서, 2번 커밋의 변경 사항은 그대로 유지됩니다.
일반적으로 git reset
보다 git revert
를 더 자주 사용하는 것이 좋습니다.