リモートの最新を取り込む(rebase、merge、push -f について)

今の勤務先は、VCSGithub、開発フローは git-flow です。

※ちなみに、会社のみんなは、クライアントは source-tree で全部やっているのだけれど、私はGithub for Mac(Editボタンやsyncボタンが好き)、git-flow系のコマンドだけコマンドラインで手で打っている。

以前の職場がSubversionだったもので(個人ではGithubを愛用していたとはいえ)、Gitでのチーム開発、初心者・・・。案の定、下記問題で行き詰まって、時間を無駄にしたわ。っていうか、ジタバタする前に、よく考えれば良かったんだなー。

やりたいこと

バージョンの上がったdevelopのfeature への取り込み。

この stackoverflow がまさに私の求めていたぴったりの情報だったので、理解を深めるため、以下に勝手に翻訳する。

http://stackoverflow.com/questions/8939977/git-push-rejected-after-feature-branch-rebase

Q. feature branch を rebase した後、git push したら reject されるのですが?

さてさて。下記はgitの単純なシナリオだと思ったのだけれど、何が足りていないのかな?

master ブランチと feature のブランチを持っている。マスタで何かして、feactureで何かして、それで、master で何か作業をする。下記のようにして何かを終える。アルファベットの順番は、コミットの順を示す。

A--B--C------F--G  (master)
            |    
            D--E  (feature)
問題点:

「既に git push origin feature がされていて、その後新たに rebase をしたという feature をバックアップしたい」となった時なのだけれど、
rebase したことによってツリーが変わってしまったために、この push は reject されてしまった。
git push --force origin feature することでしか解決ができない。

どうしても必要なのでなければ、--forceオプションを使うのは嫌なんですよね。この場合要るのですか?rebase をしたら、次の push では必ず --force するべきだということなのでしょうか?

edited Jan 25 at 12:14 Drew Noakes / asked Jan 20 '12 at 10:29 Yuval Adam

41+されたAnswer.

問題は、git push というのが、リモートブランチがあなたのローカルブランチに対して fast-foward を想定しているという点です。
ローカル、リモートブランチ間のすべての差分が、新しいコミット群を持っているローカルの中に下記のように最後まである、ということです。

Z--X--R         <- origin/some-branch (Y コミットに対して fast-forwarded の関係になれる)
           |        
            T--Y    <- some-branch

git rebase をすると、コミットDとEが新たにベースに適用されて、新しいコミット群が作られます。
rebase した後、下記のようになるわけです:

A--B--C------F--G--D'--E'   <- feature-branch
           |  
            D--E                <- origin/feature-branch

この状況において、リモートブランチはローカルに対して fast-forward にはなれません。

理論上はローカルブランチはリモートにマージさせられるのだけれど(もちろんここではそんなことはしないわけで)、git push は fast-forward でのみ動くので、マージさせようとするとエラーになります。


そして、--force オプションが何をするかなのですが、単にリモートブランチの状態を無視するだけです。リモートpush しようとしているコミットについて無視をするという設定をします。つまり、git push --force origin feacture-branch は origin/feacture-branch をローカルのfeature-branch でただ単に上書きします。

個人的な意見としては、
featureブランチをmasterでrebaseすること、
リモートリポジトリにそれらをforce push することで戻すこと
は、あなたがそのブランチで1人で作業するだけなのであれば、問題無いと思いますよ。

this answer edited Jan 20 '12 at 13:30 answered Jan 20 '12 at 10:55

【翻訳ここまで】

感想

  • で、これを読んで、よーくわかった。遅まきながらわかったよやっと!
  • でも、新たな悩みが。-f オプションでpush したら、一所懸命スクリーンショットとか貼り付けてmarkdownでとりまとめたGithubのコメントが、丸ごと消えてしまうのだ!
    • 今のチームでは、PRレビューではなくて、ブランチの各コミットごとに細かくレビューしていく、という運用でやっているので、コミットに対するGithubコメントで画面動作確認のエビデンスを添付したりすることが多い。
  • それで、参考にさせて頂いたツイートが下記。

https://twitter.com/udzura/status/379296419271548928


結論

  • 私の用途だと、rebaseではなくて、毎日こまめに merge (or pull)で最新developの取り込みをするやり方になる。
  • rebaseは一人で開発している時限定で使おうと思った。
  • うーん。そもそも、エビデンスの管理をGithubコメントでやっているのがいけてないのかもしれない。ふむー。

参考リンク