Codesigner

[Git] Git Backtracking - checkout & reset 본문

Git /git

[Git] Git Backtracking - checkout & reset

eunsukimme 2019. 4. 9. 00:55

Git을 사용하는 프로젝트를 진행항 때, 우리가 만든 변화들이 마음에 들지 않거나 버그가 발생하여 예전 버전으로 되돌리고 싶은 때가 생긴다. Git은 당신의 실수를 되돌릴 수 있는 몇 가지 eraser-like 한 명령어들을 제공한다. 이번 포스팅에서는 그러한 명령어들을 배워보도록 하자. 저번 포스팅에서 만들었던 hello.txt를 계속 사용하도록 하자. 먼저, 다음과 같이 새로운 라인의 문장을 추가해보자

C:\Users\glafu\Desktop\git_test>vim hello.txt

C:\Users\glafu\Desktop\git_test>cat hello.txt
hello world!
I'm second line!
Me third!

C:\Users\glafu\Desktop\git_test>

그런 다음 git add 후 적절한 메시지와 함께 commit 하도록 하자

C:\Users\glafu\Desktop\git_test>git add hello.txt

C:\Users\glafu\Desktop\git_test>git commit -m "Add third line"
[master 7495fd8] Add third line
 1 file changed, 1 insertion(+)

C:\Users\glafu\Desktop\git_test>

자, 이제 backtracking에 대해서 알아보도록 하자

 

 

 

head commit

 

Git에서 우리가 현재 위치하고 있는 commit을 HEAD commit이라고 한다. 대부분의 경우, 가장 최근에 만들어진 commit을 HEAD commit이라고 한다. HEAD commit을 보려면 터미널에서 다음과 같이 입력하면 된다

git show HEAD

출력 결과는 git log 명령의 출력 결과 중 HEAD커밋의 내용에 더해 커밋이 포함하는 파일 변경 내역을 확인할 수 있다.

 

 

 

git checkout

 

만약, 우리가 hello.txt 에 네번째 줄을 추가했는데, 마음에 들지 않아서 이를 취소하고 싶을 땐 어떻게 하면 좋을까? 물론 지금처럼 작은 프로젝트에 경우 간단히 메모장을 열어서 네 번째 줄을 지워줘도 되겠지만, 큰 프로젝트를 진행하고 있을 때는 정확히 어디를 수정해야 되는지 찾기 어려울 때도 있다. 그럴 때 git checkout 명령을 활용할 수 있다

git checkout HEAD filename

위 명령은 현재 Working Directory에서의 파일 내용을 HEAD 커밋, 즉 가장 최근에 만든 커밋의 것으로 복사한다. 여기서 filename은 복사해오고자 하는 파일의 이름이다. 우리는 hello.txt의 네 번째 라인을 다음과 같이 수정해 보도록 하자

C:\Users\glafu\Desktop\git_test>vim hello.txt

C:\Users\glafu\Desktop\git_test>cat hello.txt
hello world!
I'm second line!
Me third!
I believe i can fly~

C:\Users\glafu\Desktop\git_test>

현재 상황을 다시 한번 정리해보면 Working Directory에서의 hello.txt는 방금 추가한 네 번째 줄을 포함해서 총 4줄이고, add나 commit을 하지 않았으므로 Staging Area와 Repository에서의 hello.txt는 여전히 3줄이다. 자, 이제 우리가 방금 배운 checkout 명령어로 방금 만든 변화를 무마시키도록 해보자

C:\Users\glafu\Desktop\git_test>git checkout HEAD hello.txt

C:\Users\glafu\Desktop\git_test>cat hello.txt
hello world!
I'm second line!
Me third!

C:\Users\glafu\Desktop\git_test>

예상대로 우리가 추가한 네 번째 라인이 없어지고 3줄짜리 hello.txt를 출력하고 있음을 확인할 수 있다.

 

 

 

more git add

 

사실 프로젝트를 진행하다 보면 한 파일 만이 아니라 여러 파일이 변화되기 때문에 지금처럼 한 파일만을 add 하고 commit 하게 된다면 매우 번거로울 것이다. Git에서는 여러 파일들의 변화를 한 번에 add 하고 commit 할 수 있다. 

git add filename_1 filename_2 ...

git add의 파라미터로 파일들의 이름을 공백으로 구분하여 주면 여러 파일들을 한 번에 add 할 수 있다. 이를 테스트하기 위해 hello.txt에 네 번째 줄을 추가하고 새로운 텍스트 파일인 intro.txt을 만들어 Staging Area에 올려보도록 하자

C:\Users\glafu\Desktop\git_test>vim intro.txt

C:\Users\glafu\Desktop\git_test>cat intro.txt
Hi, i'm eunsu

C:\Users\glafu\Desktop\git_test>vim hello.txt

C:\Users\glafu\Desktop\git_test>cat hello.txt
hello world!
I'm second line!
Me third!
I believe i can fly~

C:\Users\glafu\Desktop\git_test>git add hello.txt intro.txt

C:\Users\glafu\Desktop\git_test>

 

 

 

git reset I

 

만약에 우리가 hello.txt에 추가한 네 번째 줄이 갑자기 마음에 들지 않게 됐다면 어떻게 해야 할까? 이미 hello.txt는 Staging Area에 올라간 상태다. 이럴 땐 git reset 커맨드를 사용하면 된다

git reset HEAD filename

위 명령은 Staging Area에 올라가 있는 해당 이름의 파일을 HEAD commit의 것으로 복사해온다. 이 명령은 Working Directory에서 작업한 내용을 변경하지 않는다. 단지 Staging Area에만 적용될 뿐이다. Staging Area에 올라간 4줄짜리 hello.txt를 git reset 키워드로 되돌려보자

C:\Users\glafu\Desktop\git_test>git reset HEAD hello.txt
Unstaged changes after reset:
M       hello.txt

C:\Users\glafu\Desktop\git_test>

출력 결과를 보면 "Unstaged changes after reset: "라고 하면서 hello.txt가 unstaged 되었다고 알려준다. 여기서 "M"은 "Modification"의 약자이다. 아무튼 실제로 Unstaged 되었는지 확인하고 싶은데, 어떻게 확인할 수 있을까? 앞에서 reset 명령이 Working Directory에는 적용되지 않고 오직 Staging Area에만 적용된다고 하였다. 눈치 빠른 독자는 벌써 알아차렸겠지만 이전 포스팅에서 git diff 가 바로 Working Directory와 Staging Area와의 차이를 보여준다고 하였는데, 이 명령을 사용하여 Working Directory에서의 hello.txt 와 Staging Area에서의 hello.txt를 비교해보도록 하자.

C:\Users\glafu\Desktop\git_test>git diff hello.txt
diff --git a/hello.txt b/hello.txt
index 62ada7d..60011cf 100644
--- a/hello.txt
+++ b/hello.txt
@@ -1,3 +1,4 @@
 hello world!
 I'm second line!
 Me third!
+I believe i can fly~

C:\Users\glafu\Desktop\git_test>

예상대로 Staging Area의 hello.txt 내용은 HEAD commit의 3줄짜리로 되돌아갔고, 조금 전에 Working Directory에서 추가한 네 번째 줄이 Staging Area와 차이가 난다고 보여주고 있다. git status 명령으로 프로젝트 상태를 확인해보자

C:\Users\glafu\Desktop\git_test>git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        new file:   intro.txt

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   hello.txt


C:\Users\glafu\Desktop\git_test>

출력 결과를 보면 "Changes not staged for commit: " 에서 hello.txt가 Staging Area에서 내려간걸 확실히 알 수 있다. 이제 이대로 commit 하도록 하자

C:\Users\glafu\Desktop\git_test>git commit -m "Add intro file"
[master 020024b] Add intro file
 1 file changed, 1 insertion(+)
 create mode 100644 intro.txt

C:\Users\glafu\Desktop\git_test>

 

 

 

git reset II

 

프로젝트를 진행한다는 것은 때로는 미로를 탐험하는 것처럼 느껴질 때도 있다. 길을 가다가 막히면 이전 길로 되돌아 가야 되기 때문이다. Git에서는 당신이 이전에 만든 커밋으로 되돌아갈 수 있도록 도와주는데, 다음과 같이 사용할 수 있다

git reset commit_SHA

위 명령은 commit의 SHA 해쉬값의 앞 7자리를 파라미터로 취한다. 예를 들어, SHA 값이 5d692065cf51a2f50ea8e7b19b5a7ae512f633ba인 커밋으로 되돌아가고자 한다면 다음과 같이 입력하면 된다

git reset 5d69206

그러면 HEAD는 해당 커밋에 위치하게 된다. 우리의 경우 git log 명령으로 커밋 이력을 확인해보면 다음과 같다

C:\Users\glafu\Desktop\git_test>git log
commit 020024b626d513c3a7505b8781b875d1f86bddd2 (HEAD -> master)
Author: eunsukimme <eunsu.dev@gmail.com>
Date:   Tue Apr 9 00:18:53 2019 +0900

    Add intro file

commit 7495fd8b75091d2c2193acc89fa4542da3b2d9c2
Author: eunsukimme <eunsu.dev@gmail.com>
Date:   Mon Apr 8 23:18:56 2019 +0900

    Add third line

commit d9e17f2638100c8f50866c811efda95909973c5c
Author: eunsukimme <eunsu.dev@gmail.com>
Date:   Mon Apr 8 22:12:06 2019 +0900

    Add first commit

C:\Users\glafu\Desktop\git_test>

우리는 intro.txt 파일을 생성하기 전인 HEAD 바로 이전 커밋으로 되돌아가 보도록 하자. 커밋의 SHA 해쉬값의 앞 7자리는 7495fd8 이므로 이 값을 git reset의 파라미터로 넘겨주자

C:\Users\glafu\Desktop\git_test>git reset 7495fd8
Unstaged changes after reset:
M       hello.txt

C:\Users\glafu\Desktop\git_test>

자, 이제 git log 명령으로 커밋 이력을 확인해보자

C:\Users\glafu\Desktop\git_test>git log
commit 7495fd8b75091d2c2193acc89fa4542da3b2d9c2 (HEAD -> master)
Author: eunsukimme <eunsu.dev@gmail.com>
Date:   Mon Apr 8 23:18:56 2019 +0900

    Add third line

commit d9e17f2638100c8f50866c811efda95909973c5c
Author: eunsukimme <eunsu.dev@gmail.com>
Date:   Mon Apr 8 22:12:06 2019 +0900

    Add first commit

C:\Users\glafu\Desktop\git_test>

성공적으로 우리가 원하는 커밋으로 되돌아간 걸 확인할 수 있다

 

 

 

git reset review

 

git reset commit_SHA을 더 잘 이해하기 위해, 아래 그림을 보도록 하자. 그림에서 각 원은 커밋을 의미한다

 

<그림 1> git reset(출처: codecademy.com)

 

Before reset: 

  • HEAD는 가장 최근에 만든 커밋을 가리킨다

After reset:

  • HEAD는 주어진 이전 커밋으로 위치하게 된다

  • 회색 원은 더 이상 프로젝트의 일부가 아니다

  • 프로젝트의 시간을 되돌리는 결과를 낳았다

 

 

 

Generalizations

 

우리는 지금까지 Git에서 Backtracking을 하는 여러 가지 방법을 배웠다. Git으로 만들어진 변화를 취소하는 여러 가지 방법들을 살펴보았는데, 정리하면 다음과 같다:

 

  • git checkout HEAD filename - Working Directory의 파일을 HEAD 커밋의 그것으로 복사해온다

  • git reset HEAD filename - Staging Area의 파일을 HEAD 커밋의 그것으로 복사해온다

  • git reset commit_SHA - 이전 커밋으로 되돌아간다(이후의 커밋은 사라진다)

 

 

주제와는 조금 다르지만 Staging Area에 여러 파일을 올리는 것 또한 배웠다. 지금 까지 배운 것들을 잘 기억해두고 다음 포스팅에서는 Git의 Branch를 다루는 는 방법을 알아보도록 하자.

 

Comments