持續(xù)部署的前提是模塊化設計、自動化測試和持續(xù)集成。使用好 Git 的分支(branch)與整合(integrate)功能,有利于高效率的持續(xù)集成。Pro Git 關于 分支 的建議是不錯的,值得采用。
整合
Rebasing(變基) 是一個很不錯的功能,和 Merging(合并) 是 一對兄弟,是用來整合來自不同分支的修改的兩種方法。
Rebasing
對于多人協(xié)同開發(fā)來說,本地修改 commit(提交) 后,在 push(推送) 代碼前,Rebasing 一下是一個很好的做法,log 看起來比較整齊,有助于閱讀和理解(由于 merge 帶來了蜘蛛網(wǎng)般的 log,想看清代碼走向非常費勁;log 中常見的 "Merge branch 'v0.7d-rebuild' of http://git.example.com/wbs.wph into v0.7d-rebuild" ,本是不必要的 merge,也自然消失了)。
請不要對已經(jīng) push 出去的東西 再次 rebase 了。
怎么理解 Rebase 呢?
假定把當前分支作為新特性分支,在開發(fā)過程中,主分支(Rebase 分支)又發(fā)生變化了,我們就要基于 Rebase 分支最新末端重新應用一下當前分支的每個 commit。
同理,rebase 概念適用于有跟蹤關系的遠程和本地分支的整合。
在 config 中設置 rebase 選項,使得 git pull 使用 rebase 整合所做修改
git config --global pull.rebase true
git config --global branch.autoSetupRebase always
- pull.rebase:git pull 時使用 rebase 而非 merge 來整合修改;
- branch.autoSetupRebase:對所有的 tracking branches 都設置 rebase;
- 在 git config 時加上 --global 選項,對所有 repo 起作用;
- 單次操作可以這么著:git pull --rebase [<remote name> <branch name>];
- pull with rebase @ gitready.com ;
采用 merge 示意圖
git pull 命令采用 merge 策略,即:pull(拉?。? fetch(抓?。? merge;



采用 rebase 示意圖
git pull 命令采用 rebase 策略,即:pull(拉?。? fetch(抓?。? rebase;



變基時出現(xiàn)沖突,怎么辦?
- 鎮(zhèn)定,沖突總能解決;
- 耐心,避免引入更多缺陷;
- 首先修改文件,解決沖突;
- 然后 add,commit 修改后的文件;
- 最后運行
git rebase --continue(請不要輕易使用 skip or abort);When you have resolved this problem, run "git rebase --continue".
If you prefer to skip this patch, run "git rebase --skip" instead.
To check out the original branch and stop rebasing, run "git rebase --abort".
沖突產(chǎn)生的原因
- 多人開發(fā),有沖突是不可避免的;
- 學會解決沖突也是一項重要技能;
- 發(fā)生沖突通常是因為兩個人修改了同一個文件;
- 如果經(jīng)常出現(xiàn)沖突,通常說明你的用法有問題,請趕緊學習;
沖突的解決之道
- 盡早集成(smaller changesets),有助于避免沖突,即使出現(xiàn)沖突也容易解決;
- 每次 pull(fetch+rebase),就是一次(代碼)集成;
請經(jīng)常 pull;不一定非要到 push 前才去 pull;
經(jīng)常 pull,經(jīng)常集成(integrating often),使得 push 不再那么匆忙(有因怕沖突而匆忙 push 的情形);當且僅當需要 push 的時候才去 push; - 每次 push,都是一次發(fā)布;
- 對于解決沖突的 commits,一定要 review code!
git log --min-parents=2 -p --cc
刪除分支的理由和時機
- 當你的兩個分支指向同一個 commit 時,就可以刪除其中一個;無冗余,保持整潔了;
- 當你的一個分支 A 已經(jīng)完全合并到另一個分支 B 上,A 分支使命已經(jīng)完成、不再使用時,就可以刪除這個分支 A;
請使用 git branch --merged 和 git branch --no-merged 來檢查是否已合并到當前分支; - 你覺得礙眼,就想任性一下要刪除時;
刪除沒有合并的分支時,git 會提醒你,當然也可以強行刪除;
了解 remote 的分支情況
- git ls-remote [<remote>]
- git remote show [<remote>]
| A commit and its tree |
|---|
| 選自 Branches in a Nutshell,理解 git 存儲機制 |

分支管理策略(Branching Workflows)

- master 分支
- dev(develop) 分支是我們的主要分支,在當下,上線發(fā)布使用 dev 分支;
- 從 dev 開分支 hotfix;
- 迭代分支(feature、topic)從 dev 分支開出,我們使用 0.8, 0.8c 這樣的方式命名;
- 迭代分支應經(jīng)常 merge dev(git merge dev);(迭代完成后)dev 合并迭代;刪除迭代分支;
- 保持適度分支,避免復雜過程;
這個分支就太復雜了,不會考慮采用
作者 nvie 在 這篇文章 里闡述的更多;
merge 示意圖
Git 會使用兩個分支的末端所指的快照(C4 和 C5)以及這兩個分支的共同祖先 Common Ancestor(C2),做一個簡單的三方合并。


高級主題
-
Deleting Remote Branches
git push origin --delete <branchname> - distributed git
- 重命名分支名字(修改分支名字)
git branch -m [<oldname>] <newname> 修改本地 oldname => newname;
git push -u origin <newname>推送到遠程;
git push origin :<oldname>刪除遠程的 oldname; -
git branch
-vv
-v, --verbose
When in list mode, show sha1 and commit subject line for each head, along with relationship to upstream branch (if any). If given twice, print the name of the upstream branch, as well (see also git remote show <remote>). -
git log --decorate --oneline --all --graph
查看所有分支(圖形形式); -
git branch -d <branchname>
如果你的 repo 是 clone 來的,并且和上游保持同步聯(lián)系,那么刪除本地分支名,就是為了清爽,你隨時可以 checkout 出來。有時會報警告:warning: deleting branch 'v0.7d-example' that has been merged to 'refs/remotes/origin/v0.7d-example', but not yet merged to HEAD.
-
git branch -d -r <branchname>
delete remote-tracking branches. 這只是刪除本地記錄的那個遠程分支名;要真正刪除遠程分支,請使用git push :<branchname>; -
git fetch --prune
-p,--prune,After fetching, remove any remote-tracking references that no longer exist on the remote. git fetch;
如果有人清理了遠程 repo 分支,你 git pull 后 并不會同步清理 本地記錄的那些遠程分支名;請使用該命令清理那些在遠程并不存在的refs;
git remote prune origin --dry-run,檢查清理 origin 無效分支,git remote update --prune origin也可以; - Learn Version Control with Git;
- 討論 Martin Fowler 對持續(xù)集成和特性分支看法的文章,內容豐富,值得看;
- Branching and Merging Primer,August 2006, Chris Birmele @ Microsoft
-
可能無法刪除遠程分支?
通常是因為該分支是當前活躍分支。在遠程 bare repo 下,執(zhí)行:git symbolic-ref HEAD refs/heads/<anotherbranchname>,也就是改換 HEAD 指向另一個分支,然后就可以刪除你想刪除的分支了;或者直接修改 HEAD 文件; - 只有部分分支推送成功的問題
有時候,你修改本地一個分支(v0.8分支),直接 push,發(fā)現(xiàn)這個分支成功推送,而另一個分支(dev分支)出了問題,如下:
$ git push
Counting objects: 2, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (2/2), 257 bytes | 0 bytes/s, done.
Total 2 (delta 1), reused 0 (delta 0)
To http://git.example.com/wbs.wph.git
0187b7f..9c68fb9 v0.8 -> v0.8
! [rejected] dev -> dev (non-fast-forward)
error: failed to push some refs to 'http://git.xxtao.com/wbs.wph.git'
hint: Updates were rejected because a pushed branch tip is behind its remote
hint: counterpart. Check out this branch and integrate the remote changes
hint: (e.g. 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
- 請每次都要仔細查看返回的信息,git 做的非常好的一點就是會認認真真地告訴你下一步應該怎么做,你照著做就好了。
- 照著做盡管并不是 100% 都成功,無論如何值得認真嘗試;
