5861

マスターにコミットした最後のいくつかのコミットを新しいブランチに移動し、それらのコミットが行われる前にマスターを元に戻したいと思います。残念ながら、私のGit-fuはまだ十分に強力ではありません、何か助けはありますか?

つまり、どうすればこれから行くことができますか

master A - B - C - D - E

これに?

newbranch     C - D - E
             /
master A - B 
4

20 に答える 20

7592

既存のブランチに移動する

コミットを既存のブランチに移動する場合は、次のようになります。

git checkout existingbranch
git merge master
git checkout master
git reset --hard HEAD~3 # Go back 3 commits. You *will* lose uncommitted work.
git checkout existingbranch

を使用して、これを行う前に、コミットされていない編集をスタッシュに保存できますgit stash。完了すると、隠されたコミットされていない編集を次のように取得できます。git stash pop

新しい支店に移動する

警告:このメソッドは、最初のコマンドで新しいブランチを作成しているために機能します:git branch newbranch。コミットを既存のブランチに移動する場合は、実行する前に変更を既存のブランチにマージする必要がありますgit reset --hard HEAD~3(上記の既存のブランチへの移動を参照)。最初に変更をマージしないと、変更は失われます。

他の状況が関係しない限り、これは分岐してロールバックすることで簡単に実行できます。

# Note: Any changes not committed will be lost.
git branch newbranch      # Create a new branch, saving the desired commits
git reset --hard HEAD~3   # Move master back by 3 commits (Make sure you know how many commits you need to go back)
git checkout newbranch    # Go to the new branch that still has the desired commits

ただし、戻るコミットの数を確認してください。または、代わりに、マスター(/現在)ブランチで「元に戻す」HEAD~3コミットのハッシュ(またはorigin / masterなどの参照)を指定することもできます。例:

git reset --hard a1b2c3d4

* 1マスターブランチからのコミットのみが「失われる」ことになりますが、心配しないでください。これらのコミットはnewbranchにあります。

警告: Gitバージョン2.0以降では、後でgit rebase元の()ブランチに新しいブランチを追加する場合、持ち越されたコミットが失われないように、リベース中にmaster明示的なオプションが必要になる場合があります。--no-fork-point設定branch.autosetuprebase alwaysすると、これが発生する可能性が高くなります。詳細については、ジョンメラーの回答を参照してください。

于 2009-10-27T03:15:15.320 に答える
1176

なぜそれが機能するのか疑問に思っている人のために(私が最初にいたように):

Cに戻り、DとEを新しいブランチに移動します。最初は次のようになります。

A-B-C-D-E (HEAD)
        ↑
      master

git branch newBranch

    newBranch
        ↓
A-B-C-D-E (HEAD)
        ↑
      master

git reset --hard HEAD~2

    newBranch
        ↓
A-B-C-D-E (HEAD)
    ↑
  master

ブランチは単なるポインターであるため、マスターは最後のコミットを指していました。newBranchを作成したときは、最後のコミットへの新しいポインターを作成しただけです。次にgit resetマスターポインタを2つのコミットに戻しました。ただし、 newBranchを移動しなかったため、元々行ったコミットを示しています。

于 2011-07-22T22:37:41.890 に答える
538

一般に...

この場合、sykoraによって公開された方法が最良のオプションです。しかし、時には最も簡単ではなく、一般的な方法ではありません。一般的な方法として、gitcherry-pickを使用します。

OPが望むものを達成するために、その2ステップのプロセス:

ステップ1-必要なマスターからのコミットをメモしますnewbranch

実行する

git checkout master
git log

に必要な(たとえば3つの)​​コミットのハッシュに注意してくださいnewbranch。ここで使用します:
Cコミット:9aa1233
Dコミット:453ac3d
Eコミット:612ecb3

注:最初の7文字またはコミットハッシュ全体を使用できます

ステップ2-それらをnewbranch

git checkout newbranch
git cherry-pick 612ecb3
git cherry-pick 453ac3d
git cherry-pick 9aa1233

または(Git 1.7.2 +では、範囲を使用)

git checkout newbranch
git cherry-pick 612ecb3~1..9aa1233

gitcherry -pickはこれらの3つのコミットをnewbranchに適用します。

于 2012-02-07T16:58:43.387 に答える
411

以前のほとんどの答えは危険なほど間違っています!

こんなことしないで:

git branch -t newbranch
git reset --hard HEAD~3
git checkout newbranch

次回実行git rebase(またはgit pull --rebase)すると、これらの3つのコミットは黙ってnewbranch!から破棄されます。(以下の説明を参照)

代わりにこれを行います:

git reset --keep HEAD~3
git checkout -t -b newbranch
git cherry-pick ..HEAD@{2}
  • 最初に、最新の3つのコミットを破棄します(コミットされていない変更を破棄するのではなく失敗するため、に--keep似ていますが、より安全です)。--hard
  • それからそれは分岐しnewbranchます。
  • 次に、それらの3つのコミットをチェリーピックしnewbranchます。それらはブランチによって参照されなくなったため、gitのreflogHEAD@{2}を使用してそれを行います:HEAD2つの操作の前、つまり1.チェックアウトnewbranchおよび2.3git resetつのコミットの破棄に使用される前のコミットです。

警告:reflogはデフォルトで有効になっていますが、手動で無効にした場合(たとえば、「ベア」gitリポジトリを使用して)、実行後に3つのコミットを取り戻すことはできませんgit reset --keep HEAD~3

reflogに依存しない代替手段は次のとおりです。

# newbranch will omit the 3 most recent commits.
git checkout -b newbranch HEAD~3
git branch --set-upstream-to=oldbranch
# Cherry-picks the extra commits from oldbranch.
git cherry-pick ..oldbranch
# Discards the 3 most recent commits from oldbranch.
git branch --force oldbranch oldbranch~3

@{-1}(必要に応じて、の代わりに(以前にチェックアウトしたブランチ)と書くことができますoldbranch)。


技術的な説明

git rebase最初の例の後に3つのコミットを破棄するのはなぜですか?これgit rebaseは、引数がない--fork-point場合、デフォルトでオプションが有効になるためです。このオプションは、ローカルreflogを使用して、強制的にプッシュされるアップストリームブランチに対して堅牢にしようとします。

コミットM1、M2、M3が含まれているときにオリジン/マスターから分岐し、自分で3つのコミットを行ったとします。

M1--M2--M3  <-- origin/master
         \
          T1--T2--T3  <-- topic

しかし、誰かがオリジン/マスターを強制的に押してM2を削除することにより、履歴を書き換えます。

M1--M3'  <-- origin/master
 \
  M2--M3--T1--T2--T3  <-- topic

ローカルのreflogを使用するgit rebaseと、origin / masterブランチの以前のインカネーションからフォークしたことがわかります。したがって、M2およびM3コミットは実際にはトピックブランチの一部ではありません。したがって、M2がアップストリームブランチから削除されたため、トピックブランチがリベースされた後も、トピックブランチにM2を配置する必要がなくなったと合理的に想定しています。

M1--M3'  <-- origin/master
     \
      T1'--T2'--T3'  <-- topic (rebased)

この動作は理にかなっており、リベースするときに一般的に正しいことです。

したがって、次のコマンドが失敗する理由は次のとおりです。

git branch -t newbranch
git reset --hard HEAD~3
git checkout newbranch

reflogを間違った状態のままにしておくためです。Gitnewbranchは、3つのコミットを含むリビジョンでアップストリームブランチをフォークしたと見なしreset --hard、アップストリームの履歴を書き換えてコミットを削除します。そのため、次に実行するgit rebaseと、アップストリームから削除された他のコミットと同様にそれらが破棄されます。

ただし、この特定のケースでは、これら3つのコミットをトピックブランチの一部と見なす必要があります。これを実現するには、3つのコミットを含まない以前のリビジョンでアップストリームをフォークする必要があります。それが私の提案した解決策であるため、どちらもreflogを正しい状態のままにします。

詳細については、gitrebaseおよびgitmerge-baseドキュメントのの定義を--fork-point参照ください

于 2016-04-06T22:38:26.490 に答える
371

これを行うさらに別の方法は、2つのコマンドを使用することです。また、現在の作業ツリーをそのまま維持します。

git checkout -b newbranch # switch to a new branch
git branch -f master HEAD~3 # make master point to some older commit

古いバージョン-私が学ぶ前にgit branch -f

git checkout -b newbranch # switch to a new branch
git push . +HEAD~3:master # make master point to some older commit 

できることpush.知っておくべき良いトリックです。

于 2014-03-26T08:13:49.977 に答える
236

gitstashを使用したはるかに簡単なソリューション

これは、間違ったブランチへのコミットに対するはるかに簡単な解決策です。master3つの誤ったコミットがあるブランチから開始します。

git reset HEAD~3
git stash
git checkout newbranch
git stash pop

いつこれを使うの?

  • 主な目的がロールバックである場合master
  • ファイルの変更を保持したい
  • 誤ったコミットに関するメッセージは気にしません
  • まだプッシュしていません
  • これを覚えやすくしたい
  • 一時的/新しいブランチ、コミットハッシュの検索とコピー、その他の頭痛の種などの複雑な問題は望ましくありません。

行番号でこれが何をするか

  1. 最後の3つのコミット(およびそれらのメッセージ)をmaster元に戻しますが、すべての作業ファイルはそのまま残します
  2. すべての作業ファイルの変更を隠し、作業ツリーをHEAD〜3の状態と完全masterに等しくします
  3. 既存のブランチに切り替えますnewbranch
  4. 隠された変更を作業ディレクトリに適用し、隠しをクリアします

git addこれで、git commit通常どおりに使用できます。すべての新しいコミットがに追加されnewbranchます。

これがしないこと

  • それはあなたの木を乱雑にするランダムな一時的な枝を残しません
  • 誤ったコミットメッセージは保持されないため、この新しいコミットに新しいコミットメッセージを追加する必要があります
  • アップデート!上矢印を使用してコマンドバッファをスクロールし、コミットメッセージを含む前のコミットを再適用します(@ARKに感謝)

目標

OPは、目標は変更を失うことなく「これらのコミットが行われる前にマスターを戻す」ことであり、このソリューションはそれを行うと述べました。

masterの代わりに誤って新しいコミットを行った場合、少なくとも週に1回はこれを行いdevelopます。通常、ロールバックするコミットは1つだけです。その場合、git reset HEAD^1行目で使用する方が、コミットを1つだけロールバックする簡単な方法です。

マスターの変更をアップストリームにプッシュした場合は、これを行わないでください

他の誰かがそれらの変更をプルした可能性があります。ローカルマスターを書き換えるだけの場合、アップストリームにプッシュしても影響はありませんが、書き換えた履歴を共同編集者にプッシュすると、頭痛の種になる可能性があります。

于 2018-05-01T07:50:07.320 に答える
32

これは技術的な意味でそれらを「動かす」ことはありませんが、同じ効果があります。

A--B--C  (branch-foo)
 \    ^-- I wanted them here!
  \
   D--E--F--G  (branch-bar)
      ^--^--^-- Opps wrong branch!

While on branch-bar:
$ git reset --hard D # remember the SHAs for E, F, G (or E and G for a range)

A--B--C  (branch-foo)
 \
  \
   D-(E--F--G) detached
   ^-- (branch-bar)

Switch to branch-foo
$ git cherry-pick E..G

A--B--C--E'--F'--G' (branch-foo)
 \   E--F--G detached (This can be ignored)
  \ /
   D--H--I (branch-bar)

Now you won't need to worry about the detached branch because it is basically
like they are in the trash can waiting for the day it gets garbage collected.
Eventually some time in the far future it will look like:

A--B--C--E'--F'--G'--L--M--N--... (branch-foo)
 \
  \
   D--H--I--J--K--.... (branch-bar)
于 2013-10-19T14:12:19.860 に答える
26

履歴を書き換えずにこれを行うには(つまり、すでにコミットをプッシュしている場合):

git checkout master
git revert <commitID(s)>
git checkout -b new-branch
git cherry-pick <commitID(s)>

その後、両方のブランチを無理なく押すことができます!

于 2016-01-21T16:10:36.243 に答える
18

これを行う最も簡単な方法:

1.ブランチの名前を自分の名前に変更masterしますnewbranch(ブランチを使用していると仮定しますmaster)。

git branch -m newbranch

2.master必要なコミットからブランチを作成します。

git checkout -b master <seven_char_commit_id>

例:git checkout -b master a34bc22

于 2020-03-21T07:24:50.123 に答える
13

ちょうどこの状況がありました:

Branch one: A B C D E F     J   L M  
                       \ (Merge)
Branch two:             G I   K     N

私が行った:

git branch newbranch 
git reset --hard HEAD~8 
git checkout newbranch

私はコミットがHEADになると思っていましたが、コミットLは今です...

履歴の正しい場所に確実に着地するために、コミットのハッシュを操作する方が簡単です

git branch newbranch 
git reset --hard #########
git checkout newbranch
于 2013-09-20T10:17:35.893 に答える
11

どうすればこれから行くことができますか

A - B - C - D - E 
                |
                master

これに?

A - B - C - D - E 
    |           |
    master      newbranch

2つのコマンドで

  • git branch -m master newbranch

与える

A - B - C - D - E 
                |
                newbranch

  • gitブランチマスターB

与える

A - B - C - D - E
    |           |
    master      newbranch
于 2019-05-16T12:00:50.470 に答える
9

プッシュされていないすべてのコミットを新しいブランチに移動する必要がある場合は、次のようにする必要があります。

  1. 現在のブランチから新しいブランチを作成します。git branch new-branch-name

  2. 新しいブランチをプッシュします:git push origin new-branch-name

  3. 古い(現在の)ブランチを最後にプッシュされた/安定した状態に戻します。git reset --hard origin/old-branch-name

一部の人々はまた、upstreamsではなくorigin、を持っています、彼らは適切に使用する必要がありますupstream

于 2019-06-17T07:38:10.773 に答える
4

これを行うことができるのは、私が使用した3つの簡単なステップです。

1)最近の更新をコミットする場所に新しいブランチを作成します。

git branch <branch name>

2)新しいブランチでコミットするための最近のコミットIDを見つけます。

git log

3)そのコミットIDをコピーします。最新のコミットリストが一番上に表示されることに注意してください。だからあなたはあなたのコミットを見つけることができます。あなたはまた、メッセージを通してこれを見つけます。

git cherry-pick d34bcef232f6c...

コミットIDの範囲を指定することもできます。

git cherry-pick d34bcef...86d2aec

これであなたの仕事は終わりました。正しいIDと正しいブランチを選択した場合は、成功します。したがって、これを行う前に注意してください。そうしないと、別の問題が発生する可能性があります。

これで、コードをプッシュできます

git push

于 2018-05-25T14:14:27.140 に答える
3

1)すべての変更をnew_branchに移動する新しいブランチを作成します。

git checkout -b new_branch

2)次に、古いブランチに戻ります。

git checkout master

3)gitrebaseを実行します

git rebase -i <short-hash-of-B-commit>

4)次に、開いたエディターに最後の3つのコミット情報が含まれます。

...
pick <C's hash> C
pick <D's hash> D
pick <E's hash> E
...

5)これら3つのコミットすべてでに変更pickします。drop次に、エディターを保存して閉じます。

...
drop <C's hash> C
drop <D's hash> D
drop <E's hash> E
...

6)これで、最後の3つのコミットが現在のブランチから削除されます(master)。+次に、ブランチ名の前に記号を付けて、ブランチを強制的にプッシュします。

git push origin +master
于 2018-06-01T05:40:11.607 に答える
3

ここでのソリューションのほとんどは、戻りたいコミットの量をカウントします。これはエラーが発生しやすい方法論だと思います。カウントには再カウントが必要になります。

HEADに配置したいコミットのコミットハッシュ、つまり最後のコミットにしたいコミットを次の方法で渡すことができます。

(コミットハッシュを参照してください)

これを回避するには:

1) git checkout master

2) git branch <feature branch> master

3) git reset --hard <commit hash>

4) git push -f origin master
于 2020-11-24T21:49:27.363 に答える
2

誰もこの方法を勧めていないことに驚きました。

git checkout master
git checkout <commit hash from which you want to split>
git checkout -b new_branch
git rebase master
git checkout master
git reset --hard <commit hash you splitted>

説明する:

  1. 分割したい場所でコミットをチェックするステップ
  2. 次に、このコミットから新しいブランチを作成します
  3. リベースを実行すると、new_branchとmasterが同期されます。これで、同じコミットを持つ2つの同じブランチができました
  4. マスターをリセットすると、分割後に最後のコミットがクリーンアップされます
  5. リストアイテム
于 2022-01-19T19:17:05.147 に答える
1

7つのコミットを1つの古いブランチから新しいブランチに移動する必要がありました。

git checkout old-branch     # in the example, master
git reset --hard h4sh       # h4sh is the hash for the commit 
git checkout -b new-branch  
git push origin new-branch

その後、両方のブランチは私が行った7つのコミットに関連していました。その後git checkout new-branch、元気にgit logなりgit statusましたが、古いブランチ(git checkout old-branch)にアクセスすると、「gitは7コミット遅れており、早送りできます」というメッセージが表示されました。このメッセージを消すのに役立ったのは次のとおりです。

git checkout old-branch
git status 
> git is behind by 7 commits and can be fast-forwarded
git push origin old-branch -f

そのステップの後、最後の7つのコミットは新しいブランチに対してのみ参照され、前のコミットはBitbucketツリーでold-branchおよびnew-branchとして参照されました。

于 2021-09-19T00:15:14.710 に答える
1

私のようなUI担当者で、VisualStudioを使用している場合。次に、次のことを実行できます。私の場合、最新のコミットを別のブランチに実行します。

  1. 前の1つ(コミット)を右クリックします。

ここに画像の説明を入力してください

  1. したがって、すべてのコミットの変更はGitの変更ペインに表示されます。

  2. 今、あなたの変更を隠します

ここに画像の説明を入力してください

  1. ターゲットのブランチに移動するか、右下隅から新しいブランチを作成します。

ここに画像の説明を入力してください

  1. 「GitChanges」から最新のStashをダブルクリックします。

  2. 「スタッシュ詳細」ペインが開きます。[ポップ]をクリックして、競合を解決します(存在する場合)。

ここに画像の説明を入力してください

  1. そして最後に、変更をコミットします。
于 2021-10-10T07:48:17.803 に答える
1

EmacsのgitporcelainMagitを使用すると、b s(magit-branch-spinoff)を押すだけでこれを行うことができます。新しいブランチの名前を入力するように求められます。Enterキーを押すと、出来上がりです。

Magitのドキュメントから:

このコマンドは、現在のブランチから開始して追跡する新しいブランチを作成してチェックアウトします。そのブランチは、アップストリームと共有する最後のコミットにリセットされます。現在のブランチにアップストリームまたはプッシュされていないコミットがない場合は、とにかく新しいブランチが作成され、以前の現在のブランチは変更されません。

これは、古いブランチで作業がすでに開始された後に機能ブランチを作成するのに役立ちます(おそらく「マスター」である必要はありません)。

于 2021-12-03T10:33:15.837 に答える
-1

他の投稿からいくつかのアイデアを取り入れ、リセットとは何の関係も避け、非常に妄想的である私の解決策は次のとおりです。

  1. git branch#変更は新しいブランチで利用可能です
  2. git push#upload、「-set-upstream」をいじる必要があるかもしれません。例:git push --set-upstream https:///
  3. GUIを介して新しいブランチがgitにあることを確認します
  4. 現在のディレクトリを破棄する
  5. gitリポジトリから再クローンする

私は誇りに思っていませんが、データを保持しました;)

于 2022-01-15T16:02:05.647 に答える