mgilson mgilson - 2 months ago 13
Git Question

Rename variable in all commits on a given branch

My repo looks something like this:

(develop) D - E - F - G - H
/
(master) A - B - C


In the course of a code review (where I propose to merge
develop
into
master
), I was asked to change the name of a variable that was introduced in
D
(e.g. change
foo
to
bar
) . If I were patient, I could look through all the commits in
D
,
E
,
F
,
G
and
H
, create fixup commits for each and then rebase away
foo
entirely so that only
bar
remains in the history.

It seems like there should be a better way. A little googling makes me believe that I should be able to make something work with
git filter-branch
, but as I'm re-writing history and all -- I'd prefer to be able to get it right the first time instead of doing a bunch of weird stuff and messing up my repo entirely...

A few helpful constraints for the purposes of this problem:


  • We can assume that the names
    foo
    and
    bar
    are globally unique. e.g. if I did a
    sed -i 's/foo/bar/g' FILE
    , I'll be left with the result I want without worrying about names like
    foobar
    being incorrectly translated to
    barbar
    .

  • I'm using OS-X -- So POSIX compliant invocations of shell utilities are preferred (though I can work to translate from GNU variants if I must)


Answer

You were already quite close with your attempt.

git filter-branch --tree-filter 'sed -i "s/foo/bar/g" $FILES'  D^..H HEAD

assuming you are on your develop branch and you replace D and H with the commit index.

If you mess something up, there is always the reflog. You can also branch before or hand-write the commit reference before as a safeguard. I would recommend performing this in a separate branch, however.

$FILES here is a list of files containing your variable. I guess you could replace it with $(git grep --name-only foo). I didn't try it wowever, and you might have to escape the $ symbol. The simplest option is to hand-write a list of files there, of course.

Edit: just tried. it works without escaping. sed however fails if there is no input file, aborting the process. You also get a copy of your old refs in .git/refs/original/, so you might need to add -f after git filter-branch if this is not your first attempt, in order to overwrite the copy.

Comments