過去の2つの任意のコミットの間にコミットを挿入する方法は?


回答:


178

OPの答えよりもさらに簡単です。

  1. git rebase -i <any earlier commit>。設定したテキストエディターにコミットのリストが表示されます。
  2. 挿入したいコミットを見つけます(それがだとしましょうa1b2c3d)。エディターで、その行をに変更pickeditます。
  3. テキストエディターを閉じて(変更を保存して)リベースを開始します。これにより、以前に選択したコミット(a1b2c3d)がコミットされたかのように、コマンドプロンプトが表示されます。
  4. 変更を行い、git commit(ほとんどのとは異なり、修正しないでくださいedit)。これにより、選択したコミットの後に新しいコミットが作成されます。
  5. git rebase --continue。これにより、連続したコミットが再生され、新しいコミットが正しい場所に挿入されたままになります。

これにより履歴が書き直され、プルしようとする他のユーザーが破壊されることに注意してください。


1
これにより、コミット後に新しいコミットが追加されました。これは、リベースした直後(最後のコミット)ではなく、リベースした直後です。結果は、挿入したい変更を加えて最後に新しいコミットを作成した場合と同じです。私の歴史A -- B -- C -- Dは望みの代わりになりましたA -- D -- B -- C
XedinUnknown 2016年

2
@XedinUnknown:次に、Rebaseを適切に使用しませんでした。
SLaks '19年

3
Dどこでもコミットできます。私たちがいて、このブランチにさえないA - B - CコミットがDあるとします。私たちはそのSHAを知っていgit rebase -i HEAD~3ますが、できます。次にAB pick行と行の間に、と言う新しい pick行を挿入しpick SHA、希望するのハッシュを与えますD。完全なハッシュである必要はなく、短縮されたものである必要があります。 git rebase -iチェリーpickは、バッファ内の行ごとにリストされているコミットをすべて選択します。それらはあなたのためにリストしたオリジナルのものである必要はありません。
Kaz

1
@Kazこれは別の有効な答えのように見えます。
BartoszKP 2018年

3
さらに簡単に、break2つのコミットの間にある専用の行でエディターのキーワードを使用できます(または最初の行で、指定したコミットの前にコミットを挿入します)。
SimonT

30

非常に単純であることがわかります。答えはここにあります。ブランチにいるとしますbranch。次の手順を実行します。

  • 新しいコミット(この場合はcommit A)を挿入した後、コミットから一時的なブランチを作成します。

    git checkout -b temp A
    
  • 変更を実行してコミットし、コミットを作成して、それを呼び出しましょうN

    git commit -a -m "Message"
    

    (またはgit addその後にgit commit

  • 新しいコミット(この場合はコミットBC)の後に必要なコミットを新しいコミットにリベースします。

    git rebase temp branch
    

-pもしあれば、おそらくマージを保存するために使用する必要があります-ciekawyによるもう存在しないコメントのおかげで

  • 一時的なブランチを削除します。

    git branch -d temp
    

この後、履歴は次のようになります。

A -- N -- B -- C

もちろん、リベース中にいくつかの競合が発生する可能性があります。

ブランチがローカルのみではない場合、これは書き換え履歴を導入するため、深刻な問題を引き起こす可能性があります。


2
私はSLaksが受け入れた回答を追跡できませんでしたが、これは私にとってはうまくいきました。必要なコミット履歴を取得した後git push --force、リモートリポジトリを変更する必要がありました。
エスケープ文字

1
そう、正しく-Xtheirsオプションの自動解決さの競合を使用してリベースを使用している場合git rebase temp branch -Xtheirs。スクリプトを挿入するのに役立つ回答です。
デビッドC

私のような初心者のために私はその後を追加したいと思いgit rebase temp branchますが、前にgit branch -d temp、あなたがしなければならないすべては、紛争や問題をマージ修正し、ステージであるgit rebase --continue、つまり何かをコミットする必要はありません、など
Pugsley

19

さらに簡単な解決策:

  1. 最後にDで新しいコミットを作成します。これで、次のことができました。

    A -- B -- C -- D
    
  2. 次に実行します:

    $ git rebase -i hash-of-A
    
  3. Gitがエディターを開き、次のようになります。

    pick 8668d21 B
    pick 650f1fc C
    pick 74096b9 D
    
  4. このようにDを一番上に移動し、保存して終了するだけです

    pick 74096b9 D
    pick 8668d21 B
    pick 650f1fc C
    
  5. 今あなたは持っているでしょう:

    A -- D -- B -- C
    

6
いい考えですが、これらの変更をwrtにするつもりなら、CにDを導入するのは難しいかもしれません。Aへ
BartoszKP 2017年

私は一緒にリベースしたい3つのコミットと、関係のない真ん中のコミットがある状況にあります。これは、そのコミットを前後のコミット行に移動できるので非常に便利です。
unflores

13

コミット履歴がpreA -- A -- B -- CであるとするAB、との間にコミットを挿入する場合の手順は次のとおりです。

  1. git rebase -i hash-of-preA

  2. Gitがエディターを開きます。コンテンツは次のようになります。

    pick 8668d21 A
    pick 650f1fc B
    pick 74096b9 C
    

    最初のものpickを次のように変更しeditます。

    edit 8668d21 A
    pick 650f1fc B
    pick 74096b9 C
    

    保存して終了。

  3. コードを変更してから git add . && git commit -m "I"

  4. git rebase --continue

今あなたのGitコミット履歴は preA -- A -- I -- B -- C


競合が発生した場合、Gitはこのコミットで停止します。を使用git diffして、競合マーカーを見つけて解決できます。すべての競合を解決した後、を使用git add <filename>してGitに競合が解決されたことを通知し、を再実行する必要がありますgit rebase --continue

リベースを元に戻す場合は、を使用しますgit rebase --abort


10

これは、私が読んだ他の回答で見られるリベース中に「編集ハック」を行わないようにする戦略です。

を使用git rebase -iすると、そのコミット以降のコミットのリストを取得できます。ファイルの先頭に「ブレーク」を追加するだけで、その時点でリベースがブレークします。

break
pick <B's hash> <B's commit message>
pick <C's hash> <C's commit message>

起動git rebaseすると、「中断」の時点で停止します。これでファイルを編集して、通常どおりコミットを作成できます。その後、でリベースを続行できgit rebase --continueます。これにより、修正が必要な競合が発生する可能性があります。道に迷った場合は、を使用していつでも中断できることを忘れないでくださいgit rebase --abort

この戦略は、コミットをどこにでも挿入できるように一般化できます。コミットを挿入したい場所に「ブレーク」を置くだけです。

履歴を書き換えた後は、忘れずにgit push -f。あなたのブランチをフェッチしている他の人に関する通常の警告が適用されます。


申し訳ありませんが、この「リベースを回避する」方法を理解できません。あなたrebaseここ走っています。コミットをリベース中に作成するか、事前に作成するかは、それほど大きな違いはありません。
BartoszKP

おっと、リベース中の「編集ハック」を回避するつもりだったのだろう。
axerologementy

正しい。私の回答もリベースの「編集」機能を使用していません。それでも、これはさらに別の有効なアプローチです-ありがとう!:-)
BartoszKP

6

すでに多くの良い答えがここにあります。「リベースなし」のソリューションを4つの簡単なステップで追加したかっただけです。


概要

git checkout A
git commit -am "Message for commit D"
git cherry-pick A..C
git branch -f master HEAD

説明

(注:このソリューションの利点の1つは、最終ステップまでブランチに触れないことです。最終結果に問題がないことを100%確信しているため、非常に便利な「事前確認」ステップがあります。 ABテストが可能です


初期状態(私はmasterあなたのブランチ名を想定しています)

A -- B -- C <<< master <<< HEAD

1)適切な場所にHEADを向けることから始めます

git checkout A

     B -- C <<< master
    /
   A  <<< detached HEAD

(オプションとして、ここでは、HEADをデタッチするのではなく、で一時的なブランチを作成しgit checkout -b temp A、プロセスの最後に削除する必要があります。他のすべてが同じままであるため、どちらのバリアントも動作します。)


2)挿入する新しいコミットDを作成する

# at this point, make the changes you wanted to insert between A and B, then

git commit -am "Message for commit D"

     B -- C <<< master
    /
   A -- D <<< detached HEAD (or <<< temp <<< HEAD)

3)次に、最後に失われたコミットBとCのコピーを用意します(さらにコミットがあった場合は同じ行になります)

git cherry-pick A..C

# (if any, resolve any potential conflicts between D and these last commits)

     B -- C <<< master
    /
   A -- D -- B' -- C' <<< detached HEAD (or <<< temp <<< HEAD)

(必要に応じてここで快適なABテスト)

今、あなたのコードを検査する瞬間は、ニーズをテストすることをテスト何でもあります。また、差分/検査/比較することができ、何を持っていたし、何を得るでしょう操作の後。


4)Cとの間のテストに応じて、C'問題がないか、問題がない。

(どちらでも)4-OK)最後に、の参照を移動しますmaster

git branch -f master HEAD

     B -- C <<< (B and C are candidates for garbage collection)
    /
   A -- D -- B' -- C' <<< master

(OR)4-KO)だけのままmaster変わらず

一時的なブランチを作成した場合は、それをgit branch -d <name>で削除するだけですが、切り離されたHEADルートに移動した場合、この時点では何もする必要はありません。新しいコミットはHEADgit checkout master

どちらの場合も(OKまたはKO)、この時点でmasterもう一度チェックアウトして再接続しHEADます。

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