git push --force-with-lease とは、遠い側の枝の先端が自分の見込んだ値のままの時だけ、上書きの push を許す書き方です。

  • --force との違いと、--force-with-lease の 3 つの書き方(何も付けない・=<ref>・=<ref>:<expect>)と --force-if-includes の役目
  • AI の席を何本も並べて push させる当社で、弾かれた push が成功に見えた 2 回と、その後に足した確かめ方
  • 弾かれた時に --force-with-lease へ逃げてはいけない場面(押そうとしている物の取り違え・共有の clone)

当社は AI の席を何本も同時に走らせ、それぞれが git で枝を押しています。並んだ席が同じ枝や同じ clone を触るので、上書きの事故は人が 1 人で押すより起きやすくなります。AI に開発の仕事を任せる考え方は AIエージェント の頁に、押した後に main へ入る手前の列は merge queue の頁にまとめています。この頁は、その手前の git push の 1 手だけを扱います。

--force と --force-with-lease の違い、書き方の 3 つの形

git push はふだん、遠い側の枝が手元の先端の祖先でない時(早送りにならない時)は更新を拒みます。rebase した枝を押し直す時はこの決まりを外す必要がありますが、--force で外すと、その間に他の人が積んだ commit を消します。--force-with-lease は、遠い側の枝が見込んだ値のままなら上書きし、違えば失敗します。公式の文書はこれを、枝に鍵を掛けずに「借りる(lease)」ようなものと説明しています(git-push・2026-11-03 に開いて確かめた)。

書き方何と比べるか公式の文書の注意
--force比べない。早送りの決まりも、他の安全の確かめも外す遠い側の commit を失いうる。押すすべての ref に効く
--force-with-lease(何も付けない)更新するすべての ref を、手元の追跡の枝(origin/<枝>)の値と比べる裏で git fetch が走ると追跡の枝が進み、守りが効かなくなる
--force-with-lease=<ref>名指しした ref だけを、追跡の枝の値と比べる同上
--force-with-lease=<ref>:<expect>名指しした ref を、書いた値 <expect> と比べる。追跡の枝が無くてもよい。<expect> が空なら、その ref がまだ無い事を求めるこれ以外の形はまだ試験中で、意味が変わりうる
--force-if-includes(--force-with-lease と一緒に)追跡の枝の先端が、手元の枝の reflog のどれかから辿れるか(取り込み済みか)を確かめる=<ref>:<expect> と組むか、単独では何もしない

出典: git-push の --force-with-lease・--force・--force-if-includes の項(git 2.55.0 の版の頁・2026-11-03 に開いて確かめた)。

公式の文書は、裏で fetch が走る環境(エディタや定時の git fetch)向けに、見た先端に印を付けてから比べる先を名指しする例を載せています。

git fetch              # 遠い側を取ってくる
git tag base master    # 見た先端に印を付ける
git rebase -i master   # 歴史を書き直す
git push --force-with-lease=master:base master:master

出典: git-push の --force-with-lease の項の例(2026-11-03 に開いて確かめた。コメントは当社の訳)。

AI の席を何本も同じ clone で動かすと、ある席の fetch が別の席の追跡の枝を進めえます。何も付けない --force-with-lease は、その時に守りが外れる形です。当社が撃ち直しで比べる先を名指しした場面は、次の節の記録にあります。

当社の記録: 弾かれた push が、grep で消えて成功に見えた

rebase した枝を次の 1 行で押しました(社の実測 2026-11-02)。

git push -q --force-with-lease 2>&1 | grep -E "✅|❌|error"

push は弾かれていました。ところが grep を通した後の出力からは拒否が消え、背後で走らせた作業は exit 0 で終わりました。遠い側の枝は古い先端のままでした(出典: 社の実測 2026-11-02)。

-q は誤りの時を除いて出力を抑える指定です(git-push の --quiet・2026-11-03 に開いて確かめた)。残った誤りの行をさらに grep で絞り、しかもパイプの終了の値は既定では最後のコマンドの物なので(Bash Reference Manual「Pipelines」・2026-11-03 に開いて確かめた)、push 自身の失敗はパイプの後ろに隠れます。

直しは、比べる先を名指しして撃ち直すことでした。

git push --force-with-lease=<枝>:<旧 SHA> origin <枝>
git fetch origin
git rev-parse HEAD origin/<枝>   # 2 行が同じ値なら載っている

出典: 社の実測 2026-11-02(撃ち直した後、遠い側の先端を git rev-parse で測って載ったことを確かめた)。

教訓は、push の出力を grep で絞らないこと、そして撃った後に手元と遠い側の先端が同じかを測ることです。出力の文言ではなく、着いた先の値で判定します。

撃ち直しの輪が、拒否を見ながら成功へ抜けた

同じ形の事故は、それより前にも起きていました(社の実測 2026-09-18)。押せるまで撃ち直す輪を、次の形で書いていました。

git push origin HEAD:main | tail -1 && break

push は non-fast-forward で拒まれました。画面には拒否が見えていましたが、パイプの終了の値は最後の tail の物なので && break が走り、輪は成功として抜けました(出典: 社の実測 2026-09-18)。人が画面を見ていれば気づけますが、AI の席は終了の値で次へ進みます。

git push origin HEAD:main >push.log 2>&1; rc=$?
git fetch origin
git rev-list --count HEAD..origin/main   # 0 でなければ着いていない

出典: 社の実測 2026-09-18(終了の値を素で採り、着地を git rev-list --count HEAD..origin/main が 0 かで測る形に直した)。

bash なら set -o pipefail でパイプの終了の値をパイプの中の失敗に合わせられます(Bash Reference Manual「Pipelines」・2026-11-03 に開いて確かめた)。ただ当社は、終了の値に頼るより、着いた先を数える方を正本にしています。

拒まれて pull でも解けない時は、押そうとしている物を疑う

2026-09-19、作業木(worktree)から git push -q origin main を撃つと non-fast-forward で拒まれました。git pull --rebase origin main を 3 回撃っても、毎回「ahead=1 behind=0」で何も変わりませんでした(出典: 社の実測 2026-09-19)。

原因は、git push origin main が手元の main の枝を押そうとしていたことでした。その作業木では別の枝に居たので、pull で直していたのは今いる枝、押していたのは古い手元の main です。公式の文書のとおり、: の後ろを書かない main は main:refs/heads/main に広がり、手元の main を元にします(git-push の refspec の項・2026-11-03 に開いて確かめた)。git push origin HEAD:main で一発で通りました(出典: 社の実測 2026-09-19)。

この時、--force や --force-with-lease で押し切っていれば、他の席が main に入れた成果を消すところでした(出典: 社の実測 2026-09-19)。手元の main の追跡の枝が遠い側と同じ値なら、--force-with-lease の守りは通ってしまいます。lease は「誰かが後から積んだか」を見る道具で、「押す物が正しいか」は見ません。

積み上げた PR を squash の後に載せ替えて押し直す

--force-with-lease を正しく使う場面もあります。当社の merge queue は squash で main に入れます。2026-09-20、積み上げた PR の下の段が main に入った瞬間、その上に積んだ PR 2 本が衝突になりました。下の段の commit が squash で別の 1 本に置き換わり、上の段の歴史と合わなくなったためです(出典: 社の実測 2026-09-20)。

当座の直しは、上の段を main の上へ載せ替えてから押し直すことでした。

git fetch origin
git rebase --onto origin/main <下の段の先端> <上の段の枝>
git push --force-with-lease origin <上の段の枝>

出典: 社の実測 2026-09-20。

自分の枝を自分で書き直した時が、--force-with-lease の出番です。比べる先を名指しすれば、載せ替えの間に別の席がその枝へ積んだ時に押し切らずに止まります。

弾かれた後の後片付けで踏んだ所

push が弾かれた後の手当てでも、2 つ踏んでいます。どちらも --force は撃っていません。

日起きた事残った物畳み方・教訓
2026-09-19push が弾かれ、rebase が衝突した後、git rebase --continue を使わずに rebase の途中のまま git commit を撃って push した着地は正しかったが、作業木に rebase の途中の状態が残ったgit rebase --quit で畳んだ。--abort は HEAD を元の枝へ戻すので使わない
2026-09-19多くの席が同時に触る共有の clone で push できず、別の作業木へ cherry-pick して押した後、本体を git reset --mixed origin/main で追いつかせた他の席が add していた変更(git mv 約 130 本)が全部 add されていない状態に戻った。作業木の中身は無事共有の clone では、追いつかせる操作が他の席の index を壊す。席ごとに作業木を分ける

出典: 社の実測 2026-09-19(2 件とも)。--quit が HEAD と index と作業木を動かさずに rebase を止め、--abort が HEAD を元の枝へ戻すことは git-rebase(2026-11-03 に開いて確かめた)。

2 件目は push の話ではありませんが、根は同じです。並んだ席が 1 つの clone を共にすると、ある席の追いつかせる操作も、ある席の fetch も、別の席の足元を動かします。--force-with-lease が比べる追跡の枝も、その足元の 1 つです。

AI の席に push を任せる時の確かめ方

上の記録を、席に渡す決まりの形に並べ直すと次のとおりです。

場面決まりもとの記録
自分の枝を rebase して押し直す--force-with-lease=<枝>:<旧 SHA> と比べる先を名指しする2026-11-02・2026-09-20
push の成否を判定する出力を grep・tail で絞らない。終了の値は素で採り、着いた先(遠い側の先端・HEAD..origin/main の数)を測る2026-11-02・2026-09-18
拒まれて pull でも変わらないrefspec を見る。今いる枝を押すなら HEAD:<枝>。force 系へ逃げない2026-09-19
rebase の途中で手が止まった--continue で進めるか、--quit で畳む2026-09-19
席を並べる席ごとに作業木を分け、1 つの clone の index を共にしない2026-09-19

出典: 社の実測 2026-09-18・2026-09-19・2026-09-20・2026-11-02。書き方の形は git-push(2026-11-03 に開いて確かめた)。

席の数が増えると、push の手前の詰まりは列(merge queue)へ、列の詰まりは作業員(self-hosted runner)と揺れる試験(flaky test)へ移っていきます。push の 1 手で嘘の成功を出さないことが、その先の数を読める前提になります。

よくある質問

git push --force-with-lease と --force の違いは何ですか?

--force は遠い側の枝を何とも比べずに上書きします。--force-with-lease は遠い側の枝が見込んだ値のままの時だけ上書きし、違えば push が失敗するので、他の人が後から積んだ commit を消さずに済みます(git-push・2026-11-03 に開いて確かめた)。

--force-with-lease はいつも安全ですか?

何も付けない形は、手元の追跡の枝と比べるだけなので、裏で git fetch が走ると守りが効かなくなると公式の文書が注意しています。比べる先を --force-with-lease=<ref>:<expect> と名指しするか、--force-if-includes を一緒に付けます(git-push・2026-11-03 に開いて確かめた)。

--force-if-includes は何をする物ですか?

追跡の枝の先端が、手元の枝の reflog のどれかから辿れるか(取り込み済みか)を確かめ、取り込んでいなければ上書きを拒みます。--force-with-lease と一緒に使う物で、単独や =<ref>:<expect> と組んだ時は何もしません(git-push・2026-11-03 に開いて確かめた)。

push が non-fast-forward で拒まれたら、--force-with-lease で押してよいですか?

自分の枝を自分で書き直した時だけです。当社では、作業木で別の枝に居たのに git push origin main が手元の main を押そうとして拒まれており、pull を 3 回撃っても解けませんでした。force 系で押し切れば他の席の成果を消すところで、git push origin HEAD:main で通りました(出典: 社の実測 2026-09-19)。

スクリプトで push の成否はどう判定すればよいですか?

出力を grep や tail で絞ると、パイプの終了の値が最後のコマンドの物になり、拒否が成功に見えます。当社はこれで 2 回、弾かれた push を成功として進めました。終了の値は素で採り、撃った後に遠い側の先端が手元と同じかを測ります(出典: 社の実測 2026-09-18・2026-11-02)。

出典

  1. git 公式文書「git-push」 https://git-scm.com/docs/git-push(git 2.55.0 の版の頁・2026-11-03 に開いて確かめた・--force-with-lease の 3 つの形と裏の fetch の注意と例・--force・--force-if-includes・--quiet・refspec の広がり方)
  2. git 公式文書「git-rebase」 https://git-scm.com/docs/git-rebase(2026-11-03 に開いて確かめた・--quit と --abort の違い)
  3. GNU「Bash Reference Manual」の Pipelines https://www.gnu.org/software/bash/manual/html_node/Pipelines.html(2026-11-03 に開いて確かめた・パイプの終了の値は最後のコマンドの物・pipefail)
  4. 社の実測 2026-11-02(grep で絞った --force-with-lease の push が弾かれたのに exit 0 で終わった事・名指しの形で撃ち直し遠い側の先端を測った事)
  5. 社の実測 2026-09-18(| tail -1 && break の輪が拒否のまま成功として抜けた事・終了の値を素で採り着地を数える形に直した事)
  6. 社の実測 2026-09-19(作業木からの git push origin main の取り違えと HEAD:main・rebase の途中の commit と --quit・共有の clone での reset --mixed が他の席の index を戻した事)
  7. 社の実測 2026-09-20(squash の merge queue で積み上げた PR が衝突し、rebase --onto と --force-with-lease で押し直した事)