I have changed several things over the last hour and committed them step by step, but I just realized I've forgot to add a changed file some commits ago (for example, the commit marked as a0865...
below).
The Log looks like this:
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
Any ideas?
-
3Essentially a duplicate of How to modify a specified commit?Dan Dascalescu– Dan Dascalescu2019年01月09日 03:18:04 +00:00Commented Jan 9, 2019 at 3:18
8 Answers 8
Use git rebase
. Specifically:
- 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). Alternatively, usegit rebase -i commitHash^
. ReplacecommitHash
with the hash of the commit you want to edit, which you can get bygit log
- Mark the commit in question (
a0865...
) for edit by changing the wordpick
at the start of the line intoedit
. 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.
- If you have previously pushed the modified commits anywhere else, then you will have to push
--force
again to update them on the remote. However, the usual warnings about using--force
apply, and you can easily lose other people's work if you are not careful and coordinate with them beforehand.
[^vimnote]: If you are using vim
then you will have to hit the Insert key to edit, then Esc and type in :wq
to save the file, quit the editor, and apply the changes. Alternatively, you can configure a user-friendly git commit editor with git config --global core.editor "nano"
.
13 Comments
git add
.edit
, DO NOT DELETE the other commits listed in the file. If you do, the commits will be deleted and you'll have to follow these steps to get them back.--no-edit
is optional and will keep your existing commit message. If you intend to update the original commit message, leave that parameter out and you'll be dropped into another editor view to change it. Also, your working directory must be clean before you can git rebase --continue
. So if you're only adding one portion of code from your stash, you'll want to re-stash before continuing the rebase (i.e. between steps 7 & 8).To "fix" an old commit with a small change, without changing the commit message of the old commit, where OLDCOMMIT
is something like 091b73a
:
git add <my fixed files>
git commit --fixup=OLDCOMMIT
git rebase --interactive --autosquash OLDCOMMIT^
You can also use git commit --squash=OLDCOMMIT
to edit the old commit message during rebase.
See documentation for git commit and git rebase. As always, when rewriting git history, you should only fixup or squash commits you have not yet published to anyone else (including random internet users and build servers).
Detailed explanation
git commit --fixup=OLDCOMMIT
copies theOLDCOMMIT
commit message and automatically prefixesfixup!
so it can be put in the correct order during interactive rebase. (--squash=OLDCOMMIT
does the same but prefixessquash!
.)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
invim
) 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
^
inOLDCOMMIT^
means it's a reference to the commit just beforeOLDCOMMIT
. (OLDCOMMIT^
is the first parent ofOLDCOMMIT
.)
Optional automation
The above steps are good for verification and/or modifying the rebase instruction sequence, but it's also possible to skip/automate the interactive rebase text editor by:
- Setting
GIT_SEQUENCE_EDITOR
to a script. - Creating a git alias to automatically autosquash all queued fixups.
- Creating a git alias to automatically fixup a single commit.
17 Comments
--autosquash
is only valid when the --interactive
option is used.git config --global core.editor "pico"
. There are several other ways to configure git and/or change your system's default editor etcetera.with git 1.7, there's a really easy way using git rebase
:
stage your files:
git add $files
create a new commit and re-use commit message of your "broken" commit
git commit -c master~4
prepend fixup!
in the subject line (or squash!
if you want to edit commit (message)):
fixup! Factored out some common XPath Operations
use git rebase -i --autosquash
to fixup your commit
8 Comments
You asked me to rebase without telling me which branch you want to rebase against, and 'branch.master.merge'
and if I then use git rebase -i --autosquash
I just get a noop
subject line, rebasing the commit onto itself. Any idea what I do wrong?git rebase -i --autosquash HEAD~10
You can try a rebase --interactive
session to amend your old commit (provided you did not already push those commits to another repo).
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:
git rebase -i <after-this-commit>
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:
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.
Comments
Here's a function that implements @Greg's answer:
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
}
Usage: (while having only the intended changes in the staging) gitamendoldcommit $OLDCOMMIT
Comments
Aditionally, if you use git rebase -i
and want to go to the first commit of your current branch you can use git rebase -i --root
. Now you could easily modify your first commit.
1 Comment
Based on the marked answer the best way to do file changes on an old commit, not the previous one, is git rebase interactive
. But instead of using HEAD~NUMBER
I prefer to use hash commits. So my answer is like the following example, I want to change the getRandomArbitrary.ts
which I wrote many commits ago:
git log
: I run this command and then find the commit which I want to edit, and get the previous hash commit:git rebase -i COPIED_HASH_COMMIT
: By running this command, Git will show me a list of commit messages, I modify the one I want to edit, only change thepick
word toedit
and save the list:Now it's time to edit. The git history goes back to when the
getRandomArbitrary.ts
file was generated (it's like a time machine - change the future 😁)After the modification, I should save the git history and turn it back to the latest, by running
git add <file>
and thengit rebase --continue
it does exactly what I want.
HINT: I changed the git history so that up-stream will reject git push
. I must run git push -f
to do a force push (only this time).
Comments
In 2023 there are tools that do this: specifically git absorb. It is a great tool with the potential to change a lot of dusty git workflows.