【git】git分支的合併

原文:  html

http://gitbook.liuhui998.com/3_3.html
http://gitbook.liuhui998.com/5_3.html
1、如何分支的合併
在git中,可使用git merge 和git rebase兩個命令來進行分支的合併。
git merge 和git rebase在大致上都差很少,下文主要以git merge來例來說解分支的合併流程。
若是你想了解分支合併的更多內容,請閱讀《 git merge簡介》,《 git rebase簡介(基本篇)》和《 git rebase簡介(高級篇)》。
git merge命令示例:
$ git merge branchname
這個命令把分支"branchname"合併到了當前分支裏面。
若有衝突(衝突--同一個文件在遠程分支和本地分支裏按不一樣的方式被修改了);那麼命令的執行輸出就像下面同樣
$ git merge next
 100% (4/4) done
Auto-merged file.txt
CONFLICT (content): Merge conflict in file.txt
Automatic merge failed; fix conflicts and then commit the result.
在有問題的文件上會有衝突標記,在你手動解決完衝突後就能夠把此文件添 加到索引(index)中去,用git commit命令來提交,就像平時修改了一個文件 同樣。
若是你用gitk來查看commit的結果,你會看到它有兩個父分支:一個指向當前的分支,另一個指向剛纔合併進來的分支。
2、解決合併中的衝突
若是執行自動合併無成功的話,git會在索引和工做樹裏設置一個特殊的狀態, 提示你如何解決合併中出現的衝突。
有衝突(conflicts)的文件會保存在索引中,除非你解決了問題了而且更新了索引,不然執行 git commit都會失敗:
$ git commit
file.txt: needs merge
若是執行 git status 會顯示這些文件沒有合併(unmerged),這些有衝突的文件裏面會添加像下面的衝突標識符:
<<<<<<< HEAD:file.txt
Hello world
=======
Goodbye
>>>>>>> 77976da35a11db4580b80ae27e8d65caf5208086:file.txt
你所須要的作是就是編輯解決衝突,(接着把衝突標識符刪掉),再執行下面的命令:
$ git add file.txt
$ git commit
注意:提交註釋裏已經有一些關於合併的信息了,一般是用這些默認信息,可是你能夠添加一些你想要的註釋。
上面這些就是你要作一個簡單合併所要知道的,可是git提供更多的一些信息來 幫助解決衝突。
3、撒銷一個合併
若是你以爲你合併後的狀態是一團亂麻,想把當前的修改都放棄,你能夠用下面的命令回到合併以前的狀態:
$ git reset --hard HEAD
或者你已經把合併後的代碼提交,但仍是想把它們撒銷:
$ git reset --hard ORIG_HEAD
可是剛纔這條命令在某些狀況會很危險,若是你把一個已經被另外一個分支合併的分支給刪了,那麼 之後在合併相關的分支時會出錯。
關於撤銷的更多內容請參考《 git reset簡介
4、快速向前合併
還有一種須要特殊對待的狀況,在前面沒有提到。一般,一個合併會產生一個合併提交(commit), 把兩個父分支裏的每一行內容都合併進來。
可是,若是當前的分支和另外一個分支沒有內容上的差別,就是說當前分支的每個提交(commit)都已經存在另外一個分支裏了,git 就會執行一個「快速向前"(fast forward)操做;git 不建立任何新的提交(commit),只是將當前分支指向合併進來的分支。
5、在合併過程當中獲得解決衝突的協助
git會把全部能夠自動合併的修改加入到索引中去, 因此git diff只會顯示有衝突的部分. 它使用了一種不常見的語法:
$ git diff
diff --cc file.txt
index 802992c,2b60207..0000000
--- a/file.txt
+++ b/file.txt
@@@ -1,1 -1,1 +1,5 @@@
++<<<<<<< HEAD:file.txt
 +Hello world
++=======
+ Goodbye
++>>>>>>> 77976da35a11db4580b80ae27e8d65caf5208086:file.txt
回憶一下, 在咱們解決衝突以後, 獲得的提交會有兩個而不是一個父提交: 一個父提交是當前分支提交前的HEAD,; 另一個父提交是被合併分支的HEAD, 被暫時存在MERGE_HEAD.
在合併過程當中, 索引中保存着每一個文件的三個版本. 三個"文件暫存(file stage)"中的每個都表明了文件的不一樣版本:
$ git show :1:file.txt  # 兩個分支共同祖先中的版本.
$ git show :2:file.txt  # HEAD中的版本.
$ git show :3:file.txt  # MERGE_HEAD中的版本.
當你使用git diff去顯示衝突時, 它在工做樹(work tree), 暫存2(stage 2)和暫存3(stage 3)之間執行三路diff操做, 只顯示那些兩方都有的塊(換句話說, 當一個塊的合併結果只從暫存2中獲得時, 是不會被顯示出來的; 對於暫存3來講也是同樣).
上面的diff結果顯示了file.txt在工做樹, 暫存2和暫存3中的差別. git不在每行前面加上單個'+'或者'-', 相反地, 它使用兩欄去顯示差別: 第一欄用於顯示第一個父提交與工做目錄文件拷貝的差別, 第二欄用於顯示第二個父提交與工做文件拷貝的差別. (參見git diff-files中的"COMBINED DIFF FORMAT"取得此格式詳細信息.)
在用直觀的方法解決衝突以後(可是在更新索引以前), diff輸出會變成下面的樣子:
$ git diff
diff --cc file.txt
index 802992c,2b60207..0000000
--- a/file.txt
+++ b/file.txt
@@@ -1,1 -1,1 +1,1 @@@
- Hello world
-Goodbye
++Goodbye world
上面的輸出顯示瞭解決衝突後的版本刪除了第一個父版本提供的"Hello world"和第二個父版本提供的"Goodbye", 而後加入了兩個父版本中都沒有的"Goodbye world".
一些特別diff選項容許你對比工做目錄和三個暫存中任何一個的差別:
$ git diff -1 file.txt      # 與暫存1進行比較
$ git diff --base file.txt          # 與上相同
$ git diff -2 file.txt      # 與暫存2進行比較
$ git diff --ours file.txt          # 與上相同
$ git diff -3 file.txt      # 與暫存3進行比較
$ git diff --theirs file.txt    # 與上相同.
還有,git log和gitk命令也爲合併操做提供了特別的協助:
$ git log --merge
$ gitk --merge
這會顯示全部那些只在HEAD或者只在MERGE_HEAD中存在的提交, 還有那些更新(touch)了未合併文件的提交.
你也可使用git mergetool, 它容許你使用外部工具如emacs或kdiff3去合併文件.
 
每次你解決衝突以後, 應該更新索引:
$ git add file.txt
完成索引更新以後, git-diff(缺省地)再也不顯示那個文件的差別, 因此那個文件的不一樣暫存版本會被"摺疊"起來.
6、多路合併
你能夠一次合併多個頭, 只需簡單地把它們做爲git merge的參數列出. 例如,
$ git merge scott/master rick/master tom/master
至關於:
$ git merge scott/master
$ git merge rick/master
$ git merge tom/master
7、子樹
有時會出現你想在本身項目中引入其餘獨立開發項目的內容的狀況. 在沒有路徑衝突的前提下, 你只須要簡單地從其餘項目拉取內容便可.
若是有衝突的文件, 那麼就會出現問題. 可能的例子包括Makefile和其餘一些標準文件名. 你能夠選擇合併這些衝突的文件, 可是更多的狀況是你不肯意把它們合併. 一個更好解決方案是把外部項目做爲一個子目錄進行合併. 這種狀況不被遞歸合併策略所支持, 因此簡單的拉取是無用的.
在這種狀況下, 你須要的是子樹合併策略.
這下面例子中, 咱們設定你有一個倉庫位於/path/to/B (若是你須要的話, 也能夠是一個URL). 你想要合併那個倉庫的master分支到你當前倉庫的dir-B子目錄下.
下面就是你所須要的命令序列:
$ git remote add -f Bproject /path/to/B (1)
$ git merge -s ours --no-commit Bproject/master (2)
$ git read-tree --prefix=dir-B/ -u Bproject/master (3)
$ git commit -m "Merge B project as our subdirectory" (4)
$ git pull -s subtree Bproject master (5)
子樹合併的好處就是它並無給你倉庫的用戶增長太多的管理負擔. 它兼容於較老(版本號小於1.5.2)的客戶端, 克隆完成以後立刻能夠獲得代碼.
然而, 若是你使用子模塊(submodule), 你能夠選擇不傳輸這些子模塊對象. 這可能在子樹合併過程當中形成問題.
譯者注: submodule是Git的另外一種將別的倉庫嵌入到本地倉庫方法.
另外, 若你須要修改內嵌外部項目的內容, 使用子模塊方式能夠更容易地提交你的修改.
相關文章
相關標籤/搜索