Gitで最後のコミットを2つに分割する方法


277

私は2本の作業の枝、持っているマスターフォーラムを、私はちょうどでいくつかの変更作ったフォーラムの私はにチェリーピックしたいという、ブランチをマスター。しかし、残念ながら、私がチェリーピックしたいコミットには、私が望まないいくつかの変更も含まれています。

解決策はおそらく、間違ったコミットを削除して、2つの別々のコミットに置き換えることです。

やってみました

git reset --hard HEAD^

これですべての変更が削除されたので、戻る必要がありました

git reset ORIG_HEAD

だから私の質問は、最後のコミットを2つの別々のコミット分割する最良の方法は何ですか?

回答:


332

インデックスを使用する必要があります。混合リセット( " git reset HEAD ^")を実行した後、変更の最初のセットをインデックスに追加して、コミットします。その後、残りをコミットします。

git add」を使用すると、ファイルで行われたすべての変更をインデックスに追加できます。ファイルで行われたすべての変更をステージングしたくない場合は、それらの一部のみをステージングするには、「git add -p」を使用できます。

例を見てみましょう。次のテキストを含むmyfileというファイルがあるとします。

something
something else
something again

私は最後のコミットでそれを変更したので、次のようになります:

1
something
something else
something again
2

これを2つに分割することにし、最初の行の挿入を最初のコミットに、最後の行の挿入を2番目のコミットにしたいとします。

最初にHEADの親に戻りますが、ファイルシステムの変更を保持したいので、引数なしで "git reset"を使用します(いわゆる "混合"リセットを行います)。

$ git reset HEAD^
myfile: locally modified
$ cat myfile
1
something
something else
something again
2

次に、 "git add -p"を使用して、コミットする変更をインデックスに追加します(=ステージングします)。「git add -p」は、インデックスに追加する必要があるファイルの変更について尋ねる対話型ツールです。

$ git add -p myfile
diff --git a/myfile b/myfile
index 93db4cb..2f113ce 100644
--- a/myfile
+++ b/myfile
@@ -1,3 +1,5 @@
+1
 something
 something else
 something again
+2
Stage this hunk [y,n,a,d,/,s,e,?]? s    # split this section into two!
Split into 2 hunks.
@@ -1,3 +1,4 @@
+1
 something
 something else
 something again
Stage this hunk [y,n,a,d,/,j,J,g,e,?]? y  # yes, I want to stage this
@@ -1,3 +2,4 @@
 something
 something else
 something again
+2
Stage this hunk [y,n,a,d,/,K,g,e,?]? n   # no, I don't want to stage this

次に、この最初の変更をコミットします。

$ git commit -m "Added first line"
[master cef3d4e] Added first line
 1 files changed, 1 insertions(+), 0 deletions(-)

これで、他のすべての変更をコミットできます(つまり、最後の行にある数字の「2」)。

$ git commit -am "Added last line"
[master 5e284e6] Added last line
 1 files changed, 1 insertions(+), 0 deletions(-)

ログをチェックして、どのようなコミットがあるかを確認しましょう。

$ git log -p -n2 | cat
Commit 5e284e652f5e05a47ad8883d9f59ed9817be59d8
Author: ...
Date: ...

    Added last line

Diff --git a/myfile b/myfile
Index f9e1a67..2f113ce 100644
--- a/myfile
+++ b/myfile
@@ -2,3 +2,4 @@
 something
 something else
 something again
+2

Commit cef3d4e0298dd5d279a911440bb72d39410e7898
Author: ...
Date: ...

    Added first line

Diff --git a/myfile b/myfile
Index 93db4cb..f9e1a67 100644
--- a/myfile
+++ b/myfile
@@ -1,3 +1,4 @@
+1
 something
 something else
 something again

1
先週、Mercurialからのgitにゆっくり慣れてきました。リセット後のgit reset [--patch|-p] <commit>手間を省くための便利なショートカットコマンドがありますgit add -p。私は正しいですか?git 1.7.9.5を使用します。
trojjer 14年

2
以前のコミットであったか、NコミットをMコミットに変更する必要があるかをリベースするなど、この手法についてもう少し詳しく説明します:emmanuelbernard.com/blog/2014/04/14/…
クリスウェスティン

84

目標:

  • 過去のコミット(splitme)を2つに分割したい。
  • コミットメッセージ維持したい。

予定:

  1. 以前のものからインタラクティブにリベースしsplitmeます。
  2. 編集splitme
  3. ファイルをリセットして、2番目のコミットに分割します。
  4. コミットを修正し、メッセージを維持し、必要に応じて変更します。
  5. 最初のコミットから分割されたファイルを追加して戻します。
  6. 新しいメッセージをコミットします。
  7. リベースを続行します。

splitme最新のコミットの場合、リベースのステップ(1および7)はスキップできます。

git rebase -i splitme^
# mark splitme commit with 'e'
git reset HEAD^ -- $files
git commit --amend
git add $files
git commit -m "commit with just some files"
git rebase --continue

最初に分割ファイルをコミットしたい場合は、-iを再度リベースして順序を入れ替えます

git rebase -i splitme^
# swap order of splitme and 'just some files'

1
git reset HEAD^不足しているパズルのピースでした。-pあまりにもうまく動作します。ありがとう!
Marius Gedminas 2013年

10
への-- $files議論に注意することが重要git resetです。パスが渡されると、git resetそれらのファイルは参照されているコミットの状態に復元されますが、コミットは変更されません。パスを省略した場合、次のステップで修正するコミットが「失われます」。
デュエリンマーカー2014

2
この方法では、受け入れられた回答と比較して、最初のコミットメッセージをコピーして貼り付ける必要がなくなります。
カルバン

また、すべてのファイルをリセットする場合は、を使用してくださいgit reset HEAD^ -- .。非常に驚くべきことに、これは正確にの動作ではありませんgit reset HEAD^
allidoiswin

52

現在のコミットを2つのコミットに変更するには、次のようにします。

どちらか:

git reset --soft HEAD^

これにより、最後のコミットが取り消されますが、すべてがステージングされたままになります。次に、特定のファイルのステージを解除できます。

git reset -- file.file

オプションで、これらのファイルの一部を再ステージングします。

git add -p file.file

新しい最初のコミットを作成します。

git commit

ステージングし、残りの変更を2番目のコミットでコミットします。

git commit -a

または:

最後のコミットからのすべての変更を元に戻し、ステージングを解除します。

git reset HEAD^

最初の変更ラウンドを選択的にステージングします。

git add -p

コミット:

git commit

残りの変更をコミットします。

git commit -a

(どちらの手順でも、新しいファイルを追加したコミットを元に戻し、これを2番目のコミットに追加したい場合はcommit -a、すでに追跡されているファイルへのステージ変更のみとして手動で追加する必要があります。)


22

を実行しgit gui、[最後のコミットを修正]ラジオボタンを選択して、最初のコミットに含めない変更をステージング解除([コミット]> [ステージングからステージ解除]、またはCtrl- U)します。それが最も簡単な方法だと思います。

実行できるもう1つのことは、コミットせずに変更をチェリーピックする(git cherry-pick -n)してから、手動で、またはgit guiコミットする前に必要な変更を選択して選択します。



13

誰も提案しないことに驚いていgit cherry-pick -n forumます。これにより、最新のforumコミットからの変更がステージングされますが、コミットはされません。その後reset、不要な変更を取り除き、保持したいものをコミットできます。


3

ダブルリバートスカッシュ法

  1. 不要な変更を削除する別のコミットを作成します。(それはファイルごとなら、これは簡単には本当にです:git checkout HEAD~1 -- files with unwanted changesgit commitされていない場合、混合変更でファイルが部分的に上演することができます。git reset fileそしてgit add -p file、中間ステップとして。)これを呼び出し元に戻します
  2. git revert HEAD–さらに別のコミットを作成します。これにより、不要な変更が追加されます。これは二重復帰です
  3. あなたが今作っ2つのコミットのうち、スカッシュ(スプリットにコミット上に最初git rebase -i HEAD~3)。これらのコミットは2番目のコミットにあるため、このコミットには不要な変更がなくなります。

利点

  • コミットメッセージを保存します
  • 分割するコミットが最後でない場合でも機能します。不要な変更が後のコミットと競合しないことのみが必要です

1

あなたはチェリーピックなので、次のことができます:

  1. cherry-pickそれはして--no-commitオプションを追加します。
  2. resetそして、使用add --patchadd --editまたはちょうどaddあなたが残しておきたいものをステージへ。
  3. commit 段階的な変更。
    • 元のコミットメッセージを再利用するには、コマンドに--reuse-message=<old-commit-ref>または--reedit-message=<old-commit-ref>オプションを追加できますcommit
  4. ステージングされていない変更をで吹き飛ばしreset --hardます。

別の方法では、元のコミットメッセージを保持または編集します。

  1. cherry-pick 通常どおり元のコミット。
  2. 不要な変更を元addに戻し、逆転のステージングに使用します。
    • 追加したものを削除する場合、この手順は簡単ですが、削除したものを追加する場合、または変更を元に戻す場合は、少し注意が必要です。
  3. commit --amend 厳選されたコミットを元に戻す。
    • 同じコミットメッセージが再度表示されます。必要に応じて、このメッセージを保持または修正できます。

0

これは、大きなコミットがあり、少量のファイルを新しいコミットに移動する必要がある場合を対象とした別の解決策になる可能性があります。これは<path>、HEADでの最後のコミットから一連のファイルを抽出し、すべて新しいコミットに移動する場合に機能します。複数のコミットが必要な場合は、他のソリューションを使用できます。

まず、ステージングされた領域とステージされていない領域にパッチを作成します。これらには、変更前と変更後のそれぞれにコードを戻すための変更が含まれます。

git reset HEAD^ <path>

$ git status
On branch <your-branch>
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        modified:   <path>

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   <path>

どうなるかを理解するには(矢印とコメントはコマンドの一部ではありません):

git diff --cached   -> show staged changes to revert <path> to before HEAD
git diff            -> show unstaged changes to add current <path> changes

<path>最後のコミットでの変更を元に戻す:

git commit --amend  -> reverts changes on HEAD by amending with staged changes

<path>変更を加えて新しいコミットを作成します。

git commit -a -m "New Commit" -> adds new commit with unstaged changes

これには、最後のコミットから抽出された変更を含む新しいコミットを作成する効果があります。

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