반응형

 

챕터 개요

  • Git을 사용하고 싶은데 시간이 없을 경우 이번 챕터 읽으면 됨
  • 2장에서 자주 사용하는 명령어가 소개됨
  • 2장에서 다음과 같은 내용 알게 됨
    1. 저장소 생성/설정 방법
    2. 파일 추적/무시 설정 방법
    3. 변경 내용 stage/commit 방법
    4. 파일/파일 패턴 무시 설정 방법
    5. 실수 수정 방법
    6. 프로젝트 히스토리 조회/커밋 비교 방법
    7. 리모트 저장소 push/pull 방법

 

목차

2. Git의 기초
2.1 Git 저장소 만들기
2.2 수정하고 저장소에 저장하기
2.3 커밋 히스토리 조회하기
2.4 되돌리기
2.5 리모트 저장소
2.6 태그
2.7 Git Alias
2.8 요약

 

 


2.1 Git 저장소 만들기

Git 저장소 만들기

  • Git 저장소를 쓰기 시작할 때 주로 다음 두 가지 방법 중 하나를 사용함
    1. 아직 버전관리를 하지 않는 로컬 디렉토리에 Git 저장소를 적용하는 방법
    2. 다른 어딘가에 있는 Git 저장소를 Clone 하는 방법
  • 로컬 디렉토리에 Git 저장소가 준비되면 작업 시작할 수 있음

 

기존 디렉토리를 Git 저장소로 만들기

  • 기존 프로젝트를 Git으로 관리하기 위해서는 프로젝트 디렉토리로 이동한 후 git init 명령을 실행해야 함
    $ git init
  • 이때 .git 이라는 하위 디렉토리가 생성되고, 그 안에 저장소에 필요한 뼈대(skeleton) 파일이 저장됨
  • 이 상태에서는 프로젝트의 어떤 파일도 관리하지 않음(정확히 어떤 파일 파일이 있는지는 Git의 내부에서 다룸)
  • 파일을 관리하기 위해서는 git add 명령으로 추가하고 git commit 명령으로 커밋해야 함
    $ git add *.c
    $ git add LICENSE
    $ git commit -m 'initial project version'
 

기존 저장소를 Clone 하기

  • 프로젝트 참여 또는 Git 저장소 복사할 때는 git clone 명령 사용
  • Subversion과 다르게 Git은 서버의 거의 모든 데이터를 복사함
  • git clone 실행 시 프로젝트 히스토리 전부 받아옴
  • 서버에 문제가 생겨도 어떤 클라이언트 저장소를 가져다가 복구할 수 있음 (서버에만 적용된 설정은 복구할 수 없지만 모든 데이터는 복구됨. 서버에 Git 설치하기에서 자세히 다룸)
  • git clone <url> 명령으로 저장소를 Clone 할 수 있음
    $ git clone https://github.com/libgit2/libgit2
  • Clone 시 새 디렉토리 생성, .git 디렉토리 생성, 저장소 데이터 전부 가져와 가장 최신 버전 Checkout
  • 새 디렉토리 이름 지정 가능
    $ git clone https://github.com/libgit2/libgit2 mylibgit
  • Git은 https://, git://, user@server:path/to/repo.git 같은 SSH 프로토콜 등 다양한 프로토콜을 지원(서버에 Git 설치하기에서 자세히 다룸)

2.2 수정하고 저장소에 저장하기

수정하고 저장소에 저장하기

여기서는 워킹 디렉토리에서 파일 수정/스냅샷 커밋

파일을 수정하다 저장하고 싶으면 스냅샷을 커밋한다.

  • Git 저장소는 Tracked/Untracked 파일을 구분
  • Tracked 파일은 Unmodified, Modified, Staged 상태 중 하나
  • Untracked 파일은 스냅샷과 Staging Area에 포함되지 않은 파일
  • Clone 하고 나면 모든 파일은 Tracked, Unmodified 상태
  • 커밋 이후 수정한 파일은 Modified 상태
  • Staged 상태의 파일을 커밋해서 저장소에 기록할 수 있음
  • 즉, 수정 -> Staging -> 커밋 -> 수정 -> Staging -> 커밋의 라이프 사이클을 반복함
 

그림 8. 파일의 라이프사이클.

 

파일의 상태 확인하기

  • git status 명령을 사용하여 파일의 상태를 확인할 수 있음
  • Clone 한 후에 git status 명령을 실행하면 아래와 같은 메시지가 출력
    $ git status
    On branch main
    Your branch is up to date with 'origin/main'.
    
    nothing to commit, working tree clean
  • Tracked 파일이 수정되지 않았다는 정보와 기본 브랜치인 main에 있음을 알 수 있음
  • Untracked 파일은 아직 없어서 git status에 나타나지 않음
  • 브랜치 관련 내용은 Git 브랜치에서 브랜치와 Refs에 대해 자세히 다룸

 

$ echo 'My Project' > README
$ git status
On branch main
Your branch is up to date with 'origin/main'.

Untracked files:
  (use "git add <file>..." to include in what will be committed)
	README

nothing added to commit but untracked files present (use "git add" to track)
  • README 파일은 새로 만든 파일로 Untracked 상태임
  • Git은 Untracked 파일을 스냅샷에 포함하지 않음
  • 파일이 Tracked 상태가 되기 전까지 Git은 커밋하지 않음
  • 일하면서 생성하는 바이너리 파일을 커밋하는 실수를 막음
  • 다음에서 README 파일을 직접 Tracked 상태로 만들 예정

 

파일을 새로 추적하기

  • README 파일을 추적하기 위해 git add 명령을 사용할 수 있음
$ git add README
  • git status 명령 실행 시 Tracked 상태에서 Staged 상태로 전환된 것을 확인 가능
$ git status
On branch main
Your branch is up to date with 'origin/main'.

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
	new file:   README
  • "Changes to be committed" 에 있는 파일은 Staged 상태
  • git add 명령은 파일 또는 디렉토리 경로를 아규먼트로 받음
  • 디렉토리의 경우 재귀적으로 하위 파일들까지 추가

 

Modified 상태의 파일을 Stage 하기

  • 이미 Tracked 상태인 CONTRIBUTING.md 라는 파일을 수정하고 나서 git status 명령 결과
$ git status
On branch main
Your branch is ahead of 'origin/main' by 1 commit.
  (use "git push" to publish your local commits)

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
	new file:   README

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	modified:   CONTRIBUTING.md
  • "Changes to be committed" 상태인 파일은 Staged 상태임
  • "Changes not staged for commit" 상태인 파일은 수정한 파일이 Tracked 상태이지만 아직 Staged 상태는 아님
  • Staged 상태로 만들려면 git add 명령을 실행해야 함
  • git add 명령은 파일을 새로 추적할 때도 사용하고, 수정한 파일을 Staged 상태로 만들 때도 사용하고, 충돌난 상태의 파일을 Resolve 상태로 만들 때도 사용함.
  • "add" 의미는 프로젝트에 파일을 추가한다기 보다는 다음 커밋에 추가한다고 인식하는 것이 좋음.
 
  • git add 명령을 실행하여 CONTRIBUTING.md 파일을 Staged 상태로 만들고 git status 명령 결과
$ git add CONTRIBUTING.md
$ git status
On branch main
Your branch is ahead of 'origin/main' by 1 commit.
  (use "git push" to publish your local commits)

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
	modified:   CONTRIBUTING.md
	new file:   README​
  • 두 파일 모두 Staged 상태이므로 다음 커밋에 포함된 상태
  • CONTRIBUTING.md 파일을 추가로 수정 후 git status 명령 결과
$ vim CONTRIBUTING.md
$ git status
On branch main
Your branch is ahead of 'origin/main' by 1 commit.
  (use "git push" to publish your local commits)

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
	modified:   CONTRIBUTING.md
	new file:   README

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	modified:   CONTRIBUTING.md
  • CONTRIBUTING.md는 Staged 상태이면서 동시에 Unstaged 상태
  • git add 명령을 실행하면 파일을 Staged 상태로 만듬
  • git commit 시점의 파일 버전이 아닌, git add 명령을 실행한 시점의 파일 버전이 커밋
  • git add 명령을 실행한 후 파일을 수정한 경우, git add 명령을 다시 실행해 최신 버전을 Staged 상태로 만들어야 함 
$ git add CONTRIBUTING.md
$ git status
On branch main
Your branch is ahead of 'origin/main' by 1 commit.
  (use "git push" to publish your local commits)

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
	modified:   CONTRIBUTING.md
	new file:   README​
 
 

파일 상태를 짤막하게 확인하기

  • git status -s 또는 git status --short 처럼 옵션을 주면 간단하게 변경 상태를 확인할 수 있다.
$ git status -s 
 M README
MM Rakefile
A  lib/git.rb
M  lib/simplegit.rb
?? LICENSE.txt
  • A 표시: 새로 생성한 파일
  • M 표시: 수정한 파일
  • 순서대로 Staging Area에서의 상태와 Working Tree에서의 상태가 표시됨
  • README 파일은 수정한 상태이지만 아직 Staged 상태가 아님
  • Rakefile 파일은 수정하고 Staged 상태, 그리고 다시 수정한 상태임 (Staged 이면서 Unstaged 상태)
  • lib/git.rb 파일은 새로 생성되고 Staged 상태
  • lib/simplegit.rb 파일은 수정하고 Staged 상태
  • LICENSE.txt 파일은 깃이 추적하지 않는 상태(추가/수정 아무 것도 모름)
 

파일 무시하기

  • Git이 관리할 필요가 없는 파일이 있음 (예: 로그 파일, 빌드 시스템이 자동 생성한 파일)
  • 무시하려면 .gitignore 파일을 만들고, 그 안에 무시할 파일 패턴을 적음
  • .gitignore 파일 예시
$ cat .gitignore
*.[oa]
*~
  • *.[oa]: 첫번째 줄은 확장자가 ".o" 나 ".a"인 파일을 무시하라
  • *~: "~"로 끝나는 모든 파일을 무시하라
  • ".o"와 ".a"는 빌드 시스템이 생성하는 오브젝트와 아카이브 파일
  • "~"로 끝나는 파일은 주로 텍스트 편집기가 임시로 생성하는 파일
  • .gitignore 파일에는 log, tmp, pid 같은 디렉토리와 자동으로 생성되는 문서도 추가 가능
  • .gitignore 파일은 처음에 만들어 두는 것이 유용하고 실수로 Git 저장소에 커밋하고 싶지 않은 파일을 커밋하는 일을 방지할 수 있음
 
  • .gitignore 파일에 입력하는 패턴은 아래 규칙을 따름
    • 아무것도 없는 라인이나, `#`로 시작하는 라인은 무시한다.
    • 표준 Glob 패턴을 사용한다. 이는 프로젝트 전체에 적용된다.
    • 슬래시(/)로 시작하면 하위 디렉토리에 적용되지(Recursivity) 않는다.
    • 디렉토리는 슬래시(/)를 끝에 사용하는 것으로 표현한다.
    • 느낌표(!)로 시작하는 패턴의 파일은 무시하지 않는다.

 

  • Glob 패턴은 정규표현식을 단순하게 만든 것으로 생각할 수 있음
  • 쉘에서 많이 사용
  • 애스터리스크(*): 문자가 하나도 없거나 하나 이상
  • [abc]: 중괄호 안에 있는 문자 중 하나
  • 물음표(?): 문자 하나
  • 하이픈(-):그 캐릭터 사이에 있는 문자 하나(예: [0-9]처럼 중괄호 안 캐릭터 사이)
  • 애스터리스크 2개(**): 디렉토리 안의 디렉토리까지 지정 가능(예: a/**/z: a/z, a/b/z, a/b/c/d/z 등)
# 확장자가 .a인 파일 무시
*.a

# 윗 라인에서 확장자가 .a인 파일은 무시하게 했지만 lib.a는 무시하지 않음
!lib.a

# 현재 디렉토리에 있는 TODO파일은 무시하고 subdir/TODO처럼 하위디렉토리에 있는 파일은 무시하지 않음
/TODO

# build/ 디렉토리에 있는 모든 파일은 무시
build/

# doc/notes.txt 파일은 무시하고 doc/server/arch.txt 파일은 무시하지 않음
doc/*.txt

# doc 디렉토리 아래의 모든 .pdf 파일을 무시
doc/**/*.pdf

 

힌트

GitHub은 다양한 프로젝트에서 자주 사용하는 .gitignore 예제를 관리하고 있다. 어떤 내용을 넣을지 막막하다면 https://github.com/github/gitignore 사이트에서 적당한 예제를 찾을 수 있다.

 

GitHub - github/gitignore: A collection of useful .gitignore templates

A collection of useful .gitignore templates. Contribute to github/gitignore development by creating an account on GitHub.

github.com

 

노트 - .gitignore`를 사용하는 간단한 방식

  • .gitignore을 최상위 디렉토리에 하나 두고 하위 디렉토리에까지 적용
  • .gitignore 정책은 현재 .gitignore 파일이 위치한 디렉토리와 하위 디렉토리에 적용
  • 다수의 .gitignore 파일을 추가로 둠으로써 정책을 적용 가능
  • 자세한 정보는 man gitignore에서 확인 가능

 

Staged와 Unstaged 상태의 변경 내용을 보기

  • 궁금한 정보: 수정된 파일의 상태(Staged/Unstaged), 어떤 파일이 Staged 상태인지
  • 정보를 얻을 수 있는 명령: git status

 

  • 궁금한 정보: 수정된 파일의 상세 내용(어떤 라인이 추가/삭제됐는지)
  • 정보를 얻을 수 있는 명령: git diff

 

README: 수정 후 staged

CONTRIBUTING.md: 수정만

$ git status
On branch main
Your branch is ahead of 'origin/main' by 2 commits.
  (use "git push" to publish your local commits)

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
	modified:   README

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

$ git diff
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 8ebb991..643e24f 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -65,7 +65,8 @@ branch directly, things can get messy.
 Please include a nice description of your changes when you submit your PR;
 if we have to read the whole diff to figure out why you're contributing
 in the first place, you're less likely to get feedback and have your change
-merged in.
+merged in. Also, split your changes into comprehensive chunks if your patch is
+longer than a dozen lines.

 If you are starting to work on a particular area, feel free to submit a PR
 that highlights your work in progress (and note in the PR title that it's

 

  • git diff 명령은 워킹 디렉토리와 Staging Area에 있는 파일을 비교함
  • git diff --staged 옵션(--cached)은 저장소에 커밋한 것과 Staging Area에 있는 것을 비교함
$ git diff --staged
diff --git a/README b/README
new file mode 100644
index 0000000..03902a1
--- /dev/null
+++ b/README
@@ -0,0 +1 @@
+My Project

 

  • git diff 명령은 마지막 커밋 후에 수정한 것을 모두 보여주지 않음
  • git diff 명령은 Unstaged 상태인 것만 보여줌
  • git diff 명령은 Staged 상태인 것과 Unstaged 상태인 것을 비교할 수 있음
$ git add CONTRIBUTING.md
$ echo '# test line' >> CONTRIBUTING.md
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    modified:   CONTRIBUTING.md

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:   CONTRIBUTING.md

$ git diff
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 643e24f..87f08c8 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -119,3 +119,4 @@ at the
 ## Starter Projects

 See our [projects list](https://github.com/libgit2/libgit2/blob/development/PROJECTS.md).
+# test line

$ git diff --cached
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 8ebb991..643e24f 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -65,7 +65,8 @@ branch directly, things can get messy.
 Please include a nice description of your changes when you submit your PR;
 if we have to read the whole diff to figure out why you're contributing
 in the first place, you're less likely to get feedback and have your change
-merged in.
+merged in. Also, split your changes into comprehensive chunks if your patch is
+longer than a dozen lines.

 If you are starting to work on a particular area, feel free to submit a PR
 that highlights your work in progress (and note in the PR title that it's

 

노트 - 외부 도구로 비교하기

  • 상용 제품도 사용할 수 있는 git difftool 명령 사용 가능
  • git difftool --tool-help 명령: 사용 가능한 도구 보여줌
$ git difftool --tool-help
'git difftool --tool=<tool>' may be set to one of the following:
		opendiff         Use FileMerge (requires a graphical session)
		vimdiff          Use Vim

The following tools are valid, but not currently available:
		araxis           Use Araxis Merge (requires a graphical session)
		bc               Use Beyond Compare (requires a graphical session)
		bc3              Use Beyond Compare (requires a graphical session)
		bc4              Use Beyond Compare (requires a graphical session)
		codecompare      Use Code Compare (requires a graphical session)
		deltawalker      Use DeltaWalker (requires a graphical session)
		diffmerge        Use DiffMerge (requires a graphical session)
		diffuse          Use Diffuse (requires a graphical session)
		ecmerge          Use ECMerge (requires a graphical session)
		emerge           Use Emacs' Emerge
		examdiff         Use ExamDiff Pro (requires a graphical session)
		guiffy           Use Guiffy's Diff Tool (requires a graphical session)
		gvimdiff         Use gVim (requires a graphical session)
		kdiff3           Use KDiff3 (requires a graphical session)
		kompare          Use Kompare (requires a graphical session)
		meld             Use Meld (requires a graphical session)
		nvimdiff         Use Neovim
		p4merge          Use HelixCore P4Merge (requires a graphical session)
		smerge           Use Sublime Merge (requires a graphical session)
		tkdiff           Use TkDiff (requires a graphical session)
		winmerge         Use WinMerge (requires a graphical session)
		xxdiff           Use xxdiff (requires a graphical session)

Some of the tools listed above only work in a windowed
environment. If run in a terminal-only session, they will fail.

 

변경사항 커밋하기

변경사항 커밋 방법 요약

  1. Staging Area에 파일을 정리하기 전에 git status로 확인
  2. git add 명령으로 추가하지 않은 파일은 커밋하지 않음
  3. git commit 으로 커밋하기 전에 git status로 확인
  4. git commit 을 실행하여 커밋함

 

$ git commit
  • Git 설정에 지정된 편집기가 실행됨
  • 편집기 설정은 시작하기에서 설명함
 

Git - 버전 관리란?

1.1 시작하기 - 버전 관리란? 이 장에서 설명하는 것은 Git을 처음 접하는 사람에게 필요한 내용이다. 먼저 버전 관리 도구에 대한 이해와 Git을 설치하는 방법을 설명하고 마지막으로 Git 서버를 설

git-scm.com


# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# On branch master
# Your branch is up-to-date with 'origin/master'.
#
# Changes to be committed:
#	new file:   README
#	modified:   CONTRIBUTING.md
#
~
~
~
".git/COMMIT_EDITMSG" 9L, 283C

 

  • 커밋 메시지 첫 줄: 비어 있음
  • 둘째 줄부터 git status 명령의 결과 입력됨
  • 커밋 메시지에는 내용 요약이 입력될 수 있거나, 새로 작성할 수도 있음
  • git commit 명령에 -v 옵션을 추가 시, 편집기에 diff 메시지가 포함됨
  • 내용 저장 시, Git은 새로운 커밋을 하나 생성

 

  • 메시지 인라인 첨부 가능
  • git commit 명령에 -m 옵션 사용
git commit -m "Check git commit -m"
[main 856d40d7e] Check git commit -m
 1 file changed, 3 insertions(+)

 

  • commit 명령은 브랜치, 체크섬, 수정/삭제된 파일과 라인 수를 출력
  • Git은 Staging Area에 속한 스냅샷을 커밋
  • 수정은 했지만, 아직 Staging Area에 넣지 않은 것은 다음에 커밋 가능
  • 커밋 시 프로젝트의 스냅샷을 기록, 스냅샷끼리 비교하거나 예전 스냅샷으로 되돌릴 수 있음
  

Staging Area 생략하기 - commit의 -a 옵션

  • Staging Area는 커밋할 파일을 정리하는데 유용하지만, 간혹 복잡하고 필요하지 않을 때도 있음
  • git commit 명령에 -a 옵션 추가 시, Tracked 상태의 파일을 자동으로 Staging Area에 넣음
  • git commit -a 수행 시 git add 명령 수행 과정 생략 가능
$ git status
On branch recover-branch
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
	modified:   README

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

$ git commit -am "Commit without add"
[recover-branch 2e51b1dda] Commit without add
 2 files changed, 6 insertions(+)

 

  • git commit 명령에 -a 옵션 추가 시, Tracked 상태의 파일을 자동으로 Staging Area에 넣음
  • 주의: 의도하지 않은 변경사항도 추가될 수 있음
  • 적절한 사용 주의 필요
 

파일 삭제하기 - git rm

  1. git rm 명령으로 Tracked 상태의 파일을 Staging Area에서 삭제한다.
  2. 삭제된 파일은 워킹 디렉토리에서도 삭제된다.
  3. git status 명령으로 상태를 확인해보면 Unstaged 상태로 표시된다.
  4. git commit 명령으로 커밋한다.
$ rm README
$ git status
On branch recover-branch
Changes not staged for commit:
  (use "git add/rm <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	deleted:    README

no changes added to commit (use "git add" and/or "git commit -a")

 

$ git rm README
rm 'README'
$ git status
On branch recover-branch
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
	deleted:    README

 

  • 커밋하면 파일은 삭제되고 Git은 이 파일을 더는 추적하지 않는다.
  • 이미 파일을 수정했거나 Staging Area(Git Index)에 추가했다면 -f 옵션을 주어 강제로 삭제해야 한다.
  • --cached 옵션을 사용하면 Staging Area에서만 제거할 수 있다.
  • .gitignore 파일에 추가하는 것을 빼먹었거나 대용량 로그 파일이나 컴파일된 파일인 .a 파일 같은 것을 실수로 추가했을 때 쓴다.
$ git rm --cached README
  • 여러 파일 또는 디렉토리 한 번에 삭제 가능
  • git rm 명령에 file-glob 패턴 사용
$ git rm log/\*.log
  • log/ 디렉토리에 있는 .log 파일을 전무 삭제하는 명령
  • * 앞에 \ 을 사용 기억하자
  • 파일명 확장 기능은 깃/쉘 둘 다 가지고 있다.

 

파일 이름 변경하기 - git mv

Git은 파일 이름의 변경이나 파일의 이동을 명시적으로 관리하지 않음

$ git mv file_from file_to

$ git mv README README_two
$ git status
On branch recover-branch
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
	renamed:    README -> README_two

아래 명령과 동일

$ mv README README_two
$ git rm README
$ git add README_two

 


2.3 커밋 히스토리 조회하기 - git log

커밋 히스토리 조회하기

$ git clone https://github.com/schacon/simplegit-progit
$ git log
commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Mon Mar 17 21:52:11 2008 -0700

    changed the version number

commit 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Sat Mar 15 16:40:33 2008 -0700

    removed unnecessary test

commit a11bef06a3f659402fe7563abf99ad00de2209e6
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Sat Mar 15 10:31:28 2008 -0700

    first commit

 

  • -p, --patch : 각 커밋의 diff 결과 보여줌
  • -<n>(-2, -3, ...) : 최근 n개의 결과 보여줌
  • --stat : 각 커밋의 통계 정보 조회
  • --pretty=oneline(short, full, fuller, oneline, format) : 해당 조건에 맞는 형식 보여줌
$ git log --pretty=format:"%h - %an, %ar : %s"
ca82a6d - Scott Chacon, 6 years ago : changed the version number
085bb3b - Scott Chacon, 6 years ago : removed unnecessary test
a11bef0 - Scott Chacon, 6 years ago : first commit

git log --pretty=format에 쓸 몇 가지 유용한 옵션

표 1. git log --pretty=format 에 쓸 몇가지 유용한 옵션`

옵션 설명
%H 커밋 해시
%h 짧은 길이 커밋 해시
%T 트리 해시
%t 짧은 길이 트리 해시
%P 부모 해시
%p 짧은 길이 부모 해시
%an 저자 이름
%ae 저자 메일
%ad 저자 시각 (형식은 –-date=옵션 참고)
%ar 저자 상대적 시각
%cn 커미터 이름
%ce 커미터 메일
%cd 커미터 시각
%cr 커미터 상대적 시각
%s 요약

 

 

author vs commiter

  • author: 원래 작업을 수행한 원작자
  • commiter : 마지막으로 해당 커밋을 적용한 자
  • 분산 환경에서의 Git 에서 자세히 다룸

표 2. git log 주요 옵션

-p 각 커밋에 적용된 패치를 보여준다.
--stat 각 커밋에서 수정된 파일의 통계정보를 보여준다.
--shortstat --stat 명령의 결과 중에서 수정한 파일, 추가된 라인, 삭제된 라인만 보여준다.
--name-only 커밋 정보중에서 수정된 파일의 목록만 보여준다.
--name-status 수정된 파일의 목록을 보여줄 뿐만 아니라 파일을 추가한 것인지, 수정한 것인지, 삭제한 것인지도 보여준다.
--abbrev-commit 40자 짜리 SHA-1 체크섬을 전부 보여주는 것이 아니라 처음 몇 자만 보여준다.
--relative-date 정확한 시간을 보여주는 것이 아니라 “2 weeks ago” 처럼 상대적인 형식으로 보여준다.
--graph 브랜치와 머지 히스토리 정보까지 아스키 그래프로 보여준다.
--pretty 지정한 형식으로 보여준다. 이 옵션에는 oneline, short, full, fuller, format이 있다. format은 원하는 형식으로 출력하고자 할 때 사용한다.
--oneline --pretty=oneline --abbrev-commit 두 옵션을 함께 사용한 것과 같다.

 

조회 제한조건

$ git log --since=2.weeks  # 지난 2주 동안 만들어진 커밋들만 조회
$ git log -S function_name  # 특정 텍스트가 포함되어 있는 커밋들만 조회

 

표 3. git log 조회 범위를 제한하는 옵션

옵션 설명
-(n) 최근 n 개의 커밋만 조회한다.
--since, --after 명시한 날짜 이후의 커밋만 검색한다.
--until, --before 명시한 날짜 이전의 커밋만 조회한다.
--author 입력한 저자의 커밋만 보여준다.
--committer 입력한 커미터의 커밋만 보여준다.
--grep 커밋 메시지 안의 텍스트를 검색한다.
-S 커밋 변경(추가/삭제) 내용 안의 텍스트를 검색한다.
노트
--author와 --grep 옵션을 함께 사용하여 모두 만족하는 커밋을 찾으려면 --all-match 옵션도 반드시 함께 사용해야 한다.

 

# Merge 커밋을 제외한 순수한 커밋을 확인해보는 명령이다.
# Junio Hamano가 2008년 10월에 Git 소스코드 저장소에서 테스트 파일을 수정한 커밋들
$ git log --pretty="%h - %s" --author=gitster --since="2008-10-01" \
   --before="2008-11-01" --no-merges -- t/
5610e3b - Fix testcase failure when extended attributes are in use
acd3b9e - Enhance hold_lock_file_for_{update,append}() API
f563754 - demonstrate breakage of detached checkout with symbolic link HEAD
d1a43f2 - reset --hard/read-tree --reset -u: remove unmerged new paths
51a94af - Fix "checkout --track -b newbranch" on detached HEAD
b0ad11e - pull: allow "git pull origin $something:$current_branch" into an unborn branch
 
노트 - 머지 커밋 표시하지 않기
저장소를 사용하는 워크플로우에 따라 머지 커밋이 차지하는 비중이 클 수도 있다. --no-merges 옵션을 사용하면 검색 결과에서 머지 커밋을 표시하지 않도록 할 수 있다.
 

2.4 되돌리기

되돌리기

한 일 되돌리기

  • 일을 하다보면 어떤 것은 되돌리고 싶을 때가 있음
  • Git을 사용하면 일반적인 실수는 대부분 복구 가능
  • 그러나 되돌린 것은 복구할 수 없음

커밋 수정하기

  • 완료한 커밋을 수정해야 할 때가 있음
  • 너무 일찍 커밋했을 때
  • 파일을 빼먹었을 때
  • 커밋 메시지를 잘못 적었을 때
  • --amend 옵션을 사용해 커밋 재작성 가능
# 아래 세 명령어는 하나의 커밋으로 기록된다. 두 번째 커밋은 첫 번째 커밋을 덮어쓴다.
$ git commit -m 'initial commit'
$ git add forgotten_file
$ git commit --amend

노트 - --amend 옵션을 사용한 커밋 수정

커밋 완전히 새로 고치는 것. 이전 커밋 완전히 사라짐.

장점: 살짝 빠진 것을 추가하거나 변경하는 것을 새 커밋으로 분리 안해서 하나의 커밋에서 처리. 작은 수정 작업을 새 커밋으로 안 만듬.

 

 

  • 일을 하다보면 어떤 것은 되돌리고 싶을 때가 있음
  • Git을 사용하면 일반적인 실수는 대부분 복구 가능
  • 그러나 되돌린 것은 복구할 수 없음.

 

파일 상태를 Unstage로 변경하기 - git reset HEAD <file>...

$ git add *
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    renamed:    README.md -> README
    modified:   CONTRIBUTING.md

$ git reset HEAD CONTRIBUTING.md
Unstaged changes after reset:
M	CONTRIBUTING.md
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    renamed:    README.md -> README

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:   CONTRIBUTING.md

노트

git reset 명령은 매우 위험하다. --hard 옵션과 함께 사용하면 더욱 위험하다. 하지만 위에서 처럼 옵션 없이 사용하면 워킹 디렉토리의 파일은 건드리지 않는다. Reset 명확히 알고 가기에서 자세히 살펴볼 예정

 

Modified 파일 되돌리기 - git checkout -- <file>...

$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    renamed:    README.md -> README

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:   CONTRIBUTING.md

$ git checkout -- CONTRIBUTING.md
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    renamed:    README.md -> README

노트

git checkout — [file] 명령은 꽤 위험한 명령이라는 것을 알아야 한다. 원래 파일로 덮어썼기 때문에 수정한 내용은 전부 사라진다. 수정한 내용이 진짜 마음에 들지 않을 때만 사용하자.

 

변경한 내용을 쉽게 버릴수는 없고 하지만 당장은 되돌려야만 하는 상황이라면 Stash와 Branch를 사용하자. Git 브랜치 에서 다루는 이 방법들이 훨씬 낫다.
Git으로 커밋 한 모든 것은 언제나 복구할 수 있다. 삭제한 브랜치에 있었던 것도, --amend 옵션으로 다시 커밋한 것도 복구할 수 있다(자세한 것은 데이터 복구 에서 다룬다). 하지만 커밋하지 않고 잃어버린 것은 절대로 되돌릴 수 없다.

 

 


2.5 리모트 저장소

리모트 저장소

주제: 리모트 저장소 관리하기

  • 리모트 저장소: 인터넷이나 네트워크 어딘가에 있는 저장소
  • 읽기만 가능/읽기 쓰기 둘 다 가능한 저장소 있음
  • 리모트 저장소 관리: 추가/삭제, 브랜치 관리, 추적 여부 관리 등을 뜻함
  • 함께 일한다는 것: Push, Pull하는 것

 

노트 - 원격 저장소라 하더라도 로컬 시스템에 위치할 수도 있다.

  • "remote" 저장소는 실제로 로컬 시스템에 존재할 수 있음
  • "remote"라는 이름은 저장소가 멀리 있다는 것을 의미하지 않음
  • Push, Pull 기능은 일반적인 원격 저장소와 동일하게 사용

 

리모트 저장소 확인하기 - git remote

git remote: 리모트 저장소의 단축 이름을 보여줌

origin이라는 이름을 볼 수 있음. 저장소를 Clone 하면 `origin`이라는 리모트 저장소가 자동으로 등록되기 때문

$ git clone https://github.com/schacon/ticgit
Cloning into 'ticgit'...
remote: Enumerating objects: 1857, done.
remote: Total 1857 (delta 0), reused 0 (delta 0), pack-reused 1857
Receiving objects: 100% (1857/1857), 334.06 KiB | 12.37 MiB/s, done.
Resolving deltas: 100% (837/837), done.
$ cd ticgit 
# git remote: 리모트 저장소의 단축 이름을 보여줌
$ git remote
origin

# -v: url 같이 볼 수 있음
$ git remote -v
origin	https://github.com/schacon/ticgit (fetch)
origin	https://github.com/schacon/ticgit (push)

# 함께 작업하는 리모트 저장소가 여러개라면 아래와 같은 결과를 얻을 수도 있음
$ cd grit
$ git remote -v
bakkdoor  https://github.com/bakkdoor/grit (fetch)
bakkdoor  https://github.com/bakkdoor/grit (push)
cho45     https://github.com/cho45/grit (fetch)
cho45     https://github.com/cho45/grit (push)
defunkt   https://github.com/defunkt/grit (fetch)
defunkt   https://github.com/defunkt/grit (push)
koke      git://github.com/koke/grit.git (fetch)
koke      git://github.com/koke/grit.git (push)
origin    git@github.com:mojombo/grit.git (fetch)
origin    git@github.com:mojombo/grit.git (push)

리모트 저장소와 데이터를 주고받는 데 사용하는 다양한 프로토콜 - 서버에 Git 설치하기 에서 자세히 다룸

 

리모트 저장소 추가하기 - git remote add <단축 이름> <url>

$ git remote
origin
$ git remote add pb https://github.com/paulboone/ticgit
$ git remote -v
origin	https://github.com/schacon/ticgit (fetch)
origin	https://github.com/schacon/ticgit (push)
pb	https://github.com/paulboone/ticgit (fetch)
pb	https://github.com/paulboone/ticgit (push)

 

url 대신 pb라는 이름 사용 가능

 

# 로컬 저장소에는 없지만 Paul의 저장소에 있는 것을 가져오려면 아래과 같이 실행
$ git fetch pb
remote: Counting objects: 43, done.
remote: Compressing objects: 100% (36/36), done.
remote: Total 43 (delta 10), reused 31 (delta 5)
Unpacking objects: 100% (43/43), done.
From https://github.com/paulboone/ticgit
 * [new branch]      master     -> pb/master
 * [new branch]      ticgit     -> pb/ticgit

 

리모트 저장소를 Pull 하거나 Fetch 하기 - git fetch <remote>

git fetch: 로컬에는 없지만 리모트 저장소에는 있는 데이터를 모두 가져옴 -> 리모트 저장소의 모든 브랜치를 로컬에서 접근 가능 -> 언제든지 merge 가능/내용 살펴볼 수 있음

 

clone, fetch, pull의 차이

  • clone: 저장소를 원격으로부터 복제, "origin" 이라는 이름으로 추가
  • fetch: 원격 저장소의 데이터를 가져오지만, 자동 Merge 안함
  • pull: 원격 저장소의 데이터를 가져오고 자동 Merge
  • git clone 시, 자동으로 로컬 브랜치가 리모트 저장소의 브랜치 추적

 

 

리모트 저장소에 Push 하기 - git push <리모트 저장소 이름> <브랜치 이름>

Upstream 저장소에 Push하기

  • Push 시 <리모트 저장소 이름> <브랜치 이름> 형식으로 입력
  • 예: git push origin main
  • Clone 한 사람이 여러 명 있을 때, 다른 사람이 Push 한 후에 Push 하려고 하면 Push 불가
  • 다른 사람이 작업한 것을 가져와서 Merge 후 Push 가능

 

리모트 저장소 살펴보기 - git remote show <리모트 저장소 이름>

git remote show <리모트 저장소 이름>: 리모트 저장소의 URL과 추적하는 브랜치 출력함

$ git remote show origin
* remote origin
  Fetch URL: https://github.com/schacon/ticgit
  Push  URL: https://github.com/schacon/ticgit
  HEAD branch: master
  Remote branches:
    master tracked
    ticgit tracked
  Local branch configured for 'git pull':
    master merges with remote master
  Local ref configured for 'git push':
    master pushes to master (up to date)
# 브랜치명을 생략하고 git push 명령을 실행할 때 어떤 브랜치가 어떤 브랜치로 Push 되는지 보여줌

 

리모트 저장소 이름을 바꾸거나 리모트 저장소를 삭제하기 - git remote rename / git remote remove(rm)

git remote rename A B: 리모트 저장소 A의 이름을 B로 변경

$ git remote rename pb paul
Renaming remote references: 100% (2/2), done.
# git remote
origin
paul
# 로컬에서 관리하던 리모트 저장소의 브랜치 이름도 바뀐다. pb/master는 paul/master로 사용하여야 한다.

git remote remove A: 리모트 저장소 A 삭제

$ git remote remove paul
$ git remote
origin

 


2.6 태그

태그

  • 태그란 Git에서 특정 커밋을 가리키는 이름
  • 다른 VCS처럼 Git도 태그를 지원
  • 보통 릴리즈할 때 사용(v1.0, 등등)

 

태그 조회하기 - git tag

$ git tag
v0.1
v1.3

# -l, --list 는 해당 태그들만 검색
$ git tag -l "v1.8.5*"
v1.8.5
v1.8.5-rc0
v1.8.5-rc1
v1.8.5-rc2
v1.8.5-rc3
v1.8.5.1
v1.8.5.2
v1.8.5.3
v1.8.5.4
v1.8.5.5

 

노트 - 와일드카드를 사용하여 Tag 리스트를 확인하려면 -l, --list 옵션을 지정

  • -l, --list 옵션을 지정하여 검색 가능
  • 예: git tag -l "v1.*"
  • 단순히 git tag 명령 실행 시 -l 또는 --list 옵션과 동일한 결과 출력
  • 와일드카드 사용 시 -l 또는 --list 옵션 필수 지정

 

태그 붙이기 - git tag

Git 태그의 종류

  1. Lightweight 태그: 특정 커밋에 대한 포인터일 뿐, 최신 커밋으로 이동하지 않음.
  2. Annotated 태그: 태그를 만든 사람의 이름, 이메일, 태그를 만든 날짜, 태그 메시지도 저장. GPG로 서명 가능.
  • 임시로 생성하는 경우나 정보 유지가 필요 없는 경우에는 Lightweight 태그 사용 가능.

 

Annotated 태그 - git tag -a <태그>

$ git tag -a v1.4 -m "my version 1.4"
$ git tag
v0.1
v1.3
v1.4
# -m 옵션으로 태그를 저장할 때 메시지를 함께 저장할 수 있음

git show <태그> : 태그 정보와 커밋 정ㅂ조 확인 가능

$ git show v1.4
tag v1.4
Tagger: Ben Straub <ben@straub.cc>
Date:   Sat May 3 20:19:12 2014 -0700

my version 1.4

commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Mon Mar 17 21:52:11 2008 -0700

    changed the version number

 

Lightweight 태그 - git tag <태그>

$ git tag v1.4-lw
$ git tag
v0.1
v1.3
v1.4
v1.4-lw
v1.5

단순한 커밋 정보만을 보여줌

$ git show v1.4-lw
commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Mon Mar 17 21:52:11 2008 -0700

    changed the version number

 

나중에 태그하기 - git tag -a <태그> <해시>

예전 커밋에 대해서도 태그 가능

$ git tag -a v1.2 9fceb02
$ git tag
v0.1
v1.2
v1.3
v1.4
v1.4-lw
v1.5

$ git show v1.2
tag v1.2
Tagger: Scott Chacon <schacon@gee-mail.com>
Date:   Mon Feb 9 15:32:16 2009 -0800

version 1.2
commit 9fceb02d0ae598e95dc970b74767f19372d61af8
Author: Magnus Chacon <mchacon@gee-mail.com>
Date:   Sun Apr 27 20:43:35 2008 -0700

    updated rakefile
...

 

태그 공유하기 - git push origin <태그>

git push: 자동으로 리모트 서버에 태그 전송하지 않음. 브랜치 공유하는 것과 같이 'git push origin <태그>' 실행

$ git push origin v1.5
Counting objects: 14, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (12/12), done.
Writing objects: 100% (14/14), 2.05 KiB | 0 bytes/s, done.
Total 14 (delta 3), reused 0 (delta 0)
To git@github.com:schacon/simplegit.git
 * [new tag]         v1.5 -> v1.5

git push origin --tags: 리모트 서버에 없는 태그 모두 전송 가능

$ git push origin --tags
Counting objects: 1, done.
Writing objects: 100% (1/1), 160 bytes | 0 bytes/s, done.
Total 1 (delta 0), reused 0 (delta 0)
To git@github.com:schacon/simplegit.git
 * [new tag]         v1.4 -> v1.4
 * [new tag]         v1.4-lw -> v1.4-lw

 

 

태그를 Checkout 하기

예를 들어 태그가 특정 버전을 가리키고 있고, 특정 버전의 파일을 체크아웃 해서 확인하고 싶다면 다음과 같이 실행한다. 단 태그를 체크아웃하면(브랜치를 체크아웃 하는 것이 아니라면) “detached HEAD”(떨어져나온 HEAD) 상태가 되며 일부 Git 관련 작업이 브랜치에서 작업하는 것과 다르게 동작할 수 있다.

$ git checkout 2.0.0
Note: checking out '2.0.0'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:

  git checkout -b <new-branch>

HEAD is now at 99ada87... Merge pull request #89 from schacon/appendix-final

$ git checkout 2.0-beta-0.1
Previous HEAD position was 99ada87... Merge pull request #89 from schacon/appendix-final
HEAD is now at df3f601... add atlas.json and cover image

 

“detached HEAD”(떨어져나온 HEAD) 상태에서는 작업을 하고 커밋을 만들면, 태그는 그대로 있으나 새로운 커밋이 하나 쌓인 상태가 되고 새 커밋에 도달할 수 있는 방법이 따로 없게 된다. 물론 커밋의 해시 값을 정확히 기억하고 있으면 가능하긴 하다. 특정 태그의 상태에서 새로 작성한 커밋이 버그 픽스와 같이 의미있도록 하려면 반드시 브랜치를 만들어서 작업하는 것이 좋다.

 

$ git checkout -b version2 v2.0.0
Switched to a new branch 'version2'

물론 이렇게 브랜치를 만든 후에 version2 브랜치에 커밋하면 브랜치는 업데이트된다. 하지만, v2.0.0 태그는 가리키는 커밋이 변하지 않았으므로 두 내용이 가리키는 커밋이 다르다는 것을 알 수 있다.

 


2.7 Git Alias

Git Alias

 

 

 


2.8 요약

요약

이제 우리는 로컬에서 사용할 수 있는 Git 명령에 대한 기본 지식은 갖추었다. 저장소를 만들고 Clone 하는 방법, 수정하고 나서 Stage 하고 커밋하는 방법, 저장소의 히스토리를 조회하는 방법 등을 살펴보았다. 이어지는 장에서는 Git의 가장 강력한 기능인 브랜치 모델을 살펴볼 것이다.

 

반응형

+ Recent posts