Git 分支與整合策略

持續(xù)部署的前提是模塊化設(shè)計(jì)、自動(dòng)化測(cè)試和持續(xù)集成。使用好 Git 的分支(branch)與整合(integrate)功能,有利于高效率的持續(xù)集成。Pro Git 關(guān)于 分支 的建議是不錯(cuò)的,值得采用。

整合

Rebasing(變基) 是一個(gè)很不錯(cuò)的功能,和 Merging(合并)一對(duì)兄弟,是用來整合來自不同分支的修改的兩種方法。

Rebasing

對(duì)于多人協(xié)同開發(fā)來說,本地修改 commit(提交) 后,在 push(推送) 代碼前,Rebasing 一下是一個(gè)很好的做法,log 看起來比較整齊,有助于閱讀和理解(由于 merge 帶來了蜘蛛網(wǎng)般的 log,想看清代碼走向非常費(fèi)勁;log 中常見的 "Merge branch 'v0.7d-rebuild' of http://git.example.com/wbs.wph into v0.7d-rebuild" ,本是不必要的 merge,也自然消失了)。
請(qǐng)不要對(duì)已經(jīng) push 出去的東西 再次 rebase 了。

怎么理解 Rebase 呢?
假定把當(dāng)前分支作為新特性分支,在開發(fā)過程中,主分支(Rebase 分支)又發(fā)生變化了,我們就要基于 Rebase 分支最新末端重新應(yīng)用一下當(dāng)前分支的每個(gè) commit。
同理,rebase 概念適用于有跟蹤關(guān)系的遠(yuǎn)程和本地分支的整合。

在 config 中設(shè)置 rebase 選項(xiàng),使得 git pull 使用 rebase 整合所做修改
git config --global pull.rebase true
git config --global branch.autoSetupRebase always
  • pull.rebase:git pull 時(shí)使用 rebase 而非 merge 來整合修改;
  • branch.autoSetupRebase:對(duì)所有的 tracking branches 都設(shè)置 rebase;
  • git config 時(shí)加上 --global 選項(xiàng),對(duì)所有 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;

由基于 C2,變?yōu)榛?C4;變基后,C3 和 C5 變?yōu)?C3' 和 C5'
變基時(shí)出現(xiàn)沖突,怎么辦?
  • 鎮(zhèn)定,沖突總能解決;
  • 耐心,避免引入更多缺陷;
  • 首先修改文件,解決沖突;
  • 然后 add,commit 修改后的文件;
  • 最后運(yùn)行 git rebase --continue(請(qǐng)不要輕易使用 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)生的原因
沖突的解決之道
  • 盡早集成(smaller changesets),有助于避免沖突,即使出現(xiàn)沖突也容易解決;
  • 每次 pull(fetch+rebase),就是一次(代碼)集成;

    請(qǐng)經(jīng)常 pull;不一定非要到 push 前才去 pull;
    經(jīng)常 pull,經(jīng)常集成(integrating often),使得 push 不再那么匆忙(有因怕沖突而匆忙 push 的情形);當(dāng)且僅當(dāng)需要 push 的時(shí)候才去 push;

  • 每次 push,都是一次發(fā)布;
  • 對(duì)于解決沖突的 commits,一定要 review code
    git log --min-parents=2 -p --cc
刪除分支的理由和時(shí)機(jī)
  • 當(dāng)你的兩個(gè)分支指向同一個(gè) commit 時(shí),就可以刪除其中一個(gè);無冗余,保持整潔了;
  • 當(dāng)你的一個(gè)分支 A 已經(jīng)完全合并到另一個(gè)分支 B 上,A 分支使命已經(jīng)完成、不再使用時(shí),就可以刪除這個(gè)分支 A;
    請(qǐng)使用 git branch --merged 和 git branch --no-merged 來檢查是否已合并到當(dāng)前分支;
  • 你覺得礙眼,就想任性一下要?jiǎng)h除時(shí);
    刪除沒有合并的分支時(shí),git 會(huì)提醒你,當(dāng)然也可以強(qiáng)行刪除;
了解 remote 的分支情況
  • git ls-remote [<remote>]
  • git remote show [<remote>]
A commit and its tree
選自 Branches in a Nutshell,理解 git 存儲(chǔ)機(jī)制
分支管理策略(Branching Workflows
A “silo” view of progressive-stability branching
  • master 分支
  • dev(develop) 分支是我們的主要分支,在當(dāng)下,上線發(fā)布使用 dev 分支;
  • 從 dev 開分支 hotfix;
  • 迭代分支(feature、topic)從 dev 分支開出,我們使用 0.8, 0.8c 這樣的方式命名;
  • 迭代分支應(yīng)經(jīng)常 merge dev(git merge dev);(迭代完成后)dev 合并迭代;刪除迭代分支;
  • 保持適度分支,避免復(fù)雜過程;
    這個(gè)分支就太復(fù)雜了,不會(huì)考慮采用

    作者 nvie這篇文章 里闡述的更多;
merge 示意圖

Git 會(huì)使用兩個(gè)分支的末端所指的快照(C4 和 C5)以及這兩個(gè)分支的共同祖先 Common Ancestor(C2),做一個(gè)簡(jiǎn)單的三方合并。


一次典型合并中所用到的三個(gè)快照
A merge commit(C6), it has more than one parent.
高級(jí)主題
  • Deleting Remote Branches
    git push origin --delete <branchname>
  • distributed git
  • 重命名分支名字(修改分支名字)
    git branch -m [<oldname>] <newname> 修改本地 oldname => newname;
    git push -u origin <newname> 推送到遠(yuǎn)程;
    git push origin :<oldname> 刪除遠(yuǎn)程的 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)系,那么刪除本地分支名,就是為了清爽,你隨時(shí)可以 checkout 出來。有時(shí)會(huì)報(bào)警告:

    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. 這只是刪除本地記錄的那個(gè)遠(yuǎn)程分支名;要真正刪除遠(yuǎn)程分支,請(qǐng)使用 git push :<branchname>;
  • git fetch --prune
    -p,--prune,After fetching, remove any remote-tracking references that no longer exist on the remote. git fetch;
    如果有人清理了遠(yuǎn)程 repo 分支,你 git pull 后 并不會(huì)同步清理 本地記錄的那些遠(yuǎn)程分支名;請(qǐng)使用該命令清理那些在遠(yuǎn)程并不存在的refs;
    git remote prune origin --dry-run,檢查清理 origin 無效分支,git remote update --prune origin 也可以;
  • Learn Version Control with Git;
  • 討論 Martin Fowler 對(duì)持續(xù)集成和特性分支看法的文章,內(nèi)容豐富,值得看;
  • Branching and Merging Primer,August 2006, Chris Birmele @ Microsoft
  • 可能無法刪除遠(yuǎn)程分支?
    通常是因?yàn)樵摲种钱?dāng)前活躍分支。在遠(yuǎn)程 bare repo 下,執(zhí)行:git symbolic-ref HEAD refs/heads/<anotherbranchname>,也就是改換 HEAD 指向另一個(gè)分支,然后就可以刪除你想刪除的分支了;或者直接修改 HEAD 文件;
  • 只有部分分支推送成功的問題
    有時(shí)候,你修改本地一個(gè)分支(v0.8分支),直接 push,發(fā)現(xiàn)這個(gè)分支成功推送,而另一個(gè)分支(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.
- 請(qǐng)每次都要仔細(xì)查看返回的信息,git 做的非常好的一點(diǎn)就是會(huì)認(rèn)認(rèn)真真地告訴你下一步應(yīng)該怎么做,你照著做就好了。
- 照著做盡管并不是 100% 都成功,無論如何值得認(rèn)真嘗試;
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容