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

日志看起来是这样的:

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

什么好主意吗?


您可以尝试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。


使用git rebase。具体地说:

Use git stash to store the changes you want to add. Use git rebase -i HEAD~10 (or however many commits back you want to see). Mark the commit in question (a0865...) for edit by changing the word pick at the start of the line into edit. Don't delete the other lines as that would delete the commits.[^vimnote] Save the rebase file, and git will drop back to the shell and wait for you to fix that commit. Pop the stash by using git stash pop Add your file with git add <file>. Amend the commit with git commit --amend --no-edit. Do a git rebase --continue which will rewrite the rest of your commits against the new one. Repeat from step 2 onwards if you have marked more than one commit for edit.

[^vimnote]:如果你正在使用vim,那么你必须按Insert键进行编辑,然后按Esc键,输入:wq保存文件,退出编辑器,并应用更改。或者,你也可以使用git config——global core配置一个用户友好的git提交编辑器。编辑“纳米”。


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

整理你的文件:

git add $files

创建一个新的提交并重新使用“坏了”提交的提交消息

git commit -c master~4

预先考虑修正!在主题行(或南瓜!)如果你想编辑commit (message)):

fixup! Factored out some common XPath Operations

使用git rebase -i——autosquash来修复你的提交


用一个小的改变来“修复”一个旧的提交,而不改变旧提交的提交消息,其中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。现在您可以轻松地修改第一次提交。


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