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"
.
-
24What if you have unstaged changes which you want to add to the edit? If I stash them, I couldn't
git add
.Sam– Sam2013年06月05日 01:35:33 +00:00Commented Jun 5, 2013 at 1:35 -
20Sam you can simply unstash the changes while on the commit in question, it will work fine.omnikron– omnikron2013年09月12日 12:13:03 +00:00Commented Sep 12, 2013 at 12:13
-
21Note: When you mark the commit with
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.David Tuite– David Tuite2013年12月04日 17:21:55 +00:00Commented Dec 4, 2013 at 17:21 -
7Regarding what @DavidTuite said, a habit of mine when doing stuff on git that I'm not sure how will turn out is creating a "branchname-ref" branch to save the current state of the timeline in case I screw things up. When I'm done, I delete it.Raphael– Raphael2016年04月29日 22:13:42 +00:00Commented Apr 29, 2016 at 22:13
-
5Note that the
--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 cangit 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).etipaced– etipaced2019年12月13日 15:55:10 +00:00Commented Dec 13, 2019 at 15:55
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.
-
3Terrific answer. When I executed the final rebase command, it opened vim to allow me to edit the commit message, which i didn't need to do. Is there a way to prevent that from happening?Jonah– Jonah2016年10月21日 04:58:55 +00:00Commented Oct 21, 2016 at 4:58
-
13@Jonah: the editor isn't opened to edit the commit message, but to confirm (or edit) the rebase steps. It cannot be avoided;
--autosquash
is only valid when the--interactive
option is used.Joel Purra– Joel Purra2016年10月21日 11:01:52 +00:00Commented Oct 21, 2016 at 11:01 -
8Using this solution I am stuck git showing up VIM. My problem is, I don't know how to use VIM. How the heck do I get out of it, how can I control this thing, this so confusing.nww04– nww042016年10月30日 13:30:58 +00:00Commented Oct 30, 2016 at 13:30
-
3@NeonWarge: the editor of choice is configurable using for example
git config --global core.editor "pico"
. There are several other ways to configure git and/or change your system's default editor etcetera.Joel Purra– Joel Purra2016年10月30日 17:12:05 +00:00Commented Oct 30, 2016 at 17:12 -
3
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
-
3+1. Nice use of the new fixup directive (1.7+): stackoverflow.com/questions/2302736/trimming-git-checkins/…VonC– VonC2010年04月27日 08:15:06 +00:00Commented Apr 27, 2010 at 8:15
-
@knittl I was trying out your method to add another file to an old commit of mine (not pushed) but when rebasing I get
You asked me to rebase without telling me which branch you want to rebase against, and 'branch.master.merge'
and if I then usegit rebase -i --autosquash
I just get anoop
subject line, rebasing the commit onto itself. Any idea what I do wrong?oschrenk– oschrenk2012年03月01日 16:24:43 +00:00Commented Mar 1, 2012 at 16:24 -
9@oschrenk: You need to provide a commit to which you want to rebase, e.g.
git rebase -i --autosquash HEAD~10
knittl– knittl2012年03月01日 16:42:25 +00:00Commented Mar 1, 2012 at 16:42 -
1Good answer but I also needed to add a commit against which to rebase. Would be great if you could update it.Paul Odeon– Paul Odeon2013年03月08日 09:44:50 +00:00Commented Mar 8, 2013 at 9:44
-
@PaulOdeon: I don't understand your question. What are you trying to do, and where are you having problems?knittl– knittl2013年03月08日 16:23:51 +00:00Commented Mar 8, 2013 at 16:23
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.
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
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.
-
Great, It returns a list of commits and the developer can edit the one hi/she wants to modify. Thanks.AmerllicA– AmerllicA2024年09月26日 09:41:55 +00:00Commented Sep 26, 2024 at 9:41
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).
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.