Git: Difference between revisions
No edit summary |
(→config) |
||
(51 intermediate revisions by the same user not shown) | |||
Line 2: | Line 2: | ||
Git 사용법 정리. | Git 사용법 정리. | ||
== branching == | == Basic == | ||
[[File:Git branch.png| | === Trees === | ||
[[File:Git_reset-workflow.png|500px||thumb|branching model]] | |||
git 은 일반적으로 세가지 트리를 관리하는 시스템이다. | |||
* HEAD : Role. | |||
* Index : 마지막 커밋 스냅샵, 다음 커밋의 부모 커밋. | |||
* Working Directory : 다음에 커밋할 스냅샷 | |||
==== HEAD ==== | |||
HEAD는 현재 브랜치를 가리키는 포인터이며, 브랜치에 담긴 커밋 중 가작 마지막 커밋을 가리킨다. 지금의 HEAD가 가리키는 커밋은 바로 다음 커밋의 부모가 된다. 단순하게 생각하면 HEAD 는 마지막 커밋의 스냅샷이다. HEAD기 가리키는 스냅샷을 살펴보기는 쉽다. 아래는 HEAD 스냅샷의 디렉토리 리스팅과 각 파일의 SHA-1 체크섬을 보여주는 예제다. | |||
<pre> | |||
$ git cat-file -p HEAD | |||
tree 388d18182352b623ae494e5db098a9234572c1c0 | |||
parent 6cb15d5061504f012a22528fc77d02a29005ce61 | |||
author pchero <pchero21@gmail.com> 1431027284 +0200 | |||
committer pchero <pchero21@gmail.com> 1431027284 +0200 | |||
Added null paramater access control. | |||
- If get null byte, just return null | |||
$ git ls-tree -r HEAD | |||
100755 blob c57d76c4bfef251a72818044af96dea2af3e4fb0 Makefile | |||
100755 blob de92fb96b5a3088c7d762e6ec8da3e946e94047a README | |||
100755 blob 031939c8afccd8bb862eac748aa075d2831eb985 conf/zmq_manager.conf | |||
</pre> | |||
==== Index ==== | |||
Index 는 바로 다음에 커밋할 것들이다. 바로 Staging Area 이다. Staging Area 는 사용자가 git commit 명령을 실행했을 때 git이 처리할 것들이 있는 곳이다. | |||
먼저 Index 는 워킹 디렉토리에서 마지막으로 Checkout 한 브랜치의 파일 목록과 파일 내용으로 채워진다. 이후 파일 변경작업을 하고 변경한 내용으로 Index 를 업데이트 할 수 있다. 이렇게 업데이트하고 git commit 명령을 실행하면 Index 는 새 커밋으로 변환된다. | |||
==== Working Directory ==== | |||
Working directory 는 일종의 Sandbox 로 생각하면 된다. | |||
=== Branching === | |||
[[File:Git branch.png|500px||thumb|branching model]] | |||
git에서의 브랜치 사용은, 단순한 명령어를 사용할 줄 아는 것보다 어떤 구조로 브랜치가 뻗어나가고, 통합되는지를 아는 것이 더 중요하다. 자동으로 생성되는 master branch 에는 Tag 와 같이 배포된 버전만을 관리하도록 한다. 그리고, develop branch 에는 현재 진행중인 모든 변경사항들이 적용될 수 있도록 한다. 그리고, 새로운 기능을 개발해야 하는 상황이라면 develop branch에서 새로운 branch 를 파생하여 개발하도록 한다(이건 약간 다를 수있다). hotfix 의 경우, master branch 에서 파생하여 수정 후, 바로 적용할 수 있도록 한다. | git에서의 브랜치 사용은, 단순한 명령어를 사용할 줄 아는 것보다 어떤 구조로 브랜치가 뻗어나가고, 통합되는지를 아는 것이 더 중요하다. 자동으로 생성되는 master branch 에는 Tag 와 같이 배포된 버전만을 관리하도록 한다. 그리고, develop branch 에는 현재 진행중인 모든 변경사항들이 적용될 수 있도록 한다. 그리고, 새로운 기능을 개발해야 하는 상황이라면 develop branch에서 새로운 branch 를 파생하여 개발하도록 한다(이건 약간 다를 수있다). hotfix 의 경우, master branch 에서 파생하여 수정 후, 바로 적용할 수 있도록 한다. | ||
Line 10: | Line 46: | ||
여기서 중요한 점은, branching 을 하는 과정에서는 어떠한 정해진 룰이 없다는 것이다. 그냥 각기 상황에 맞는 방식을 적용하여 사용하면 된다. | 여기서 중요한 점은, branching 을 하는 과정에서는 어떠한 정해진 룰이 없다는 것이다. 그냥 각기 상황에 맞는 방식을 적용하여 사용하면 된다. | ||
== Commands == | |||
=== branch === | === branch === | ||
branch 를 생성/삭제/변경 한다. | branch 를 생성/삭제/변경 한다. | ||
Line 24: | Line 61: | ||
$ git branch --edit-description [<branchname>] | $ git branch --edit-description [<branchname>] | ||
</source> | </source> | ||
git-2.16 버전부터 git branch 의 기본 동작 방식이 변경되었다. 마치 less 명령어와 같이 출력된다. 원래 설정으로 돌아가고 싶다면 pager.branch 설정을 false 로 설정하면 된다<ref>https://stackoverflow.com/questions/48341920/git-branch-command-behaves-like-less</ref>. | |||
<pre> | |||
git config --global pager.branch false | |||
</pre> | |||
==== -v, -vv, --verbose ==== | |||
Branch 상세 정보를 보여준다. | |||
<source lang=bash> | |||
$ git branch -vv | |||
* master e993892 [origin/master: ahead 2] Test change 2 | |||
</source> | |||
==== -d, -D ==== | |||
지정된 Branch 를 삭제한다. | |||
* -d : Merge 가 완료된 Branch 를 삭제한다. | |||
* -D : Merge 여부와 상관없이 Branch 를 삭제한다. | |||
<pre> | |||
$ git branch -D tmp | |||
Deleted branch tmp (was 78e4777). | |||
</pre> | |||
=== checkout === | === checkout === | ||
해당 브랜치 또는 특정 커밋시점으로 소스를 되돌린다. 아직 staging 에 있지 않은 파일에 checkout 을 적용하면 파일을 수정 전으로 되돌린다. | |||
==== -b ==== | |||
브랜치 생성과 동시에 checkout 까지 동시에 한다. | 브랜치 생성과 동시에 checkout 까지 동시에 한다. | ||
<source lang=bash> | <source lang=bash> | ||
Line 32: | Line 93: | ||
</source> | </source> | ||
== | === clean === | ||
Remove untracked files from the working tree. | |||
Untracked file 들을 삭제한다. | |||
==== -d ==== | |||
Remove untracked directories in addition to untracked files. If an untracked directory is managed by a different Git repository, it is not removed by default. | |||
Use -f option twice if you really want to remove such a directory. | |||
Untracked directory 와 디렉토리 안에 있는 파일들도 함께 삭제 한다. | |||
<pre> | |||
$ git clean -fd | |||
Removing playbooks/playbook_asterisk_deployment.yml | |||
</pre> | |||
==== -f, --force ==== | |||
If the Git configuration variable clean.requireForce is not set to false, git clean will refuse to delete files or directories unless given -f, -n or -i. | |||
Git will refuse to delete directories with .git sub directory or file unless a second -f is given. | |||
<pre> | |||
$ git clean -f | |||
Removing ansible.cfg | |||
Removing roles/asterisk/tasks/asterisk_deployment.yml | |||
</pre> | |||
==== -n, --dry-run ==== | |||
Don't actually remove anythin, just show what would be done. | |||
<pre> | |||
$ git clean -n | |||
Would remove ansible.cfg | |||
Would remove roles/asterisk/tasks/asterisk_deployment.yml | |||
</pre> | |||
=== | === clone === | ||
==== -b, --branch ==== | |||
clone 시 특정 브랜치를 지정하여 clone 할 때 사용하는 옵션이다. | |||
<pre> | <pre> | ||
$ git clone -b <branch> <remote_repo> | $ git clone -b <branch> <remote_repo> | ||
Line 50: | Line 143: | ||
</pre> | </pre> | ||
== pull == | === pull === | ||
==== pull all branches ==== | |||
<pre> | |||
$ git pull --all | |||
</pre> | |||
=== push === | |||
현재 commit 의 내용을 remote 로 push 한다. | |||
==== -u, --set-upstream ==== | |||
로컬 브랜치 내용을 remote 로 push 한다. | |||
<pre> | |||
$ git push --set-upstream origin <local branch name> | |||
</pre> | |||
--all 옵션과 같이 사용할 경우, 현재 로컬에 있는 모든 브랜치의 내용을 remote 로 push 한다. | |||
<pre> | |||
$ git push --all -u | |||
</pre> | |||
=== commit === | |||
==== --amend ==== | |||
기존의 commit 에 내용 수정하기 | |||
<pre> | |||
$ git commit --amend | |||
</pre> | |||
=== rebase === | |||
Git에서 한 Branch 에서 다른 Branch 로 합치는 방법은 두 가지가 있다. 하나는 Merge 이고, 다른 하나는 Rebase 이다. Merge 가 소스를 통합하는 방식이라면, Rebase 는 다른 Branch 에서 변경된 사항을 패치(Patch)로 만들고, 이를 다시 본래의 Branch 에 적용시키는 방법이다. rebase 는 Branch 단위로만 가능하며, Commit 단위로는 불가능하다. rebase 를 위해서는 반드시 Branch 를 생성해야 한다<ref>http://stackoverflow.com/questions/7758128/how-to-git-rebase-i-for-a-range-of-commits</ref>. | |||
<pre> | |||
git rebase [-i | --interactive] [options] [--onto <newbase>] | |||
<upstream> [<branch>] | |||
git rebase [-i | --interactive] [options] --onto <newbase> | |||
--root [<branch>] | |||
git rebase --continue | --skip | --abort | |||
</pre> | |||
<pre> | |||
$ git checkout experiment | |||
$ git rebase master | |||
</pre> | |||
==== -i, --interactive ==== | |||
rebase 될 commit 의 리스트를 작성하고, 각각의 commit 에 대해 수행할 작업을 지정할 수 있는 interactive 모드를 시작한다. 보통은 commit 들을 합치고 싶을 때 가장 널리 사용되는 명령 중 하나이다. | |||
<pre> | |||
$ git rebase -i HEAD~3 | |||
pick 23c7d18 Additional features | |||
pick 3ba2192 Create billing database | |||
pick 4caf479 - fix warns level for compiling client on freebsd.. | |||
# Rebase 1666596..4caf479 onto 1666596 | |||
# | |||
# Commands: | |||
# p, pick = use commit | |||
# r, reword = use commit, but edit the commit message | |||
# e, edit = use commit, but stop for amending | |||
# s, squash = use commit, but meld into previous commit | |||
# f, fixup = like "squash", but discard this commit's log message | |||
# x, exec = run command (the rest of the line) using shell | |||
# | |||
# These lines can be re-ordered; they are executed from top to bottom. | |||
# | |||
# If you remove a line here THAT COMMIT WILL BE LOST. | |||
# | |||
# However, if you remove everything, the rebase will be aborted. | |||
# | |||
# Note that empty commits are commented out | |||
</pre> | |||
사용가능한 Command 들의 각각의 기능은 다음과 같다. | |||
* p, pick : commit 된 내용을 그냥 그대로 사용한다. | |||
* r, reword : commit 된 내용을 그냥 그대로 사용한다. 단, commit 메시지를 수정한다. | |||
* e, edit : commit 된 내용을 그냥 그대로 사용한다. 단, 수정을 위해 잠시 정지(stop) 한다. | |||
* s, squash : commit 된 내용을 그냥 그대로 사용한다. 단, 여러개의 커밋들을 하나의 커밋으로 합친다. | |||
* f, fixup : squash 와 비슷하다. 단, commit message 는 사용하지 않는다. | |||
* x, exec : 쉘을 통한 command 를 실행한다. | |||
squash 및 fixup 은 이전 커밋들을 대상으로만 수행할 수 있다. 최근 커밋을 이전 커밋으로 합하는 명령어가 아니기 때문이다. 그리고, 절대로 이미 push 했던 커밋을 대상으로는 rebase 해서는 안된다. | |||
==== --abort ==== | |||
rebase 중 잘못 선택하거나 실수로 의도하는 것과 달라진 경우, 해당 rebase 를 취소하고자 할 때 사용하는 명령어이다. | |||
<source lang=bash> | |||
$ git rebase --abort | |||
</source> | |||
==== --continue ==== | |||
rebase 중, merge 가 깨진 경우, 해당 파일을 수정 및 add 한 후, 계속해서 rebase 를 진행할 때 사용하는 명령어이다. | |||
<source lang=bash> | |||
$ git rebase --continue | |||
</source> | |||
=== show-brarnch === | |||
브랜치와 커밋 내용을 확인한다. | |||
<pre> | |||
$ git show-branch | |||
[master] Oversized message cut and substitute | |||
</pre> | |||
==== -a, --all ==== | |||
remote-tacking 브랜치와 로컬 브랜치 모두를 보여준다. | |||
<pre> | |||
$ git show-branch -a | |||
* [master] Oversized message cut and substitute | |||
! [origin/HEAD] Oversized message cut and substitute | |||
! [origin/develop] Oversized message cut and substitute | |||
! [origin/master] Oversized message cut and substitute | |||
---- | |||
*+++ [master] Oversized message cut and substitute | |||
</pre> | |||
=== diff === | |||
Commit, Branch, Working 디렉토리 사이의 diff 를 나타낸다. | |||
<pre> | |||
git diff [options] [<commit>] [--] [<path>...] | |||
git diff [options] --cached [<commit>] [--] [<path>...] | |||
git diff [options] <commit> <commit> [--] [<path>...] | |||
git diff [options] <blob> <blob> | |||
git diff [options] [--no-index] [--] <path> <path> | |||
</pre> | |||
==== Branch compare ==== | |||
Branch 끼리의 diff 를 보여준다. | |||
<pre> | |||
$ git diff <branch 1> <branch 2> | |||
$ git diff tmp tmp1 | |||
diff --git a//main.c b/main.c | |||
index 237d99a..b54bca3 100644 | |||
--- a/main.c | |||
+++ b/main.c | |||
@@ -518,6 +518,90 @@ static bool validate_sms_table(const char* table_name, const char* attach_db) | |||
return true; | |||
} | |||
... | |||
</pre> | |||
==== HEAD ==== | |||
현재 파일들의 상태(아직 commit 되지 않은 상태의 변경도 포함)와 HEAD 와의 차이를 보여준다. | |||
=== mv === | |||
파일, 심볼릭링크 또는 디렉토리의 이동 및 rename 을 한다. | |||
git 디렉토리에서 단순히 git 명령어가 아닌, unix/linux mv 명령어로 파일을 옮기게 되면 git 에서는 파일이동이 아닌, 파일 삭제, 새로운 파일 생성으로 받아들이게 된다. | |||
만약 unix/linux 명령어 mv 로 파일이동을 하게 될 경우, 파일 트래킹 하기가 정말 어려워진다. git에서는 가급적 git mv를 사용하도록 하자. | |||
==== -n, --dry-run ==== | |||
실제로 파일이동을 하지 않는다. 단지 어떻게 되는지만을 보여준다. | |||
<pre> | |||
$ git mv -n conf/freeswitch.xml ./ | |||
Checking rename of 'conf/freeswitch.xml' to 'freeswitch.xml' | |||
Renaming conf/freeswitch.xml to freeswitch.xml | |||
</pre> | |||
=== reset === | |||
HEAD 가 가리키는 커밋을 변경한다. | |||
<pre> | |||
git reset [-q] [<tree-ish>] [--] <paths>... | |||
git reset (--patch | -p) [<tree-ish>] [--] [<paths>...] | |||
git reset [--soft | --mixed | --hard | --merge | --keep] [-q] [<commit>] | |||
</pre> | |||
==== --mixed ==== | |||
Index 를 변경한다. 기본 동작방식이다. | |||
==== --soft ==== | |||
Index 와 working directory 를 건드리지 않는다. 대신 HEAD 만을 이동한다. | |||
==== --hard ==== | |||
Index 와 Working directory 를 변경한다. 즉, 로컬에 있는 모든 변경 내용과 확정본을 포기한다. 원격 저장소의 최신 이력을 가져오고, 로컬 master branch 가 해당 이력을 가리키도록 한다. | |||
<source lang=bash> | |||
$ git reset --hard origin/master | |||
HEAD is now at gba2192 test commit | |||
</source> | |||
=== remote === | |||
현재 주시(track)중인 원격(remote) 저장소 내용들을 관리한다. | |||
<pre> | |||
git remote [-v | --verbose] | |||
git remote add [-t <branch>] [-m <master>] [-f] [--mirror] <name> <url> | |||
git remote rename <old> <new> | |||
git remote rm <name> | |||
git remote set-head <name> (-a | -d | <branch>) | |||
git remote set-url [--push] <name> <newurl> [<oldurl>] | |||
git remote set-url --add [--push] <name> <newurl> | |||
git remote set-url --delete [--push] <name> <url> | |||
git remote [-v | --verbose] show [-n] <name> | |||
git remote prune [-n | --dry-run] <name> | |||
git remote [-v | --verbose] update [-p | --prune] [group | remote]... | |||
</pre> | |||
==== set-url ==== | |||
Remote url 을 설정한다. pull/push 등을 하는 target url 을 변경한다. ssh/https 등의 접속 방식을 변경할 때 사용한다. | |||
<pre> | |||
$ git remote -v | |||
origin git@github.com:pchero/jade-agent.git (fetch) | |||
origin git@github.com:pchero/jade-agent.git (push) | |||
$ git remote set-url origin https://github.com/pchero/jade-agent.git | |||
$ git remote -v | |||
origin https://github.com/pchero/jade-agent.git (fetch) | |||
origin https://github.com/pchero/jade-agent.git (push) | |||
</pre> | |||
* https://help.github.com/en/articles/changing-a-remotes-url | |||
==== update ==== | |||
지정된 group 에 속한 원격 저장소 내용들을 update 한다. 만약 group 이 지정되어 있지 않다면, remotes.default 에 설정된 내용을 사용하게 된다. 만약 remotes.default 에 설정된 내용이 없다면, 전체 원격 저장소 내용들을 update 한다. | |||
With --prune option, prune all the remotes that are updated. | |||
<pre> | |||
$ git remote update | |||
Fetching origin | |||
remote: Counting objects: 18, done. | |||
remote: Total 18 (delta 7), reused 7 (delta 7), pack-reused 11 | |||
Unpacking objects: 100% (18/18), done. | |||
From https://github.com/pchero/asterisk-zmq | |||
2109230..9991691 master -> origin/master | |||
2109230..43c3fbb devel -> origin/devel | |||
* [new tag] v1.5 -> v1.5 | |||
</pre> | |||
=== fetch === | |||
원격 저장소의 변경 이력을 Download 한다. | |||
<source lang=bash> | |||
$ git fetch origin | |||
</source> | |||
=== archive === | |||
=== log === | |||
Commit 이력을 확인한다. | |||
<source lang=bash> | |||
$ git log | |||
commit 70b8a6e47475ed18d586be2e1625531981efdb18 | |||
Author: pchero <pchero@pchero21.com> | |||
Date: Mon Jun 20 10:47:28 2016 +0200 | |||
Test change 2 | |||
- Test change 2 | |||
Change-Id: Id09dc1f32bb584678c6cdef2f2eb4fabd6756a09 | |||
commit 668cbd8f92c81d075d5619722713272484f065ce | |||
Author: pchero <pchero@pchero21.com> | |||
Date: Mon Jun 20 10:14:03 2016 +0200 | |||
Test change commit 1 | |||
- Test change commit 1 | |||
- Test change again | |||
- Added Test change 1-1 | |||
Change-Id: Ic13c9ec5d79cd682b5a4d4126e7acf6a9d16663a | |||
</source> | |||
=== config === | |||
git 환경변수 값을들 설정/변경/삭제 한다. | |||
<pre> | |||
$ git config [options] | |||
</pre> | |||
==== core.editor ==== | |||
default editor 를 설정한다. | |||
<pre> | |||
$ git config --global core.editor vim | |||
</pre> | |||
==== user.email ==== | |||
commit 시 사용되는 email address 를 설정한다. | |||
<pre> | |||
$ git config --global user.email "pchero21@gmail.com" | |||
</pre> | |||
==== user.name ==== | |||
commit 사 사용되는 user name 을 설정한다. | |||
<pre> | |||
$ git config --global user.name "pchero" | |||
</pre> | |||
==== pager.branch ==== | |||
branch 시, list 가 less 처럼 작동하는걸 막아준다. | |||
<pre> | |||
$ git config --global pager.branch false | |||
</pre> | |||
==== --global ==== | |||
global config file 을 사용한다. | |||
<pre> | |||
$ git config --global core.editor "vim" | |||
</pre> | |||
== Advanced == | |||
=== merge conflict === | |||
git merge conflict 발생 시 처리방법. | |||
<pre> | |||
$ git merge | |||
fatal: You have not concluded your merge (MERGE_HEAD exists). | |||
Please, commit your changes before you can merge. | |||
</pre> | |||
=== .gitignore === | |||
git directory 에서 제외하고자 하는 파일/디렉토리명을 명시하면 된다. | |||
.terraform 디렉토리를 제외하고 싶다면, | |||
<pre> | |||
$ cat .gitignore | |||
.terraform | |||
</pre> | |||
처럼 하면 된다. | |||
=== squash commits === | |||
다른 프로젝트에 Merge Request 를 할때, 여러개의 Commit 메시지를 하나의 commit 로 줄여야 할 때가 있다. | |||
<pre> | |||
$ git rebase -i master | |||
... | |||
$ git push --force origin <target branch> | |||
</pre> | |||
가끔은 뭔가가 꼬여서 안될때가 있다. 그럴땐 patch 를 만들어서 모든 commit 를 지우고 patch를 적용하자. | |||
<pre> | |||
$ git diff master..origin/<target branch> > patch | |||
$ git checkout <target brach> | |||
$ git rebase -pi master | |||
## delete all commits | |||
$ git apply patch | |||
$ git add . | |||
$ git commit | |||
$ git push --force origin <target branch> | |||
</pre> | |||
== Errors == | |||
=== server certificate verification failed. CAfile === | |||
다음과 같은 에러가 있었다. | |||
<pre> | |||
pchero@jenkins:~/git$ git clone https://lab.cluster.gsi.dit.upm.es/sefarad/sefarad.git | |||
Cloning into 'sefarad'... | |||
fatal: unable to access 'https://lab.cluster.gsi.dit.upm.es/sefarad/sefarad.git/': server certificate verification failed. CAfile: /etc/ssl/certs/ca-certificates.crt CRLfile: none | |||
</pre> | |||
SSL verify 옵션을 끄면된다. | |||
<pre> | |||
export GIT_SSL_NO_VERIFY=1 | |||
</pre> | |||
* 출처: https://stackoverflow.com/questions/21181231/server-certificate-verification-failed-cafile-etc-ssl-certs-ca-certificates-c | |||
=== | === error: unpack failed: error Missing tree === | ||
<pre> | |||
error: unpack failed: error Missing tree fa6b09d4f5dc8ee6fcb0553396530f97a3033856 | |||
</pre> | |||
다음과 같은 순서로 작업을 진행했을 경우 발생하는 에러이다. | |||
<pre> | <pre> | ||
- Create a new branch on head. | |||
- Do some modifications on new branchs | |||
- Somebody also make modifications on head branch | |||
- Try to push your branch | |||
</pre> | </pre> | ||
git pull 진행 후, 다시 push 를 하면 된다. | |||
* 출처 : https://stackoverflow.com/questions/7236738/how-can-i-recover-my-git-repository-for-a-missing-tree-error | |||
== See also == | == See also == | ||
* http://stackoverflow.com/questions/10312521/how-to-fetch-all-git-branches - How to fetch all git branches | * http://stackoverflow.com/questions/10312521/how-to-fetch-all-git-branches - How to fetch all git branches | ||
* https://git-scm.com/book/ko/v1/Git-%EB%B8%8C%EB%9E%9C%EC%B9%98-Rebase%ED%95%98%EA%B8%B0 - Git-브랜치-Rebase하기 | |||
* https://progit.org/ - progit book | |||
* https://git-scm.com/book/ko/v2/Git-도구-Reset-명확히-알고-가기 - Reset 명확히 알고 가기 | |||
== References == | == References == | ||
<references /> | <references /> | ||
[[category: | [[category:version control]] |
Latest revision as of 22:49, 10 August 2020
Overview
Git 사용법 정리.
Basic
Trees
git 은 일반적으로 세가지 트리를 관리하는 시스템이다.
- HEAD : Role.
- Index : 마지막 커밋 스냅샵, 다음 커밋의 부모 커밋.
- Working Directory : 다음에 커밋할 스냅샷
HEAD
HEAD는 현재 브랜치를 가리키는 포인터이며, 브랜치에 담긴 커밋 중 가작 마지막 커밋을 가리킨다. 지금의 HEAD가 가리키는 커밋은 바로 다음 커밋의 부모가 된다. 단순하게 생각하면 HEAD 는 마지막 커밋의 스냅샷이다. HEAD기 가리키는 스냅샷을 살펴보기는 쉽다. 아래는 HEAD 스냅샷의 디렉토리 리스팅과 각 파일의 SHA-1 체크섬을 보여주는 예제다.
$ git cat-file -p HEAD tree 388d18182352b623ae494e5db098a9234572c1c0 parent 6cb15d5061504f012a22528fc77d02a29005ce61 author pchero <pchero21@gmail.com> 1431027284 +0200 committer pchero <pchero21@gmail.com> 1431027284 +0200 Added null paramater access control. - If get null byte, just return null $ git ls-tree -r HEAD 100755 blob c57d76c4bfef251a72818044af96dea2af3e4fb0 Makefile 100755 blob de92fb96b5a3088c7d762e6ec8da3e946e94047a README 100755 blob 031939c8afccd8bb862eac748aa075d2831eb985 conf/zmq_manager.conf
Index
Index 는 바로 다음에 커밋할 것들이다. 바로 Staging Area 이다. Staging Area 는 사용자가 git commit 명령을 실행했을 때 git이 처리할 것들이 있는 곳이다.
먼저 Index 는 워킹 디렉토리에서 마지막으로 Checkout 한 브랜치의 파일 목록과 파일 내용으로 채워진다. 이후 파일 변경작업을 하고 변경한 내용으로 Index 를 업데이트 할 수 있다. 이렇게 업데이트하고 git commit 명령을 실행하면 Index 는 새 커밋으로 변환된다.
Working Directory
Working directory 는 일종의 Sandbox 로 생각하면 된다.
Branching
git에서의 브랜치 사용은, 단순한 명령어를 사용할 줄 아는 것보다 어떤 구조로 브랜치가 뻗어나가고, 통합되는지를 아는 것이 더 중요하다. 자동으로 생성되는 master branch 에는 Tag 와 같이 배포된 버전만을 관리하도록 한다. 그리고, develop branch 에는 현재 진행중인 모든 변경사항들이 적용될 수 있도록 한다. 그리고, 새로운 기능을 개발해야 하는 상황이라면 develop branch에서 새로운 branch 를 파생하여 개발하도록 한다(이건 약간 다를 수있다). hotfix 의 경우, master branch 에서 파생하여 수정 후, 바로 적용할 수 있도록 한다.
새로운 기능을 위한 branch 를 생성할 때, 두 가지 방식을 사용할 수 있다. 하나는 master branch 에서 파생하는 방법이고, 다른 하나는 develop branch 에서 파생하는 방법이다. develop branch 에서 파생할 경우에는 현재 적용을 위해 테스트 중인 모든 기능과의 호환성을 함께 테스트할 수 있지만 그만큼 현재 배포중인 버전과의 차이가 많이 난다는 문제가 있다. 하지만, master branch에서 파생하는 경우는, 정 반대의 문제가 발생하게 된다.
여기서 중요한 점은, branching 을 하는 과정에서는 어떠한 정해진 룰이 없다는 것이다. 그냥 각기 상황에 맞는 방식을 적용하여 사용하면 된다.
Commands
branch
branch 를 생성/삭제/변경 한다. <source lang=bash> $ git branch [--color[=<when>] | --no-color] [-r | -a] [--list] [-v [--abbrev=<length> | --no-abbrev]] [--column[=<options>] | --no-column] [(--merged | --no-merged | --contains) [<commit>]] [<pattern>...] $ git branch [--set-upstream | --track | --no-track] [-l] [-f] <branchname> [<start-point>] $ git branch (--set-upstream-to=<upstream> | -u <upstream>) [<branchname>] $ git branch --unset-upstream [<branchname>] $ git branch (-m | -M) [<oldbranch>] <newbranch> $ git branch (-d | -D) [-r] <branchname>... $ git branch --edit-description [<branchname>] </source>
git-2.16 버전부터 git branch 의 기본 동작 방식이 변경되었다. 마치 less 명령어와 같이 출력된다. 원래 설정으로 돌아가고 싶다면 pager.branch 설정을 false 로 설정하면 된다<ref>https://stackoverflow.com/questions/48341920/git-branch-command-behaves-like-less</ref>.
git config --global pager.branch false
-v, -vv, --verbose
Branch 상세 정보를 보여준다. <source lang=bash> $ git branch -vv
- master e993892 [origin/master: ahead 2] Test change 2
</source>
-d, -D
지정된 Branch 를 삭제한다.
- -d : Merge 가 완료된 Branch 를 삭제한다.
- -D : Merge 여부와 상관없이 Branch 를 삭제한다.
$ git branch -D tmp Deleted branch tmp (was 78e4777).
checkout
해당 브랜치 또는 특정 커밋시점으로 소스를 되돌린다. 아직 staging 에 있지 않은 파일에 checkout 을 적용하면 파일을 수정 전으로 되돌린다.
-b
브랜치 생성과 동시에 checkout 까지 동시에 한다. <source lang=bash> $ git checkout -b feature_1212 Switched to a new branch 'feature_1212' </source>
clean
Remove untracked files from the working tree.
Untracked file 들을 삭제한다.
-d
Remove untracked directories in addition to untracked files. If an untracked directory is managed by a different Git repository, it is not removed by default.
Use -f option twice if you really want to remove such a directory.
Untracked directory 와 디렉토리 안에 있는 파일들도 함께 삭제 한다.
$ git clean -fd Removing playbooks/playbook_asterisk_deployment.yml
-f, --force
If the Git configuration variable clean.requireForce is not set to false, git clean will refuse to delete files or directories unless given -f, -n or -i.
Git will refuse to delete directories with .git sub directory or file unless a second -f is given.
$ git clean -f Removing ansible.cfg Removing roles/asterisk/tasks/asterisk_deployment.yml
-n, --dry-run
Don't actually remove anythin, just show what would be done.
$ git clean -n Would remove ansible.cfg Would remove roles/asterisk/tasks/asterisk_deployment.yml
clone
-b, --branch
clone 시 특정 브랜치를 지정하여 clone 할 때 사용하는 옵션이다.
$ git clone -b <branch> <remote_repo> Example $ git clone -b my-branch git@github.com:user/myproject.git Alternative (no public key setup needed): $ git clone -b my-branch https://git@github.com/username/myproject.git With Git 1.7.10 and later, add --single-branch to prevent fetching of all branches. Example, with OpenCV 2.4 branch: $ git clone -b 2.4 --single-branch https://github.com/Itseez/opencv.git opencv-2.4
pull
pull all branches
$ git pull --all
push
현재 commit 의 내용을 remote 로 push 한다.
-u, --set-upstream
로컬 브랜치 내용을 remote 로 push 한다.
$ git push --set-upstream origin <local branch name>
--all 옵션과 같이 사용할 경우, 현재 로컬에 있는 모든 브랜치의 내용을 remote 로 push 한다.
$ git push --all -u
commit
--amend
기존의 commit 에 내용 수정하기
$ git commit --amend
rebase
Git에서 한 Branch 에서 다른 Branch 로 합치는 방법은 두 가지가 있다. 하나는 Merge 이고, 다른 하나는 Rebase 이다. Merge 가 소스를 통합하는 방식이라면, Rebase 는 다른 Branch 에서 변경된 사항을 패치(Patch)로 만들고, 이를 다시 본래의 Branch 에 적용시키는 방법이다. rebase 는 Branch 단위로만 가능하며, Commit 단위로는 불가능하다. rebase 를 위해서는 반드시 Branch 를 생성해야 한다<ref>http://stackoverflow.com/questions/7758128/how-to-git-rebase-i-for-a-range-of-commits</ref>.
git rebase [-i | --interactive] [options] [--onto <newbase>] <upstream> [<branch>] git rebase [-i | --interactive] [options] --onto <newbase> --root [<branch>] git rebase --continue | --skip | --abort
$ git checkout experiment $ git rebase master
-i, --interactive
rebase 될 commit 의 리스트를 작성하고, 각각의 commit 에 대해 수행할 작업을 지정할 수 있는 interactive 모드를 시작한다. 보통은 commit 들을 합치고 싶을 때 가장 널리 사용되는 명령 중 하나이다.
$ git rebase -i HEAD~3 pick 23c7d18 Additional features pick 3ba2192 Create billing database pick 4caf479 - fix warns level for compiling client on freebsd.. # Rebase 1666596..4caf479 onto 1666596 # # Commands: # p, pick = use commit # r, reword = use commit, but edit the commit message # e, edit = use commit, but stop for amending # s, squash = use commit, but meld into previous commit # f, fixup = like "squash", but discard this commit's log message # x, exec = run command (the rest of the line) using shell # # These lines can be re-ordered; they are executed from top to bottom. # # If you remove a line here THAT COMMIT WILL BE LOST. # # However, if you remove everything, the rebase will be aborted. # # Note that empty commits are commented out
사용가능한 Command 들의 각각의 기능은 다음과 같다.
- p, pick : commit 된 내용을 그냥 그대로 사용한다.
- r, reword : commit 된 내용을 그냥 그대로 사용한다. 단, commit 메시지를 수정한다.
- e, edit : commit 된 내용을 그냥 그대로 사용한다. 단, 수정을 위해 잠시 정지(stop) 한다.
- s, squash : commit 된 내용을 그냥 그대로 사용한다. 단, 여러개의 커밋들을 하나의 커밋으로 합친다.
- f, fixup : squash 와 비슷하다. 단, commit message 는 사용하지 않는다.
- x, exec : 쉘을 통한 command 를 실행한다.
squash 및 fixup 은 이전 커밋들을 대상으로만 수행할 수 있다. 최근 커밋을 이전 커밋으로 합하는 명령어가 아니기 때문이다. 그리고, 절대로 이미 push 했던 커밋을 대상으로는 rebase 해서는 안된다.
--abort
rebase 중 잘못 선택하거나 실수로 의도하는 것과 달라진 경우, 해당 rebase 를 취소하고자 할 때 사용하는 명령어이다. <source lang=bash> $ git rebase --abort </source>
--continue
rebase 중, merge 가 깨진 경우, 해당 파일을 수정 및 add 한 후, 계속해서 rebase 를 진행할 때 사용하는 명령어이다. <source lang=bash> $ git rebase --continue </source>
show-brarnch
브랜치와 커밋 내용을 확인한다.
$ git show-branch [master] Oversized message cut and substitute
-a, --all
remote-tacking 브랜치와 로컬 브랜치 모두를 보여준다.
$ git show-branch -a * [master] Oversized message cut and substitute ! [origin/HEAD] Oversized message cut and substitute ! [origin/develop] Oversized message cut and substitute ! [origin/master] Oversized message cut and substitute ---- *+++ [master] Oversized message cut and substitute
diff
Commit, Branch, Working 디렉토리 사이의 diff 를 나타낸다.
git diff [options] [<commit>] [--] [<path>...] git diff [options] --cached [<commit>] [--] [<path>...] git diff [options] <commit> <commit> [--] [<path>...] git diff [options] <blob> <blob> git diff [options] [--no-index] [--] <path> <path>
Branch compare
Branch 끼리의 diff 를 보여준다.
$ git diff <branch 1> <branch 2> $ git diff tmp tmp1 diff --git a//main.c b/main.c index 237d99a..b54bca3 100644 --- a/main.c +++ b/main.c @@ -518,6 +518,90 @@ static bool validate_sms_table(const char* table_name, const char* attach_db) return true; } ...
HEAD
현재 파일들의 상태(아직 commit 되지 않은 상태의 변경도 포함)와 HEAD 와의 차이를 보여준다.
mv
파일, 심볼릭링크 또는 디렉토리의 이동 및 rename 을 한다. git 디렉토리에서 단순히 git 명령어가 아닌, unix/linux mv 명령어로 파일을 옮기게 되면 git 에서는 파일이동이 아닌, 파일 삭제, 새로운 파일 생성으로 받아들이게 된다.
만약 unix/linux 명령어 mv 로 파일이동을 하게 될 경우, 파일 트래킹 하기가 정말 어려워진다. git에서는 가급적 git mv를 사용하도록 하자.
-n, --dry-run
실제로 파일이동을 하지 않는다. 단지 어떻게 되는지만을 보여준다.
$ git mv -n conf/freeswitch.xml ./ Checking rename of 'conf/freeswitch.xml' to 'freeswitch.xml' Renaming conf/freeswitch.xml to freeswitch.xml
reset
HEAD 가 가리키는 커밋을 변경한다.
git reset [-q] [<tree-ish>] [--] <paths>... git reset (--patch | -p) [<tree-ish>] [--] [<paths>...] git reset [--soft | --mixed | --hard | --merge | --keep] [-q] [<commit>]
--mixed
Index 를 변경한다. 기본 동작방식이다.
--soft
Index 와 working directory 를 건드리지 않는다. 대신 HEAD 만을 이동한다.
--hard
Index 와 Working directory 를 변경한다. 즉, 로컬에 있는 모든 변경 내용과 확정본을 포기한다. 원격 저장소의 최신 이력을 가져오고, 로컬 master branch 가 해당 이력을 가리키도록 한다. <source lang=bash> $ git reset --hard origin/master HEAD is now at gba2192 test commit </source>
remote
현재 주시(track)중인 원격(remote) 저장소 내용들을 관리한다.
git remote [-v | --verbose] git remote add [-t <branch>] [-m <master>] [-f] [--mirror] <name> <url> git remote rename <old> <new> git remote rm <name> git remote set-head <name> (-a | -d | <branch>) git remote set-url [--push] <name> <newurl> [<oldurl>] git remote set-url --add [--push] <name> <newurl> git remote set-url --delete [--push] <name> <url> git remote [-v | --verbose] show [-n] <name> git remote prune [-n | --dry-run] <name> git remote [-v | --verbose] update [-p | --prune] [group | remote]...
set-url
Remote url 을 설정한다. pull/push 등을 하는 target url 을 변경한다. ssh/https 등의 접속 방식을 변경할 때 사용한다.
$ git remote -v origin git@github.com:pchero/jade-agent.git (fetch) origin git@github.com:pchero/jade-agent.git (push) $ git remote set-url origin https://github.com/pchero/jade-agent.git $ git remote -v origin https://github.com/pchero/jade-agent.git (fetch) origin https://github.com/pchero/jade-agent.git (push)
update
지정된 group 에 속한 원격 저장소 내용들을 update 한다. 만약 group 이 지정되어 있지 않다면, remotes.default 에 설정된 내용을 사용하게 된다. 만약 remotes.default 에 설정된 내용이 없다면, 전체 원격 저장소 내용들을 update 한다.
With --prune option, prune all the remotes that are updated.
$ git remote update Fetching origin remote: Counting objects: 18, done. remote: Total 18 (delta 7), reused 7 (delta 7), pack-reused 11 Unpacking objects: 100% (18/18), done. From https://github.com/pchero/asterisk-zmq 2109230..9991691 master -> origin/master 2109230..43c3fbb devel -> origin/devel * [new tag] v1.5 -> v1.5
fetch
원격 저장소의 변경 이력을 Download 한다. <source lang=bash> $ git fetch origin </source>
archive
log
Commit 이력을 확인한다. <source lang=bash> $ git log
commit 70b8a6e47475ed18d586be2e1625531981efdb18 Author: pchero <pchero@pchero21.com> Date: Mon Jun 20 10:47:28 2016 +0200
Test change 2 - Test change 2 Change-Id: Id09dc1f32bb584678c6cdef2f2eb4fabd6756a09
commit 668cbd8f92c81d075d5619722713272484f065ce Author: pchero <pchero@pchero21.com> Date: Mon Jun 20 10:14:03 2016 +0200
Test change commit 1 - Test change commit 1 - Test change again - Added Test change 1-1 Change-Id: Ic13c9ec5d79cd682b5a4d4126e7acf6a9d16663a
</source>
config
git 환경변수 값을들 설정/변경/삭제 한다.
$ git config [options]
core.editor
default editor 를 설정한다.
$ git config --global core.editor vim
user.email
commit 시 사용되는 email address 를 설정한다.
$ git config --global user.email "pchero21@gmail.com"
user.name
commit 사 사용되는 user name 을 설정한다.
$ git config --global user.name "pchero"
pager.branch
branch 시, list 가 less 처럼 작동하는걸 막아준다.
$ git config --global pager.branch false
--global
global config file 을 사용한다.
$ git config --global core.editor "vim"
Advanced
merge conflict
git merge conflict 발생 시 처리방법.
$ git merge fatal: You have not concluded your merge (MERGE_HEAD exists). Please, commit your changes before you can merge.
.gitignore
git directory 에서 제외하고자 하는 파일/디렉토리명을 명시하면 된다.
.terraform 디렉토리를 제외하고 싶다면,
$ cat .gitignore .terraform
처럼 하면 된다.
squash commits
다른 프로젝트에 Merge Request 를 할때, 여러개의 Commit 메시지를 하나의 commit 로 줄여야 할 때가 있다.
$ git rebase -i master ... $ git push --force origin <target branch>
가끔은 뭔가가 꼬여서 안될때가 있다. 그럴땐 patch 를 만들어서 모든 commit 를 지우고 patch를 적용하자.
$ git diff master..origin/<target branch> > patch $ git checkout <target brach> $ git rebase -pi master ## delete all commits $ git apply patch $ git add . $ git commit $ git push --force origin <target branch>
Errors
server certificate verification failed. CAfile
다음과 같은 에러가 있었다.
pchero@jenkins:~/git$ git clone https://lab.cluster.gsi.dit.upm.es/sefarad/sefarad.git Cloning into 'sefarad'... fatal: unable to access 'https://lab.cluster.gsi.dit.upm.es/sefarad/sefarad.git/': server certificate verification failed. CAfile: /etc/ssl/certs/ca-certificates.crt CRLfile: none
SSL verify 옵션을 끄면된다.
export GIT_SSL_NO_VERIFY=1
error: unpack failed: error Missing tree
error: unpack failed: error Missing tree fa6b09d4f5dc8ee6fcb0553396530f97a3033856
다음과 같은 순서로 작업을 진행했을 경우 발생하는 에러이다.
- Create a new branch on head. - Do some modifications on new branchs - Somebody also make modifications on head branch - Try to push your branch
git pull 진행 후, 다시 push 를 하면 된다.
See also
- http://stackoverflow.com/questions/10312521/how-to-fetch-all-git-branches - How to fetch all git branches
- https://git-scm.com/book/ko/v1/Git-%EB%B8%8C%EB%9E%9C%EC%B9%98-Rebase%ED%95%98%EA%B8%B0 - Git-브랜치-Rebase하기
- https://progit.org/ - progit book
- https://git-scm.com/book/ko/v2/Git-도구-Reset-명확히-알고-가기 - Reset 명확히 알고 가기
References
<references />