tags:

views:

741

answers:

2

I want to fix a file in past commit. This might affect all ascending commits.

Is there an easy way to do that? Can you give me a guideline of how to do that?

Many times when I commit twice I find that I've had error in the first commit, and I wish to fix the error without having to 'git reset' my last good commit.

For clarification. I want to change the actual commit, that is, I want the content of the past commit to be changed. IOW I want to change history!

+9  A: 

If you only want to amend the second to last commit (eg. not long ago, especially not before many branches and merges), then I use this procedure:

  1. git checkout -b tmp bad-commit
  2. fix the files
  3. git commit --amend
  4. git rebase tmp master

If you have merges in between, you may wanna try rebase -i -p, but the results may vary.

jpalecek
nope, that won't fix the *commit*. It will fix the tip of the branch but my history will be polluted with errors.I want to fix the actual commit before pushing it to the server.I want to change history!
Elazar Leibovich
This WILL change your history. After the rebase, the commit accessible from the tip of your branch, with the right name, will be the fixed commit. When you push, the bad commit won't be sent to the server.
jpalecek
My bad, you're correct of course.
Elazar Leibovich
It think the last rebase command should be `rebase --onto tmp bad-commit master`. As it currently stands the rebase would try to apply the bad commit to the fixed commit which may have not effect but might either cause conflicts or preserve and unwanted change depending on how radical the 'fix' was.
Charles Bailey
@Charles Bailey: To be 100 % sure, you'd have to use your command. However, I usually don't bother and it causes a conflict (which is easy to solve).
jpalecek
Tbh this even works when several merges have been performed, I had to fix a commit that was 2 weeks old, there were a few conflicts after running rebase but sorted within 10 minutes. life saver!
Rob
+4  A: 

It looks like:

You can find an example of rebase interactive in this comment: you could then avoid the temporary branch, but again, it is more complex.

I also rebase often to clean up the history of development so that changes are correct and grouped properly.

A made-up example:
I rename function foo to bar and commit it with a comment that says, "renamed foo to bar".
Then I move on to the next feature or fix, and commit that, and move on to the next.
Halfway through that, I find that I missed an instance of foo!
I commit my work in progress (or use git-stash), fix the missing 'foo' and commit that, then use git-rebase --interactive to merge the all the foo fixes together into one clean commit.
If I didn't use git-stash, then I'll use git-commit --amend (another form of rebasing) when I finally finish the feature that was in progress.

When my patches are pushed for review, all the pieces are correct and tell a coherent story. Sometimes I use git-rebase --interactive just to make adjacent temporally-separated changes which affect the same bits, so that changes are in context.

VonC