チームメイトの1人が、いくつかのコミットをメインの開発ブランチに誤ってプッシュしました。私たちは小さな共同チームです。私たちのリモートリポジトリは、内部サーバーでホストされています。
これがコミットログの先頭です(これらのコミットはすべてすでにプッシュされています)。
$ git log develop -6 --pretty=oneline --abbrev-commit
faada93 Merge branch 'develop' of <our_repo_path>.git
244d174 Support classes again
a97a877 Pruned all unused references (again).
8c29252 Merge branch 'develop' of <our_repo_path>.git
a78b993 Support models & methods - product types & categories
da8b496 Resolved JIRA issue PPF-182
da8b496
はdevelop
ブランチに残したい最後のコミットなので、最後の5つのコミットを元に戻す必要がありました。 「機能ブランチ」で作業を続けるために、8c29252
から新しいブランチを作成しました。
私は この答え と このLinusからの投稿 に導かれて多くのことを試しましたが、最終的には以下のターミナル履歴で確認できることを行いました。しかし、私がやったことが「正しい方法」であるかどうかはわかりません。私が見つけた情報は複雑でした。この特定の問題に対する「最善の解決策」を見分けることができませんでした。
私が選択したアプローチ(詳細は以下を参照)は、履歴を損なうことなく、これらの5つのコミットを元に戻す良い方法でしたか?同じことを達成するためのより簡単なまたは「より正しい」方法はありますか?
とりわけ、da8b496
(git checkout -b new-develop da8b496
)から新しいブランチを作成して、現在のdevelop
ブランチを破棄することを検討しましたが、それは正しくありませんでした。
最初に、コミットa78b993
と8c29252
の新しいブランチを作成しました。これらのコミットには保持したい作業が含まれ、最終的にメインの開発ブランチにマージされます。
$ git checkout -b new-feature-brach 8c29252
その後、開発ブランチで問題のコミットを元に戻しました。
私は最初にこれを試しましたが、うまくいきませんでした(コミットの一部がマージである可能性が高いため)
$ git revert a78b993..HEAD
error: a cherry-pick or revert is already in progress
hint: try "git cherry-pick (--continue | --quit | --abort)"
fatal: revert failed
だから…代わりに各コミットを手動で元に戻しました。一つずつ:
$ git revert -m 1 faada93
[develop 40965a5] Revert "Merge branch 'develop' of <our_repo_path>.git"
8 files changed, 167 insertions(+), 3 deletions(-)
$ git revert 244d174
[develop 3cebd68] Revert "Support classes again"
45 files changed, 557 insertions(+), 1572 deletions(-)
(list of affected files)
$ git revert a97a877
error: could not revert a97a877... Pruned all unused references (again).
hint: after resolving the conflicts, mark the corrected paths
hint: with 'git add <paths>' or 'git rm <paths>'
hint: and commit the result with 'git commit'
$ git mergetool
Merging:
exampleFile1.cs
exampleFile2.cs
Deleted merge conflict for 'exampleFile1.cs':
{local}: deleted
{remote}: modified file
Use (m)odified or (d)eleted file, or (a)bort? m
Deleted merge conflict for 'exampleFile2.cs':
{local}: deleted
{remote}: modified file
Use (m)odified or (d)eleted file, or (a)bort? m
$ git commit -m "Adding files to be reverted along with the next commit."
[develop 15bc02b] Adding files to be able to revert the next commit in line.
2 files changed, 239 insertions(+)
(list of affected files here)
$ git revert -m 1 8c29252
# On branch develop
# Your branch is ahead of 'Origin/develop' by 3 commits.
# (use "git Push" to publish your local commits)
#
# Untracked files:
# (use "git add <file>..." to include in what will be committed)
#
# exampleFile1.cs.orig
# exampleFile2.cs.orig
nothing added to commit but untracked files present (use "git add" to track)
$ git revert a78b993
[develop 841e77c] Revert "Support models & methods - product types & categories"
2 files changed, 239 deletions(-)
(list of affected files here)
すべての復元が完了した後、ログをコミットします。
$ git log develop -10 --pretty=oneline --abbrev-commit
841e77c Revert "Support models & methods - product types & categories"
15bc02b Adding files to be able to revert the next commit in line.
3cebd68 Revert "Support classes again"
40965a5 Revert "Merge branch 'develop' of <our_repo_path>.git"
faada93 Merge branch 'develop' of <our_repo_path>.git
244d174 Support classes again
a97a877 Pruned all unused references (again).
8c29252 Merge branch 'develop' of <our_repo_path>.git
a78b993 Support models & methods - product types & categories
da8b496 Resolved JIRA issue PPF-182
復帰後のグラフ:
$ git log --graph --oneline -8 develop
* 841e77c Revert "Support models & methods - product types & categories"
* 15bc02b Adding files to be able to revert the next commit in line.
* 3cebd68 Revert "Support classes again"
* 40965a5 Revert "Merge branch 'develop' of <our_repo_path>.git"
* faada93 Merge branch 'develop' of <our_repo_path>.git
|\
| * a97a877 Pruned all unused references (again).
| * 8c29252 Merge branch 'develop' of <our_repo_path>.git
| |\
| | * da8b496 Resolved JIRA issue PPF-182
私には正しいようです。最後に、保持したくないバックアップファイルをいくつか削除します。
$ git clean -fd
(list of affected files here)
現在のステータスはクリーンです:
$ git status
# On branch develop
# Your branch is ahead of 'Origin/develop' by 4 commits.
# (use "git Push" to publish your local commits)
#
nothing to commit, working directory clean
次に、すべてをリモートにプッシュします。
git Push Origin develop
同じ場所に配置された小さなチームがあるので、コミュニケーションは問題ではありません。見たとおりにコミット履歴を表示します。
git branch -f develop dab4896
git branch newfeature 8c29252
git Push -f Origin develop newfeature
全員に再フェッチしてもらいます。完了です。
このような間違いは、書き直す理由の1つです。
履歴が変わっても、ブランチを作成して前に戻って実験することができます。 Gitは、「あなたが持っているべきである」と決して言う必要がないことを意味します。 あなたがより好きな現実に収束するなら、それを続けてください。そうでなければ、それを捨てます。
以下の例では、リポジトリ内の他のすべてをそのままにする新しいブランチを作成します。
最初に、冒険を開始した時点でスクラッチブランチを作成します。
$ git checkout -b tmp-revert faada93
コミット範囲を指定すると、 git revert
は複数のコミットを取り消します。
$ git revert da8b496..faada93
スコットチャコンによる Pro Git の第2版の Git Internals — Git Objects 、セクション10.2の図を検討してください。ベン・ストラウブ。最上位のコミット(「3番目のコミット」)には、1a410e
で始まるSHA1ハッシュがあります。この履歴のコンテキストでは、1a410e^{tree}
は3c4e9c
に解決されます。つまり、3番目のコミットの右側にあるツリーオブジェクトがすぐに解決されます。
図151 from Pro Git 、第2版.
このモデルを調べて、gitがcontentを追跡する方法を理解します。ツリーが2番目のコミットと同じである4番目の新しいコミット(つまり、0155eb
)を作成すると、新しいコミットオブジェクトが追加され、shareまたは「ポイント」新しい重複オブジェクトを追加するのではなく、既存のツリーとブロブ。
git commit-tree
を使用してこの低レベルのスティッチングを実行する方法を学ぶために読んでください。
作業する別の一時的なブランチを作成することから始めます。
$ git checkout -b tmp-ctree faada93
この時点で、ツリー(つまり、コミットされたコード)が、保持したい最後のコミットであるda8b496
のツリーと同一である新しいコミットを作成します。このツリーは、git:da8b496^{tree}
で直接アドレス指定できます。
git commit-tree
は、「磁器」ではなく、gitの低レベルコマンドである「配管」です。使いづらい、または使い慣れていないように感じるかもしれませんが、この場合、必要な結果を正確に制御できます。
ツリーがda8b496
と同じであり、親(-p
)が現在のブランチの先端であるfaada93
である、アタッチされていない新しいコミットを作成します。 git commit-tree
は、以下のコマンドがecho
コマンドで提供する標準入力の新しいコミットのコミットメッセージを読み取ることに注意してください。
$ echo da8b496に戻す|\ git commit-tree da8b496 ^ {tree} -p $(git rev-parse tmp-ctree) new-commit-sha1
上記の斜体部分はコマンドの一部ではありません。これは、git commit-tree
が新しく作成されたコミットのSHA1ハッシュを出力することを示しています。新しいコミットのSHA1がわかっているため、ブランチをそのポイントに移動できます。例:、
$ gitマージ new-commit-sha1
上記のコマンドで、new-commit-sha1をgit commit-tree
からの出力に置き換えます。 (同じことをgit reset --hard new-commit-sha1
で行うこともできますが、ハードリセットは鋭いツールであり、カジュアルな使用は避けた方がよいでしょう。)
上記のすべてを1つの複合コマンドにまとめることができます。
$ git merge --ff-only $(echo Revert back to da8b496 |\ git commit-tree da8b496 ^ {tree} -p $(git rev-parse tmp-ctree))
--ff-only
の- git merge
への切り替えは、予期しない事態を防ぐためのものです。あなたの意図は、新しいコミットが現在のブランチヘッドの早送りまたは子孫になることです。実際、その直接の子です!
上の一時的なブランチを削除するには、別のブランチに切り替えて、McManus氏を解雇します。あなたの他のブランチはあなたがそれらを残したのと同じようになります。
$ git checkout develop $ git branch -D tmp-revert tmp-ctree
あなたが確認できるように、2つは同一でなければなりません
$ git diff tmp-revert tmp-ctree
保持するには、それをdevelop
ブランチにマージします。
$ git checkout develop $ git merge --ff-only tmp-ctree $ git Push Origin develop
これはこの回答の複製と見なすことができることをお勧めします: 現在のgitブランチをマスターブランチにする
Jefromiの優れたソリューションは次のとおりです。
[git branch better_branch <last good commit>]
git checkout better_branch
git merge --strategy=ours master # keep the content of this branch, but record a merge
git checkout master
git merge better_branch # fast-forward master up to the merge
あなたがしようとしていることは非常に危険です。
実際、すでにリポジトリにプッシュしたコミットを元に戻して削除できますが、誰かがすでに変更をプルしていて、削除しようとしているcommitIdを持っている場合、リポジトリは「不安定」になり、gitは次のことができなくなります履歴から削除されたコミットを削除したため、プルとプッシュを処理します。
これを行う(commitを元に戻して削除する)のは、誰もまだこのcommitをプルしていない場合に限ります。