元記事はこちら: http://blog.extracheese.org/2010/12/rebase-is-safe.html
(翻訳の公開は本人より許諾済みです)
翻訳の間違い等があればブログコメントやTwitter(@oshow)などで遠慮無くご指摘ください。
Rebaseは安全である
なにやら Git についての嘘がまかり通っているらしい: git rebase は安全ではない、という。push 済みの変更をあなたが rebase してしまい、皆がタチの悪いマージ大惨事に陥ってしまうという類の危険のことでは「ない」。そんなものは本当の、よく知られた危険であり、そんなことしちゃいけないってのは皆受け入れているはずだ。
私が言っている嘘というのは git rebase はそもそもあなたの履歴を不安定にするものであり、コンパイルできないまたはテストをパスしない変更を混入するから、これは深刻な問題だ、というものだ。主な症状としては git bisect が中断する。テストが壊れているリビジョンが存在する場合、慎重にやるなら bisect はそれをスキップするが、そうでないなら、本来突き止めるべきではないものを bisect が見つけてしまう(false positive)ことになる。
確かにそれは悪く聞こえる。しかし問題が、新しく rebase されたコミットがテストをパスするかわからないということならば、なぜテストを走らせないのか?
この例のように。:
(set -e; git rev-list --reverse origin/master..master | while read rev; do echo "Checking out: $(git log --oneline -1 $rev)"; git checkout -q $rev; python runtests.py; done)これは難しいことじゃない――シェルによるただの while ループだ。origin/master から master の間の全リビジョンをチェックアウトし、それぞれのリビジョンでテストを走らせる。Expector Gadget(訳注:著者の自作テストツール)の2つのリビジョンでそれを走らせたら、こう出力される:
Checking out: 4f56581 Split tests into many files .................... ------------------------------------------------- Ran 20 tests in 0.019s OK Checking out: 44de2c2 pyflakes .................... ------------------------------------------------- Ran 20 tests in 0.019s OKこれはたった1.1秒しかかかってない。もし遅かったら、それはあなたのユニットテストが遅いからだ(Git のせいではない)。無論テストの遅さは bisect や継続的インテグレーション、開発フロー内の繰り返し作業、その他多くのものを遅くする。そこでは、rebase はボトルネックではない。
このコマンドはテストが失敗した時点で停止する――最初に set -e をしているためだ。だから、もしどれかのリビジョンがテストをパスしなかったら、あなたはそのテストの出力結果を見せられ、コマンドは停止し、そしてチェックアウトされたリビジョンがあなたの前に残される。あなたはおそらく git checkout master して、そのリビジョンを修正するために対話的リベースをしたいはずだ。私の場合、こういうことは実際には滅多に起こらない。rebase は変更なしでほとんどいつも働いているが、リポジトリ履歴を壊したくないならば、チェックはいまだ重要だ。
あなたは、チェックアウトがワーキングコピーを粉砕するか、さもなくばカオスな状況を引き起こすのではないかと心配するかもしれない。もう一度言うと set -e が我々を守ってくれる。もしワーキングコピーが汚かったら最初の git checkout が失敗し、サブシェルは終了するだろう:
Checking out: 4f56581 Split tests into many files error: You have local changes [...]; cannot switch branches.私はこのシェルコマンドを複数のプロジェクト、私一人のものと6人程度の小さなチームの両方で採用して大成功を収めた。これは元々 Mercurial の patch queue の中の全てのリビジョンに対してテストを走らせる、似たコマンドから来ている。patch queue は コミットを rebase する Mercurial における方法であり、Mercurial ユーザは本記事を Git 固有の問題だと思わないように。
過去に、私はコマンドをスクリプトに落としこむことさえ面倒臭がっていた。私には zsh の巨大なヒストリサイズ(100,000コマンド)があり、"rev-list" を履歴検索をするためにただ ^R を打つだけでよかった。でも今は私の dotfiles リポジトリにコマンドをスクリプト化したところなので、あなたも自身のプロジェクトで簡単にこれを使うことができる。
本記事の教訓は、あなたはツールに深く携わる必要があるということだ: Git を理解し、そしてまた Unix を理解せよ。それらをよく使うことを学び(例えば Unix では、私のスクリーンキャストの "Python to Shell to Ruby" や "A Raw View into My Unix Hackery" を見よ)、両方共の根本的なモデルを学び(例えばUnixでは、"The Tar Pipe" を見よ)、そしてそれらを一緒に使う方法を特に学ぼう。どちらかだけを学ぶとか、両方を中途半端にするとかして、問題が起こったときにそれらのツールに文句を言うのはやめよう。プログラムを書くのは難しい、だからって色んなものをとっ替えひっ替えするのはイクナイ。
(もしこの記事が楽しめたなら、"Why I Switched to Git From Mercurial" もいいかもしれない。)
0 件のコメント:
コメントを投稿