git-分支管理
軟件版本:
操作系統:ubuntu10.04
內核版本:Linux version 2.6.32-36-generic
git 版本:git version 1.7.0.4
目錄:
1. 介紹
2. 創建分支
3. 切換分支
4. 合並分支
5. 刪除分支
6. 分支管理操作
6.1 分支清單
6.2 查看已合並分支
6.3 查看未合並分支
6.4 分支重命名
7. 分支衍合(rebase)
8. 參考資料
1. 介紹
分支本質上其實就是一個指向某次提交的可變指針。git 的默認分支名字為 master 。而我們是怎么知道當前處於哪個分支當中呢?答案就是在於 HEAD 這個十分特殊的指針,它專門用於指向於本地分支中的當前分支。我們可以理解為:
commit <-- branch <-- HEAD
2. 創建分支
當我們需要調試某個 BUG 或者嘗試添加或修改程序中的某個模塊,而又不能影響主分支的開發時。就可以通過創建分支來滿足需求。
創建分支相當於是創建一個新的分支指針指向當前所在的提交。例如我們在 Commit_3 上創建分支 Branch_1 :
$git branch Branch_1
如圖所示,Branch_1 指向提交 Commit_3 。
從上圖可知,雖然我們創建了一個新分支,但是 HEAD 仍然指向 master 。如果希望在創建分支的同時切換到新分支上,我們可以通過以下命令實現:
$git checkout -b Branch_1
HEAD 指向 Branch_1 。
3. 切換分支
在項目開發的過程中,分支之間的切換是一件非常普遍的事情。比如在某分支上調試 BUG ,突然需要在主分支中添加點代碼,就需要在分支間進行切換。
分支之間的切換其實就是使 HEAD 指向指定的分支,以后的提交將從屬於該分支。切換命令為:
$git checkout Branch_1
這時候進行提交的話,那么這次的提交就是屬於 Branch_1 分支的。
4. 合並分支
當某分支上的工作完成了,那么就需要合並到其它分支上。分支合並命令為:
$git merge branch_name
現在我們要對下面的項目進行一次合並分支的演示:
將 branch_1 合並到 master 主分支上:
$git merge branch_1
Auto-merging file
CONFLICT (content): Merge conflict in file
Automatic merge failed; fix conflicts and then commit the result.
$git status
# On branch master
# Unmerged paths:
# (use "git add/rm <file>..." as appropriate to mark resolution)
#
# both modified: file
#
no changes added to commit (use "git add" and/or "git commit -a")
由於 commit_3 和 B_C_1 這兩次提交都修改了同一個文件,所以在合並的過程中就會產生沖突,需要我們手動解決。git status 中 Unmerged paths: 這欄告訴我們哪些文件在合並的過程中產生沖突。
git 會在有沖突的文件中加入標記,file 的內容會變為:
commit_1
<<<<<<< HEAD
commit_2
=======
branch_1 commit 1
>>>>>>> branch_1
可以看到文件的一部分內容被 ======= 分隔開,上半部分是 HEAD 的內容,下半部分就是 branch_1 中的內容。你可以直接修改該文件來解決沖突,也可以通過 git mergetool 命令來解決。
我們可以使用 git mergetool 來解決這個事情。
$git mergetool
merge tool candidates: meld opendiff kdiff3 tkdiff xxdiff tortoisemerge gvimdiff diffuse ecmerge p4merge araxis emerge vimdiff
Merging the files: file
Normal merge conflict for 'file':
{local}: modified
{remote}: modified
Hit return to start merge resolution tool (meld):
在我的環境中,默認使用 meld 來解決合並沖突。我們來看一下解決完之后的 git 狀態:
$git status
# On branch master
# Changes to be committed:
#
# modified: file
#
# Untracked files:
# (use "git add <file>..." to include in what will be committed)
#
# file.orig
git 狀態顯示 file 已經被放入到暫存區里了,只需要提交一下就可以了。file.orig 是一個備份文件。
$git commit
[master 3f8596e] Merge branch 'branch_1'
$git status
# On branch master
# Untracked files:
# (use "git add <file>..." to include in what will be committed)
#
# file.orig
nothing added to commit but untracked files present (use "git add" to track)
提交后我們來看一下提交日志。
$git lg
* 3f8596e00cbd01320a31c0e7e2715ac12dffc48c @ (HEAD, master)
|\ Author: Eddy <he_jianfa@126.com>
| | Date: Thu Mar 29 11:02:22 2012 +0800 (15 seconds ago)
| |
| | Commit subject: Merge branch 'branch_1'
| |
| * 6d5867c77debde72d12f3187ab972944f88624be @ (branch_1)
| | Author: Eddy <he_jianfa@126.com>
| | Date: Thu Mar 29 10:25:50 2012 +0800 (37 minutes ago)
| |
| | Commit subject: branch_1: commit 1
| |
* | c773ca7c9a0154876b7de4ed66cabe704da6f29d @
|/ Author: Eddy <he_jianfa@126.com>
| Date: Tue Mar 27 08:58:52 2012 +0800 (2 days ago)
|
| Commit subject: commit_2
|
* c438c48d1cd9615490d8be830683487de858e7b3 @
Author: Eddy <he_jianfa@126.com>
Date: Tue Mar 27 08:51:54 2012 +0800 (2 days ago)
Commit subject: commit_1
合並提交后,branch_1 仍然指向原來的 commit 。示意圖:
5. 刪除分支
被合並后的分支自然就失去了它存在的意義了,現在我們來把 branch_1 分支刪除掉。
$git branch -d branch_1
Deleted branch branch_1 (was 6d5867c).
6. 分支管理操作
下面來介紹一些關於分支管理中的一些常用操作。
6.1 分支清單
$ git branch
branch_1
branch_2
* master
帶 * 號的分支表示是當前分支。
6.2 查看已合並分支
$ git branch --merged
branch_1
* master
6.3 查看未合並分支
$ git branch --no-merged
branch_2
6.4 分支重命名
$git branch -m branch_2 branch_renamed
7. 分支衍合(rebase)
衍合(rebase)其實就是以補丁的形式將當前分支打到指定的分支上,最后當前分支會和指定分支結合在一起。它與合並(merge)的區別就在於當前分支會和指定分支合並在一起並產生一個新的提交,使得整個 git 項目看起來更加整潔;而 merge 則會保留所有的分支提交記錄。
假如我們對下圖所示的 git 項目進行衍合。
將會達到下面的結果。
我們現在來演示一下具體的操作過程,假設我們正處在 branch_1 分支中。現在要和 master 分支進行衍合。
$git rebase master
First, rewinding head to replay your work on top of it...
Applying: branch_1
Using index info to reconstruct a base tree...
Falling back to patching base and 3-way merge...
Auto-merging file
CONFLICT (content): Merge conflict in file
Failed to merge in the changes.
Patch failed at 0001 branch_1
When you have resolved this problem run "git rebase --continue".
If you would prefer to skip this patch, instead run "git rebase --skip".
To restore the original branch and stop rebasing run "git rebase --abort".
在衍合的過程中會對文件進行合並,從上面的打印可以看出在合並的過程中出現沖突,導致衍合失敗。利用第四節中提到的方法解決該沖突,然后根據上面的打印提示繼續衍合。
$git mergetool
merge tool candidates: meld opendiff kdiff3 tkdiff xxdiff tortoisemerge gvimdiff diffuse ecmerge p4merge araxis emerge vimdiff
Merging the files: file
Normal merge conflict for 'file':
{local}: modified
{remote}: modified
Hit return to start merge resolution tool (meld):
$git rebase --continue
Applying: branch_1
衍合完成后,當前正處在 branch_1 分支上,如圖所示:
然后我們就需要回到 master 分支上,將 master 與 branch_1 合並。
$git checkout master
Switched to branch 'master'
$git merge branch_1
Updating 12c963d..82d3623
Fast-forward
file | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)
最終就達到我們想要的結果了。
$git status
# On branch master
nothing to commit (working directory clean)
$git lg
* 82d36231ff46f362885a8a369cb80cf95009058a @ (HEAD, master, branch_1)
| Author: Eddy <he_jianfa@126.com>
| Date: Thu Mar 29 17:48:58 2012 +0800 (37 seconds ago)
|
| Commit subject: branch_1
|
* 12c963d83d23a7ffc78ca2e13935b5d36fbf5d76 @
| Author: Eddy <he_jianfa@126.com>
| Date: Thu Mar 29 16:22:39 2012 +0800 (87 minutes ago)
|
| Commit subject: commit 3
|
* 0850a6759874ed23042cb0fddb43b5c7d28e5b7b @
| Author: Eddy <he_jianfa@126.com>
| Date: Thu Mar 29 16:21:19 2012 +0800 (88 minutes ago)
|
| Commit subject: commit 2
|
* 82e24403d7b4a562dedf343955df8196fe353bf6 @
Author: Eddy <he_jianfa@126.com>
Date: Thu Mar 29 16:20:59 2012 +0800 (89 minutes ago)
Commit subject: commit 1
與第四節的分支合並結果對比,整個 git 項目確實要整潔許多。
8. 參考資料
[1] 《pro git》