Subversion, Git, Mercurialそれぞれでのcherrypicking
つまみ食いとか青田買いといわれるcherrypickingはある特定のコミットをブランチから抜き出して別のブランチに反映させるというものです。
Subversion, Git, Mercuriaそれぞれのやり方を調べてみました。
まずSubversionいってみましょう。
準備
$ svnadmin create repos $ svn checkout file:///tmp/repos work Checked out revision 0. $ cd work/ $ svn mkdir tags branches trunk A tags A branches A trunk $ svn commit -m "add initial dir" Adding branches Adding tags Adding trunk Committed revision 1.
trunkの直下にhelloディレクトリをつくりいくつかコミットしてみます。
$ cd trunk/ $ svn mkdir hello A hello $ svn commit -m "add directory" Adding trunk/hello Committed revision 2. $ cd hello/ $ echo 1 > a.txt $ svn add a.txt A a.txt $ svn commit -m "first commit" a.txt Adding a.txt Transmitting file data . Committed revision 3. $ echo 2 >> a.txt $ svn commit -m "second commit" a.txt Sending a.txt Transmitting file data . Committed revision 4.
次にブランチを作ってワーキングコピーを切り替えます。
$ svn copy file:///tmp/repos/trunk/hello file:///tmp/repos/branches/hello -m "create branch" Committed revision 5. $ svn switch file:///tmp/repos/branches/hello At revision 5.
ブランチで新たにb.txtというファイルを作り変更します。
$ echo 1 > b.txt $ svn add b.txt A b.txt $ svn commit -m "first commit for branch" b.txt Adding b.txt Transmitting file data . Committed revision 6. $ echo 2 >> b.txt $ svn commit -m "second commit for branch" b.txt Sending b.txt Transmitting file data . Committed revision 7.
trunkに戻ります。ブランチでつくったb.txtは無いですね。
$ svn switch file:///tmp/repos/trunk/hello D b.txt Updated to revision 7. $ ls a.txt
trunkでa.txtに変更を加えます。
$ echo 3 >> a.txt $ svn commit -m "third commit for trunk" a.txt Sending a.txt Transmitting file data . Committed revision 8. $ echo 4 >> a.txt $ svn commit -m "fourth commit for trunk" a.txt Sending a.txt Transmitting file data . Committed revision 9.
ブランチに切り替えます。trunkでa.txtにした変更は無いかわりにb.txtはあります。
$ svn switch file:///tmp/repos/branches/hello U a.txt A b.txt Updated to revision 9. $ ls a.txt b.txt $ cat a.txt 1 2
trunkでa.txtに3を加えた変更であるリビジョン8をつまみ食いします。
svn mergeでつまみ食いして最終的に反映させるにはsvn commitします。
mergeinfoプロパティを見れば何をつまみ食いしたかわかります。
$ svn merge -c 8 file:///tmp/repos/trunk/hello --- Merging r8 into '.': U a.txt $ svn diff Property changes on: . ___________________________________________________________________ Added: svn:mergeinfo Merged /trunk/hello:r8 Index: a.txt =================================================================== --- a.txt (revision 9) +++ a.txt (working copy) @@ -1,2 +1,3 @@ 1 2 +3 $ svn commit -m "svn merge r8" a.txt Sending a.txt Transmitting file data . Committed revision 10. $ svn mergeinfo file:///tmp/repos/trunk/hello r8
次にGitいってみましょう。作るファイルはSubversionの時と同じです。まずはmasterブランチでa.txtを作ります。
$ mkdir hello $ cd hello $ echo 1 > a.txt $ git init $ git add a.txt $ git commit -m "first commit" a.txt [master (root-commit) 8d42fb0] first commit 1 files changed, 1 insertions(+), 0 deletions(-) create mode 100644 a.txt $ echo 2 >> a.txt $ git commit -m "second commit" a.txt [master baee205] second commit 1 files changed, 1 insertions(+), 0 deletions(-)
次にhotfixブランチを作ってb.txtというファイルを追加します。
$ git branch hotfix $ git checkout hotfix Switched to branch 'hotfix' $ echo 1 > b.txt $ git add b.txt $ git commit -m "first commit for hotfix branch" b.txt [hotfix 9249a7a] first commit for hotfix branch 1 files changed, 1 insertions(+), 0 deletions(-) create mode 100644 b.txt $ echo 2 >> b.txt $ git commit -m "second commit for hotfix branch" b.txt [hotfix c106823] second commit for hotfix branch 1 files changed, 1 insertions(+), 0 deletions(-) $ git branch * hotfix master
masterブランチに戻ってa.txtに3と4を追加します。3を加えた0804feeをあとでつまみ食いします。
$ git checkout master Switched to branch 'master' $ echo 3 >> a.txt $ git commit -m "third commit for master branch" a.txt [master 0804fee] third commit for master branch 1 files changed, 1 insertions(+), 0 deletions(-) $ echo 4 >>a.txt $ git commit -m "fourth commit for master branch" a.txt [master c2869d6] fourth commit for master branch 1 files changed, 1 insertions(+), 0 deletions(-) $ git log --pretty=oneline --graph --abbrev-commit * c2869d6 fourth commit for master branch * 0804fee third commit for master branch * baee205 second commit * 8d42fb0 first commit
hotfixブランチに戻ります。
$ git checkout hotfix Switched to branch 'hotfix' $ ls a.txt b.txt $ cat a.txt 1 2 $ git log --pretty=oneline --graph --abbrev-commit * c106823 second commit for hotfix branch * 9249a7a first commit for hotfix branch * baee205 second commit * 8d42fb0 first commit
masterブランチでa.txtに3を加えた0804feeをつまみ食いします。
git cherry-pickでつまみ食いします。Subversionとは異なりコミットする必要はありません。
$ git cherry-pick 0804fee Finished one cherry-pick. [hotfix 8e21ed9] third commit for master branch 1 files changed, 1 insertions(+), 0 deletions(-) $ cat a.txt 1 2 3 $ git diff $ git log --pretty=oneline --graph --abbrev-commit * 8e21ed9 third commit for master branch * c106823 second commit for hotfix branch * 9249a7a first commit for hotfix branch * baee205 second commit * 8d42fb0 first commit
最後にMercurial行ってみます。
事前準備として~/.hgrcに以下のように記述します。hg transplantがつまみ食いに相当するコマンドなのですがこれを有効にするためにtransplantと記述します。graphlogの部分はhg glogというコミットグラフを有効にするためで無くてもつまみ食いできます。
[extensions] transplant = hgext.graphlog =
次にdefaultブランチでa.txtを用意しておきます。
$ mkdir hello $ cd hello/ $ echo 1 > a.txt $ hg init $ hg add a.txt $ hg commit -m "first commit" a.txt $ echo 2 >> a.txt $ hg commit -m "second commit" a.txt
hotfixブランチでb.txtを作ります。
$ hg branch hotfix marked working directory as branch hotfix $ echo 1 > b.txt $ hg add b.txt $ hg commit -m "first commit for hotfix branch" b.txt $ echo 2 >>b.txt hg commit -m "second commit for hotfix branch" b.txt
defaultブランチに戻ってa.txtに変更を加えます。
$ hg update default 0 files updated, 0 files merged, 1 files removed, 0 files unresolved $ echo 3 >>a.txt $ hg commit -m "third commit for default branch" a.txt $ echo 4 >> a.txt $ hg commit -m "fourth commit for default branch" a.txt
hotfixブランチに移動してつまみ食いします。
移動する際に-Cつけないとabort: update spans branches, use 'hg merge' or 'hg update -C' to lose changesと言われます。
つまみ食いはhg transplant -b ブランチ名 -m リビジョン です。
$ hg update -C hotfix 2 files updated, 0 files merged, 0 files removed, 0 files unresolved $ cat a.txt 1 2 $ hg transplant -b default -m 4 applying b92e71274b5f 4:b92e71274b5f merged at 712a433bd6b0 $ cat a.txt 1 2 3 $ hg diff $ hg glog @ changeset: 6:712a433bd6b0 |\ branch: hotfix | | tag: tip | | parent: 3:8461d663b5dc | | parent: 4:b92e71274b5f | | user: wyukawa@ubuntu-vbox | | date: Thu Mar 25 21:38:44 2010 +0900 | | summary: third commit for default branch | | | | o changeset: 5:6cc982156ae2 | |/ user: wyukawa@ubuntu-vbox | | date: Thu Mar 25 21:42:43 2010 +0900 | | summary: fourth commit for default branch | | | o changeset: 4:b92e71274b5f | | parent: 1:93e446343985 | | user: wyukawa@ubuntu-vbox | | date: Thu Mar 25 21:38:44 2010 +0900 | | summary: third commit for default branch | | o | changeset: 3:8461d663b5dc | | branch: hotfix | | user: wyukawa@ubuntu-vbox | | date: Thu Mar 25 21:37:52 2010 +0900 | | summary: second commit for hotfix branch | | o | changeset: 2:1801deebe08e |/ branch: hotfix | user: wyukawa@ubuntu-vbox | date: Thu Mar 25 21:37:34 2010 +0900 | summary: first commit for hotfix branch | o changeset: 1:93e446343985 | user: wyukawa@ubuntu-vbox | date: Thu Mar 25 21:36:45 2010 +0900 | summary: second commit | o changeset: 0:e4da2e60f814 user: wyukawa@ubuntu-vbox date: Thu Mar 25 21:36:12 2010 +0900 summary: first commit
まとめ
どれが楽かは何とも言えない気もしますが、Gitはつまみ食いするリビジョンにハッシュ値を指定する一方、MercurialとSubversionは連番の数字ですね。
Mercurialはマージしなくても全ブランチを含めたコミットグラフが見れるのがいいかも。Subversionもそんなに面倒じゃないかも。
コマンドの対応関係はだいたい以下のようです。
ブランチの切り替え | svn switch | git checkout | hg update | ||||
つまみ食い | svn merge | git cherry-pick | hg transplant |
いじょ。