Your posts match “ Mercurial ” tag:

在 Git 中做到 Mercurial queue 的行爲

queue
Credit: Vegpuff/Wikipedia cc

前言

接觸 Mozilla 的專案一陣子,自然也學了 Mercurial,一套分散式的版本控制系統。由於設計哲學的不同,Mercurial 擁有許多額外的官方插件可以使用,其中 Mercurial Queue 是這篇的主題,就來談談在 Git 中如何做到類似的行爲。

Mercurial Queue

操作細節不多談。概論來說,你必須先建立一個裝 patch 的 queue,然後找一個 commit 在上面新增一個空白的 patch,接着開始對 Mercuail 管理的程式碼開始做修改,修改就會進到 queue 最上方的 patch。queue 裏面裝的 patch 其實就是你修改後的 diff 檔案,一個 patch 就是一份 diff,位於 queue 最下面的 patch 會先被套用 (FIFO),你可以在 .hg/YOUR_PATCH_Q_NAME/YOUR_PATCH_NAME 找到他們。這樣的好處 (我認爲的) 就是,即使在你修改的同時這個專案進行了更新,開發者可以直接把 queue 裏面的 patch 全部先卸下,移動到最新的 commit 後再套用上去。

Git

Git 要做到類似的事情我有兩個想法:

  • git rebase (但是不可逆,精確的說是很麻煩)
  • git diff (比較彈性)

先假設我們有下面的樹

  G-dev
  |
  F
  |
  E
  |
A-B-C-D-master

現在我們要做的,是將 dev 分支中所做的改變應用到 master 分支上 (可能是爲了測試,可能是爲何合併)。

git rebase

$ git checkout dev
$ git rebase master #May need to fix conflict

這個做法很直覺,但是很難撤銷。雖然做到 mq 套用功能,卻沒辦法把 patch 套用到其他 commit 上。

git diff

$ git checkout master
$ git diff ...dev > patch_name
$ git apply patch_name #Apply won't store change into staged

$ git add -u
$ git commit

白話來說,就是先找出你想要套用的 commit 和 dev 分支的共同祖先,接着 diff dev 和該祖先得到 dev 分支所做的修改並導入 patch 檔案,再套用到你選擇的 commit 上。這裏產生出來的 patch 本質上就是 mq 裏面的 patch,只差在 mq 裏面多了一些資訊 (commit 本文等),以及這個方法產生的 patch 是一坨而非像 mq 有多個 patch 疊在一起。要取出更細的 patch 就自行 git diff ...dev~

結語

不是做不到,而是很難做。

使用 Git 分支來模擬 mq 的麻煩就在於儲存的內容不同,Git 存的是快照,mq 存的是 diff,雖然互相模擬是可行的,但是既然開發者選了某一個工具來用,就依照該工具的哲學來使用/管理自己的專案吧!

話說,好像真的有工具可以讓 Git 擁有 mq 的功能,我猜本質上就是把上面的東西包裝成易用的界面,或許。

補充 2015/04/28

git format-patch 可以作出 per commit 的 patches。