git push --force-with-lease
はgit push --force
と違って、他の人がpushしていたら良い感じにコケてくれるので安全、という話を聞き、さっそく使っています。
- git push --force でなく git push --force-with-lease を使う - valid,invalid
- --force considered harmful; understanding git's --force-with-lease - Atlassian Developers
ただ、ちょっとだけ注意しないとな、と思ったところがあるので書き残しておきます。
前提
git 2.6.4で確認
最後にfetchしたタイミングでの一致を保証する
man git-push
を見るとこんな記述があります。
--force-with-lease alone, without specifying the details, will protect all remote refs that are going to be updated by requiring their current value to be the same as the remote-tracking branch we have for them.
つまり--force-with-lease
はremote refsとローカルのremote-tracking branchのrefsの間に違いがないかどうかで、正否を判定しているわけですね。
ちなみにrefsというのはコミットへのポインタみたいなもので、ブランチやタグなどの単位で.git/refs
配下に保存されているものです。
remoteのrefsはgit ls-remote
で見られて、多分これと一致判定をしている様子です。
なので、remote-tracking branchのrefsが、push --force-with-lease
時のremote refsと一致しているときは通る、ということです。
普通に上書きされちゃうパターン
ということは、push --force-with-lease
前にfetch
をしていると、refsが一致して問題ないって勘違いしちゃう。
git checkout dev
# いくつかの変更をコミット & 同時にremoteに他の人がpush
git fetch origin dev
git push --force-with-lease origin dev
これが通っちゃうということですね。
こんなことをわざわざすることはあまりないとは思いますが、例えば次のようにorigin/master
に対してrebaseするような場合はあり得るかなあと思います。
git checkout dev
# ↓ここ
git fetch origin
git rebase origin/master
git push --force-with-lease origin dev
git fetch origin
とすると全部のブランチがfetchされるのですが、現在いるトピックブランチもfetchされてしまうので、結果的にさっきの例と同じ状況になってしまう、というわけですね。
僕はよくこういうことやるので、しっかりとgit fetch origin master
としたうえでrebaseしないとな、と思った次第です。
※もしくは、remote-tracking branchのorigin/master
に対するrebaseではなく、ローカルへmasterをpullしてからrebaseすればこの問題は起こりません