Pro git - 2.2

Updated:

Pro git - 수정하고 저장소에 저장하기

  • 워킹 디렉토리의 모든 파일은 크게 두 가지로 나뉜다.
  1. Tracked(관리대상) : 이미 스냅샷에 포함되어 있던 파일. Unmodified, modified, staged 상태 중 하나. 즉, Git이 알고 있는 파일

  2. Untracked(비관리대상) : tracked 나머지 파일. 워킹 디렉토리에 있는 파일 중 스냅샷에도 staging area에 포함되지 않은 파일.

    내 생각 : 그럼 untracked는 새로 만든 파일을 말하는 듯?

1. 파일의 상태 확인하기

  • 파일 상태 확인하기 위해서 git status 명령을 사용한다.
  • 아래는 clone한 후에 바로 이 명령을 실행하면 아래와 같이 보임
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
nothing to commit, working directory clean
  • 위의 내용은 tracked 파일은 하나도 수정되지 않았다는 의미
  • untracked 파일은 아직 없어서 목록에 나타나지 않는다.
  • 현재 작업 중인 브랜치를 알려주며 서버의 같은 브랜치로부터 진행된 작업이 없는 것을 나타낸다.

  • README 파일을 만든 예제는 다음과 같다.
$ echo 'My Project' > README
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
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 파일은 새로 만든 파일이기 때문에 git status 를 실행하면 ‘Untracked files’에 들어 있다.

    내생각이 역시나 맞았다.

2. 파일을 새로 추적하기

  • git add 명령으로 파일을 새로 추적할 수 있다.
$ git add README
  • git status 명령을 다시 실행하면 README 파일이 tracked 상태이면서 커밋에 추가될 staged 상태라는 것을 확인할 수 있다.
$ 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)

    new file:   README
  • “Changes to be committed” 에 들어 있는 파일은 Staged 상태라는 것을 의미
  • 커밋하면 git add 를 실행한 시점의 파일이 커밋되어 저장소 히스토리에 남는다.
  • git add 명령은 파일 또는 디렉토리의 경로를 아규먼트로 받는다. 디렉토리면 아래에 있는 모든 파일들까지 재귀적으로 추가

3. Modified 상태의 파일을 Stage 하기

  • tracked 상태인 파일을 수정하는 방법
  • CONTRIBUTING.md 라는 파일을 수정하고 나서 git status 명령을 다시 실행하면 결과는 아래와 같다.
$ 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)

    new file:   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
  • CONTRIBUTING.md 파일은 “Changes not staged for commit” 에 있다.
  • 이것은 수정한 파일이 Tracked 상태이지만 아직 Staged 상태는 아니라는 것이다.
  • Staged 상태로 만들려면 git add 명령을 실행해야 한다.
  • Merge 할 때 충돌난 상태의 파일을 Resolve 상태로 만들때도 사용한다.
  • add의 의미는 프로젝트에 파일을 추가한다기 보다는 다음 커밋에 추가한다라는 의미.
  • git add 명령 후 git status 명령으로 결과를 확인해보자.
$ git add 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)

    new file:   README
    modified:   CONTRIBUTING.md
  • 두 파일 모두 staged 상태이므로 다음 커밋에 포함.
  • 이때 CONTRIBUTING.md 파일을 수정했다고 가정. 그후 다시 git status 명령어 실행
$ vim 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)

    new file:   README
    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
  • 그러면 위와 같이 CONTRIBUTING.md 가 Staged 상태이면서 동시에 Unstaged 상태로 나옴.
  • 따라서 commit 전 마지막 최종 git add 하여 최신 버전을 staged 상태로 만들어야 함

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

  • git status -s 또는 git status --short 처럼 옵션을 주면 현재 변경한 상태를 짤막하게 보여준다.
$ git status -s
 M README
MM Rakefile
A  lib/git.rb
M  lib/simplegit.rb
?? LICENSE.txt
  • 아직 추적하지 않는 새 파일 앞에는 ?? 표시가 붙는다.
  • Staged 상태로 추가한 파일 중 새로 생성한 파일 앞에는 A 표시가, 수정한 파일 앞에는 M 표시가 붙는다.
  • 왼쪽에는 Staging Area에서의 상태를, 오른쪽에는 Working Tree에서의 상태를 표시한다.
  • README 파일 같은 경우 내용을 변경했지만 아직 Staged 상태로 추가하지는 않았다.
  • lib/simplegit.rb 파일은 내용을 변경하고 Staged 상태로 추가까지 한 상태이다.
  • Rakefile 은 변경하고 Staged 상태로 추가한 후 또 내용을 변경해서 Staged 이면서 Unstaged 상태인 파일이다.

5. 파일 무시하기

  • 로그, 빌드 시스템이 자동으로 생성한 파일같이 무시하려면 .gitignore 파일을 만들고 그 안에 무시할 파일 패턴을 적는다.
$ cat .gitignore
*.[oa]
*~
  • 첫 라인은 확장자가 “.o” or “.a” 인 파일을 Git이 무시하라는 의미
  • 둘째 라인은 ~로 끝나는 모든 파일을 무시하라는 의미

5.1 .gitignore 패턴 규칙

  1. 아무것도 없는 라인이나, #로 시작하는 라인은 무시한다.
  2. 표준 Glob 패턴을 사용한다. 이는 프로젝트 전체에 적용된다.
  3. 슬래시(/)로 시작하면 하위 디렉토리에 적용되지(Recursivity) 않는다.
  4. 디렉토리는 슬래시(/)를 끝에 사용하는 것으로 표현한다.
  5. 느낌표(!)로 시작하는 패턴의 파일은 무시하지 않는다.
  • glob 패턴은 정규표현식을 단순하게 만든 것
  • 애스터리스크(*)는 문자가 하나도 없거나 하나 이상을 의미. 전체를 의미하는듯?
  • [abc] 는 중괄호 안에 있는 문자 중 하나를 의미. 즉, a,b,c중 하나
  • 물음표(?)는 문자 하나를 의미
  • [0-9] 처럼 중괄호 안의 캐릭터 사이에 하이픈(-)을 사용하면 그 캐릭터 사이에 있는 문자 하나를 말한다.
  • 애스터리스크 2개를 사용하여 디렉터리 안의 디렉토리까지 지정할 수 있다.
  • 즉, a/**/z 패턴은 a/z, a/b/z, a/b/c/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
  • .gitignore 파일을 하나만 두는 것이 아니라 하위 디렉토리에도 추가로 둘 수도 있다.
  • .gitignore 정책은 현재 .gitignore 파일이 위치한 디렉토리와 그 하위 디렉토리에 적용된다.
  • 그래서 보통 루트 디렉토리에 둔다.
  • 리눅스 커널 소스 저장소에는 .gitignore 파일이 206개나 있음.

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

  • 파일이 변경됐다는 사실이 아니라 어떤 내용이 변경되었는지 살펴 보려면 git diff 명령어 사용
  • README 파일을 수정해서 Staged 상태로 만들고 CONTRIBUTING.md 파일은 그냥 수정만 해둔다. 이 상태에서 git status 명령을 실행하면 아래와 같은 메시지를 볼 수 있다.
$ 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:   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 diff 명령을 실행하면 수정했지만 아직 staged 상태가 아닌 파일을 비교해 볼 수 있다.
$ 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
  • 이 명령은 워킹 디렉토리에 있는 것과 Staging Area에 있는 것을 비교한다. 그래서 수정하고 아직 Stage 하지 않은 것을 보여준다.
  • 만약 커밋하려고 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 상태인 것들만 보여준다.
  • 수정한 파일을 모두 Staging Area에 넣었다면 git diff 명령은 아무것도 출력하지 않는다.
  • 수정한 파일을 모두 Staging Area에 넣고 다시 파일을 수정한 후 git diff 명령을 사용한다면 Staged 상태인 것과 Unstaged 상태인 것을 비교한다.

6.1 외부 도구로 비교하기

  • git diff 대신 git difftool 명령을 사용해서 emerge, vimdiff 같은 도구로 비교할 수 있다.
  • git difftool --tool-help 라는 명령은 사용가능한 도구를 보여준다.

7. 변경사항 커밋하기

  • git commit
# 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
  • On branch master #을 지우고 wq로 저장하면 커밋됨
  • -v 옵션을 추가하면 편집기에 diff 메시지도 추가
  • -m 옵션은 메시지를 인라인으로 첨부할 수 있음
$ git commit -m "Story 182: Fix benchmarks for speed"
[master 463dc4f] Story 182: Fix benchmarks for speed
 2 files changed, 2 insertions(+)
 create mode 100644 README

8. Staging Area 생략하기

  • git commit 명령을 실행할 때 -a 옵션을 추가하면 Git은 Tracked 상태의 파일을 자동으로 Staging Area에 넣는다
$ git status
On branch master
Your branch is up-to-date with 'origin/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:   CONTRIBUTING.md

no changes added to commit (use "git add" and/or "git commit -a")
$ git commit -a -m 'added new benchmarks'
[master 83e38c7] added new benchmarks
 1 file changed, 5 insertions(+), 0 deletions(-)

9. 파일 삭제하기

  • git rm 명령으로 Tracked 상태의 파일을 삭제한 후에(정확하게는 Staging Area에서 삭제하는 것) 커밋해야 한다.

  • 이 명령은 워킹 디렉토리에 있는 파일도 삭제하기 때문에 실제로 파일도 지워진다.
  • 단순히 워킹 디렉터리에서 파일을 삭제하고 git status 명령으로 상태를 확인하면 Git은 현재 “Changes not staged for commit” (즉, Unstaged 상태)라고 표시해준다.
$ rm PROJECTS.md
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes not staged for commit:
  (use "git add/rm <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        deleted:    PROJECTS.md

no changes added to commit (use "git add" and/or "git commit -a")
  • git rm 명령을 실행하면 삭제한 파일은 Staged 상태가 된다.
$ git rm PROJECTS.md
rm 'PROJECTS.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)

    deleted:    PROJECTS.md
  • 커밋하면 파일은 삭제되고 Git은 이 파일을 더는 추적하지 않는다
  • 이미 파일을 수정했거나 Staging Area에(역주 - Git Index라고도 부른다) 추가했다면 -f 옵션을 주어 강제로 삭제해야 한다.
  • 반대로 Staging Area에서만 제거하고 워킹 디렉토리에 있는 파일은 지우지 않고 남겨둘 수 있다.
  • .gitIgnore 파일에 추가하는 것을 빼먹었거나 대용량 로그 파일, 컴파일된 파일 같은 것을 실수로 추가했을 때 쓴다. –cached 옵션을 사용한다.
$ git rm --cached README
  • 여러 개의 파일이나 디렉토리를 한꺼번에 삭제할 수도 있다. 아래와 같이 git rm 명령에 file-glob 패턴을 사용한다.
$ git rm log/\*.log
  • * 앞에 \ 을 사용한 것을 기억하자. 파일명 확장 기능은 쉘에만 있는 것이 아니라 Git 자체에도 있기 때문에 필요하다.
  • 이 명령은 log/ 디렉토리에 있는 .log 파일을 모두 삭제한다
$ git rm \*~
  • 이 명령은 ~ 로 끝나는 파일을 모두 삭제한다.

10. 파일 이름 변경하기

  • 파일 이름의 변경이나 파일의 이동을 명시적으로 관리하지 않는다.
  • 다시 말해서 파일 이름이 변경됐다는 별도의 정보를 저장하지 않는다.
  • 아래와 같이 이름을 변경할 수 있다.
$ git mv README.md README
$ 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)

    renamed:    README.md -> README
  • 하지만 변경 된 사실은 알고 있다. 그리고 아래는 위의 명령을 수행한 것과 같은 명령어다.
$ mv README.md README
$ git rm README.md
$ git add README
  • git mv 명령은 일종에 단축 명령어다.
  • 중요한 것은 mv만 썼을 때 꼭 rm / add를 실행줘야 한다.