質問
gitリベースを簡単に元に戻す方法を知っている人はいますか?
思いつく唯一の方法は、手動で実行することです。
- git checkout 両方のブランチの親をコミットします
- そこから一時ブランチを作成します
- すべてのコミットを手動でチェリーピックする
- リベースしたブランチを手動で作成したブランチに置き換えます
私の現在の状況では、両方のブランチからのコミットを簡単に見つけることができるので、これはうまくいきます(1つは私のもので、もう1つは同僚のものでした)。
ただし、私のアプローチは最適ではなく、エラーが発生しやすいように思えます (自分のブランチ 2 つをリベースしたばかりだとします)。
何か案は?
説明:私は、大量のコミットが再実行されるリベースについて話しています。一つだけではありません。
解決
最も簡単な方法は、リベースが開始される直前のブランチのヘッド コミットを見つけることです。 レフログ...
git reflog
そして、現在のブランチをそこにリセットします (リセットする前に絶対に確実であることについての通常の注意事項があります) --hard
オプション)。
古いコミットが HEAD@{5}
参照ログ内:
git reset --hard HEAD@{5}
Windows では、参照を引用する必要がある場合があります。
git reset --hard "HEAD@{5}"
を実行するだけで、旧ヘッド候補の履歴を確認できます。 git log HEAD@{5}
(ウィンドウズ: git log "HEAD@{5}"
).
ブランチごとの reflog を無効にしていない場合は、次のようにするだけで済みます。 git reflog branchname@{1}
リベースでは、最終ヘッドに再アタッチする前にブランチ ヘッドがデタッチされるためです。最近確認していないので再度確認してみます。
デフォルトでは、すべての reflog が非ベア リポジトリに対してアクティブ化されます。
[core]
logAllRefUpdates = true
他のヒント
実際、リベースにより開始点が保存されます。 ORIG_HEAD
したがって、これは通常次のように単純です。
git reset --hard ORIG_HEAD
しかし reset
, rebase
そして merge
すべてオリジナルを保存してください HEAD
へのポインタ ORIG_HEAD
したがって、リベース以降にこれらのコマンドのいずれかを実行して元に戻そうとしている場合は、reflog を使用する必要があります。
Charles の答えは機能しますが、次のようにすることもできます。
git rebase --abort
後片付けをする reset
.
そうしないと、「Interactive rebase already started
”.
git reflog
リベース前後のすべての変更が表示され、リセットする適切な変更を見つけることができます。しかし、ここでこの他の超簡単な方法についてまだ誰も言及していないことに私は驚きました。
リベースでは古い状態がそのまま残ります ORIG_HEAD
, したがって、次を実行することで最後のリベースを元に戻すことができます。
git reset --hard ORIG_HEAD
もちろん、ブランチを古いチップのダングリングコミットオブジェクトにリセットするのが最善の解決策です。これにより、労力を費やすことなく以前の状態が復元されます。しかし、それらのコミットをたまたま紛失してしまった場合 (f.ex.その間にリポジトリをガベージ コレクションしたため、またはこれが新しいクローンであるため)、いつでもブランチを再度リベースできます。この鍵となるのは、 --onto
スイッチ。
想像的に次のようなトピック ブランチがあるとします。 topic
, 、分岐したこと master
の先端のとき master
でした 0deadbeef
専念。ある時点で topic
支店、やったね git rebase master
. 。ここで、これを元に戻したいとします。その方法は次のとおりです。
git rebase --onto 0deadbeef master topic
これにより、すべてのコミットが取得されます topic
オンになっていないもの master
そしてそれらを上に再生します 0deadbeef
.
と --onto
, 、自分の歴史をかなり並べ替えることができます どんな形でも.
楽しむ。:-)
実際、重要な操作を実行する前に、ブランチにバックアップ タグを置きます (ほとんどのリベースは簡単ですが、複雑に見える場合はそうします)。
その後、復元は次のように簡単です git reset --hard BACKUP
.
万一に備えて ブランチをリモート リポジトリにプッシュしました (通常はオリジンです)そして、(マージなしで)リベースが成功しました(git rebase --abort
「進行中のリベースはありません」と表示されます) ブランチをリセットする コマンドの使用:
git restart --hardorigin/{ブランチ名}
例:
$ ~/work/projects/{ProjectName} $ git status
On branch {branchName}
Your branch is ahead of 'origin/{branchName}' by 135 commits.
(use "git push" to publish your local commits)
nothing to commit, working directory clean
$ ~/work/projects/{ProjectName} $ git reset --hard origin/{branchName}
HEAD is now at 6df5719 "Commit message".
$ ~/work/projects/{ProjectName} $ git status
On branch {branchName}
Your branch is up-to-date with 'origin/{branchName}.
nothing to commit, working directory clean
リベースが完了しておらず、リベースの途中である場合は、次のように機能します。
git rebase --abort
使用する reflog
私にはうまくいきませんでした。
私にとってうまくいったのは説明と同様でした ここ. 。リベースされたブランチにちなんで名付けられた .git/logs/refs 内のファイルを開き、次のような「rebase finsihed」を含む行を見つけます。
5fce6b51 88552c8f Kris Leech <me@example.com> 1329744625 +0000 rebase finished: refs/heads/integrate onto 9e460878
その行にリストされている 2 番目のコミットをチェックアウトします。
git checkout 88552c8f
これに失われた変更が含まれていることを確認すると、分岐して安堵のため息をつきました。
git log
git checkout -b lost_changes
複数のコミットの場合、どのコミットもそのコミットに至るまでのすべての履歴を参照することに注意してください。したがって、Charles の答えでは、「古いコミット」を「古いコミットの最新のもの」と読み替えてください。そのコミットにリセットすると、そのコミットに至るまでのすべての履歴が再び表示されます。これで希望通りのことができるはずです。
@Allan と @Zearin の解決策に従って、単純にコメントできればよかったのですが、十分な評判がないので、次のコマンドを使用しました。
する代わりに git rebase -i --abort
(注意してください -私)私はただそうする必要がありました git rebase --abort
(それなし の -私).
両方を使用する -i
そして --abort
同時に、Git に使用方法/オプションのリストが表示されます。
したがって、このソリューションでの以前と現在のブランチのステータスは次のとおりです。
matbhz@myPc /my/project/environment (branch-123|REBASE-i)
$ git rebase --abort
matbhz@myPc /my/project/environment (branch-123)
$
リモート ブランチに対して正常にリベースできたが、それができない場合 git rebase --abort
作業内容を保存したり、強制的なプッシュを避けるためにいくつかのトリックを実行することはできます。誤ってリベースされた現在のブランチが次の名前であるとします。 your-branch
そして追跡しています origin/your-branch
git branch -m your-branch-rebased
# 現在のブランチの名前を変更しますgit checkout origin/your-branch
# オリジンが認識している最新の状態にチェックアウトしますgit checkout -b your-branch
- チェック
git log your-branch-rebased
, 、と比較してくださいgit log your-branch
欠落しているコミットを定義しますyour-branch
git cherry-pick COMMIT_HASH
コミットごとにyour-branch-rebased
- 変更をプッシュします。2 つのローカル支店が関連付けられていることに注意してください。
remote/your-branch
そしてあなたはプッシュするだけでいいですyour-branch
master を自分の feature ブランチにリベースし、何かを壊す新しいコミットが 30 個得られたとします。多くの場合、不正なコミットを削除するのが最も簡単であることがわかりました。
git rebase -i HEAD~31
最新の 31 コミットの対話型リベース (選択しすぎても問題ありません)。
削除したいコミットを選択し、「pick」の代わりに「d」でマークを付けるだけです。これで、コミットが削除され、事実上リベースが取り消されます (リベース時に取得したばかりのコミットのみを削除した場合)。
ブランチにいる場合は、以下を使用できます。
git reset --hard @{1}
HEAD の参照ログだけが存在するわけではありません(によって取得されます) git reflog
)、各ブランチの reflog もあります (次によって取得されます)。 git reflog <branch>
)。それで、あなたがオンの場合は、 master
それから git reflog master
そのブランチに対するすべての変更をリストします。変更内容を参照できます。 master@{1}
, master@{2}
, 、など。
git rebase
通常、HEAD は複数回変更されますが、現在のブランチは 1 回だけ更新されます。
@{1}
は単に 現在のブランチのショートカット, したがって、次と等しいです。 master@{1}
あなたがオンなら master
.
git reset --hard ORIG_HEAD
使用した場合は機能しません git reset
インタラクティブ中に rebase
.
初心者やハード リセットを行うのが怖い人は、reflog からコミットをチェックアウトして、新しいブランチとして保存できます。
git reflog
リベースを開始する直前のコミットを見つけます。見つけるには、さらに下にスクロールする必要がある場合があります (Enter キーまたは PageDown キーを押します)。HEAD 番号をメモし、57 を置き換えます。
git checkout HEAD@{57}
ブランチ/コミットを確認し、問題がないようであれば、この HEAD を使用して新しいブランチを作成します。
git checkout -b new_branch_name
git restart --hardorigin/{ブランチ名}
これは、リベースによって行われたすべてのローカル変更をリセットするための正しい解決策です。
私が普段やっていることは、git reset #commit_hash
リベースが効果がなかったと思われる最後のコミットまで。
それから git pull
これで、ブランチはマスターと完全に一致し、リベースされたコミットがブランチ内に存在しないはずです。
これで、このブランチ上のコミットを厳選することができます。
git rebase 内で何かを台無しにした場合、たとえば git rebase --abort
, コミットされていないファイルがある間は、それらは失われ、 git reflog
役に立ちません。これは私に起こったことであり、ここでは既成概念にとらわれずに考える必要があります。私のように幸運で IntelliJ Webstorm を使用している場合は、次のことができます。 right-click->local history
また、バージョン管理ソフトウェアでどんな間違いを犯したとしても、ファイル/フォルダーを以前の状態に戻すことができます。別のフェールセーフを実行しておくことは常に良いことです。