変更されたファイルをGitの古い(最後ではない)コミットに追加する方法


461

過去1時間にいくつかの変更を加え、それらを段階的にコミットしましたが、変更したファイルをいくつかのコミット前に追加するのを忘れていることに気づきました。

ログは次のようになります。

    GIT TidyUpRequests u:1 d:0> git log 
    commit fc6734b6351f6c36a587dba6dbd9d5efa30c09ce 
    Author: David Klein <> 
    Date:   Tue Apr 27 09:43:55 2010 +0200

        The Main program now tests both Webservices at once

    commit 8a2c6014c2b035e37aebd310a6393a1ecb39f463 
    Author: David Klein <>
    Date:   Tue Apr 27 09:43:27 2010 +0200

        ISBNDBQueryHandler now uses the XPath functions from XPath.fs too

    commit 06a504e277fd98d97eed4dad22dfa5933d81451f 
    Author: David Klein <> 
    Date:   Tue Apr 27 09:30:34 2010 +0200

        AmazonQueryHandler now uses the XPath Helper functions defined in XPath.fs

    commit a0865e28be35a3011d0b6091819ec32922dd2dd8 <--- changed file should go here
    Author: David Klein <> 
    Date:   Tue Apr 27 09:29:53 2010 +0200

        Factored out some common XPath Operations

何か案は?


回答:


694

を使用しgit rebaseます。具体的には:

  1. git stash追加する変更を保存するために使用します。
  2. 使用しますgit rebase -i HEAD~10(または、確認したい多くのコミットを戻します)。
  3. 行の先頭のa0865...単語pickをに変更して、問題のコミットを編集用にマークしeditます。コミットを削除するため、他の行は削除しないでください。[^ vimnote]
  4. リベースファイルを保存すると、gitがシェルに戻り、コミットが修正されるのを待ちます。
  5. を使用して収納をポップします git stash pop
  6. でファイルを追加しますgit add <file>
  7. コミットをで修正しgit commit --amend --no-editます。
  8. git rebase --continue新しいコミットに対して残りのコミットを書き換えるa を実行します。
  9. 編集用に複数のコミットをマークした場合は、ステップ2以降を繰り返します。

[^ vimnote]:使用している場合はvimInsertキーを押して編集し、次にEsc入力し:wqてファイルを保存し、エディターを終了して変更を適用する必要があります。または、でユーザーフレンドリーなgit commitエディター設定できますgit config --global core.editor "nano"


23
編集に追加したいステージングされていない変更がある場合はどうなりますか?隠しておけばできなかったgit add
サム

15
問題のコミット中に変更を元に戻すことができますが、問題なく動作します。
omn​​ikron 2013

17
注:コミットをeditでマークした場合、ファイルにリストされている他のコミットは削除しないでください。実行すると、コミットが削除されるため、これらの手順に従ってコミットを取り戻す必要があります。
David Tuite

2
@DavidTuiteが言ったことに関して、gitで何かを行うときの私の習慣は、どうなるか分からないので、混乱した場合にタイムラインの現在の状態を保存するために「branchname-ref」ブランチを作成することです。完了したら、それを削除します。
Raphael

1
ステップ6で、。(ドット)コマンド内。正しいコマンド:git add .
Tom

323

古いコミットのコミットメッセージを変更せずに、小さな変更で古いコミットを「修正」するにOLDCOMMITは、次のようになり091b73aます。

git add <my fixed files>
git commit --fixup=OLDCOMMIT
git rebase --interactive --autosquash OLDCOMMIT^

を使用git commit --squash=OLDCOMMITして、リベース中に古いコミットメッセージを編集することもできます。


  • git rebase --interactiveテキストエディター(構成可能)が表示され、リベース命令シーケンスを確認(または編集)します。ファイルにリベース命令の変更に関する情報があります。ただ保存して終了(エディタ:wqvimリベースを続行するが)。
  • --autosquash--fixup=OLDCOMMITコミットは自動的に希望の順序に配置されます。オプションが使用されている--autosquash場合にのみ有効であることに注意してください--interactive
  • ^OLDCOMMIT^直前にコミットすることを意味し、それは参照ですOLDCOMMIT

上記の手順は、rebase命令シーケンスの検証や変更に適していますが、次の方法でインタラクティブなrebaseテキストエディターをスキップ/自動化することもできます。

git commitおよびgit rebaseを参照してください。いつものように、git historyを書き換えるときは、まだ誰にも公開していない(ランダムなインターネットユーザーやビルドサーバーを含む)コミットを修正またはスカッシュするだけです。


18
他のオプションよりもはるかに明確で、魅力的
でした

5
@Jonah:エディターは、コミットメッセージを編集するために開かれるのではなく、リベース手順を確認(または編集)するために開かれます。それは避けられません。オプションが使用されている--autosquash場合にのみ有効です--interactive
Joel Purra、2016年

5
このソリューションを使用すると、gitがVIMを表示して立ち往生しています。私の問題は、VIMの使い方がわかりません。一体どうやってそれから抜け出すのか、どうやってこれを制御できるのか、これはとても混乱しています。
ネオンウォージ

2
@NeonWarge:選択したエディターは、たとえばを使用して構成可能git config --global core.editor "pico"です。gitを設定したり、システムのデフォルトエディタなどを変更したりするには、他にいくつかの方法があります
Joel Purra、2016年

2
1行の素敵なエイリアスこちら
idanp

61

git 1.7では、本当に簡単な方法がありgit rebaseます:

ファイルをステージングします。

git add $files

新しいコミットを作成し、「壊れた」コミットのコミットメッセージを再利用する

git commit -c master~4

fixup!件名の先頭に追加する(またはsquash!コミット(メッセージ)を編集する場合):

fixup! Factored out some common XPath Operations

git rebase -i --autosquashあなたのコミットを修正するために使用します


2
+1。新しいフィックスアップ指令のニース使用(1.7以降):stackoverflow.com/questions/2302736/trimming-git-checkins/...
VonC

@knittl私は自分の古いコミット(プッシュされていない)に別のファイルを追加する方法を試していましたが、リベースするときに取得You asked me to rebase without telling me which branch you want to rebase against, and 'branch.master.merge'し、次に使用git rebase -i --autosquashするnoopとサブジェクト行が表示されるだけで、コミット自体にリベースします。私が間違っていることは何か考えていますか?
オシュレンク2012年

7
@oschrenk:リベースするコミットを提供する必要があります。例git rebase -i --autosquash HEAD~10
knittl

1
良い答えですが、リベースするコミットを追加する必要もありました。あなたがそれを更新することができれば素晴らしいでしょう。
ポールオデオン2013年

@PaulOdeon:私はあなたの質問を理解していません。何をしようとしていて、どこに問題がありますか?
knittl 2013年

8

rebase --interactiveセッションを試行して、古いコミットを修正できます(これらのコミットを別のリポジトリにまだプッシュしていない場合)。

時にはb.2で修正されたもの。コミットがパッチシリーズに深く埋め込まれているため、修正された完全ではない完全なコミットに修正することはできません。
それがまさに対話型リベースの目的です。たくさんの "a"と "b"の後で、コミットを再配置して編集し、複数のコミットを1つにつぶすことによって、それを使用してください。

そのまま保持する最後のコミットから開始します。

git rebase -i <after-this-commit>

エディターは、現在のブランチのすべてのコミット(マージコミットは無視)で起動されます。これらのコミットは、指定されたコミットの後に来ます。
このリストのコミットを思い通りに並べ替えたり、削除したりできます。リストは多かれ少なかれこのように見えます:

pick deadbee The oneline of this commit
pick fa1afe1 The oneline of the next commit
...

onelineの説明は、純粋にあなたの喜びのためのものです。git rebaseはそれらを調べませんが、コミット名(この例では「deadbee」と「fa1afe1」)を見るので、名前を削除または編集しないでください。

コマンド「pick」をコマンド「edit」に置き換えることで、そのコミットの適用後に停止するようにgit rebaseに指示できるため、ファイルやコミットメッセージを編集し、コミットを修正して、リベースを続行できます。

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