git翻訳後記(1) - cherry-pick

はじめに

Git入門というgitのリファレンスマニュアルの日本語訳を載せている有名なページがありますが、最近ここで翻訳のお手伝いをさせてもらっています。
はじめはgitの勉強がしたくて、どうせやるなら少し位は人の役にたった方がいいだろう、位の軽い気持ちで始めたものですが、実際にやってみると本を読むだけではなかなか分からないことが分かったり、そもそも翻訳作業自体もGitHubを使って行われているため結果的に実践練習になったりと、思っていた以上に得るものが多いと感じています。またリファレンスマニュアルというものはどうして簡潔に書く必要があるため、そこには載らないけど有用だなーと思うことも調べたり聞いたりでちょこちょこ出てきます。
そこで、gitに関して役にたった、知って得した、といったことを、私自身の復習や文章を書く練習も兼ねて翻訳後記として少しずつ載せていこうと思います。

git-cherry-pick(1)の(1)って?

まずはつい最近翻訳したもので、git-cherry-pick(1)です。いきなり話題がそれますが、unix系のリファレンスマニュアルとかによくついている、(1)とか(2)の意味って分かりますか?私は結構最近まで知らなかったのですが、
manual page - Rubyリファレンスマニュアル

数字はセクション番号を示します。例えば

  1. コマンド
  2. システムコール
  3. ライブラリ関数

などと分類わけされています。各セクションの意味は intro(1) などに説明がありますのでそちらも参照してください。

なんですって、だからgit-cherry-pick(1)はgit-cherry-pickというコマンドってことなんですね。

マージコミットのための-mオプション

git-cherry-pickは、ある特定の一つのコミットを現在のブランチに適用するコマンドです。gitの便利な機能として良く紹介されるものなので、それ自体の使い方は割愛します(リファレンスマニュアルを見て下さい^^:)。翻訳中に唯一意味が分からなかったのは-mオプションです。英語をざっと読んでも???で、Git入門の管理人さんに助けてもらい、やっと理解することが出来ました。そもそも-mオプションの翻訳自体が私の文章ではなかったりします・・・。多分日本語訳を読んでもgitの専門用語が分からないと難しいと思うので(マージコミットってそもそもなんだよ!!みたいな)、ざっと説明します。

branchA
A-B\
    E <- これがマージコミット
C-D/

branchB
F-G-H-I

この時のEをマージコミットとリファレンスマニュアル上では言っているようです、親コミットが2つ以上ある状態といってもいいかもしれません。例えばbranchBからEをチェリーピックしようとすると、B-Eの差分を適用するべきか、D-Eの差分を適用するべきか分からずにgitはチェリーピックを失敗させます。両方ともチェリーピックしてしまってもいいような気もしますが、バージョン管理ソフトなので慎重であることに悪いことは無さようです。

そこで登場するのが-mオプションです。要はB-Eをチェリーピックしたいのか、D-Eなのかを指定出来ればいい訳で、-m 1ならばB-E, -m 2ならばD-Eのようになる訳です(どちらの番号が割り当てられるかは状況によって異なります)。実際にgitを動かして試してみると良く分かるので、実際の例を挙げてみます。

# 適当な場所にレポジトリを作成
% cd ~/tmp/
% mkdir gittest2
% git init
Initialized empty Git repository in /Users/ongaeshi/tmp/gittest2/.git/

# ちょっと分かりづらいが、a.txtという空のファイルを作ってadd, commitするという慣用句
% file=a.txt && touch $file && git add $file && git commit -m $file
[testA fbd551] a.txt
 0 files changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 a.txt

# ブランチtestB、testCを作成し、きちんと作成されていることを確認
% git branch testB
% git branch testC
% git branch
* master
  testB
  testC

# testBに切り替え、b.txtを作ってコミット
% git checkout testB
Switched to branch 'testB'
% file=b.txt && touch $file && git add $file && git commit -m $file
[testB c4bf61c] b.txt
 0 files changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 b.txt

# testCに切り替え、c.txtを作ってコミット
% git checkout testC
Switched to branch 'testC'
% file=c.txt && touch $file && git add $file && git commit -m $file
[testC 2628a18] c.txt
 0 files changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 c.txt

# testBをtestCにマージ、ここでマージコミットが作成される
% git merge testB
Merge made by recursive.
 0 files changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 b.txt

# masterブランチに切り替え
% git checkout master
Switched to branch 'master'

# testCの一番最後のコミット(つまりマージコミット)をチェリーピックしようとしても失敗する
% git cherry-pick testC
fatal: Commit 4894845a5f8dbb7cbbd065bec2580c8f1a2eeb4f is a merge but no -m option was given.

# -mオプションを使う、1を指定するとb.txtがチェリーピックされる
% git cherry-pick -m 1 testC
Finished one cherry-pick.
[master b2f3654] Merge branch 'testB' into testC
 0 files changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 b.txt

# 2を指定するとc.txtがチェリーピックされる
% git cherry-pick -m 2 testC
Finished one cherry-pick.
[master 66cac05] Merge branch 'testB' into testC
 0 files changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 c.txt

# チェリーピック完了
% ls
a.txt	b.txt	c.txt

そもそもマージコミットをチェリーピックしたいという状況がどれだけあるかは分かりませんが、いざそういう状況になった時に出来ないと思いこまずに済めば安心ですね。

おわりに

Git入門では、現在も一緒にマニュアル翻訳をしてくれる人を募集しているようです(私もforkしてpullリクエストを出して参加し始めた口です)。gitに興味があり多少英文の読み書きが出来るのであれば、簡単なコマンドからでもチャレンジしてみてはどうでしょうか?gitは大量のコマンドがあるので、文章量が少ないコマンドも結構あります。

forkして出来るかどうか試すだけなら他の人にさほど迷惑もかからず、自分が楽しく出来そうかどうかを確認出来るのはgithub(そしてgitをはじめとする分散レポジトリの)のいい所だと思います。私自身も試しにforkしてみて、全然翻訳出来なそうだったらすぐにやめようと思っていました(^^: