기본 개념
파일들의 상태
- Untracked
- Tracked : git이 tracking하고 있음.
- Unmodified
- Modified : commit 이후 수정되었음.
- Unstaged
- Staged : 수정 내역이 차기 commit 대상 리스트에 포함됨. (git add 명령어로 리스트에 포함시킨다.)
commit
- 각 commit은 snapshot 파일의 포인터를 가지고 있으며, snapshot 파일은 blob 파일들의 포인터를 가지고 있다.[1]
- 또한 각 commit은 이전 commit의 포인터도 가지고 있다.
브랜치
- 브랜치는 특정 commit을 가리키는 41바이트의 파일에 불과하다.
- HEAD 포인터는 현재 작업 중인 브랜치를 가리킨다.
- merge시에는 fast-forward 또는 recursive strategy가 쓰인다.
- 전자는 단순히 포인터만 옮겨놓는 반면, 후자는 부모가 둘인 새 commit을 만든다.
- merge에서 문제가 발생하면 git은 표준 형태로 파일을 고쳐놓으며, 하나를 골라서 add해주자.
- 이후에 git commit으로 머지를 종료할 수 있다.
- tracking branch
- git branch -vv에서 누가 더 앞서가는지 확인할 수 있다.
- 하지만, 비교는 로컬에서 이뤄진다.
- 정확한 비교를 위해서는 먼저 git fetch --all을 해줘야 한다.
명령어들
기본 명령어
$ git add <file_name> # untracked, unstaged -> staged
$ git commit # git commit -m은 써도 되는지 모르겠다.
config 확인/되돌리기
- git에서 확인하는 config 파일들은 다음과 같다. (priority 순으로 나열)
- .git/config (해당 project)
- ~/.gitconfig, ~/.config/git/config (해당 사용자)
- /etc/gitconfig (전체 사용자)
$ git config --list
$ git config --local --list # 내가 추가한 config 리스트
$ git config [<file-option>] --unset-all <name> [value_regex] # unset all
$ git config [<file-option>] --remove-section <name> # remove specific section
실제 파일 다루기
$ rm a.out # a.out만 달랑 삭제했으므로 unstaged. 계속 tracking한다.
$ git rm a.out # git 명령어를 사용했으므로 삭제 행위가 staged되었다. 따라서 더 이상 tracking하지 않는다. 물론 원본도 삭제됨.
$ git rm --cached a.out # staging area에서만 삭제한다. git에서 관리하기 싫은 파일 제거시 사용.
$ git mv <before> <after> # 위와 마찬가지로 git은 mv의 결과를 알고 있다.
status, diff & log
$ git status
$ git status -s # svn st 모양으로 이쁘게 나옴. awk 먹이기 좋아보인다.
$ git status -v # diff까지 붙여서 보여준다.
$ git diff # 마지막으로 staged/committed된 이후의 diff만 보여준다. 즉, unstaged들의 last record와의 diff.
$ git diff --staged # staging area 내의 파일들의 diff. --cached 명령어도 동일한 기능을 한다.
$ git log # 최근 log부터 나온다.
$ git log -p -2 # 최근 2 커밋의 diff를 보여준다. -2 옵션이 없으면 싹 다 보여줌.
$ git log --pretty=oneline # 각 커밋의 해시와 메시지를 한 줄씩 보여준다.
$ git log -S <function_name> # 해당 이름의 함수를 건드린 commit만 보여준다.
$ git log -p <ci_hash> # 특정 commit의 직전 버전과의 diff를 보여준다.
$ git diff <ci_hash>~ <ci_hash> # 상동
되돌리기
$ git commit --amend # 이전의 commit을 덮어쓸 기회를 준다. 메시지 편집 기회도 준다.
$ git reset HEAD <file> # file을, staged -> unstaged
$ git checkout -- <file> # file을, 이전 commit버전으로 덮어써버린다. (commit버전 이후의 수정 내역은 사라진다.)
브랜치 다루기
$ git branch <name> # 새로운 이름의 브랜치를 만든다. 새 브랜치와 HEAD가 가리키는 브랜치는 동일한 commit을 가리킨다.
$ git checkout <name> # HEAD가 새 브랜치를 가리키게 한다.
$ git co -b <name> # 위의 두 명령어를 합쳤다.
$ git commit # commit을 하게 되면 브랜치는 분기된다. 왜? 새롭게 만들어지는 SHA-1 체크섬 hash 값이 다를 테니까.
$ git co master # master 브랜치로 (뒤로) 이동하며, working dir의 데이터도 해당 시점으로 돌려놓는다.
$ git log --oneline --decorate --graph --all # 브랜치 히스토리를 출력한다.
$ git log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit # 좀 더 이쁘게 출력한다.
$ git co master; git merge hotfix # master로 돌아가서 hotfix 브랜치를 merge한다.
$ git branch -d hotfix # hotfix 브랜치가 더 이상 필요하지 않으면 지운다.
$ git branch [-v] # 모든 branch를 보여준다.
$ git branch -vv # tracking branch 정보를 보여준다.
$ git branch --merged # merge된 branch만 보여준다. (master랑 merge됐으면, merge 직전의 commit을 가리키는 상태로 계속 남는다.) *표시가 없으면 지워도 된다.
$ git branch --no-merged # merge되지 않은 branch만 보여준다. -d 옵션으로 지울 수 없다.
Remote와의 작업
$ git remote add <name> <url>
$ git remove -v # 등록된 remote repo를 모두 보여준다.
$ git remote show <name> # 해당 remote repo의 정보를 보여준다.
$ git clone <url> # remote를 모조리 복사해온다.
$ git fetch <name> # remote와 local의 diff를 복사해온다. 하지만 내 작업을 merge해주지는 않는다.
$ git pull <name> # git fetch + git merge. 따라서 working dir의 데이터까지 바꿔놓는다.
$ git fetch origin # origin과의 commit diff를 복사해오고, 로컬의 origin/master 포인터가 실제 origin의 master 포인터와 동일한 commit을 가리키게 한다.
$ git co -b master origin/master # fetch만으로는 수정 가능한 브랜치가 만들어지지 않는다. checkout 명령어로 만들어줘야 한다. (clone에서는 자동으로 수행되는 듯)
$ git push origin master # 내 master를 origin의 master에 push한다.
$ git push origin a:b # 내 a를 origin의 b에 push한다.
$ git branch -u origin/master # 현재 branch가 origin/master를 tracking하게 만든다.
$ git fetch --all; git branch -vv # 서버에서 최신 데이터를 받아온 뒤 tracking 상황을 체크한다.
$ git push origin --delete serverfix # origin에서 serverfix 브랜치를 지운다.
기타
$ git config --global alias.st 'status -'s # git st == svn st