如何将更改的文件添加到Git中的旧(不是最后)提交


How to add a changed file to an older (not last) commit in Git

在过去的一个小时里,我已经改变了一些事情,并一步一步地提交了它们,但是我刚刚意识到我在一些提交之前忘记了添加一个更改过的文件。

日志如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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

有什么想法吗?


使用git rebase。明确地:

  • 使用git stash存储要添加的更改。
  • 使用git rebase -i HEAD~10(或者你想看到的许多承诺)。
  • 通过将行首的单词pick改为edit,将有问题的commit(a0865...标记为edit。不要像删除提交那样删除其他行。[^vimnote]
  • 保存rebase文件,git将返回shell,等待您修复提交。
  • git stash pop弹出藏匿处
  • git add 添加文件。
  • 修改与git commit --amend --no-edit的承诺。
  • 做一个git rebase --continue,它将改写你对新的承诺的其余部分。
  • 如果已将多个提交标记为要编辑,请从步骤2开始重复。
  • [^vimnote]:如果使用vim,则必须按insertakbd键进行编辑,然后按esc并键入:wq保存文件,退出编辑器并应用更改。或者,您可以使用git config --global core.editor"nano"配置一个用户友好的git提交编辑器。


    在不更改旧提交的提交消息的情况下,通过小的更改"修复"旧提交,其中OLDCOMMIT091b73a类似:

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

    您还可以使用git commit --squash=OLDCOMMIT在重新平衡期间编辑旧的提交消息。

    • git rebase --interactive将弹出一个文本编辑器(可配置)来确认(或编辑)重新设定指令序列。文件中有关于REBASE指令更改的信息,只需保存并退出编辑器(EDOCX1中的:wq)即可继续执行REBASE。
    • --autosquash将自动将任何--fixup=OLDCOMMIT承诺按所需顺序排列。注意,只有在使用--interactive选项时,--autosquash才有效。
    • OLDCOMMIT^中的^表示在OLDCOMMIT之前的承诺。

    上述步骤有助于验证和/或修改REBASE指令序列,但也可以通过以下方式跳过/自动化交互式REBASE文本编辑器:

    • GIT_SEQUENCE_EDITOR设置为脚本。
    • 创建Git别名以自动取消所有排队的修正。
    • 创建Git别名以自动修复单个提交。

    请参见git commit和git rebase。和往常一样,在重写Git历史记录时,您应该只修复或压缩尚未发布给任何其他人(包括随机互联网用户和构建服务器)的提交。


    使用git 1.7,使用git rebase有一个非常简单的方法:

    准备文件:

    1
    git add $files

    创建一个新的提交,并重新使用"中断"提交的提交消息

    1
    git commit -c master~4

    在主题行(或如果要编辑commit(message))中预先发送fixup!

    1
    fixup! Factored out some common XPath Operations

    git rebase -i --autosquash修正你的承诺


    您可以尝试一个rebase --interactive会话来修改您的旧承诺(前提是您尚未将这些承诺推送到另一个回购协议)。

    Sometimes the thing fixed in b.2. cannot be amended to the not-quite perfect commit it fixes, because that commit is buried deeply in a patch series.
    That is exactly what interactive rebase is for: use it after plenty of"a"s and"b"s, by rearranging and editing commits, and squashing multiple commits into one.

    Start it with the last commit you want to retain as-is:

    1
    git rebase -i

    An editor will be fired up with all the commits in your current branch (ignoring merge commits), which come after the given commit.
    You can reorder the commits in this list to your heart's content, and you can remove them. The list looks more or less like this:

    1
    2
    3
    pick deadbee The oneline of this commit
    pick fa1afe1 The oneline of the next commit
    ...

    The oneline descriptions are purely for your pleasure; git rebase will not look at them but at the commit names ("deadbee" and"fa1afe1" in this example), so do not delete or edit the names.

    By replacing the command"pick" with the command"edit", you can tell git rebase to stop after applying that commit, so that you can edit the files and/or the commit message, amend the commit, and continue rebasing.