I was writing a simple script in the school computer, and committing the changes to Git (in a repo that was in my pendrive, cloned from my computer at home). After several c
If you are the only user of this repository, you can rewrite history using either git filter-branch (as svick wrote), or git fast-export/git fast-import plus filter script (as described in article referenced in docgnome answer), or interactive rebase. But either of those would change revisions from first changed commit onwards; this means trouble for anybody that based his/her changes on your branch pre-rewrite.
RECOVERY
If other developers didn't based their work on pre-rewrite version, simplest solution would be to re-clone (clone again).
Alternatively they can try git rebase --pull
, which would fast-forward if there weren't any changes in their repository, or rebase their branch on top of re-written commits (we want to avoid merge, as it would keep pre-rewrite comits forever). All of this assuming that they do not have not comitted work; use git stash
to stash away changes otherwise.
If other developers use feature branches, and/or git pull --rebase
doesn't work e.g. because upstream is not set up, they have to rebase their work on top of post-rewrite commits. For example just after fetching new changes (git fetch
), for a master
branch based on / forked from origin/master
, one needs to run
$ git rebase --onto origin/master origin/master@{1} master
Here origin/master@{1}
is pre-rewrite state (before fetch), see gitrevisions.
Alternate solution would be to use refs/replace/ mechanism, available in Git since version 1.6.5. In this solution you provide replacements for commits that have wrong email; then anybody who fetches 'replace' refs (something like fetch = +refs/replace/*:refs/replace/*
refspec in appropriate place in their .git/config
) would get replacements transparently, and those who do not fetch those refs would see old commits.
The procedure goes something like this:
Find all commits with wrong email, for example using
$ git log --author=user@wrong.email --all
For each wrong commit, create a replacement commit, and add it to object database
$ git cat-file -p |
sed -e 's/user@wrong\.email/user@example.com/g' > tmp.txt
$ git hash-object -t commit -w tmp.txt
Now that you have corrected commit in object database, you have to tell git to automatically and transparently replace wrong commit by corrected one using git replace command:
$ git replace
Finally, list all replacement to check if this procedure succeded
$ git replace -l
and check if replacements take place
$ git log --author=user@wrong.email --all
You can of course automate this procedure... well, all except using git replace
which doesn't have (yet) batch mode, so you would have to use shell loop for that, or replace "by hand".
NOT TESTED! YMMV.
Note that you might encounter some rough corners when using refs/replace/
mechanism: it is new, and not yet very well tested.