git push --force はなぜダメなの
git push --force
って、なんか絶対やってはいけない空気を感じますよね。でも結局なぜダメなのか。あまり理解してない気がしたので、まとめてみます。
そもそもどういう場面で使うか
チーム開発をやっている時に、remoteとlocalで整合性が取れなくなることがある。例えば以下のような状況では git push
できない。
<remote> <local> A A | | B B | | C D ← 存在するはずの C というコミットがないのでpushできない!!
この場合いくつか解決方法はあるが、私だったら以下のようにする。
git checkout local git stash save "stash D" // Dという変更を一旦退避 git merge remote // remoteをマージして Cコミットを取り込む git stash apply // これで A-B-C-D という順番になる git push // ✌️
しかし様々な事情から stashした変更をapplyするのがめちゃくちゃ面倒だったりして、「あ〜もう上書きしていいスカ(笑)」となる瞬間は誰しもある。ここで登場するのが git push --force
である。
force オプションの何が悪か
1人で開発している際には大きな問題になることはなさそう。問題となるのはチーム開発の時である。先ほどの例を取ると、 git push --force
はかなり破壊的なコマンドであることが分かる。
git checkout local // local は A-B-D, remoteは A-B-C git push --force // remote は localに上書きされてしまい、 A-B-Dとなる(Cというコミットが消える)
チームのメンバーのコミットを吹き飛ばす、みたいなことが起こり得るので結構危険である。
じゃあ脳死で force-with-lease を使えばいいのか
--force-with-lease
はこのような破壊的な force
オプションを回避するためのオプションである。--force-with-lease
はremoteのrefsとlocalのrefsを比較して、他人のコミットなどがあればpushをrejectしてくれる君である。これで安心。
と言いたいところだが、仕組みとしてこの--force-with-lease
を付けていても、remoteを上書きしてしまう場合がある。それは push する前に fetchコマンドを実行していた時である。
--force-with-lease
は詰まるところ単にremoteのrefsとlocalのrefsを比較しているだけなので、ここが揃ってしまっていたら、すり抜けてしまう。
結局どうしたらいいの
チームメンバーとコミュニケーションを取りながら開発をしましょう。極力共同で作業しているブランチでは --force
も --force-with-lease
も使わないようにして、面倒でもブランチの整合性を取るように心がけましょう。