Git 分支與整合策略

持續(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;

由基于 C2,變?yōu)榛?C4;變基后,C3 和 C5 變?yōu)?C3' 和 C5'
變基時出現(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)生的原因
沖突的解決之道
  • 盡早集成(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
A “silo” view of progressive-stability branching
  • 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),做一個簡單的三方合并。


一次典型合并中所用到的三個快照
A merge commit(C6), it has more than one parent.
高級主題
  • 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% 都成功,無論如何值得認真嘗試;
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容