1. Git概念
1.1. Git庫中由三部分組成
Git 倉庫就是那個.git 目錄,其中存放的是我們所送出的文檔索引内容,Git 可基于文檔索引内容對其所管理的文檔進行内容追蹤,進而實作文檔的版本控制。.git目錄位于工作目錄内。
1) 工作目錄:使用者本地的目錄;
2) Index(索引):将工作目錄下所有檔案(包含子目錄)生成快照,存放到一個臨時的存儲區域,Git 稱該區域為索引。
3) 倉庫:将索引通過commit指令送出至倉庫中,每一次送出都意味着版本在進行一次更新。

1.2. 使用Git時的初始化事項
1.2.1. Git初始化配置
1) 配置使用git倉庫的人員姓名
git config --global user.name "Your Name Comes Here"
2) 配置使用git倉庫的人員email
1.2.2. Git文檔忽略機制
工作目錄中有一些檔案是不希望接受Git 管理的,譬如程式編譯時生成的中間檔案等等。Git 提供了文檔忽略機制,可以将工作目錄中不希望接受Git 管理的文檔資訊寫到同一目錄下的.gitignore 檔案中。
例如:工作目錄下有個zh目錄,如果不想把它加入到Git管理中,則執行:
echo “zh” > .gitignore
git add .
有關gitignore 檔案的諸多細節知識可閱讀其使用手冊:man gitignore
1.3. Git與Repo的比較
Git操作一般對應一個倉庫,而Repo操作一般對應一個項目,即一個項目會由若幹倉庫組成。
例如,在操作整個Recket項目時使用Repo,而操作其中的某個倉庫時使用Git。在包含隐藏目錄.git的目錄下執行git操作。
2. Git help
Git help 擷取git基本指令
(如果要知道某個特定指令的使用方法,例如:使用Git help clone,來擷取git clone的使用方法)
3. Git本地操作基本指令
3.1. Git init
或者使用git init-db。
建立一個空的Git庫。在目前目錄中産生一個.git 的子目錄。以後,所有的檔案變化資訊都會儲存到這個目錄下,而不像CVS那樣,會在每個目錄和子目錄下都建立一個CVS目錄。
在.git目錄下有一個config檔案,可以修改其中的配置資訊。
3.2. Git add
将目前工作目錄中更改或者新增的檔案加入到Git的索引中,加入到Git的索引中就表示記入了版本曆史中,這也是送出之前所需要執行的一步。
可以遞歸添加,即如果後面跟的是一個目錄作為參數,則會遞歸添加整個目錄中的所有子目錄和檔案。例如:
git add dir1 ( 添加dir1這個目錄,目錄下的所有檔案都被加入 )
Git add f1 f2 ( 添加f1,f2檔案)
git add . ( 添加目前目錄下的所有檔案和子目錄 )
3.3. Git rm
從目前的工作目錄中和索引中删除檔案。
可以遞歸删除,即如果後面跟的是一個目錄做為參數,則會遞歸删除整個目錄中的所有子目錄和檔案。例如:
git rm –r * (進入某個目錄中,執行此語句,會删除該目錄下的所有檔案和子目錄)
git rm f1 (删除檔案f1,包含本地目錄和index中的此檔案記錄)
git rm --ached f1 (删除檔案f1,不會删除本地目錄檔案,隻删除index中的檔案記錄;将已經git add的檔案remove到cache中,這樣commit的時候不會送出這個檔案, 适用于一下子添加了很多檔案, 卻又想排除其中個别幾個檔案的情況.)
3.4. Git commit
送出目前工作目錄的修改内容。
直接調用git commit指令,會提示填寫注釋。通過如下方式在指令行就填寫送出注釋:git commit -m "Initial commit of gittutor reposistory"。 注意,和CVS不同,git的送出注釋必須不能為空,否則就會送出失敗。
git commit還有一個 -a的參數,可以将那些沒有通過git add辨別的變化一并強行送出,但是不建議使用這種方式。
每一次送出,git就會為全局代碼建立一個唯一的commit辨別代碼,使用者可以通過git reset指令恢複到任意一次送出時的代碼。
git commit –-amend –m “message” (在一個commit id上不斷修改送出的内容)
3.5. Git status
檢視版本庫的狀态。可以得知哪些檔案發生了變化,哪些檔案還沒有添加到git庫中等等。 建議每次commit前都要通過該指令确認庫狀态。
最常見的誤操作是, 修改了一個檔案, 沒有調用git add通知git庫該檔案已經發生了變化就直接調用commit操作, 進而導緻該檔案并沒有真正的送出。這時如果開發者以為已經送出了該檔案,就繼續修改甚至删除這個檔案,那麼修改的内容就沒有通過版本管理起來。如果每次在 送出前,使用git status檢視一下,就可以發現這種錯誤。是以,如果調用了git status指令,一定要格外注意那些提示為 “Changed but not updated:”的檔案。 這些檔案都是與上次commit相比發生了變化,但是卻沒有通過git add辨別的檔案。
3.6. Git log
檢視曆史日志,包含每次的版本變化。每次版本變化對應一個commit id。
Git log -1
-1的意思是隻顯示一個commit,如果想顯示5個,就-5。不指定的話,git log會從該commit一直往後顯示。
Git log --stat –summary (顯示每次版本的詳細變化)
在項目日志資訊中,每條日志的首行(就是那一串字元)為版本更新送出所進行的命名,我們可以将該命名了解為項目版本号。項目版本号應該是唯一的,預設由 Git 自動生成,用以标示項目的某一次更新。如果我們将項目版本号用作git-show 指令的參數,即可檢視該次項目版本的更新細節。例如:
1) Git log
2)Git show
實際上,上述指令并非是真正的進行版本号自定義,隻是制造了一個tag對象而已,這在進行項目版本對外釋出時比較有用。
3.7. Git merge
把伺服器上下載下傳下來的代碼和本地代碼合并。或者進行分支合并。
例如:目前在master分支上,若想将分支dev上的合并到master上,則git merge dev
注意:git merge nov/eclair_eocket (是将伺服器git庫的eclair_eocket分支合并到本地分支上)
git rebase nov/eclair_eocket (是将伺服器git庫的eclair_eocket分支映射到本地的一個臨時分支上,然後将本地分支上的變化合并到這個臨時分支,然後再用這個臨時分支初始化本地分支)
3.8. Git diff
把本地的代碼和index中的代碼進行比較,或者是把index中的代碼和本地倉庫中的代碼進行比較。
1) Git diff
比較工作目錄和Index中的代碼。
2) Git diff - - cached
比較index和本地倉庫中的代碼。
3.9. Git checkout
3.9.1. 切換到分支
1) 建立一個新分支,并切換到該分支上
Git checkout –b 新分支名
2)切換到某個已經建立的本地分支local_branch
Git checkout local_branch
(使用cat .git/HEAD後,顯示refs:refs/heads/ local_branch)
3) 切換到伺服器上的某個分支remote_branch
Git checkout remote_branch
(遠端分支remote_branch可以通過 git branch –r 列出)
4) 切換到某個commit id
Git checkout commit_id
(使用cat .git/HEAD後,顯示commit_id)
5) 切換到某個tag
Git checkout tag
(使用cat .git/HEAD後,顯示tag)
注意: 除了1)和2)外,其餘三種都隻是切換到了一個臨時的( no branch )狀态 (this head is detached),這時用 git branch 可以看到處于(no branch)上, cat .git/HEAD 看到指向相應的commit id。 這個(no branch)隻是臨時存在的,并不是一個真正建立的branch。 如果此時執行2),則這個(no branch)就自動消失了;如果執行1), 則建立新分支 new branch,并把這個(no branch)挂到這個新分支上,此時cat .git/refs/heads/new_branch 可以看到已經指向了剛才那個commit id。
3.9.2. 用已有分支初始化新分支
執行下面的指令,在切換到某個已經建立的local branch或者某個remote branch或者某個commit id 或者某個tag的同時,建立新分支new_branch,并且挂到這個新分支上。
1) 切換到某個已經建立的本地分支local_branch,并且使用此分支初始化一個新分支new_branch。
git checkout –b new_branch local_branch
2) 切換到某個遠端分支remote_branch,并且用此分支初始化一個新分支new_branch。
Git checkout –b new_branch remote_branch
3) 切換到某個commit id,并建立新分支new_branch
Git checkout –b new_branch commit_id
4) 切換到某個tag,并建立新分支new_branch
Git checkout –b new_branch tag
3.9.3. 還原代碼
例如 “git checkout app/model/user.rb” 就會将user.rb檔案從上一個已送出的版本中更新回來,未送出的工作目錄中的内容全部會被覆寫。
3.10. Git-ls-files
檢視目前的git庫中有那些檔案。
3.11. Git mv
重命名一個檔案、目錄或者連結。
例如:Git mv helloworld.c helloworld1.c (把檔案helloworld.c 重命名為 helloworld1.c)
3.12. Git branch
3.12.1. 總述
在 git 版本庫中建立分支的成本幾乎為零,是以,不必吝啬多建立幾個分支。當第一次執行git init時,系統就會建立一個名為“master”的分支。 而其它分支則通過手工建立。
下面列舉一些常見的分支政策:
建立一個屬于自己的個人工作分支,以避免對主分支 master 造成太多的幹擾,也友善與他人交流協作;
當進行高風險的工作時,建立一個試驗性的分支;
合并别人的工作的時候,最好是建立一個臨時的分支用來合并,合并完成後再“fetch”到自己的分支。
對分支進行增、删、查等操作。
注意:分支資訊一般在.git/refs/目錄下,其中heads目錄下為本地分支,remotes為對應伺服器上的分支,tags為标簽。
3.12.2. 檢視分支
git branch 列出本地git庫中的所有分支。在列出的分支中,若分支名前有*,則表示此分支為目前分支。
git branch –r 列出伺服器git庫的所有分支。
(可以繼續使用指令 “ git checkout -b 本地分支名 伺服器分支名”來擷取伺服器上某個分支的代碼檔案)。
3.12.3. 檢視目前在哪個分支上
cat .git/HEAD
3.12.4. 建立一個分支
1) git branch 分支名
雖然建立了分支,但是不會将目前工作分支切換到新建立的分支上,是以,還需要指令“git checkout 分支名” 來切換,
2) git checout –b 分支名
不但建立了分支,還将目前工作分支切換到了該分支上。
3.12.5. 切換到某個分支:git checkout 分支名
切換到主分支:git checkout master
3.12.6. 删除分支
git branch –D 分支名
注意: 删除後,發生在該分支的所有變化都無法恢複。強制删除此分支。
3.12.7. 比較兩個分支上的檔案的差別
git diff master 分支名 (比較主分支和另一個分支的差別)
3.12.8. 檢視分支曆史
git-show-branch (檢視目前分支的送出注釋及資訊)
git-show-branch -all(檢視所有分支的送出注釋及資訊)例如:
* [dev] d2
! [master] m2
--
* [dev^] d1
* [dev~2] d0
*+ [master] m2
在上述例子中, “--”之上的兩行表示有兩個分支dev和master, 且dev分支上最後一次送出的日志是“d2”,master分支上最後一次送出的日志是 “m2”。 “--”之下的幾行表示了分支演化的曆史,其中 dev表示發生在dev分支上的最後一次送出,dev^表示發生在dev分支上的倒數第二次送出。dev~2表示發生在dev分支上的倒數第三次送出。
3.12.9. 檢視目前分支的操作記錄
git whatchanged
3.12.10. 合并分支
法一:
git merge “注釋” 合并的目标分支 合并的來源分支
如果合并有沖突,git會有提示。
例如:git checkout master (切換到master分支)
git merge HEAD dev~2 (合并master分支和dev~2分支)或者:git merge master dev~2
法二:
git pull 合并的目标分支 合并的來源分支
例如: git checkout master (切換到master分支)
git pull . dev~2(合并目前分支和dev~2分支)
3.13. Git rebase
一般在将伺服器最新内容合并到本地時使用,例如:在版本C時從伺服器上擷取内容到本地,修改了本地内容,此時想把本地修改的内容送出到伺服器上;但發現伺服器上的版本已經變為G了,此時就需要先執行Git rebase,将伺服器上的最新版本合并到本地。例如:
用下面兩幅圖解釋會比較清楚一些,rebase指令執行後,實際上是将分支點從C移到了G,這樣分支也就具有了從C到G的功能。
3.14. Git reset
庫的逆轉與恢複除了用來進行一些廢棄的研發代碼的重置外,還有一個重要的作用。比如我們從遠端clone了一個代碼庫,在本地開發後,準備送出回遠端。但是本地代碼庫在開發時,有功能性的commit,也有出于備份目的的commit等等。總之,commit的日志中有大量無用log,我們并不想把這些 log在送出回遠端時也送出到庫中。 是以,就要用到git reset。
git reset的概念比較複雜。它的指令形式:git reset [--mixed | --soft | --hard] [<commit-ish>]
指令的選項:
--mixed 這個是預設的選項。如git reset [--mixed] dev^(dev^的定義可以參見2.6.5)。它的作用僅是重置分支狀态到dev1^, 但是卻不改變任何工作檔案的内容。即,從dev1^到dev1的所有檔案變化都保留了,但是dev1^到dev1之間的所有commit日志都被清除了, 而且,發生變化的檔案内容也沒有通過git add辨別,如果您要重新commit,還需要對變化的檔案做一次git add。 這樣,commit後,就得到了一份非常幹淨的送出記錄。 (回退了index和倉庫中的内容)
--soft相當于做了git reset –mixed,後,又對變化的檔案做了git add。如果用了該選項, 就可以直接commit了。(回退了倉庫中的内容)
--hard這個指令就會導緻所有資訊的回退, 包括檔案内容。 一般隻有在重置廢棄代碼時,才用它。 執行後,檔案内容也無法恢複回來了。(回退了工作目錄、index和倉庫中的内容)
例如:
切換到使用的分支上;
git reset HEAD^ 回退第一個記錄
git reset HEAD~2 回退第二個記錄
如果想把工作目錄下的檔案也回退,則使用git reset - - hard HEAD^ 回退第一個記錄
git reset - - hard HEAD~2 回退第二個記錄
還可以使用如下方法:
将目前的工作目錄完全復原到指定的版本号,假設如下圖,我們有A-G五次送出的版本,其中C的版本号是 bbaf6fb5060b4875b18ff9ff637ce118256d6f20,我們執行了'git reset bbaf6fb5060b4875b18ff9ff637ce118256d6f20'那麼結果就隻剩下了A-C三個送出的版本
3.15. Git revert
還原某次對版本的修改,例如:git revert commit_id (其中commit_id為commit代碼時生成的一個唯一表示的字元串)
例如:(3.6中)git revert dfb02e6e4f2f7b573337763e5c0013802e392818 (執行此操作,則還原上一次commit的操作)
3.16. Git config
利用這個指令可以新增、更改Git的各種設定,例如 “git config branch.master.remote origin” 就将master的遠端版本庫設定為别名叫做origin版本庫。
3.17. Git show
顯示對象的不同類型。
3.18. Git tag
建立、列出、删除或者驗證一個标簽對象(使用GPG簽名的)。
可以将某個具體的版本打上一個标簽,這樣就不需要記憶複雜的版本号哈希值字元串了,例如你可以使用 “git tag revert_version bbaf6fb5060b4875b18ff9ff637ce118256d6f20” 來标記這個被你還原的版本,那麼以後你想檢視該版本時,就可以使用 revert_version标簽名,而不是哈希值了。
4. Git伺服器操作指令(與伺服器互動)
4.1. Git clone
取出伺服器的倉庫的代碼到本地建立的目錄中(與伺服器互動)
通過git clone擷取遠端git庫後,.git/config中的開發者資訊不會被一起clone過來。仍然需要為本地庫的.git/config檔案添加開發者資訊。此外,開發者還需要自己添加 . gitignore檔案。
通過git clone擷取的遠端git庫,隻包含了遠端git庫的目前工作分支。如果想擷取其它分支資訊,需要使用 “git branch –r” 來檢視, 如果需要将遠端的其它分支代碼也擷取過來,可以使用指令 “ git checkout -b 本地分支名 遠端分支名”,其中,遠端分支名為 “git branch –r” 所列出的分支名, 一般是諸如“origin/分支名”的樣子。如果本地分支名已經存在, 則不需要“-b”參數。
4.2. Git pull
從伺服器的倉庫中擷取代碼,和本地代碼合并。(與伺服器互動,從伺服器上下載下傳最新代碼,等同于: Git fetch + Git merge)
從其它的版本庫(既可以是遠端的也可以是本地的)将代碼更新到本地,例如:“git pull origin master ”就是将origin這個版本庫的代碼更新到本地的master主分支。
git pull可以從任意一個git庫擷取某個分支的内容。用法如下:
需要注意的是,git pull也可以用來合并分支。 和git merge的作用相同。 是以,如果你的本地分支已經有内容,則git pull會合并這些檔案,如果有沖突會報警。
4.3. Git push
将本地commit的代碼更新到遠端版本庫中,例如 “git push origin”就會将本地的代碼更新到名為orgin的遠端版本庫中。
需要格外注意的是,git push好像不會自動合并檔案。是以,如果git push時,發生了沖突,就會被後push的檔案内容強行覆寫,而且沒有什麼提示。 這在合作開發時是很危險的事情。
4.4. Git fetch
從伺服器的倉庫中下載下傳代碼。(與伺服器互動,從伺服器上下載下傳最新代碼)
相當于從遠端擷取最新版本到本地,不會自動merge,比Git pull更安全些。
使用此方法來擷取伺服器上的更新。
例如:如果使用git checkout nov/eclair_rocket (nov/eclair_rocket為伺服器上的分支名),則是擷取上次使用git fetch指令時從伺服器上下載下傳的代碼;如果先使用 git fetch ,再使用git checkout nov/eclair_rocket,則是先從伺服器上擷取最新的更新資訊,然後從伺服器上下載下傳最新的代碼。
本文轉自einyboy部落格園部落格,原文連結:http://www.cnblogs.com/einyboy/archive/2012/11/26/2788752.html,如需轉載請自行聯系原作者。