2. Git

2.1. 라이프 사이클

Untracked - Unmodified - Modified - Staged:

# 아래 명령어로 파일은 Untracked -> Staged 상태로 변경된다.
git add aa.txt
# 상태는 다음과 같이 변한다.
# Tracked 파일을 수정할 경우 Unmodified -> Modified
# 수정한 파일을 Staged로 올리면 Modified -> Staged
# Commit을 하면 Staged -> Unmodified
# 파일을 삭제하면 Unmodified -> Untrackted

2.2. rev-parse

2.3. diff

Modified이나 Staged가 아닌 파일을 비교할때는 git diff 를 사용한다.

Staged인 파일을 비교할때는 git diff –staged 를 사용한다.

git diff 《shaxxx》 《shaxxxxxx》 로 2개의 커밋을 비교할 수도 있다.

또는 git master~20:pom.xml diff master:pom.xml 와 같은 명령을 사용해도 된다.

2.4. Branch

로컬 브랜치 만들면서 원격 브랜치 연결:

git fetch
git checkout branch1

2.5. Rebase

기존 브랜치의 최신 변경 사항위에 현재 브랜치의 패치를 적용할때 사용한다.

예를들어 갈라져 나온 브랜치(feature-1)에서 작업이 끝났을때 기존 브랜치(보통, master)의 최신의 마지막 변경 사항 위에 현 브랜치의 내용을 패치하여 브랜치의 흔적을 지우고 master에서 작업 된것 처럼 커밋을 정리할때 사용한다.

이 후 합칠 브랜치로 Checkout 후 merge 명령으로 바로 Fast-forward 하여 Rebase한 브랜치가 만든 마지막 커밋을 가르킨다.

명령어는 다음과 같다.:

# 갈라져 나온 브랜치 (feature-1)
git checkout feature-1
# 공통 조상 부터 패치를 만들어 master에 적용시킨다.
git rebase master
# master로 HEAD를 바꾼뒤 fast-forward한다.
git checkout master
git merge feature-1

히스토리를 선형적으로 정리할 수 있다는 장점이 있으며, 갈라져 나온 브랜치가 계속 관리되는 브랜치가 아닐때 rebase를 사용하면 좋다. 단 merge로 생성한 commit을 서버에 push한 뒤 다시 로컬에서 rebase로 정리한 뒤 commit을 하면 그 사이에 작업한 다른 개발자의 결과물은 이전 병합 commit을 가르키게 되므로 히스토리가 꼬이게 된다.

2.5.1. 히스토리 정리하기

커밋 삭제, 순서 변경, 메시지 변경(이전 커밋), 커밋 Squash등을 수행할 수 있다.

원격에 푸시하기 전에 하는 것을 권장한다. 보통 강제 PUSH는 협업에서 다른 사람의 히스토리를 꼬이게 하므로 권장하지 않는다.

커밋을 삭제하고 싶을 경우 rebase를 이용해 에디팅 할 수 있다.:

git rebase -i HEAD~3 #최신의 커밋메시지 3개를 선택하여 커밋을 조작할 수 있는 도구를 제공한다. "git reset --hard 해시값" 도 사용 가능
                     #보통 VIM에 어떤 텍스트파일이 열리며 pick으로 시작하는 문장을 지우면 실제 커밋이 제거된다.
git push -f origin master #보통 강제 PUSH는 권장하지 않는다.

커밋 메시지를 수정하고 싶을 경우 rebase를 이용해 에디팅 할 수 있다.:

git rebase -i HEAD~3  #최신의 커밋메시지 3개를 선택하여 커밋을 조작할 수 있는 도구를 제공한다.
                      #보통 VIM에 어떤 텍스트파일이 열리며 수정하고 싶은 pick으로 시작하는 행을 edit으로 수정하고 닫는다.
git commit --amend    #해당 커밋으로 체크아웃되며 --amend 를 이용해 메시지를 수정한다.
git rebase --continue #다음 수정할 커밋으로 진행한다. 더이상 수정할 항목이 없을 경우 수정을 반영한 상태로 rebase 전 상태로 돌아감.
git rebase --abort    # rebase를 작업을 중단하고 모든 수정을 포기한다.
git push -f origin master #보통 강제 PUSH는 권장하지 않는다.

커밋을 분리하고 싶을 경우 rebase를 이용해 에디팅 할 수 있다.:

git rebase -i HEAD~5 #최신의 커밋메시지 5개를 선택하여 커밋을 조작할 수 있는 도구를 제공한다.
                     #보통 VIM에 어떤 텍스트파일이 열리며 분리하고 싶은 pick으로 시작하는 행을 edit으로 수정하고 닫는다. 바로 edit 커밋으로 체크아웃된다.
git reset HEAD~1     # 바로 현재 HEAD(edit할 대상) 직전 커밋으로 돌린다.
git add a.txt
git commit -m "분리된 첫번째 커밋"
git add b.txt
git commit -m "분리된 두번째 커밋"
git rebase --continue #다음 수정할 커밋으로 진행한다. 더이상 수정할 항목이 없을 경우 수정을 반영한 상태로 rebase 전 상태로 돌아감.
git rebase --abort   # rebase를 작업을 중단하고 모든 수정을 포기한다.
git push -f origin master #보통 강제 PUSH는 권장하지 않는다.

2.6. Merge

Fast-forward는 commit 포인터를 그대로 다른 브랜치의 commit 포인터로 이동시키는 것이다. 단 이동할 commit의 조상이 현재 브랜치여야 한다.

git checkout master
git merge feature-1

Fast-forward가 가능하지 않을 경우 3-way merge를 수행한다. 공통조상, 현재 브랜치의 커밋, 병합할 브랜치의 커밋을 이용해 병합을 수행한다. commit 포인터를 생성된 commit으로 이동시킨다. 3-way merge 알고리즘 에 대해 잘 설명한 링크이다.

../_images/merge.png

2.7. Cherry Pick

Cherry Pick은 다른 브랜치의 특정 커밋들을 선택하여 현재 브랜치에 적용하고 싶을때 사용하는 명령어이다.

마스터에서 다른 브랜치의 커밋을 적용할 수 있다. 이때 커밋 해시를 이용해야만 한다.:

git checkout master
git cherry-pick commitSha

Cherry Pick 옵션은 다음과 같다.:

git cherry-pick commitSha -edit       #커밋 메시지를 수정한 뒤 커밋한다.
git cherry-pick commitSha --no-commit #커밋을 하지 않고 내용만 붙인다.
git cherry-pick commitSha --signoff   #커밋을 하면서 메시지의 끝에 시그니쳐를 붙인다.

2.8. Reset

현재 브랜치를 유지한채 HEAD만 이전 커밋으로 이동시킬 수 있다.:

git reset --soft HEAD~ : HEAD만 바꾼다. Index나 Working Directory는 그대로 둔다.
git reset HEAD~ : HEAD를 바꾸고, Index 영역을 HEAD가 가르키는 상태로 바꾼다.
git reset --hard HEAD~ : HEAD는 바꾸고, Index과 Working Directory 영역을 HEAD가 가르키는 상태로 바꾼다.

2.9. Squash

Squash는 여러개의 커밋을 정리하는 것을 말한다. 커밋이 각각 존재할 필요가 없을 경우, 하나의 커밋으로 관리되어야 할 경우 Squash를 사용한다.

Git 도구에는 Squash를 위한 여러가지 명령을 제공한다. 대표적으로 git reset –soft xxxxxx 을 이용해서 현재 인덱스를 가지고 과거의 커밋을 수정하는 방법이 있다.

예를들어 3개의 커밋을 하나의 1개의 커밋으로 만들고 싶을때 다음 명령으로 작업을 진행하면 된다.

git fetch : 로컬 컴퓨터에 전체 브랜치 목록을 받아온다.
git checkout patch-1 : 특정 브랜치로 이동한다.
git reset --soft xxxxxx : 특정 커밋으로 이동한다. (Squash될 커밋 또는 그 커밋의 이전 커밋)
git commit --amend : **Squash될 커밋 중 첫번째 커밋으로 이동할 경우** 바로 커밋 메시지를 수정하여 커밋한다. 예를들어 Squash할 3개의 커밋중 첫번째 커밋으로 이동한 경우 사용할 수 있다.
git commit -m "xxxxx" : **Squash될 커밋의 이전 커밋으로 이동할 경우** 바로 커밋한다.
git push origin +patch-1 : 원격 저장소에 강제로 푸쉬한다.

그 외에도 git rebase -i HEAD~5 으로 Squash를 할 수 있다.:

git fetch : 로컬 컴퓨터에 전체 브랜치 목록을 받아온다.
git checkout patch-1 : 특정 브랜치로 이동한다.
git rebase -i HEAD~5 : 3개를 1개로 하고 싶다면 가장 부모 커밋을 pick하고 그 이후 2개를 squash로 수정한다.
                     : 엔터를 입력하면 3개의 커밋 메시지를 합친 메시지가 vim에 출력되고 저장하면 squash가 완료된다.

2.10. Commit

실수로 Staged하는 파일을 까먹었다면 –amend로 해결할 수 있다.:

git commit -m "commit missing some files"
git add forgotten_file
git commit --amend

실수로 Staged 했다면 reset으로 해결할 수 있다.:

git reset HEAD go_unstaged.md

실수로 Modified 했다면 checkout으로 해결할 수 있다.:

git checkout -- go_unmodified.md

2.11. Stash

Tracked Modified 이거나 Staged 인 파일들을 임시로 저장할 수 있다.:

git stash save
git stash list
git stash apply

2.12. Clean

추적되고 있지 않은 파일을 제거한다.:

git clean -f
git clean -fxd

환경 변수(clean.requireForce)에 따라 -f 옵션이 필요할 수 있다. 경로가 주어지지 않을 경우 재귀적으로 자식을 방문하지 않으므로 -d 옵션이 필요하다.