출처 : git-scm.com
7.1 Git 도구 - 리비전 조회하기
지금까지 일상적으로 자주 사용하는 명령들과 몇 가지 워크플로를 배웠다. 파일을 추적하고 커밋하는 등의 기본적인 명령뿐만 아니라 Staging Area가 왜 좋은지도 배웠고 가볍게 토픽 브랜치를 만들고 Merge 하는 방법도 다뤘다. 이제는 Git 저장소로 충분히 소스코드를 관리할 수 있을 것이다.
이 장에서는 일상적으로 사용하지는 않지만 위급한 상황에서 반드시 필요한 Git 도구를 살펴본다.
리비전 조회하기
리비전 하나를 조회할 수도 있고 범위를 주고 여러 개를 조회할 수도 있다. 거의 필요하진 않지만 알아두면 좋다.
리비전 하나 가리키기
SHA-1 해시 값으로도 커밋을 외울 수 있지만, 사람이 사용하기 좋은 방법이 있다. 이 절에서는 커밋을 표현하는 방법을 몇 가지 설명한다.
SHA-1 줄여 쓰기
Git은 해시 값의 앞 몇 글자만으로도 어떤 커밋인지 충분히 식별할 수 있다. 중복되지 않으면 해시 값의 앞 4자만으로도 나타낼 수 있다. 즉 짧은 SHA-1 값이라고 해도 유일해야 한다.
먼저 git log
명령으로 어떤 커밋이 있는지 조회하는 예제를 보자.
$ git log
commit 734713bc047d87bf7eac9674765ae793478c50d3
Author: Scott Chacon <schacon@gmail.com>
Date: Fri Jan 2 18:32:33 2009 -0800
fixed refs handling, added gc auto, updated tests
commit d921970aadf03b3cf0e71becdaab3147ba71cdef
Merge: 1c002dd... 35cfb2b...
Author: Scott Chacon <schacon@gmail.com>
Date: Thu Dec 11 15:08:43 2008 -0800
Merge commit 'phedders/rdocs'
commit 1c002dd4b536e7479fe34593e72e6c6c1819e53b
Author: Scott Chacon <schacon@gmail.com>
added some blame and merge stuff
git show
명령으로 `1c002dd…`로 시작하는 커밋을 조회할 수 있다. 다음 명령은 모두 같다(단 짧은 해시 값이 다른 커밋과 중복되지 않다고 가정).
$ git show 1c002dd4b536e7479fe34593e72e6c6c1819e53b
$ git show 1c002dd4b536e7479f
$ git show 1c002d
git log
명령에 `--abbrev-commit`이라는 옵션을 추가하면 짧고 중복되지 않는 해시 값을 보여준다. 기본으로 7자를 보여주고 해시 값이 중복되는 경우 더 긴 해시 값을 보여준다.
$ git log --abbrev-commit --pretty=oneline
ca82a6d changed the version number
085bb3b removed unnecessary test code
a11bef0 first commit
보통은 8자에서 10자 내외로도 충분히 유일하게 커밋을 나타낼 수 있다.
꽤 큰 프로젝트인 Linux 커널은 45만 개 이상의 커밋, 360만 개 이상의 오브젝트가 있다. Linux 커널 프로젝트는 해시 값 11개만 사용해도 충돌이 없다.
Note | SHA-1 해시 값에 대한 단상 Git을 쓰는 사람들은 가능성이 작긴 하지만 언젠가 SHA-1 값이 중복될까 봐 걱정한다. 정말 그렇게 되면 어떤 일이 벌어질까? 이미 있는 SHA-1 값이 Git 데이터베이스에 커밋되면 새로운 개체라고 해도 이미 커밋된 것으로 생각한다. 그래서 해당 SHA-1 값의 커밋을 Checkout 하면 항상 처음 저장한 커밋만 Checkout 된다. 그러나 해시 값이 중복되는 일은 일어나기 어렵다. SHA-1 값의 크기는 20 바이트(160비트)이다. 해시 값이 중복될 확률이 50%가 되는 데 필요한 개체의 수는 280이다. 이 수는 1자 2,000해 ('자’는 '경’의 '억’배 - 1024, 충돌 확률을 구하는 공식은 아직도 SHA-1 해시 값이 중복될까 봐 걱정하는 사람들을 위해 좀 더 덧붙이겠다. 지구에서 약 6억 5천만 명의 인구가 개발하고 각자 매초 Linux 커널 히스토리 전체와(360만 개) 맞먹는 개체를 쏟아 내고 바로 Push 한다고 가정하자. 이런 상황에서 해시 값의 충돌 날 확률이 50%가 되기까지는 약 2년이 걸린다. 그냥 어느 날 동료가 한순간에 모두 늑대에게 물려 죽을 확률이 훨씬 더 높다. |
브랜치로 가리키기
브랜치를 사용하는 것이 커밋을 나타내는 가장 쉬운 방법이다. 커밋 개체나 SHA-1 값이 필요한 곳이면 브랜치 이름을 사용할 수 있다. 만약 topic1
브랜치의 최근 커밋을 보고 싶으면 아래와 같이 실행한다. topic1
브랜치가 `ca82a6d`를 가리키고 있기 때문에 두 명령의 결과는 같다.
$ git show ca82a6dff817ec66f44342007202690a93763949
$ git show topic1
브랜치가 가리키는 개체의 SHA-1 값에 대한 궁금증은 `rev-parse`이라는 Plumbing 도구가 해결해 준다.Git의 내부에서 이 뚫어뻥에 대해 시원하게 설명한다. 기본적으로 `rev-parse`은 저수준 명령이기 때문에 평소에는 전혀 필요하지 않다. 그래도 한번 사용해보고 어떤 결과가 나오는지 알아 두자.
$ git rev-parse topic1
ca82a6dff817ec66f44342007202690a93763949
RefLog로 가리키기
Git은 자동으로 브랜치와 HEAD가 지난 몇 달 동안에 가리켰었던 커밋을 모두 기록하는데 이 로그를 ‘`Reflog’'라고 부른다.
`git reflog`를 실행하면 Reflog를 볼 수 있다.
$ git reflog
734713b HEAD@{0}: commit: fixed refs handling, added gc auto, updated
d921970 HEAD@{1}: merge phedders/rdocs: Merge made by recursive.
1c002dd HEAD@{2}: commit: added some blame and merge stuff
1c36188 HEAD@{3}: rebase -i (squash): updating HEAD
95df984 HEAD@{4}: commit: # This is a combination of two commits.
1c36188 HEAD@{5}: rebase -i (squash): updating HEAD
7e05da5 HEAD@{6}: rebase -i (pick): updating HEAD
Git은 브랜치가 가리키는 것이 달라질 때마다 그 정보를 임시 영역에 저장한다. 그래서 예전에 가리키던 것이 무엇인지 확인해 볼 수 있다. @{n}
규칙을 사용하면 아래와 같이 HEAD가 5번 전에 가리켰던 것을 알 수 있다.
$ git show HEAD@{5}
순서뿐 아니라 시간도 사용할 수 있다. 어제 날짜의 master
브랜치를 보고 싶으면 아래와 같이 한다.
$ git show master@{yesterday}
이 명령은 어제 master 브랜치가 가리키고 있던 것이 무엇인지 보여준다. Reflog에 남아있을 때만 조회할 수 있기 때문에 너무 오래된 커밋은 조회할 수 없다.
git log -g
명령을 사용하면 git reflog
결과를 git log
명령과 같은 형태로 볼 수 있다.
$ git log -g master
commit 734713bc047d87bf7eac9674765ae793478c50d3
Reflog: master@{0} (Scott Chacon <schacon@gmail.com>)
Reflog message: commit: fixed refs handling, added gc auto, updated
Author: Scott Chacon <schacon@gmail.com>
Date: Fri Jan 2 18:32:33 2009 -0800
fixed refs handling, added gc auto, updated tests
commit d921970aadf03b3cf0e71becdaab3147ba71cdef
Reflog: master@{1} (Scott Chacon <schacon@gmail.com>)
Reflog message: merge phedders/rdocs: Merge made by recursive.
Author: Scott Chacon <schacon@gmail.com>
Date: Thu Dec 11 15:08:43 2008 -0800
Merge commit 'phedders/rdocs'
Reflog의 일은 모두 로컬의 일이기 때문에 내 Reflog가 동료의 저장소에는 있을 수 없다. 이제 막 Clone 한 저장소는 아무것도 한 것이 없어서 Reflog가 하나도 없다. git show HEAD@{2.months.ago}
같은 명령은 적어도 두 달 전에 Clone 한 저장소에서나 사용할 수 있다. 그러니까 이 명령을 5분 전에 Clone 한 저장소에 사용하면 아무 결과도 나오지 않는다.
계통 관계로 가리키기
계통 관계로도 커밋을 표현할 수 있다. 이름 끝에 `^`를 붙이면 Git은 해당 커밋의 부모를 찾는다. 프로젝트 히스토리가 아래와 같을 때는 아래처럼 한다.
$ git log --pretty=format:'%h %s' --graph
* 734713b fixed refs handling, added gc auto, updated tests
* d921970 Merge commit 'phedders/rdocs'
|\
| * 35cfb2b Some rdoc changes
* | 1c002dd added some blame and merge stuff
|/
* 1c36188 ignore *.gem
* 9b29157 add open3_detach to gemspec file list
‘HEAD^`는 바로 ``HEAD의 부모’'를 의미하므로 바로 이전 커밋을 보여준다.
$ git show HEAD^
commit d921970aadf03b3cf0e71becdaab3147ba71cdef
Merge: 1c002dd... 35cfb2b...
Author: Scott Chacon <schacon@gmail.com>
Date: Thu Dec 11 15:08:43 2008 -0800
Merge commit 'phedders/rdocs'
‘^`뒤에 숫자도 사용할 수 있다. 예를 들어 `d921970^2`는 ``d921970의 두 번째 부모’'를 의미한다. 그래서 두 번째 부모가 있는 Merge 커밋에만 사용할 수 있다. 첫 번째 부모는 Merge 할 때 Checkout 했던 브랜치를 말하고 두 번째 부모는 Merge 한 대상 브랜치를 의미한다.
$ git show d921970^
commit 1c002dd4b536e7479fe34593e72e6c6c1819e53b
Author: Scott Chacon <schacon@gmail.com>
Date: Thu Dec 11 14:58:32 2008 -0800
added some blame and merge stuff
$ git show d921970^2
commit 35cfb2b795a55793d7cc56a6cc2060b4bb732548
Author: Paul Hedderly <paul+git@mjr.org>
Date: Wed Dec 10 22:22:03 2008 +0000
Some rdoc changes
계통을 표현하는 방법으로 ‘~`라는 것도 있다. `HEAD~`와 `HEAD^`는 똑같이 첫 번째 부모를 가리킨다. 하지만, 그 뒤에 숫자를 사용하면 달라진다. `HEAD~2`는 명령을 실행할 시점의 “첫 번째 부모의 첫 번째 부모”, 즉 ``조부모’'를 가리킨다. 위의 예제에서 `HEAD~3`은 아래와 같다.
$ git show HEAD~3
commit 1c3618887afb5fbcbea25b7c013f4e2114448b8d
Author: Tom Preston-Werner <tom@mojombo.com>
Date: Fri Nov 7 13:47:59 2008 -0500
ignore *.gem
이것은 `HEAD^`와 같은 표현이다. 부모의 부모의 부모 즉 증조 부모쯤 되겠다.
$ git show HEAD^^^
commit 1c3618887afb5fbcbea25b7c013f4e2114448b8d
Author: Tom Preston-Werner <tom@mojombo.com>
Date: Fri Nov 7 13:47:59 2008 -0500
ignore *.gem
이 두 표현을 같이 사용할 수도 있다. 위의 예제에서 `HEAD~3^2`를 사용하면 증조부모의 Merge 커밋의 부모의 부모를 조회한다.
범위로 커밋 가리키기
커밋을 하나씩 조회할 수도 있지만, 범위를 주고 여러 커밋을 한꺼번에 조회할 수도 있다. 범위를 사용하여 조회할 수 있으면 브랜치를 관리할 때 유용하다. 상당히 많은 브랜치를 가지고 있고 ‘`왜 이 브랜치들은 아직도 주 브랜치에 Merge도 안 되고 뭐임?’'라는 의문이 들면 범위를 주고 어떤 브랜치인지 쉽게 찾을 수 있다.
Double Dot
범위를 표현하는 문법으로 Double Dot(..)을 많이 쓴다. Double Dot은 어떤 커밋들이 한쪽에는 관련됐고 다른 쪽에는 관련되지 않았는지 Git에게 물어보는 것이다. 예들 들어 범위를 설명하는 데 사용할 예제과 같은 커밋 히스토리가 있다고 가정하자.

experiment 브랜치의 커밋들 중에서 아직 master 브랜치에 Merge 하지 않은 것들만 보고 싶으면 ‘master..experiment`라고 사용한다. 이 표현은 ``master에는 없지만, experiment에는 있는 커밋’'을 의미한다. 여기에서는 설명을 쉽게 하려고 실제 조회 결과가 아니라 범위를 설명하는 데 사용할 예제의 문자를 사용한다.
$ git log master..experiment
D
C
반대로 `experiment`에는 없고 `master`에만 있는 커밋이 궁금하면 브랜치 순서를 거꾸로 사용한다. `experiment..master`는 `experiment`에는 없고 `master`에만 있는 것을 알려준다.
$ git log experiment..master
F
E
experiment
브랜치를 Merge 할 때마다 Merge 하기 전에 무엇이 변경됐는지 확인해보고 싶을 것이다. 그리고 리모트 저장소에 Push 할 때도 마찬가지로 차이점을 확인해보고 싶을 것이다. 이럴 때 굉장히 유용하다.
$ git log origin/master..HEAD
이 명령은 origin
저장소의 master
브랜치에는 없고 현재 Checkout 중인 브랜치에만 있는 커밋을 보여준다. Checkout 한 브랜치가 `origin/master`라면 `git log origin/master..HEAD`가 보여주는 커밋이 Push 하면 서버에 전송될 커밋들이다. 그리고 한쪽의 Refs를 생략하면 Git은 HEAD라고 가정하기 때문에 `git log origin/master..`는 `git log origin/master..HEAD`와 같다.
세 개 이상의 Refs
Double Dot은 간단하고 유용하지만 두 개 이상의 브랜치에는 사용할 수 없다. 그러니까 현재 작업 중인 브랜치에는 있지만 다른 여러 브랜치에는 없는 커밋을 보고 싶으면 ..`으로는 확인할 수 없다. Git은 `^`이나 `--not
옵션 뒤에 브랜치 이름을 넣으면 그 브랜치에 없는 커밋을 찾아준다. 아래의 명령 세 가지는 모두 같은 명령이다.
$ git log refA..refB
$ git log ^refA refB
$ git log refB --not refA
이 옵션들은 Double Dot으로는 할 수 없는, 세 개 이상의 Refs에 사용할 수 있는 장점이 있다. 예를 들어 `refA`나 `refB`에는 있지만 `refC`에는 없는 커밋을 보려면 아래 중 한 명령을 사용한다.
$ git log refA refB ^refC
$ git log refA refB --not refC
이 조건을 잘 응용하면 작업 중인 브랜치와 다른 브랜치을 매우 상세하게 비교해볼 수 있다.
Triple Dot
Triple Dot은 양쪽에 있는 두 Refs 사이에서 공통으로 가지는 것을 제외하고 서로 다른 커밋만 보여준다.범위를 설명하는 데 사용할 예제의 커밋 히스토리를 다시 보자. 만약 `master`와 `experiment`의 공통부분은 빼고 다른 커밋만 보고 싶으면 아래와 같이 하면 된다.
$ git log master...experiment
F
E
D
C
우리가 아는 log
명령의 결과를 최근 날짜순으로 보여준다. 이 예제에서는 커밋을 네 개 보여준다.
그리고 log
명령에 --left-right
옵션을 추가하면 각 커밋이 어느 브랜치에 속하는지도 보여주기 때문에 좀 더 이해하기 쉽다.
$ git log --left-right master...experiment
< F
< E
> D
> C
위와 같은 명령을 사용하면 원하는 커밋을 좀 더 꼼꼼하게 살펴볼 수 있다.
'Programming > Git' 카테고리의 다른 글
Git_#7.3_Git 도구 - Stashing과 Cleaning (0) | 2017.04.13 |
---|---|
Git_#7.2_Git 도구 - 대화형 명령 (0) | 2017.04.13 |
Git_#6.5_GitHub - GitHub 스크립팅 (0) | 2017.04.13 |
Git_#6.4_GitHub - Organization 관리하기 (0) | 2017.04.13 |
Git_#6.3_GitHub - GitHub 프로젝트 관리하기 (0) | 2017.04.13 |