- Git
git remoteの変更・追加・削除とpush rejectedの対処法
git remoteとは、ローカルリポジトリに「リモートリポジトリの名前とURLの組」を登録・変更・削除するコマンドです。 origin はその名前のひとつで、git clone したときに自動で付く既定の名前にすぎません。URLを変えたいときは git remote set-url、追加は git remote add、削除は git remote remove を使います。
この記事では、remote の全操作を Git 2.43.0 で実際に動かした実行結果つき で一覧にします。さらに、push したときに出る ! [rejected](non-fast-forward、fetch first、stale info)や src refspec main does not match any、has no upstream branch などを ローカルの bare リポジトリで再現 し、エラーメッセージの原文・原因・解決コマンドを対応表にまとめました。最後に、--force-with-lease と --force の違いも、同じ状況で両方を実行して比べます。
git remoteとpushエラーの早見表
やりたいこと別のコマンド
| やりたいこと | コマンド | 補足 |
|---|---|---|
| 登録済みのリモートをURLつきで見る | git remote -v |
fetch用とpush用の2行が出る |
| リモートを追加する | git remote add origin <URL> |
名前は自由。最初の1つは origin が慣例 |
| URLを変更する | git remote set-url origin <新URL> |
HTTPS⇔SSH の切り替えもこれ |
| URLだけ取り出す | git remote get-url origin |
スクリプト向き |
| push 先だけ変える | git remote set-url --push origin <URL> |
fetch 元はそのまま |
| push 先を2か所にする | git remote set-url --add --push origin <URL> |
1回の push で両方へ送る |
| 名前を変える | git remote rename origin upstream |
追跡ブランチ名も一緒に変わる |
| 削除する | git remote remove origin |
rm でも同じ |
| 詳しい状態を見る | git remote show origin |
リモートに問い合わせて表示 |
| 消えたブランチの追跡を掃除 | git remote prune origin |
git fetch --prune でも同じ |
| 本家を追加する(fork 運用) | git remote add upstream <URL> |
git fetch upstream で取得 |
pushエラーの対応表(すべて再現して確認)
| エラーメッセージ(原文の要点) | 原因 | 解決コマンド |
|---|---|---|
! [rejected] main -> main (fetch first) |
リモートに、手元にまだ無いコミットがある | git pull --rebase origin main → git push |
! [rejected] main -> main (non-fast-forward) |
fetch 済みだが、手元の履歴がリモートの続きになっていない | git pull --rebase origin main → git push |
! [rejected] ... (stale info) |
--force-with-lease の確認で、リモートが想定より進んでいた |
git fetch → 取り込んでから再度 push |
error: remote origin already exists. |
同じ名前のリモートが登録済み | git remote set-url origin <URL> |
error: src refspec main does not match any |
その名前のローカルブランチが無い/コミットが1つも無い | git branch で名前を確認、または最初のコミットを作る |
fatal: The current branch main has no upstream branch. |
上流ブランチ(push 先の対応づけ)が未設定 | git push -u origin main |
fatal: 'origin' does not appear to be a git repository |
リモート未登録、またはURLの打ち間違い | git remote -v で確認し add/set-url |
fatal: No configured push destination. |
リモートが1つも無い | git remote add origin <URL> |
! [remote rejected] ... (non-fast-forward) |
サーバー側の設定で履歴の書き換えを受け付けていない | 管理者に確認、または通常のコミットで直す |
Permission denied (publickey). |
SSH 鍵が未登録・未ロード(公式ドキュメントで確認) | ssh -T git@github.com で接続確認 |
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「git remoteの変更・追加・削除とpush rejectedの対処法」
検証環境と再現用のセットアップ
この記事の出力は、次の環境で取得しました。GitHub などの外部サービスには接続せず、同じマシン上の bare リポジトリ(作業ツリーを持たない、サーバー役のリポジトリ) をリモートとして使っています。手元でも同じ手順で試せます。
| 項目 | 内容 |
|---|---|
| Git | 2.43.0(Linux) |
| 公式ドキュメントの最新版 | 2.55.0(2026-06-29 更新の git-push マニュアルで確認) |
| リモート役 | git init --bare で作ったローカルリポジトリ |
| メッセージの言語 | 英語(LC_ALL=C) |
# サーバー役(bare リポジトリ)を3つ作る
mkdir -p ~/remote-lab/server ~/remote-lab/work
cd ~/remote-lab
git init --bare server/shop.git
git init --bare server/shop-fork.git
git init --bare server/backup.git
# 作業用リポジトリを作り、最初のコミットを置く
cd work
git init shop && cd shop
echo "# shop" > README.md
git add . && git commit -m "first commit"
以降は ~/remote-lab/work/shop の中で実行しています。一部の出力に含まれる長い絶対パスは /work/server.git に短縮して載せています。リモートのURLは相対パス ../../server/shop.git ですが、GitHub の URL に置き換えても操作は同じです。
git remoteの基本操作を実行結果で確認する
リモートを確認する(git remote -v)
リモートを登録する前は、何も表示されません。
$ git remote -v
$
この状態で git push すると、次のように案内されます。
$ git push
fatal: No configured push destination.
Either specify the URL from the command-line or configure a remote repository using
git remote add <name> <url>
and then push using the remote name
git push <name>
「origin が見つからない」系のメッセージが出たら、まず git remote -v で登録内容を見る のが近道です。
リモートを追加する(git remote add)
$ git remote add origin ../../server/shop.git
$ git remote -v
origin ../../server/shop.git (fetch)
origin ../../server/shop.git (push)
1つのリモートに対して fetch 用と push 用の2行 が表示されます。通常は同じURLですが、後で説明するように別々にもできます。
同じ名前でもう一度 add すると、次のエラーになります(終了コードは 3)。
$ git remote add origin ../../server/backup.git
error: remote origin already exists.
すでにある名前のURLを差し替えたいときは add ではなく set-url を使います。別のリモートとして並べたいなら、backup など別の名前で add します。
初回のpushと上流ブランチ(-u)
リモートを登録した直後に、引数なしで git push すると次のようになります。
$ git push
fatal: The current branch main has no upstream branch.
To push the current branch and set the remote as upstream, use
git push --set-upstream origin main
To have this happen automatically for branches without a tracking
upstream, see 'push.autoSetupRemote' in 'git help config'.
上流ブランチ(upstream branch)とは、「このローカルブランチは、どのリモートのどのブランチと対応するか」という対応づけ です。-u(--set-upstream)を付けて一度 push すると記録されます。
$ git push -u origin main
To ../../server/shop.git
* [new branch] main -> main
branch 'main' set up to track 'origin/main'.
$ git status -sb
## main...origin/main
毎回 -u を付けるのが手間なら、push.autoSetupRemote を有効にすると、上流が無いブランチでも git push だけで設定されます。次の出力は一時的に設定を渡して試したものです。
$ git switch -c feature/new
$ git -c push.autoSetupRemote=true push
To /work/server.git
* [new branch] feature/new -> feature/new
branch 'feature/new' set up to track 'origin/feature/new'.
常に有効にするなら git config --global push.autoSetupRemote true です。設定項目の全体像は、既存記事「git config設定一覧とおすすめalias」にまとめています。
URLを変更する(git remote set-url)
リポジトリの引っ越しや、HTTPS と SSH の切り替えで使います。
$ git remote set-url origin https://github.com/example/shop.git
$ git remote -v
origin https://github.com/example/shop.git (fetch)
origin https://github.com/example/shop.git (push)
存在しない名前を指定すると、次のエラーになります。
$ git remote set-url nothere x
error: No such remote 'nothere'
名前を変える(git remote rename)
$ git remote add upstream ../../server/shop-fork.git
$ git remote rename upstream source
$ git remote -v
origin ../../server/shop.git (fetch)
origin ../../server/shop.git (push)
source ../../server/shop-fork.git (fetch)
source ../../server/shop-fork.git (push)
rename すると、.git/config の見出しだけでなく リモート追跡ブランチ(upstream/main → source/main)や、各ブランチの上流設定も一緒に書き換わります。 手で設定ファイルを直すより、コマンドに任せるほうが漏れがありません。
削除する(git remote remove)
$ git remote remove source
$ git remote remove source
error: No such remote: 'source'
1回目は何も表示されずに成功し、2回目は「その名前は無い」というエラーになります。削除されるのは手元の登録とリモート追跡ブランチだけで、サーバー上のリポジトリには何も起きません。 安心して試せます。
詳しい状態を見る(git remote show)
$ git remote show origin
* remote origin
Fetch URL: ../../server/shop.git
Push URL: ../../server/shop.git
HEAD branch: main
Remote branch:
main tracked
Local branch configured for 'git pull':
main merges with remote main
Local ref configured for 'git push':
main pushes to main (up to date)
| 表示 | 意味 |
|---|---|
Fetch URL / Push URL |
取得元と送信先のURL |
HEAD branch |
リモートの既定ブランチ |
tracked |
追跡中のリモートブランチ |
stale |
リモートでは消えたが、手元に追跡ブランチが残っている |
up to date / fast-forwardable / local out of date |
そのまま push できるかどうかの目安 |
show はリモートに実際に問い合わせます。ネットワークを使わずに設定だけ見たいときは git remote show -n origin を使います。
消えたブランチの追跡を掃除する(git remote prune)
別の人がリモートのブランチを削除しても、手元の origin/feature/login は git fetch だけでは消えません。 次の出力は、同僚役のクローンから git push origin --delete feature/login を実行したあとの様子です。
$ git fetch origin
$ git branch -r
origin/feature/login
origin/main
$ git remote show origin
* remote origin
...
Remote branches:
main tracked
refs/remotes/origin/feature/login stale (use 'git remote prune' to remove)
--dry-run で対象を確認してから掃除します。
$ git remote prune origin --dry-run
Pruning origin
URL: ../../server/shop.git
* [would prune] origin/feature/login
$ git remote prune origin
Pruning origin
URL: ../../server/shop.git
* [pruned] origin/feature/login
$ git branch -r
origin/main
毎回の fetch で自動的に掃除したい場合は git fetch --prune、常に有効にするなら git config --global fetch.prune true が便利です。
.git/configの中身を読む
git remote の各コマンドは、リポジトリ内の .git/config を書き換えています。origin を登録して git push -u origin main した直後の中身は次のとおりです。
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
[remote "origin"]
url = ../../server/shop.git
fetch = +refs/heads/*:refs/remotes/origin/*
[branch "main"]
remote = origin
merge = refs/heads/main
| 行 | 意味 | 書き換えるコマンド |
|---|---|---|
[remote "origin"] |
リモート名 | remote add / rename / remove |
url = ... |
取得元(push 先を兼ねる) | remote set-url |
pushurl = ... |
push 先だけ別にする場合のURL | remote set-url --push |
fetch = +refs/heads/*:refs/remotes/origin/* |
リモートの全ブランチを origin/名前 として取り込む指定(refspec) |
remote add が自動で書く |
[branch "main"] の remote / merge |
main の上流ブランチ | push -u / branch --set-upstream-to |
fetch の行の先頭にある + は、「リモート追跡ブランチは早送りでなくても更新してよい」という意味 です。リモートで履歴が書き換えられても、origin/main は fetch のたびにリモートと同じ位置に合わせられます。
設定ファイルをエディタで直接編集しても動きますが、rename のように関連箇所が複数あるものはコマンドのほうが安全です。値を1つ確認するだけなら次のように取り出せます。
$ git config --get remote.origin.url
../../server/shop.git
HTTPSとSSHを切り替える
GitHub の公式ドキュメントで確認した URL の形式は次の2種類です。
| 方式 | URLの形 | 認証 |
|---|---|---|
| HTTPS | https://github.com/OWNER/REPOSITORY.git |
個人アクセストークン(PAT)や認証ヘルパー |
| SSH | git@github.com:OWNER/REPOSITORY.git |
SSH 鍵 |
切り替えは set-url に新しい形のURLを渡すだけです。
$ git remote set-url origin git@github.com:example/shop.git
$ git config --get remote.origin.url
git@github.com:example/shop.git
HTTPS に戻すときも同じ要領です。
git remote set-url origin https://github.com/example/shop.git
切り替えたあとは git fetch origin を1回実行して、認証が通るか確かめる と安心です。fetch は手元の作業内容を変えないので、確認に向いています。
remote -v の表示と設定値が違って見えるとき
検証環境では、SSH 形式で set-url したのに git remote -v には HTTPS のURLが表示されました。調べると、環境側で url.https://github.com/.insteadOf git@github.com: という URL の読み替え設定(insteadOf) が入っていました。
| 確認コマンド | 表示されるもの |
|---|---|
git config --get remote.origin.url |
.git/config に保存された値そのまま |
git remote -v / git remote get-url origin |
insteadOf を適用したあとの、実際に接続するURL |
git config --show-origin --get-regexp 'url\..*' |
読み替え設定がどこで定義されているか |
「set-url したのに表示が変わらない」と感じたら、insteadOf の設定を確認する と原因が見つかります。
認証まわりのエラー(公式ドキュメントで確認)
次の2つは外部サービスへの接続が必要なため、この記事では再現していません。GitHub の公式ドキュメントの記載をもとに整理します。
| メッセージ | 状況 | 確認すること |
|---|---|---|
Permission denied (publickey). |
SSH でサーバーが接続を受け付けなかった | ssh -vT git@github.com で接続確認、ssh-add -l -E sha256 で鍵がロード済みか、アカウントに公開鍵を登録済みか。接続ユーザー名は git |
| HTTPS でパスワードを求められる | パスワード認証は廃止済み | パスワード欄に個人アクセストークンを入力する、または SSH に切り替える |
鍵の作成から登録までの手順は、既存記事「SSH鍵の作成とGitHub接続|Permission deniedの対処法」で順を追って説明しています。
複数のリモートを使う(originとupstream)
forkした本家をupstreamとして追加する
自分用のコピー(fork)を origin、本家を upstream と呼ぶのが広く使われている習慣です。
$ git remote add upstream ../../server/shop-fork.git
$ git remote
origin
upstream
$ git remote -v
origin ../../server/shop.git (fetch)
origin ../../server/shop.git (push)
upstream ../../server/shop-fork.git (fetch)
upstream ../../server/shop-fork.git (push)
本家の変更を取り込む流れは次のとおりです。
git fetch upstream # 本家の最新を取得
git switch main
git merge --ff-only upstream/main # 自分の main を本家に追いつかせる
git push origin main # 自分の fork にも反映
push先だけ変える(--push)
本家には取得だけして、うっかり push しないようにしたい場合は、push 用のURLに存在しない値を入れておく方法があります。
$ git remote set-url --push upstream no_push
$ git remote -v
origin ../../server/shop.git (fetch)
origin ../../server/shop.git (push)
upstream ../../server/shop-fork.git (fetch)
upstream no_push (push)
$ git push upstream main
fatal: 'no_push' does not appear to be a git repository
fatal: Could not read from remote repository.
Please make sure you have the correct access rights
and the repository exists.
.git/config には pushurl = no_push の1行が加わります。fetch は今までどおり動き、push だけが止まる ので、読み取り専用のリモートとして扱えます。
1回のpushで2か所に送る(--add --push)
バックアップ用のリポジトリにも同時に送りたいときは、push 用URLを2つ登録します。
$ git remote set-url --add --push origin ../../server/shop.git
$ git remote set-url --add --push origin ../../server/backup.git
$ git remote -v
origin ../../server/shop.git (fetch)
origin ../../server/shop.git (push)
origin ../../server/backup.git (push)
$ git push origin main
Everything up-to-date
To ../../server/backup.git
* [new branch] main -> main
ポイントは、元のURLも --add --push で登録し直すこと です。pushurl を1つでも設定すると、push では url が使われなくなるためです。設定ファイルは次のようになります。
[remote "origin"]
url = ../../server/shop.git
fetch = +refs/heads/*:refs/remotes/origin/*
pushurl = ../../server/shop.git
pushurl = ../../server/backup.git
元に戻すには git config --unset-all remote.origin.pushurl を実行します。
push rejectedを再現して直す
ここからは、push が受け付けられない状況を1つずつ再現します。登場人物は、同じリポジトリをクローンした Taro と Hanako の2人です。
rejectedが起きる仕組み
gitGraph
commit id: "first commit"
branch hanako
commit id: "hanako: update README"
checkout main
commit id: "taro: add taro.txt"
通常の push は「リモートの先端に、自分のコミットを継ぎ足すだけ」で済む場合(fast-forward、早送り)にだけ成功します。 上の図のように、Hanako が先に push したあとで Taro が別のコミットを push しようとすると、継ぎ足しでは済まないので Git は受け付けません。これは、Hanako のコミットがリモートから見えなくなるのを防ぐための動作です。
(fetch first):リモートに未取得のコミットがある
Hanako が先に push し、Taro はまだ fetch していない状態です。
$ git push origin main
To ../../server/shop.git
! [rejected] main -> main (fetch first)
error: failed to push some refs to '../../server/shop.git'
hint: Updates were rejected because the remote contains work that you do not
hint: have locally. This is usually caused by another repository pushing to
hint: the same ref. If you want to integrate the remote changes, use
hint: 'git pull' before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
(non-fast-forward):取得済みだが取り込んでいない
git fetch だけして、もう一度 push すると、かっこの中の理由が変わります。
$ git fetch origin
From ../../server/shop
d23c20d..3550478 main -> origin/main
$ git push origin main
To ../../server/shop.git
! [rejected] main -> main (non-fast-forward)
error: failed to push some refs to '../../server/shop.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. If you want to integrate the remote changes,
hint: use 'git pull' before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
$ git status -sb
## main...origin/main [ahead 1, behind 1]
| 理由 | 手元の状態 | 違い |
|---|---|---|
fetch first |
リモートの新しいコミットをまだ取得していない | Git は「リモートに知らないコミットがある」ことだけ分かっている |
non-fast-forward |
取得済みで、ahead 1, behind 1 のように枝分かれしている |
追跡ブランチと比べて、継ぎ足しにならないと判定された |
どちらも解決方法は同じで、リモートの変更を取り込んでから push し直します。
解決:取り込んでからpushする
$ git pull --rebase origin main
From ../../server/shop
* branch main -> FETCH_HEAD
Successfully rebased and updated refs/heads/main.
$ git push origin main
To ../../server/shop.git
3550478..5fe34cd main -> main
取り込み方は2通りあります。
| 方法 | コマンド | 履歴 | 向いている場面 |
|---|---|---|---|
| リベース | git pull --rebase origin main |
一直線になる | 自分のコミットがまだ共有されていないとき |
| マージ | git pull --no-rebase origin main |
マージコミットができる | 枝分かれの記録を残したいとき |
違いの詳細は既存記事「git mergeとrebaseの違い」で扱っています。途中でコンフリクトが出たら、該当ファイルを直して git add → git rebase --continue で続けます。
git pullで「divergent branches」と表示されたとき
取り込み方を決めていない状態で、枝分かれしたブランチに git pull すると、次のように尋ねられます。
$ git pull
From ../../server/shop
5fe34cd..5008c26 main -> origin/main
hint: You have divergent branches and need to specify how to reconcile them.
hint: You can do so by running one of the following commands sometime before
hint: your next pull:
hint:
hint: git config pull.rebase false # merge
hint: git config pull.rebase true # rebase
hint: git config pull.ff only # fast-forward only
...
fatal: Need to specify how to reconcile divergent branches.
git pull --rebase のように毎回指定するか、git config --global pull.rebase true などで既定を決めておくと、この表示は出なくなります。
pushの出力記号の読み方
push の結果は、行頭の記号で読み取れます(意味は公式マニュアルで確認)。
| 記号 | 意味 | この記事での出力例 |
|---|---|---|
| (空白) | 早送りで push できた | 3550478..5fe34cd main -> main |
* |
新しいブランチやタグを作った | * [new branch] main -> main |
+ |
強制更新した | + 10430ee...b57c742 feature/cart -> feature/cart (forced update) |
- |
削除した | - [deleted] feature/login |
! |
受け付けられなかった | ! [rejected] main -> main (fetch first) |
= |
すでに最新(--verbose で表示) |
― |
..(ドット2つ)は早送り、...(ドット3つ)は強制更新 という違いもあります。
そのほかのpushエラーを再現する
src refspec main does not match any
$ git push origin master
error: src refspec master does not match any
error: failed to push some refs to '../../server/shop.git'
「push 元として指定した名前(src refspec)に当てはまるものが、手元に無い」 という意味です。再現できた原因は次の2つでした。
| 原因 | 確認方法 | 解決 |
|---|---|---|
ブランチ名が違う(main と master など) |
git branch で現在の名前を見る |
正しい名前で push する。名前を変えるなら git branch -m main |
| まだ1つもコミットしていない | git log が does not have any commits yet になる |
git add . → git commit -m "first commit" のあとで push |
2つ目は、git init と git remote add の直後にそのまま push したときに起きます。空のリポジトリで試した結果が次の出力です。
$ git init && git remote add origin ../../server/shop.git
$ git push -u origin main
error: src refspec main does not match any
error: failed to push some refs to '../../server/shop.git'
does not appear to be a git repository
リモート名が未登録のとき、またはURLに打ち間違いがあるときに出ます。
$ git push origin main
fatal: '../server-typo.git' does not appear to be a git repository
fatal: Could not read from remote repository.
Please make sure you have the correct access rights
and the repository exists.
git remote -v でURLを見直し、git remote set-url origin <正しいURL> で直します。メッセージの後半は権限が足りない場合にも共通で出るため、まずURLの綴り、次にアクセス権の順で確認する と切り分けやすくなります。
上流ブランチと名前が違うとき
ローカルブランチ名と、上流に設定したリモートブランチ名が違うと、引数なしの git push は確認を求めます。
$ git push
fatal: The upstream branch of your current branch does not match
the name of your current branch. To push to the upstream branch
on the remote, use
git push origin HEAD:feature/cart
To push to the branch of the same name on the remote, use
git push origin HEAD
...
案内のとおり、送り先を明示すれば push できます。git push origin HEAD は「今いるブランチを、同じ名前で送る」という書き方で、ブランチ名を打たずに済むので覚えておくと便利です。
タグが (already exists) になる
$ git push origin v1
To ../../server/shop.git
! [rejected] v1 -> v1 (already exists)
error: failed to push some refs to '../../server/shop.git'
hint: Updates were rejected because the tag already exists in the remote.
リモートにあるタグと同じ名前で、別のコミットを指すタグを push したときの表示です。公開済みのタグは動かさず、v1.0.1 のように新しい名前を付ける のが分かりやすい運用です。命名の考え方は既存記事「git tagとセマンティックバージョニング」を参照してください。
--force-with-leaseと--forceの違いを再現する
git commit --amend や git rebase で push 済みのコミットを書き換えると、通常の push は non-fast-forward になります。 このときに使うのが強制 push です。作業ブランチ feature/cart で、3つの状況を試しました。
状況A:自分だけが使うブランチでコミットを書き換えた
$ git commit --amend -m "cart: add cart page"
$ git push origin feature/cart
To /work/server.git
! [rejected] feature/cart -> feature/cart (non-fast-forward)
error: failed to push some refs to '/work/server.git'
...
$ git push --force-with-lease origin feature/cart
To /work/server.git
+ 10430ee...b57c742 feature/cart -> feature/cart (forced update)
リモートの先端が、手元の追跡ブランチ origin/feature/cart と同じ位置だったので、強制更新が通りました。
状況B:その間にHanakoがpushしていた
Hanako が同じブランチにテストを追加して push したあと、Taro が(fetch せずに)もう一度コミットを書き換えて強制 push します。
$ git push --force-with-lease origin feature/cart
To /work/server.git
! [rejected] feature/cart -> feature/cart (stale info)
error: failed to push some refs to '/work/server.git'
stale info は、「手元が覚えているリモートの位置と、実際のリモートの位置が違う」という意味 です。Hanako のコミットは残ったままです。
状況C:同じ場面で--forceを使うと
比較のため、サーバーのコピーに対して --force を実行しました。
$ git --git-dir=../server-copy.git log --oneline -3 feature/cart
13bf495 hanako: more tests
97cd66f hanako: add cart test
b57c742 cart: add cart page
$ git push --force ../server-copy.git feature/cart
To ../server-copy.git
+ 13bf495...5ed74d5 feature/cart -> feature/cart (forced update)
$ git --git-dir=../server-copy.git log --oneline -3 feature/cart
5ed74d5 cart: add cart page (v3)
b57c742 cart: add cart page
512bbbc first commit
Hanako の2つのコミットが、ブランチの履歴から見えなくなりました。同じ状況で元のサーバーに --force-with-lease を使った場合は、状況Bと同じく stale info で止まりました。
| オプション | 確認する内容 | 他の人のコミットがあるとき |
|---|---|---|
--force |
何も確認しない | そのまま上書きする |
--force-with-lease |
リモートの先端が、手元の追跡ブランチと同じか | stale info で止まる |
--force-with-lease --force-if-includes |
上に加えて、追跡ブランチの内容を手元に取り込み済みか | 取り込んでいなければ止まる |
fetchしたあとは--force-if-includesを足す
--force-with-lease は「追跡ブランチと同じか」を見るので、fetch して追跡ブランチだけが最新になると、取り込んでいなくても通ってしまいます。 --dry-run(実際には送らない確認モード)で試した結果です。
$ git fetch origin
b57c742..97cd66f feature/cart -> origin/feature/cart
$ git push --force-with-lease --dry-run origin feature/cart
To /work/server.git
+ 97cd66f...a77c6d7 feature/cart -> feature/cart (forced update)
$ git push --force-with-lease --force-if-includes --dry-run origin feature/cart
To /work/server.git
! [rejected] feature/cart -> feature/cart (remote ref updated since checkout)
error: failed to push some refs to '/work/server.git'
hint: Updates were rejected because the tip of the remote-tracking branch has
hint: been updated since the last checkout. If you want to integrate the
hint: remote changes, use 'git pull' before pushing again.
エディタや GUI ツールが裏で自動的に fetch している環境では、気づかないうちにこの状態になります。公式マニュアルにも、引数なしの --force-with-lease はバックグラウンドの fetch と相性に注意が必要だと書かれています。--force-if-includes を一緒に付けておくと、取り込み漏れに気づけます。
強制pushの安全な手順
# 1. リモートの最新を取得して、差分を確認する
git fetch origin
git log --oneline HEAD..origin/feature/cart # 自分に無いコミットがあれば表示される
# 2. 表示されたコミットがあれば取り込む
git rebase origin/feature/cart
# 3. 確認つきで強制 push する
git push --force-with-lease --force-if-includes origin feature/cart
毎回打つのが長いので、alias にしておくと使いやすくなります。
git config --global alias.pushf "push --force-with-lease --force-if-includes"
期待する位置を明示する書き方もあります。公式マニュアルで確認した3つの形式は次のとおりです。
| 形式 | 確認する内容 |
|---|---|
--force-with-lease |
push 対象すべてについて、追跡ブランチと同じ位置か |
--force-with-lease=<ブランチ> |
指定したブランチだけ、追跡ブランチと同じ位置か |
--force-with-lease=<ブランチ>:<期待値> |
指定したブランチが、明示したコミットと同じ位置か(最も厳密) |
強制pushを使う場面の判断表
| 状況 | おすすめの方法 |
|---|---|
| 自分だけが使う作業ブランチで、コミットを整理した | --force-with-lease --force-if-includes |
| 複数人が使うブランチで、直前のコミットを直したい | 書き換えずに、修正のコミットを追加する(git revert も選択肢) |
main などの共有ブランチ |
強制 push は使わず、通常の push か プルリクエストで反映する |
サーバーが [remote rejected] を返す |
ブランチ保護の設定を管理者に確認する |
最後の行は、サーバー側で書き換えを受け付けない設定(receive.denyNonFastForwards)にして再現しました。
$ git push --force-with-lease origin feature/cart
remote: error: denying non-fast-forward refs/heads/feature/cart (you should pull first)
To /work/server.git
! [remote rejected] feature/cart -> feature/cart (non-fast-forward)
error: failed to push some refs to '/work/server.git'
[rejected] は手元の Git の判断、[remote rejected] はサーバー側の判断 です。後者はオプションを変えても通らないので、設定やルールを確認します。GitHub などのブランチ保護も、同じくサーバー側で止める仕組みです。
エラーが出たときの確認チェックリスト
上から順に確認すると、ほとんどの場合は原因にたどり着けます。
| 順番 | 確認すること | コマンド |
|---|---|---|
| 1 | リモートの名前とURLは合っているか | git remote -v |
| 2 | 今いるブランチ名は何か | git branch --show-current |
| 3 | コミットは1つ以上あるか | git log --oneline -3 |
| 4 | 上流ブランチは設定されているか、何コミットずれているか | git status -sb |
| 5 | リモートに未取得のコミットはあるか | git fetch origin → git log --oneline HEAD..origin/main |
| 6 | 認証は通るか | git fetch origin、SSH なら ssh -T git@github.com |
| 7 | サーバー側のルール(ブランチ保護)はどうか | [remote rejected] の表示を確認 |
よくある質問
Q. originという名前は変えてもよいですか?
A. はい。origin は git clone が付ける既定の名前で、特別な機能はありません。git remote rename origin github のように変えると、追跡ブランチや上流設定も一緒に更新されます。チームで共有する手順書やスクリプトが origin を前提にしていることが多いので、そろえておくと説明が簡単になります。
Q. git remote removeを実行すると、GitHub上のリポジトリも消えますか?
A. 消えません。削除されるのは、手元の .git/config の登録と、origin/main などのリモート追跡ブランチだけです。同じURLで git remote add し直して git fetch すれば、元の状態に戻ります。
Q. rejectedが出たら、とりあえずgit pullでよいですか?
A. fetch first と non-fast-forward は、取り込めば解決します。git pull --rebase origin <ブランチ名> で取り込み、コンフリクトがあれば解消してから push し直してください。stale info や [remote rejected] は意味が違うので、この記事の対応表で原因を確認するのがおすすめです。
Q. --force-with-leaseを付ければ、共有ブランチでも強制pushしてよいですか?
A. 他の人のコミットを上書きしにくくなりますが、すでに pull した人の手元とは履歴がずれます。強制 push は自分だけが使う作業ブランチに限り、共有ブランチは修正コミットの追加や git revert で直すと、全員の作業がそのまま続けられます。
まとめ
- リモートの操作は
git remote -vで確認、addで追加、set-urlで変更、renameで改名、removeで削除。削除されるのは手元の登録だけ remote origin already existsはset-urlで差し替え、No such remoteは名前の確認で解決する- HTTPS⇔SSH の切り替えも
set-url。表示が変わらないときは insteadOf の読み替え設定を確認する (fetch first)と(non-fast-forward)は、git pull --rebaseで取り込んでから push し直すsrc refspec ... does not match anyはブランチ名の違いか、コミットが無い状態。has no upstream branchはgit push -u origin <ブランチ>で解決する- 強制 push は
--force-with-lease --force-if-includesを使うと、他の人のコミットがあるときにstale infoで止まってくれる [remote rejected]はサーバー側の判断。ブランチ保護などのルールを確認する
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「git remoteの変更・追加・削除とpush rejectedの対処法」
株式会社RJCでは、Gitのリモート操作やエラーの読み解き方を仲間と学び合っています。こうした知識を共有しながら、日々技術を磨いています。
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。