Question

Suppose I have a git branch and in final review before sharing it, I find a bunch of small errors, like spelling errors, for example. What I would like to do is apply that one patch as a "fixup", but have it actually affect many commits so there is no sign of the errors in the final history.

That is, if I change line A in one commit then change line B in another commit and then I have a patch that affects both line A and B, I'd like to do a rebase where the commit changing line A gets fixed by the A part of that patch and the commit changing line B gets the B part without manually figuring out which commits those are. Is there an easy way to do this?

I think the pseudocode script would be something like:

collect all hunks from the fixup
for commit in the history we are rebasing:
    check out commit
    for hunk in fixups:
        try:
            apply hunk to the working tree
        except:
            continue
        remove hunk from fixups
    commit the working tree.
Was it helpful?

Solution

It appears that git rebase --autosquash provides most of this functionality: If you have a commit that starts with fixup! then git rebase --autosquash will reorder that commit and make it a fixup, merging it in.

Furthermore, this seems to provide the rest of the functionality I was asking about!: https://github.com/torbiak/git-autofixup

With git autofixup, it takes your working changes, finds which parts of it go with what, and makes potentially several fixup! commits automatically. So...

  1. Make fixup changes.
  2. Run git autofixup master and it'll take the working changes and make one or more fixup! commits automatically.
  3. Finally do git rebase --autosquash master and the fixup! commits will be reordered into place.

OTHER TIPS

Here's a partial answer. It's ugly, but it works in a simple case.

I have a a commit, ce580fe, that renames something in several places. I want to make the original names never appear in the file. This is working at least in one case:

git rebase -i 0881a5a --exec "git diff ce580fe^ ce580fe | git apply --reject; git add -u; git commit --amend -C HEAD"
git diff ce580fe | git apply; git add -u git commit --amend -C HEAD # Apply any changes that got missed.

That is, at each rebase step, it applies the diff for ce580fe and allows part of the diff to be rejected. It adds all changes to known files and amends the commit with the same commit message. Then finally apply the difference between what's left and ce580fe to make the tree look like ce580fe.

It's kludgy that it doesn't do anything with the .rej file that git apply --reject produces. For actual renaming, using git rebase -i --exec with a search-and-replace line would probably be better.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top