Git

Git의 여러 가지 되돌리기 기능들(checkout, reset, revert)

git을 사용할 때 명령어를 항상 옳게 사용하면 좋겠지만 사람이라는게 실수를 하기 마련이죠.
그러기 위해서 필요한 것이 되돌리는 작업들입니다. 이번 시간에는 git의 여러 가지 되돌리기와 관련된 명령어를 알아보고자 합니다.

1. 수정사항 되돌리기

개인적으로 가장 빈번하게 발생하는 경우입니다. 코드를 작성하면서 여러 군데에 로그를 출력하는 코드를 삽입했다던가, 개발 환경에서만 작동하는 코드를 임시로 넣었을 때 그 내용을 되돌리는 경우입니다.
물론 기존 커밋과 비교해서 일일이 원본으로 수정해도 되지만, 수정한 내용이 많거나 여러 군데에 흩어져 있을 경우에는 상당히 귀찮은 작업입니다.

소스 트리 같은 툴에서는 간단하게 되돌릴 수 있는데 명령어로도 (당연히) 가능합니다.
이때 사용하는 것이 git checkout 입니다.

만약 몰랐던 분이라면 조금 놀라실 수도 있겠습니다. (실은 제가 처음 알았을 때 그랬습니다..ㅎ) checkout을 브랜치를 변경하는 명령어로만 알고 있었으니까요.

예시를 보겠습니다.

우선 초기 상태를 만들기 위해 file1이라는 파일을 하나 생성하고 커밋했습니다.

텍스트 한 줄을 file1에 추가했습니다. status를 보면 modified 된 것을 알 수 있습니다.
이 상태에서 추가된 라인을 지워도 원래 상태로 돌아오겠지만, 명령어로도 되돌릴 수 있습니다.

status를 보면 원래 상태로 돌아온 것을 알 수 있습니다.

checkout 명령어를 이용해 수정한 내용을 되돌릴 때 명령어 뒤에 오는 것은 엄밀히 말해 파일 명이 아닌 pathspec 입니다.
즉, 위와 같이 여러 개의 파일이 수정된 상황에서 현재 디렉토리로 path를 주게 되면

모든 수정된 파일을 되돌릴 수 있게 됩니다.

하나 주의해야할 점은 새롭게 추가된 파일, 다시 말하자면 Untracked file의 경우에는 checkout을 하더라도 삭제되지 않습니다.

2. Unstaging

역시나 빈번하게 발생하는 상황입니다. add 명령어로 stage 상태로 만든 파일을 다시 unstage 상태로 만드는 것입니다.
마찬가지로 소스트리에서는 간단하게 가능하지만 명령어로 하는 방법을 알아보고자 합니다.

file1을 수정한 후에 stage 상태로 만들었습니다.
그런데 사실 unstaging에 대한 해법은 이미 나와있습니다. 잘 보면 unstaging 하려면 reset 명령어를 이용하라는 메시지가 나와있습니다.

reset 명령어로 unstage 상태로 만들었습니다.
(테스트해보니 HEAD를 소문자로 입력해도 정상적으로 동작합니다.)

3. Commit 되돌리기

3.1. reset

3.1.1. mixed

앞서 reset 명령어가 등장했으니 좀 더 자세히 알아보겠습니다.
reset은 말그대로 커밋을 되돌리는 명령어입니다.

우선 초기 상태를 위와 같이 만들었습니다.
git을 연습하기 위한 repository인지라 여러 커밋 내용들이 있는데 아래 커밋들은 무시하고 현재 reset origin이라는 커밋부터 시작한다고 보시면 됩니다.

연습을 위해 몇가지 커밋을 추가하겠습니다. file1, file2를 추가하고 각각 커밋했습니다.

reset 명령어 뒤에 체크섬을 주어 초기 커밋으로 되돌리기를 시도했습니다.
log를 보면 처음 상태인 reset origin 이후의 커밋들이 전부 사라진 것을 볼 수 있습니다.

그런데 이게 왠걸? file1과 file2는 그대로 존재합니다.
status를 보면 어떻게 된 상태인지를 파악할 수 있는데요,
기본적으로 reset을 사용하게 되면 해당 커밋 이후의 내용은 현재 내가 수정한 것처럼 내용 자체는 남아있게 됩니다.

reset을 사용할 때 아무 옵션을 주지 않으면 --mixed 옵션이 기본적으로 들어가게 되는데 그 동작이 위와 같습니다.

3.1.2. soft

이번에는 --soft 옵션을 주고 테스트 해보겠습니다.
동일하게 file1, file2를 추가하고, 각각 커밋한 후 진행했습니다.

일단 log상으로는 동일하게 커밋 내용이 사라졌네요.

리셋 이후의 수정한 내용 또한 동일하게 존재합니다. 다만, 해당 내용들이 staging area에 존재하게 됩니다.

3.1.3. hard

마지막으로 --hard 옵션을 테스트해보겠습니다.
역시나 동일한 커밋 상태에서 진행했습니다.

마찬가지로 커밋이 리셋되었습니다.

네, 보시는 바와 같이 --hard옵션은 해당 커밋 이후의 내용을 모조리 날려버립니다.
상당히 강력하면서 위험한 옵션이네요.

3.1.4. 정리

정리하자면 다음과 같습니다.

  • reset은 두 가지 용도로 사용 가능합니다. unstaging이나 commit reset.
  • commit reset의 경우 세 가지 옵션이 존재하며(mixed, soft, hard), default는 mixed입니다.
    공통적으로 리셋시킨 커밋 이후의 커밋은 사라지게 됩니다.
  • mixed option : 리셋 이후의 커밋 내용들이 unstage 상태로 존재
  • soft option : 리셋 이후의 커밋 내용들이 stage 상태로 존재
  • hard option : 리셋 이후의 커밋 내용들이 전부 삭제

3.2. revert

reset 명령어의 경우 해당 커밋 이후는 전부 삭제가 됩니다.
그런데 특정 커밋만 되돌리고 싶은 경우도 발생할 수 있지 않을까요?
그럴 때 사용하는 것이 revert 명령어입니다.

기본 상태는 위와 같습니다. revert origin 커밋을 기준으로 file1과 file2를 추가했습니다.
이 상태에서 file1을 추가한 커밋만 되돌리고 싶다면 아래와 같이 명령어를 실행하면 됩니다.

1
git revert [되돌릴 커밋]

그러면 위와 같은 창이 뜨게 됩니다. revert message를 입력합니다.

로그를 보면 reset과는 다르게 커밋이 사라지지 않고, 오히려 좀 전에 입력한 메시지로 새로운 커밋이 생성되었습니다.

파일 상태를 보면 file1이 사라진 것을 알 수 있습니다.
즉, revert 명령어는 해당 커밋을 취소하는 커밋을 생성하는 것입니다.

그런데 이전 커밋을 취소하고 수정 후에 다시 반영하고 싶은 경우도 있지 않을까요?
그럴 때는 -n 옵션을 사용하면 됩니다.

-n 옵션을 사용하게 되면 이전과는 다르게 바로 커밋 메시지를 작성하는 창으로 전환되지 않습니다.
그리고 취소한 변경사항이 stage area에 존재하게 됩니다.
취소한 내용이 파일 내용을 수정한 것이라면 원하는 대로 다시 수정해 커밋하면 됩니다.

4. 정리

이번 포스팅에서는 git의 여러 가지 되돌리기 기능들을 살펴보았습니다.
사실 문서를 보니 제가 포스팅에 작성한 내용 말고도 merge를 되돌린다거나 하는 등의 내용이 있었는데요,
그런 내용들은 저도 좀 더 공부를 한 후에 다음에 다른 포스팅으로 정리해보겠습니다.

Share