Table of contents


NOTICE: The most data in this page is come from Pro Git.

Basic

The Three States

  1. committed - the data is safely stored in your local database
  2. modified - file is changed but have not committed
  3. staged - marked a modified file in its current version to go into your next commit snapshot.

git_101_001.png

  • The Git directory is where Git stores the metadata and object database for your project
  • The working directory is a single checkout of one version of the project.
  • The staging area is a simple file, generally contained in your Git directory, that stores information about what will go into your next commit. It’s sometimes referred to as the index, but it’s becoming standard to refer to it as the staging area.

Basic Git workflow

  1. You modify files in your working directory.
  2. You stage the files, adding snapshots of them to your staging area.
  3. You do a commit, which takes the files as they are in the staging area and stores that snapshot permanently to your Git directory.

Install Git

Windows

download msysgit and install it.

Linux
$ yum install git-core


$ apt-get install git-core

Terms

  • HEAD : 一個特殊的指標(pointer),它指向current branch.
  • master : 預設的branch
  • origin : 預設遠端的master branch
  • remote : 遠端 repository
  • tracking branch: 從遠端fetch到local端的branch
  • rebase : 將原先branch出來的時間點(版本)向前或向後移動,這樣可以讓該branch移除或加入功能別的branch的功能
  • cherry pick commit : 只挑選同一branch的部份commits做merge

    A - B - C - D - E   master
      \ - X - Y  - Z   branch 1
    
rebase

本來branch 1不包含B特性,可以透過rebase將B包含進去

A - B - C - D - E   master
      \ - X - Y  - Z   branch 1
cherry pick commit

如果將branch 1 merge 回master,會包含X,Y,Z特性,但可以透過cherry pick commit,則可以選擇merge時不包含X,或X,Y

A - B - C - D - E    master
  \ - X - Y  - Z   branch 1

Tracking Branches

跟遠端repository的branch有對應關係的local branch,叫tracking branch,如果branch是一個tracking branch 那麼push時,會自動push到遠端的對應的branch,如果不是tracking branch,就需要特別指定要push到遠端的那一個branch

像這樣 git push origin master,我們在init git repository後,第一次的push需要下這個commit,就是 因為一開始local的(master) barnch 沒有跟遠端的關聯,所以我們要跟git說要push到遠端(預設遠端的名字叫origin,當然, 你也可以取其他的名稱ex: github,bitbucket或mycompany)的master上

Command

從遠端fetch到local端的branch是無法直接更改的,想要更改必須在建立自已新的branch

checkout -b branch1  remote_server/branch1
checkout -b feature/peak --track origin/feature/peak

config

config有三個等級,由小到大分別為

  1. 庫等級(repository裡),只會單一的repository有影響
  2. 全局(global),放在user home,對user會存取的庫有影響
  3. 系統等級(system),放在系統的配置目錄下(ex: /etc),對所有的user有影響

而優先權則相反,以repository的為主,再來是global的,最後才是system的,很直覺也很合理

list config
$ git config --list
user.name=Scott Chacon
user.email=schacon@gmail.com
color.status=auto
color.branch=auto
color.interactive=auto
color.diff=auto
...

config是git跟svn最大不同的地方,git必需要正確定user info後,操作會才正常

config user name and email
$ git config --global user.name "Kent Chiu"
$ git config --global user.email kent.chiu@example.com
clone from windows local
file:///d:/PATH/PROJECT_HOME

add

add是個多功能的指令,它可以

  • 把untrack file變成tracked file
  • 把modified file變成staged file

或commit時同時做add的動作(不建議)

$ git add -a -m 'comment'

commit

$ git add *.c
$ git add README
# files need be staged before commit
$ git commit -m 'initial project version'

提交所有控版下的檔案

$ git commit -a -m 'comment'
# 也可以把 a (all) m (message)合在一起用 
$ git commit -am 'comment'

如果對前一次提交的訊息不滿意,可以透過amend做修改

$ git commit --amend -m 'modify comment'

rm

remove files. 如果是直接從file system刪檔,而沒透過git指令,那該檔案的狀態會變成 Changed but not updated (unstaged)

上面的add command並不會把檔案刪除的動作加到stage裡

remove file and delete it
$git rm myfile.txt
remove files from staged

untracking files but keep in file system. 這個指定通常用在想把版控的檔案變成非版控

$git rm --staged myfile.txt
清除untracked files

如果想快速的清除還沒有加到 index 的 file ,可以用以下的指令

$git clean -f -d

參數 -d 是指連 untracked 的目錄一併清除

mv

搬移/更名

$ git  README README.txt

status

顯示異動檔案狀態

log

顯示異動檔案細節

$ git log
常用參數
  • -p 列出細節
  • -n n表數字,列出最新的幾個
  • –graph 祖譜圖
  • –pretty 改變預設的輸出格式
  • –pretty:format自定輸出格式 $ git log --pretty=format:"%h - %an, %ar : %s"
過濾(limit by commit attributes)
$ git log --author=kent
$ git log --committer=kent 
$ git log --grep="commit .*message"
search for a change
$ git log -S"Some code change"
$ git log --pickaxe-regex -S "some.*text"
limit by changes to specific path
git lot -- some/file

遠端相關的指令

show remote repositories
$ git remote -v
origin  git://github.com/schacon/ticgit.git
adding remote repositories
$ git remote add pb git://github.com/paulboone/ticgit.git
$ git remote -v
origin  git://github.com/schacon/ticgit.git
pb  git://github.com/paulboone/ticgit.git

gitk

Using a GUI to Visualize History.

mergetool

Calling merge tool.

reset

將檔案unsatged

  工作區         暫存區          HEAD
    | <---------- |                       git reset         重置加入暫存區的動作(也就是取消 git add) 
                  | <---------- |         git reset --soft  重置加入版本庫的動作(也就是取消commited),但commmit過的檔案會保留在工作區                
    | <---------- | <---------- |         git reset --hard  完整的取消整個commit,工作區會的檔案會被恢復到送個版本

git reset, git reset HEAD, git reset --mixed這三個指令做的是一樣的事 git reset --hard 使用上要小心,commit的歷史記錄會不見

使用時機

  • git reset 不小心加入不想加入暫存取(index)的檔案,可用這個取消
  • git reset --soft 想重新修正某一次的commit (git commit --amend就是透過這個指令完成的)
  • git reset --hard 回到某個版本,就像完做過異動一樣,merge失敗時,也常用這個來恢復到merged前的狀態

git reset --hard 只會退回到上一個commit,如果要退更多,就要直接指定commit id git reset --hard <commit id>

diff

  工作區         暫存區          HEAD
     
    | <---------> |                       git diff                  比對工作區跟暫存區的差異
                  | <---------> |         git diff --staged         比對HEAD跟暫存區的差異
    | <-----------------------> |         git diff HEAD             比對HEAD跟工作區的差異
                            ┌-> |
                            |   |         git diff $commit $commit  比對兩個commits間的差異
                            └-> |

如果是要比對某個檔在在不同的 commits 間的差異,可使用以下指令 git diff $commit $commit -- path/file

解讀diff

@@ -3,7 +3,7 @@
 <h1>Tag Colud</h1>
 <ul>
   <li><a href='/blog/categories/actionbar'>Actionbar (1)</a></li>
-  <li><a href='/blog/categories/android'>Android (26)</a></li>
+  <li><a href='/blog/categories/android'>Android (24)</a></li>
   <li><a href='/blog/categories/apache'>Apache (8)</a></li>
   <li><a href='/blog/categories/broadcast-receiver'>Broadcast_receiver (2)</a><
   <li><a href='/blog/categories/cdi'>Cdi (2)</a></li>

diff中的資訊包含兩部份,第一部份是異動概要 @@ -3,7 +3,7 @@,第二部份是異動細節 第一部份的是資訊 @@ -3,7 +3,7 @@是說原始文件從第3行開始,後面的7行(也就是第3~10行)異動成為新文件的第3行到第7行(也是第3~10行),本例中因為是調整了某一行的內容,所以異動範圍都是七行,如果新的文件的範圍可能更大(ex:加了幾行),或更小(刪了幾行)。

上述的異動範為7行,是指相關的上下文共有七行,而不是這七行都有改到

第二部份比較直覺,就上例中的第六行

-  <li><a href='/blog/categories/android'>Android (26)</a></li>

及第七行

+  <li><a href='/blog/categories/android'>Android (24)</a></li>

代表著第六行的內容被異動成第七行

show

review last commit
$ git show
 
### output ###
 
commit b8d5b1e2944d1785a3e8ca15979f9c462eb611c9
Author: Kent Chiu <kent.chiu@techmore.com.tw>
Date:   Thu Feb 18 13:07:49 2010 +0800
 
    foo
 
diff --git a/dir/foo b/dir/foo
new file mode 100644
index 0000000..257cc56
--- /dev/null
+++ b/dir/foo
@@ -0,0 +1 @@
+foo
show the stats
$ git show --stat
 
### output ###
 
commit b8d5b1e2944d1785a3e8ca15979f9c462eb611c9
Author: Kent Chiu <kent.chiu@techmore.com.tw>
Date:   Thu Feb 18 13:07:49 2010 +0800
 
    foo
 
 dir/foo |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)
show SVN style status
$ git show --name-status
 
### output ###
 
commit b8d5b1e2944d1785a3e8ca15979f9c462eb611c9
Author: Kent Chiu <kent.chiu@techmore.com.tw>
Date:   Thu Feb 18 13:07:49 2010 +0800
 
    foo
 
A       dir/foo

push

deleting remote branches
$ git push origin :serverfix
To git@github.com:schacon/simplegit.git
 - [deleted]         serverfix

This is called by

$ git push [remotename] [localbranch]:[remotebranch]
$ git push origin                    :serverfix 

let localbranch blank means deleted it.

git 1.7之後提供這個指令可以刪遠端server git push origin --delete <branchName>

git 全域設定檔

ini git configuration

~/.gitconfig

[user]
	name = kent
	email = kent@mail.com

[alias]
	st = status
    ci = commit
    co = checkout
    br = branch

[color]
	ui = true
	diff = auto
	status = auto
	branch = auto

常用指令

檢視 fetch 下來但尚未被 merged 的資料

從遠端 fetch 新資料下來,如果想先在做 merge 前先查看資料的異動狀況,可以透過 log 跟 diff,log 可以查看 commits 的記錄,而 diff 可以對檔案內容做比對

查看 fetch 下來,等著被 merged 的 commits

    $ git fetch                 # 或者是用 git remote update 來 fetch 所有 branches
    $ git log HEAD..origin      # 在pull (也就是 merge ) 前,可以先用這個指令查看那些 commits 會被 merged
    $ git diff HEAD...origin    # 在pull (也就是 merge ) 前,可以先用這個指令查看那些 diffs 會被 merged

執行 fetch 是把 server 上的 branch 更新到 local repository 的 remote branch 所以需要進行差異性檢視的內容是 HEAD 到 origin

checkout 新的 remote branch 並 tracking

之前常會發生 checkout 每個 branch後,要 push 遠端server時,卻都只是 push 到 local,這是因為預設的 checkout 指令是不會去 tracking remote branch 所以,如果要 checkout 後能夠讓 branch 成為 track branch,就要加上 --track 的參數

	$ checkout -b new_branch --track origin/branch_name 

Resource