取り消し - git 作業 ブランチ




最新のコミットをGitで新しいブランチに移動する (8)

git stashを使ったもっと簡単な解決法

次の場合:

  • 主な目的はmasterをロールバックすることです
  • 変更を保存したいが、個々のコミットについて特に気にしない。
  • まだプッシュしていない
  • 一時的な枝やその他の頭痛でこれが簡単で複雑にならないようにしたい

それでは、次のように(3つの間違ったコミットを持つブランチmasterから始めて)はるかに簡単です。

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

これは行番号で何をしますか?

  1. 最後の3つのコミット(およびそのメッセージ)をmasterに戻しますが、すべての作業ファイルはそのまま残します。
  2. すべての作業ファイルの変更を破棄し、 master作業ツリーをHEAD〜3の状態にします
  3. 既存ブランチにnewbranch
  4. 変更した変更を作業ディレクトリに適用し、stashをクリアします。

いつものようにgit addgit commitを使うことができます。 すべての新しいコミットがnewbranchに追加されnewbranch

これがしないこと

  • それはあなたの木を乱しているランダムな一時的な枝を残すことはありません
  • 誤ったコミットとコミットメッセージは保持されないので、この新しいコミットに新しいコミットメッセージを追加する必要があります

目標

OPは、変更が失われることなく「コミットが行われた前にマスターを取り戻す」ことを目標としており、この解決策はそのことを示しています。

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

上流のマスターの変更をプッシュした場合、これを行わないでください

他の人がこれらの変更を引っ張っているかもしれません。 ローカルマスタを書き換えているだけであれば、上流にプッシュしても影響はありませんが、書き直された履歴を共同編集者にプッシュすると頭痛を引き起こす可能性があります。

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

つまり、どうすればこのことができますか?

master A - B - C - D - E

これに?

newbranch     C - D - E
             /
master A - B 

一般に...

この場合、sykoraが公開するメソッドが最適です。 しかし時には最も簡単ではないし、一般的な方法ではない。 一般的な方法については、 git cherry-pickを使用してください:

OPが望んでいるものを実現するために、その2ステッププロセス:

ステップ1 - あなたがnewbranch望むマスターからのコミット

実行する

git checkout master
git log

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

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

ステップ2 - 彼らをnewbranch置く

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

OR(Git 1.7.2以降、使用範囲)

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

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


新しいブランチに移動する

警告:このメソッドは、最初のコマンド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 (GONE from master)
git checkout newbranch    # Go to the new branch that still has the desired commits

しかし、どれくらい多くのコミットが戻ってくるかを確認してください。 あるいは、 HEAD~3代わりに、 マスタ (/ current)ブランチの "元に戻す"ために、コミットのハッシュ(またはorigin / masterのような参照)

git reset --hard a1b2c3d4

* 1あなたはマスターブランチからのコミットを "失う"ことになりますが、気にしないでください。これらのコミットはnewbranchにあります!

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

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

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

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

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

git checkout -b new_branch

2)次に古い枝に戻ります。

git checkout master

3)git rebaseを実行する

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つのコミットのすべてをdropするようにpickを変更しdrop 。 次に、エディタを保存して閉じます。

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

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

git push origin +master

これは技術的な意味で「移動」しませんが、同じ効果があります。

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)

これは私が使った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


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

あなたは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後にgit reset --hard HEAD~2

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

ブランチは単なるポインタなので、最後のコミットを指しています。 newBranchを作成したときは、単に最後のコミットに新しいポインタを作成しました。 次に、 git resetを使用して、 マスターポインタを2つのコミットの後ろに移動しました。 しかし、あなたがnewBranchを動かさなかったので、それはもともとしたコミットを指しています。


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

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

両方の枝を無理に押すことができます!





branching-and-merging