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

日志看起来是这样的:

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

什么好主意吗?


当前回答

用一个小的改变来“修复”一个旧的提交,而不改变旧提交的提交消息,其中OLDCOMMIT类似于091b73a:

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

你也可以使用git commit——squash=OLDCOMMIT在改基期间编辑旧的提交消息。

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


详细解释

git commit --fixup=OLDCOMMIT copies the OLDCOMMIT commit message and automatically prefixes fixup! so it can be put in the correct order during interactive rebase. (--squash=OLDCOMMIT does the same but prefixes squash!.) git rebase --interactive will bring up a text editor (which can be configured) to confirm (or edit) the rebase instruction sequence. There is info for rebase instruction changes in the file; just save and quit the editor (:wq in vim) to continue with the rebase. --autosquash will automatically put any --fixup=OLDCOMMIT commits in the correct order. Note that --autosquash is only valid when the --interactive option is used. The ^ in OLDCOMMIT^ means it's a reference to the commit just before OLDCOMMIT. (OLDCOMMIT^ is the first parent of OLDCOMMIT.)


可选的自动化

上面的步骤对于验证和/或修改rebase指令序列很好,但也可以通过以下方式跳过/自动化交互式rebase文本编辑器:

将GIT_SEQUENCE_EDITOR设置为脚本。 创建一个git别名来自动压缩所有排队的修复。 创建一个git别名来自动修复一次提交。

其他回答

下面是一个实现@Greg答案的函数:

function gitamendoldcommit() {
    printf "\n\nPress any key if you have no changes other than those you want to add to $1."
    printf "(You can commit your unwanted changes and undo later.):\n\n"
    read foo
    printf "\n\nChange 'pick' to 'edit' in front of $1 (top one), save, close the editor & press any key..."
    printf "Resolve any possible conflicts, if any. then: git add .; git rebase --continue\n\n"
    git rebase -i $1^

    git stash pop
    git add .
    git commit --amend --no-edit
    git rebase --continue
}

用法:(当在staging中只有预期的更改时)gitamendoldcommit $OLDCOMMIT

另外,如果你使用git rebase -i,并且想要去当前分支的第一次提交,你可以使用git rebase -i——root。现在您可以轻松地修改第一次提交。

用一个小的改变来“修复”一个旧的提交,而不改变旧提交的提交消息,其中OLDCOMMIT类似于091b73a:

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

你也可以使用git commit——squash=OLDCOMMIT在改基期间编辑旧的提交消息。

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


详细解释

git commit --fixup=OLDCOMMIT copies the OLDCOMMIT commit message and automatically prefixes fixup! so it can be put in the correct order during interactive rebase. (--squash=OLDCOMMIT does the same but prefixes squash!.) git rebase --interactive will bring up a text editor (which can be configured) to confirm (or edit) the rebase instruction sequence. There is info for rebase instruction changes in the file; just save and quit the editor (:wq in vim) to continue with the rebase. --autosquash will automatically put any --fixup=OLDCOMMIT commits in the correct order. Note that --autosquash is only valid when the --interactive option is used. The ^ in OLDCOMMIT^ means it's a reference to the commit just before OLDCOMMIT. (OLDCOMMIT^ is the first parent of OLDCOMMIT.)


可选的自动化

上面的步骤对于验证和/或修改rebase指令序列很好,但也可以通过以下方式跳过/自动化交互式rebase文本编辑器:

将GIT_SEQUENCE_EDITOR设置为脚本。 创建一个git别名来自动压缩所有排队的修复。 创建一个git别名来自动修复一次提交。

在2023年,有一些工具可以做到这一点:特别是git吸收。它是一个伟大的工具,有潜力改变很多灰尘的git工作流程。

您可以尝试rebase—交互式会话来修改旧的提交(前提是您还没有将这些提交推到另一个repo)。

有时在b。2中固定。不能修改为它修复的不太完美的提交,因为该提交深埋在补丁系列中。 这正是交互式rebase的用途:在大量的“a”和“b”之后使用它,通过重新安排和编辑提交,并将多个提交压缩为一个。 从你想保留的最后一个提交开始:

git rebase -i <after-this-commit>

编辑器将被启动,其中包含当前分支中的所有提交(忽略合并提交),合并提交紧跟在给定的提交之后。 您可以根据自己的意愿对列表中的提交进行重新排序,也可以删除它们。这个列表大致是这样的:

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

这一行描述纯粹是为了让你高兴;Git rebase不会查看它们,而是查看提交名称(本例中为“deadbee”和“fa1afe1”),因此不要删除或编辑这些名称。 通过将“pick”命令替换为“edit”命令,你可以告诉git rebase在应用提交后停止,这样你就可以编辑文件和/或提交消息,修改提交,并继续rebase。