修正したコミットをリモートGitリポジトリにプッシュするにはどうすればよいですか?


662

ソースコードで少し作業した後、いつものことをコミットしてから、リモートリポジトリにプッシュしました。しかし、ソースコードでインポートを整理するのを忘れていることに気づきました。したがって、前のコミットを置き換えるamendコマンドを実行します。

> git commit --amend

残念ながら、コミットをリポジトリにプッシュバックすることはできません。次のように拒否されます。

> git push origin
To //my.remote.repo.com/stuff.git/
 ! [rejected]        master -> master (non-fast forward)
error: failed to push some refs to '//my.remote.repo.com/stuff.git/'

私は何をすべきか?(リモートリポジトリにアクセスできます。)


--amendがコミットメッセージを変更するだけだった場合はどうなりますか?最後のコミットメッセージを既にリモートにプッシュされている場合、それだけで編集する方法はありますか?私はGithubでそれを行い、非早送りについて同じメッセージを受け取りました。...そして、私は以下のソリューションを適用したが、マージはちょうどより上にコミットメッセージを追加

7
@faB:よくある質問だと思います。コミットメッセージはコミットとともにハッシュされるため、それを変更するとrevid(ハッシュ)が変更されます。明確でない場合は、できません。IIRCは、帯域外の情報をメモに保存できます(そのため、既存のコミットを変更せずに注釈を付けることができます)。特定のコミットにラベルを付けるには、タグを使用します
sehe

1
間もなく(git1.8.5、2013年第4四半期)git push -forceより慎重実行できるようになります
VonC

3
こちらがカウボーイスタイル。これ以上学んだり、以前のgit amendを元に戻す方法を模索したりしないでください。いくつかのプレースホルダーコードを追加する、つまり、コメントを追加する、コードを少しクリーンアップする、またはいくつかのダッシュダッシュダッシュを追加するだけです。次に、実際にコミットしてリモートにプッシュします。できました!
nehem 2015年

@ user58777 -amendがコミットメッセージを変更するだけで、それ以降にローカルコミットを行わなかった場合は、ローカルブランチを、コミットメッセージを修正する前にプッシュしたリモートコミットにリセットできます。
Scott Ahten、

回答:


504

私は実際にリポジトリを使用してプッシュし--force.gitLinus BIG TIMEに叱られました。一般的に、これは他の人々に多くの問題を引き起こします。簡単な答えは「それをしないでください」です。

とにかく、他の人がそうするためのレシピを与えたので、ここではそれらを繰り返しません。ただし、修正したコミットを--force(または+ master)でプッシュしたの状況から回復するためのヒントを次に示します。

  1. を使用git reflogして、修正した古いコミットを見つけます(これoldをと呼びますnew。修正によって作成した新しいコミットを呼び出します)。
  2. 間のマージを作成oldしてnew、ツリー記録newなどを、git checkout new && git merge -s ours old
  3. それをマスターにマージします git merge master
  4. マスターを結果で更新する git push . HEAD:master
  5. 結果を押し出します。

その後、コミットあなたはプッシュを改正し、強制的に抹殺に自分の仕事をベースとしているために不幸に十分だった人は、結果のマージは、あなたが好むことがわかりますでしょうnew超えますold。彼らの後にマージは、間の競合は表示されませんoldnew、彼らが苦しむする必要はありませんので、あなたの改正によるものです。


17
私は、修正されたコミットを(履歴を破壊することによって)強制的にプッシュするとどうなるかをよく知っています。幸いなことに、リモートリポジトリがネットワークドライブ上にあるプロジェクトの開発者は私しかいなかったので、それほど大きな問題ではありませんでした。私は修正コミットをマージすることを考えたことがないので、これを賛成します。
スポーク09年

62
当社では、非常に定期的に、個人が開発した機能ブランチを強制的にプッシュします。
OndraŽižka12年

2
Linusから叱責されたのは、強制オプションを使用して履歴を消去したからではなく、行うべきではないからです。GabrielleVのソリューションは履歴を変更しないため、問題なく機能します。
user411279 2013年

2
この回答の作成者(gitster)はもう存在しないようですので、アイテム番号1を明確にするために誰かが助けてください:古いコミットを見つけてください。バックアップがない場合、どこにありますか?修正して強制的に押しても破壊されないでしょうか?たぶん、彼はツリーにまだそれを持っている友人/協力者からそれを取得することを言及していますか?
Beco博士、2016年

2
git reflogそれを見つけるために使用できるブレコ博士
Simon Zyx

269

Gitの安全機能が表示されています。ブランチのヘッドコミットは、プッシュするブランチの現在のヘッドコミットの直接の子孫ではないため、Gitはリモートブランチをブランチで更新することを拒否します。

これが当てはまらない場合、2人のユーザーがほぼ同時に同じリポジトリにプッシュすると、同時に新しいコミットが発生したことを認識できず、最後にプッシュした人はいずれもせずに前のプッシャーの作業を失います。彼らはこれを実現しています。

自分だけがプッシュしていることがわかっていて、修正されたコミットをプッシュするか、ブランチを巻き戻すコミットをプッシュしたい場合は、-fスイッチを使用してGitにリモートブランチを強制的に更新できます。

git push -f origin master

Gitではリモートリポジトリが構成変数を使用して遠端で非早送りプッシュを拒否できるため、これでも機能しない場合がありますreceive.denynonfastforwards。この場合、拒否の理由は次のようになります(「リモート拒否」の部分に注意してください):

 ! [remote rejected] master -> master (non-fast forward)

これを回避するには、リモートリポジトリの設定を変更するか、ダーティハックとしてブランチを削除して再作成する必要があります。

git push origin :master
git push origin master

一般的に、最後のパラメーターgit pushは形式を使用します<local_ref>:<remote_ref>。ここlocal_refで、はローカルリポジトリremote_refのブランチの名前で、はリモートリポジトリのブランチの名前です。このコマンドペアは2つの省略形を使用します。:masternull local_refがあるので、nullブランチがリモート側masterにプッシュされます。つまり、リモートブランチが削除されます。ブランチ名がない場合:、指定された名前のローカルブランチが同じ名前のリモートブランチにプッシュされます。masterこの状況ではの略ですmaster:master


2
これはgithubでは機能しませんでした。次のメッセージが表示されました:[リモート拒否]マスター(現在のブランチの削除は禁止されています)
vedang

強制的にプッシュしたくなかった(これで問題が解決することはわかっていた)が、今は仕方がないと思う。
vedang

1
これは、assemblaでホストされている私のリポジトリで機能した唯一のソリューションです。
ジャスティン

1
リモートマスターブランチを削除すると、リモートリポジトリのスペースが解放されますか?
Mr_and_Mrs_D 2012

1
@Mr_and_Mrs_D:すぐではありませんがgit gc、reflogが期限切れになると、古いオブジェクトが削除されます。リポジトリを複製する人は、ブランチが更新されるとすぐに到達できなくなったオブジェクトを取得しません。
CBベイリー

211

簡単な発言:誰も簡単な答えをここに投稿していないという事実は、Git CLIによって示される絶望的なユーザーの敵意を示しています。

とにかく、これを行う「明白な」方法は、あなたがプッシュを強制しようとしなかったと仮定すると、最初にプルすることです。これにより、修正された(したがって、修正されていない)変更がプルされ、再びそれが得られます。

競合を解決したら、もう一度プッシュできます。

そう:

git pull

プルでエラーが発生する場合は、ローカルリポジトリの構成に問題がある可能性があります(.git / configブランチセクションに間違った参照がありました)。

以降

git push

たぶん、あなたは件名が "Trivial merge"であることを告げる追加のコミットを取得するでしょう。


2
はい、私はこれについて書いた、参照stackoverflow.com/questions/253055/...を ;)
Spoike

10
これは私が期待したようには実際には機能しません。2つの新しいコミットが作成されます。古いもののレプリカですが、変更が変更されています。そして、1つのマージコミットは空の差分で行われます。古いコミットを変更せずに残し、私が修正しようとしていた機密データを明らかにしました。私は信じているgit push -fか、git resetここに行くための唯一の方法です。
2013年

40
技術的には問題に答えていますが、実際には問題を解決していません。あなたが言ったように、それは追加のコミットを生成しますが、人々がコミットを修正する主な理由は、新しいものを作成しないようにすることです。したがって、ポスターがあなたの指示に従った場合、彼は望ましい結果を得ることができません。そもそもコミットを修正しないのと同じくらい意味があります。
Dan Jones

102

短い答え:修正されたコミットを公開リポジトリにプッシュしないでください。

長い答え:git commit --amendandのようないくつかのGitコマンドgit rebaseは実際に履歴グラフを書き換えます。これは、変更を公開していない限り問題ありませんが、一度公開したら、履歴をいじってはいけません。誰かが既に変更を取得している場合、そのユーザーが再度プルしようとすると失敗する可能性があるためです。 。コミットを修正する代わりに、変更を加えた新しいコミットを作成するだけです。

ただし、修正したコミットを本当にプッシュしたい場合は、次のように実行できます。

$ git push origin +master:master

先頭の+記号は、「早送り」コミットが発生しない場合でも、プッシュを発生させます。(早送りコミットは、プッシュしている変更がすでにパブリックリポジトリにある変更の直接の子孫である場合に発生します。)


5
これはgit push -fとどのように異なる(良いまたは悪い)か。ありがとう!
ベントフォード

11
@bentford:基本的にはと同じですgit push -f
mipadi

54

すでにを作成した後、変更をプッシュする非常にシンプルでクリーンな方法を次に示しますcommit --amend

git reset --soft HEAD^
git stash
git push -f origin master
git stash pop
git commit -a
git push origin master

これは次のことを行います。

  • ブランチヘッドを親コミットにリセットします。
  • この最後のコミットを隠しておきます。
  • リモートへのプッシュを強制します。リモートは今、最後のコミットを持っていません。
  • あなたの隠し場所をポップします。
  • きれいにコミットします。
  • リモートにプッシュします。

これを別のブランチまたはリモートに適用する場合は、「origin」と「master」を必ず変更してください。


3
2備考:-別のブランチで作業している場合は、ブランチの名前を必ず変更してください- git add変更を含めるには、コミット前に使用する必要がありました。
SylvainB 2017

1
Windows CMDでは、最初のコマンドはエスケープする必要があります:git reset --soft "HEAD^"。残りは問題なく動作します。
MrMister

2
「非常にシンプルでクリーンな方法。」cit。この手順には、強制プッシュが含まれます。上記の回答のすべての批評に照らして、この手順が実際にクリーンな手順であるかどうかはわかりません。
Na13-c

24

私はローカルで修正されたコミットを破棄し、新しい変更を上に追加することでそれを解決しました:

# Rewind to commit before conflicting
git reset --soft HEAD~1

# Pull the remote version
git pull

# Add the new commit on top
git add ...
git commit
git push

2
これは最も単純なバージョンです!
mknaf

別の「変更」コミットを追加することは、履歴を書き換えることよりも優れています。@mknafに同意します
sdkks 2018

8

私も同じ問題を抱えていました。

  • すでにプッシュされた最後のコミットを誤って修正した
  • ローカルで多くの変更を行い、約5回コミットしました
  • プッシュしようとした、エラーが発生した、パニックが発生した、リモートがマージされた、多くの非マイファイルを取得した、プッシュされた、失敗した、など

Gitの初心者として、完全なFUBARだと思いました

解決策:@baraとやや似ている+ローカルバックアップブランチを作成

# Rewind to commit just before the pushed-and-amended one.
# Replace <hash> with the needed hash.
# --soft means: leave all the changes there, so nothing is lost.
git reset --soft <hash>

# Create new branch, just for a backup, still having all changes in it.
# The branch was feature/1234, new one - feature/1234-gone-bad
git checkout -b feature/1234-gone-bad

# Commit all the changes (all the mess) not to lose it & not to carry around
git commit -a -m "feature/1234 backup"

# Switch back to the original branch
git checkout feature/1234

# Pull the from remote (named 'origin'), thus 'repairing' our main problem
git pull origin/feature/1234

# Now you have a clean-and-non-diverged branch and a backup of the local changes.
# Check the needed files from the backup branch
git checkout feature/1234-gone-bad -- the/path/to/file.php

多分それは速くてきれいな解決策ではなく、私の履歴を失いました(5ではなく1コミット)、しかしそれは1日の仕事を節約しました。


6

コードをリモートブランチ(GitHub / Bitbucket)にプッシュしていない場合は、コマンドラインでコミットメッセージを次のように変更できます。

 git commit --amend -m "Your new message"

特定のブランチで作業している場合は、次のようにします。

git commit --amend -m "BRANCH-NAME: new message"

間違ったメッセージでコードをすでにプッシュしている場合は、メッセージを変更するときに注意する必要があります。つまり、コミットメッセージを変更してもう一度プッシュしようとすると、問題が発生します。スムーズにするには、次の手順に従ってください。

それを行う前に、答え全体を読んでください

git commit --amend -m "BRANCH-NAME : your new message"

git push -f origin BRANCH-NAME                # Not a best practice. Read below why?

重要な注意:強制プッシュを直接使用すると、他の開発者が同じブランチで作業しているコードの問題が発生する可能性があります。したがって、これらの競合を回避するには、強制プッシュを行う前にブランチからコードをプルする必要があります。

 git commit --amend -m "BRANCH-NAME : your new message"
 git pull origin BRANCH-NAME
 git push -f origin BRANCH-NAME

これは、すでにプッシュされている場合にコミットメッセージを変更するときのベストプラクティスです。


1
最後の例でコミットを正常にプルバックした場合、なぜプッシュを強制する必要があるのですか?標準的なプッシュで十分ではないでしょうか?ありがとう
Thomas

トーマスが尋ねた質問は実際には非常に有効です。私はプルに続いてプッシュを強制する必要はありませんでした。
Na13-c

回避策があるので、「ベストプラクティス」と呼ばない--forceでください。承認された回答を参照してください
Farid

5

修正されていないコミットを誰もプルしていないことがわかっている場合は、の--force-with-leaseオプションを使用してくださいgit push

TortoiseGitでは、「プッシュ...」オプション「強制:破棄する可能性があります」と「既知の変更」をチェックして同じことを行うことができます。

Force(既知の変更を破棄する場合があります)では、リモートリポジトリがより安全な非早送りプッシュを受け入れることができます。これにより、リモートリポジトリのコミットが失われる可能性があります。注意して使用してください。これにより、リモートの他のユーザーからの不明な変更が失われるのを防ぐことができます。サーバーブランチがリモートトラッキングブランチと同じコミットを指しているかどうかを確認します(既知の変更)。はいの場合、強制プッシュが実行されます。それ以外の場合は拒否されます。gitにはリモート追跡タグがないため、このオプションを使用してタグを上書きすることはできません。


4

Gitリモートには既にこれらのコミットファイルがあるため、このエラーが発生します。これを機能させるには、ブランチを強制的にプッシュする必要があります。

git push -f origin branch_name

また、チームの他の誰かが同じブランチにプッシュした可能性があるので、リモートからコードをプルしてください。

git pull origin branch_name

これは、コミットをリモートに強制的にプッシュする必要がある場合の1つです。


この回答が以前の回答で挙げられた主要なコメントを説明していないのはなぜですか
Na13-c

2

ここでは、すでに行った後に変更をプッシュするための非常にシンプルかつクリーンな方法であるgit add "your files"とはgit commit --amend

git push origin master -f

または:

git push origin master --force

それは悪いと聞いていますが、それは間違いないと思います。gitがデフォルトで失敗する(そして--forceが必要になる)には(良い)理由があります。
Rolf

1

私はリモートリポジトリからプルすることでこの問題を修正し、発生したマージの競合に対処し、コミットしてからプッシュする必要がありました。しかし、もっと良い方法があるように感じます。


あんまり。リモートリポジトリからローカルコピーを更新していないことが問題である可能性があります。マージを手動で処理する必要がある場合があるため、Gitはプッシュしません。私の他の返信では、プッシュを強制するコマンド(および説明)がありますが、リモートの変更が削除される可能性があることに注意してください。
mipadi 2008年

1

私はGitに指示されたことをそのまま実行し続けました。そう:

  • 修正されたコミットのためにプッシュできません。
  • 提案されたようにプルを行います。
  • マージは失敗します。手動で修正します。
  • 新しいコミット(「merge」というラベルが付いている)を作成してプッシュします。
  • 動いているようです!

注:修正されたコミットは最新のものです。


1
もっと評判が良ければ、反対票を投じるので、ここで丁寧に質問します。どちらがあなたが被害者であったのですか?修正した人?コミットを修正してブランチをプルして作業した人?改正の前か、それとも後か。私はあなたを誤解したので、私はすべての変更をクリアしました...幸い、それほど多くはありませんでした...
BartisÁron

1

コミットの作成者とコミッターを変更すると、次のことがうまくいきました。

git push -f origin master

Gitは、これらがメタ情報セクションのみが異なる同一のデルタのコミットであることを理解するのに十分スマートでした。

ローカルヘッドとリモートヘッドの両方が問題のコミットを指摘しました。



0

ここでは、以前のコミットで編集を修正した方法:

  1. これまでの作業を保存します。
  2. 今のところ、変更を隠しておく:git stash最後のコミットの状態では、作業コピーはクリーンです。
  3. 編集と修正を行います。
  4. 「修正」モードで変更をコミットします。git commit --all --amend
  5. エディターがログメッセージ(デフォルトでは古いログメッセージ)を要求します。エディターに問題がなければ、保存して終了します。

    新しい変更が古いコミットに追加されます。自分自身を参照してくださいgit loggit diff HEAD^

  6. 隠しておいた変更を再適用します(行われた場合)。 git stash apply

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.