Git Basics (2)
Tracking status, changes and commit history
깃은 파일에 대한 변경 히스토리를 추적할 때 매우 유용하게 쓰일 수 있다.
“Software Development”를 hello.txt
내용에 붙이고 git status
커맨드를 실행하여 마지막 커밋으로부터 무엇이 변경되었는지 확인해보자.
echo Software Development >> hello.txt
git status
다음과 같은 아웃풋이 나올 것이다.
On branch master
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
no changes added to commit (use "git add" and/or "git commit -a")
hello.txt
를 스테이징하기 전에 가장 최근의 커밋과 얼마나 다른지 확인할 수 있다. 리눅스의 diff
커맨드와 비슷하게 git diff
는 두 개의 깃 데이터 소스 (i.e. commits, branches, files, etc)들 간의 차이점을 보여준다.
git diff
를 실행하면 다음과 같은 아웃풋이 나온다.
diff --git a/hello.txt b/hello.txt
index dec4cb0..f4a4437 100644
--- a/hello.txt
+++ b/hello.txt
@@ -1 +1,2 @@
Hello World
+Software Development
자, 이제 파일을 staging area에 추가한다.
git add hello.txt
git status
다음과 같은 아웃풋이 나올 것이다.
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
modified: hello.txt
이 때, 만약 스테이징 된 파일이나 이전 커밋의 스테이징된 파일의 변경 사항을 보려면 git diff --staged
를 하면 된다.
이제 커밋을 하기 위해 다음과 같이 실행한다.
git commit -m "add course name to hello.txt"
이제 다시
find .git/objects -type f
를 실행해보면 깃 레포지토리에 6개의 object가 있는 것을 확인할 수 있다. 2개는 commit object이고, 각각 자신의 tree object를 가지고 있다. 또 2개의 blob object가 있다. 이제 hello.txt와 hello.bak이 서로 다른 내용을 담고 있기 때문에 2개의 blob object가 존재하는 것이다. 구별하기 위해서 git cat-file -p
커맨드를 사용하여 확인할 수 있다. 그러나 모든 레포지토리는 많은 커밋들을 가지고 있고 디폴트로 깃은 가장 최근 것만 보여준다. 가장 최근의 커밋을 찾기 위해 cat 명령어를 사용하여 확인할 수 있다.
cat .git/refs/heads/master
아웃풋은 가장 최근 커밋을 포함하는 SHA1 해시 파일 이름이다. 그 파일을 다음과 같이 확인해보자.
git cat-file -p <file name outputted from the last command>
다음과 같은 아웃풋이 나올 것이다.
tree 78b63e73cb6a5dabdad47d1168dbbc0b7a405db4
parent c104d14008cdcef613ec0ef06bdd8af708db0d8b
author Basem <basem.suleiman@sydney.edu.au> 1532582657 +1000
committer Basem <basem.suleiman@sydney.edu.au> 1532582657 +1000
add course name to hello.txt
첫 커밋과 다르게 이번에는 parent commit object에 대한 정보도 있다. 깃이 내용의 변경에 대한 히스토리를 추적하는 방법이 이것이다. 모든 커밋들은 그것의 부모 포인터로 연결되어 있다. 링크드 리스트 구조를 갖으며 이 리스트의 헤드는 외부 파일이 포인팅하고 있다. 즉, 우리의 레포지토리 커밋 히스토리는 head -> c2 -> c1
인 것이다.
때때로는 파일들을 staging area에 먼저 추가하지 않고 커밋하고 싶을 때도 있을 것이다. 이 때는 git commit
에 -a
flag을 달아주면 git add
를 건너뛰고 커밋할 수 있다.
Checking commit logs
모든 변경 사항들을 커밋하였으면, 이제 어떤 일들이 일어났는지를 다시 확인하고 싶을 수도 있다. 커밋 히스토리는 다음과 같이 확인할 수 있다.
git log
다음과 같은 아웃풋을 볼 수 있을 것이다.
Author: Sui <sui.man@google.com>
Date: Sun May 12 20:23:21 2021 +1000
add course name to course.txt
commit af55a4046cfc58804565fae37683fc902fb008ec
Author: Sui <sui.man@google.com>
Date: Sun May 12 20:01:11 2021 +1000
My First Commit
git log
는 디폴트로 모든 커밋을 시간 역순으로 나열한다.
다음과 같은 flag를 사용하여 제한 사항을 둘 수도 있다.
예를 들어,
git log -n
은 최근 n개의 커밋만 표시하고,
git log -n -p
는 최근 n개의 커밋, 그리고 각 커밋에 대하여 그것의 전 커밋과의 차이점을 보여준다.
git log tool의 몇 가지 데코레이션 기능도 있다. 예를 들어 그래프를 커맨드 라인에 그릴 수 있다.
git log --graph
다음과 같은 아웃풋이 나올 것이다.
* commit e7432094641cfbf534295c95d4114df887f732df (HEAD -> master)
| Author: Sui <sui.man@google.com>
| Author: Sui <sui.man@google.com>
| Date: Sun Jul 21 20:18:24 2019 +1000
|
| add course name to hello.txt
|
* commit af55a4046cfc58804565fae37683fc902fb008ec
Author: Sui <sui.man@google.com>
Date: Sun Jul 21 20:01:49 2019 +1000
My First Commit
위와 같은 경우는 매우 단순한 예시이고, 더 많은 커밋을 가진 레포지토리들을 더 복잡하고 지저분한 아웃풋이 나올 수 있다. 커밋의 아웃풋을 좀 더 간략화하기 위해, --oneline
이나 --decorate
flag를 사용할 수 있다.
NOTE: 현재 2.14.4 버전 이후의 git에서는 디폴트로 –decorate으로 로그가 나오기 때문에, git log
와 git log --decorate
아웃풋이 같은 것을 확인할 수 있다.
git log --graph --oneline --decorate
를 실행하면 다음과 같이 나온다.
* e743209 (HEAD -> master) add course name to hello.txt
* af55a40 My First Commit
좀 더 큰 프로젝트로 해보면 다음과 같이 나온다.
* 0e25143 (HEAD, master) Merge branch 'feature'
|\
| * 16b36c6 Fix a bug in the new feature
| * 23ad9ad Start a new feature
* | ad8621a Fix a critical security issue
|/
* 400e4b7 Fix typos in the documentation
* 160e224 Add the initial code base
깃은 reference logs, 혹은 reflogs라는 메커니즘을 사용하여 브랜치에 대한 업데이트 또한 추적한다. 각 git ref에 대해, 레포지토리에서의 업데이트를 보여주는 reflog가 있다. 다음과 같이 실행한다.
git reflog
HEAD ref가 모든 커밋들이 생기는 과정 동안 어떻게 업데이트 되었는지 보려면,
git reflog show HEAD
를 하면 된다.
git reflog를 실행하면,
3557078 (HEAD -> master) HEAD@{0}: commit: Committed unit.txt and unit.bak
9643a7c HEAD@{1}: commit (initial): My First Commit
다음과 같이 커밋들이 어떻게 가르키고 있는지 포인터 정보가 나오고, 특정 ref에 대해, 예를 들어 HEAD ref에 대해 보려면 git reflog show HEAD
를 한다.
그러면 위와 동일하게 나오고, 만약 제일 최근 커밋의 ref를 보려면 git reflog show HEAD@{0}
를 해본다. 또 위와 동일하게 나온다.
만약, 첫 커밋을 기준으로 보려면 git reflog show HEAD@{1}
을 한다.
그럴 경우,
9643a7c HEAD@{1}: commit (initial): My First Commit
다음과 같이 나오고, 만약 git reflog show HEAD@{2}
를 해보면, 이는 존재하지 않기 떄문에 다음과 같은 오류가 뜬다.
fatal: log for 'HEAD' only has 2 entries
히스토리에 두 개의 커밋밖에 없기 때문에 당연한 결과이다.
Leave a comment