Question

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 commits I realized I was committing stuff as the root user.

Is there any way to change the author of these commits to my name?

Was it helpful?

Solution

Changing the author (or committer) would require re-writing all of the history. If you're okay with that and think it's worth it then you should check out git filter-branch. The man page includes several examples to get you started. Also note that you can use environment variables to change the name of the author, committer, dates, etc. -- see the "Environment Variables" section of the git man page.

Specifically, you can fix all the wrong author names and emails for all branches and tags with this command (source: GitHub help):

#!/bin/sh

git filter-branch --env-filter '
OLD_EMAIL="your-old-email@example.com"
CORRECT_NAME="Your Correct Name"
CORRECT_EMAIL="your-correct-email@example.com"
if [ "$GIT_COMMITTER_EMAIL" = "$OLD_EMAIL" ]
then
    export GIT_COMMITTER_NAME="$CORRECT_NAME"
    export GIT_COMMITTER_EMAIL="$CORRECT_EMAIL"
fi
if [ "$GIT_AUTHOR_EMAIL" = "$OLD_EMAIL" ]
then
    export GIT_AUTHOR_NAME="$CORRECT_NAME"
    export GIT_AUTHOR_EMAIL="$CORRECT_EMAIL"
fi
' --tag-name-filter cat -- --branches --tags

OTHER TIPS

Using Interactive Rebase

You could do

git rebase -i -p <some HEAD before all of your bad commits>

Then mark all of your bad commits as "edit" in the rebase file. If you also want to change your first commit, you have to manually add it as first line in the rebase file (follow the format of the other lines). Then, when git asks you to amend each commit, do

 git commit --amend --author "New Author Name <email@address.com>" 

edit or just close the editor that opens, and then do

git rebase --continue

to continue the rebase.

You could skip opening the editor altogether here by appending --no-edit so that the command will be:

git commit --amend --author "New Author Name <email@address.com>" --no-edit && \
git rebase --continue

Single Commit

As some of the commenters have noted, if you just want to change the most recent commit, the rebase command is not necessary. Just do

 git commit --amend --author "New Author Name <email@address.com>"

This will change the author to the name specified, but the committer will be set to your configured user in git config user.name and git config user.email. If you want to set the committer to something you specify, this will set both the author and the committer:

 git -c user.name="New Author Name" -c user.email=email@address.com commit --amend --reset-author

Note on Merge Commits

There was a slight flaw in my original response. If there are any merge commits between the current HEAD and your <some HEAD before all your bad commits>, then git rebase will flatten them (and by the way, if you use GitHub pull requests, there are going to be a ton of merge commits in your history). This can very often lead to very different history (as duplicate changes may be "rebased out"), and in the worst case, it can lead to git rebase asking you to resolve difficult merge conflicts (which were likely already resolved in the merge commits). The solution is to use the -p flag to git rebase, which will preserve the merge structure of your history. The manpage for git rebase warns that using -p and -i can lead to issues, but in the BUGS section it says "Editing commits and rewording their commit messages should work fine."

I've added -p to the above command. For the case where you're just changing the most recent commit, this is not an issue.

You can also do:

git filter-branch --commit-filter '
        if [ "$GIT_COMMITTER_NAME" = "<Old Name>" ];
        then
                GIT_COMMITTER_NAME="<New Name>";
                GIT_AUTHOR_NAME="<New Name>";
                GIT_COMMITTER_EMAIL="<New Email>";
                GIT_AUTHOR_EMAIL="<New Email>";
                git commit-tree "$@";
        else
                git commit-tree "$@";
        fi' HEAD

Note, if you are using this command in the Windows command prompt, then you need to use " instead of ':

git filter-branch --commit-filter "
        if [ "$GIT_COMMITTER_NAME" = "<Old Name>" ];
        then
                GIT_COMMITTER_NAME="<New Name>";
                GIT_AUTHOR_NAME="<New Name>";
                GIT_COMMITTER_EMAIL="<New Email>";
                GIT_AUTHOR_EMAIL="<New Email>";
                git commit-tree "$@";
        else
                git commit-tree "$@";
        fi" HEAD

One liner, but be careful if you have a multi-user repository - this will change all commits to have the same (new) author and committer.

git filter-branch -f --env-filter "GIT_AUTHOR_NAME='Newname'; GIT_AUTHOR_EMAIL='new@email'; GIT_COMMITTER_NAME='Newname'; GIT_COMMITTER_EMAIL='new@email';" HEAD

With linebreaks in the string (which is possible in bash):

git filter-branch -f --env-filter "
    GIT_AUTHOR_NAME='Newname'
    GIT_AUTHOR_EMAIL='new@email'
    GIT_COMMITTER_NAME='Newname'
    GIT_COMMITTER_EMAIL='new@email'
  " HEAD

It happens when you do not have a $HOME/.gitconfig initialized. You may fix this as:

git config --global user.name "you name"
git config --global user.email you@domain.com
git commit --amend --reset-author

tested with git version 1.7.5.4

For a single commit:

git commit --amend --author="Author Name <email@address.com>"

(extracted from asmeurer's answer)

In the case where just the top few commits have bad authors, you can do this all inside git rebase -i using the exec command and the --amend commit, as follows:

git rebase -i HEAD~6 # as required

which presents you with the editable list of commits:

pick abcd Someone else's commit
pick defg my bad commit 1
pick 1234 my bad commit 2

Then add exec ... --author="..." lines after all lines with bad authors:

pick abcd Someone else's commit
pick defg my bad commit 1
exec git commit --amend --author="New Author Name <email@address.com>" -C HEAD
pick 1234 my bad commit 2
exec git commit --amend --author="New Author Name <email@address.com>" -C HEAD

save and exit editor (to run).

This solution may be longer to type than some others, but it's highly controllable - I know exactly what commits it hits.

Thanks to @asmeurer for the inspiration.

Github has a nice solution, which is the following shell script:

#!/bin/sh

git filter-branch --env-filter '

an="$GIT_AUTHOR_NAME"
am="$GIT_AUTHOR_EMAIL"
cn="$GIT_COMMITTER_NAME"
cm="$GIT_COMMITTER_EMAIL"

if [ "$GIT_COMMITTER_EMAIL" = "your@email.to.match" ]
then
    cn="Your New Committer Name"
    cm="Your New Committer Email"
fi
if [ "$GIT_AUTHOR_EMAIL" = "your@email.to.match" ]
then
    an="Your New Author Name"
    am="Your New Author Email"
fi

export GIT_AUTHOR_NAME="$an"
export GIT_AUTHOR_EMAIL="$am"
export GIT_COMMITTER_NAME="$cn"
export GIT_COMMITTER_EMAIL="$cm"
'

As docgnome mentioned, rewriting history is dangerous and will break other people's repositories.

But if you really want to do that and you are in a bash environment (no problem in Linux, on Windows, you can use git bash, that is provided with the installation of git), use git filter-branch:

git filter-branch --env-filter '
  if [ $GIT_AUTHOR_EMAIL = bad@email ];
    then GIT_AUTHOR_EMAIL=correct@email;
  fi;
export GIT_AUTHOR_EMAIL'

To speed things up, you can specify a range of revisions you want to rewrite:

git filter-branch --env-filter '
  if [ $GIT_AUTHOR_EMAIL = bad@email ];
    then GIT_AUTHOR_EMAIL=correct@email;
  fi;
export GIT_AUTHOR_EMAIL' HEAD~20..HEAD

When taking over an unmerged commit from another author, there is an easy way to handle this.

git commit --amend --reset-author

You can use this as a alias so you can do:

git change-commits GIT_AUTHOR_NAME "old name" "new name"

or for the last 10 commits:

git change-commits GIT_AUTHOR_EMAIL "old@email.com" "new@email.com" HEAD~10..HEAD

Add to ~/.gitconfig:

[alias]
    change-commits = "!f() { VAR=$1; OLD=$2; NEW=$3; shift 3; git filter-branch --env-filter \"if [[ \\\"$`echo $VAR`\\\" = '$OLD' ]]; then export $VAR='$NEW'; fi\" $@; }; f "

Source: https://github.com/brauliobo/gitconfig/blob/master/configs/.gitconfig

Hope it is useful.

This is a more elaborated version of @Brian's version:

To change the author and committer, you can do this (with linebreaks in the string which is possible in bash):

git filter-branch --env-filter '
    if [ "$GIT_COMMITTER_NAME" = "<Old name>" ];
    then
        GIT_COMMITTER_NAME="<New name>";
        GIT_COMMITTER_EMAIL="<New email>";
        GIT_AUTHOR_NAME="<New name>";
        GIT_AUTHOR_EMAIL="<New email>";
    fi' -- --all

You might get one of these errors:

  1. The temporary directory exists already
  2. Refs starting with refs/original exists already
    (this means another filter-branch has been run previously on the repository and the then original branch reference is backed up at refs/original)

If you want to force the run in spite of these errors, add the --force flag:

git filter-branch --force --env-filter '
    if [ "$GIT_COMMITTER_NAME" = "<Old name>" ];
    then
        GIT_COMMITTER_NAME="<New name>";
        GIT_COMMITTER_EMAIL="<New email>";
        GIT_AUTHOR_NAME="<New name>";
        GIT_AUTHOR_EMAIL="<New email>";
    fi' -- --all

A little explanation of the -- --all option might be needed: It makes the filter-branch work on all revisions on all refs (which includes all branches). This means, for example, that tags are also rewritten and is visible on the rewritten branches.

A common "mistake" is to use HEAD instead, which means filtering all revisions on just the current branch. And then no tags (or other refs) would exist in the rewritten branch.

  1. run git rebase -i <sha1 or ref of starting point>
  2. mark all commits that you want to change with edit (or e)
  3. loop the following two commands until you have processed all the commits:

    git commit --amend --reuse-message=HEAD --author="New Author <new@author.email>" ; git rebase --continue

This will keep all the other commit information (including the dates). The --reuse-message=HEAD option prevents the message editor from launching.

I use the following to rewrite the author for an entire repository, including tags and all branches:

git filter-branch --tag-name-filter cat --env-filter "
  export GIT_AUTHOR_NAME='New name';
  export GIT_AUTHOR_EMAIL='New email'
" -- --all

Then, as described in the MAN page of filter-branch, remove all original refs backed up by filter-branch (this is destructive, backup first):

git for-each-ref --format="%(refname)" refs/original/ | \
xargs -n 1 git update-ref -d

I adapted this solution which works by ingesting a simple author-conv-file (format is the same as one for git-cvsimport). It works by changing all users as defined in the author-conv-file across all branches.

We used this in conjunction with cvs2git to migrate our repository from cvs to git.

i.e. Sample author-conv-file

john=John Doe <john.doe@hotmail.com>
jill=Jill Doe <jill.doe@hotmail.com>

The script:

 #!/bin/bash

 export $authors_file=author-conv-file

 git filter-branch -f --env-filter '

 get_name () {
     grep "^$1=" "$authors_file" |
     sed "s/^.*=\(.*\) <.*>$/\1/"
 }

 get_email () {
     grep "^$1=" "$authors_file" |
     sed "s/^.*=.* <\(.*\)>$/\1/"
 }

 GIT_AUTHOR_NAME=$(get_name $GIT_COMMITTER_NAME) &&
     GIT_AUTHOR_EMAIL=$(get_email $GIT_COMMITTER_NAME) &&
     GIT_COMMITTER_NAME=$GIT_AUTHOR_NAME &&
     GIT_COMMITTER_EMAIL=$GIT_AUTHOR_EMAIL &&
     export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL &&
     export GIT_COMMITTER_NAME GIT_COMMITTER_EMAIL
 ' -- --all

I found the presented versions way to aggressive, especially if you commit patches from other developers, this will essentially steal their code.

The version below does work on all branches and changes the author and comitter separately to prevent that.

Kudos to leif81 for the all option.

#!/bin/bash

git filter-branch --env-filter '
if [ "$GIT_AUTHOR_NAME" = "<old author>" ];
then
    GIT_AUTHOR_NAME="<new author>";
    GIT_AUTHOR_EMAIL="<youmail@somehost.ext>";
fi
if [ "$GIT_COMMITTER_NAME" = "<old committer>" ];
then
    GIT_COMMITTER_NAME="<new commiter>";
    GIT_COMMITTER_EMAIL="<youmail@somehost.ext>";
fi
' -- --all
  1. Change commit author name & email by Amend, then replacing old-commit with new-one:

    $ git checkout <commit-hash>                            # checkout to the commit need to modify  
    $ git commit --amend --author "name <author@email.com>" # change the author name and email
    
    $ git replace <old-commit-hash> <new-commit-hash>      # replace the old commit by new one
    $ git filter-branch -- --all                           # rewrite all futures commits based on the replacement                   
    
    $ git replace -d <old-commit-hash>     # remove the replacement for cleanliness 
    $ git push -f origin HEAD              # force push 
    
  2. Another way Rebasing:

    $ git rebase -i <good-commit-hash>      # back to last good commit
    
    # Editor would open, replace 'pick' with 'edit' before the commit want to change author
    
    $ git commit --amend --author="author name <author@email.com>"  # change the author name & email
    
    # Save changes and exit the editor
    
    $ git rebase --continue                # finish the rebase
    

I should point out that if the only problem is that the author/email is different from your usual, this is not a problem. The correct fix is to create a file called .mailmap at the base of the directory with lines like

Name you want <email you want> Name you don't want <email you don't want>

And from then on, commands like git shortlog will consider those two names to be the same (unless you specifically tell them not to). See http://schacon.github.com/git/git-shortlog.html for more information.

This has the advantage of all the other solutions here in that you don't have to rewrite history, which can cause problems if you have an upstream, and is always a good way to accidentally lose data.

Of course, if you committed something as yourself and it should really be someone else, and you don't mind rewriting history at this point, changing the commit author is probably a good idea for attribution purposes (in which case I direct you to my other answer here).

A single command to change the author for the last N commits:

git rebase -i HEAD~4 -x "git commit --amend --author 'Author Name <author.name@mail.com>' --no-edit"

NOTES

  • the --no-edit flag makes sure the git commit --amend doesn't ask an extra confirmation
  • when you use git rebase -i, you can manually select the commits where to change the author,

the file you edit will look like this:

pick 897fe9e simplify code a little
exec git commit --amend --author 'Author Name <author.name@mail.com>' --no-edit
pick abb60f9 add new feature
exec git commit --amend --author 'Author Name <author.name@mail.com>' --no-edit
pick dc18f70 bugfix
exec git commit --amend --author 'Author Name <author.name@mail.com>' --no-edit

You can then still modify some lines to see where you want to change the author. This gives you a nice middle ground between automation and control: you see the steps that will run, and once you save everything will be applied at once.

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:

  1. Find all commits with wrong email, for example using

    $ git log --author=user@wrong.email --all
    
  2. For each wrong commit, create a replacement commit, and add it to object database

    $ git cat-file -p <ID of wrong commit> | 
      sed -e 's/user@wrong\.email/user@example.com/g' > tmp.txt
    $ git hash-object -t commit -w tmp.txt
    <ID of corrected commit>
    
  3. 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 <ID of wrong commit> <ID of corrected commit>
    
  4. 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.

The fastest, easiest way to do this is to use the --exec argument of git rebase:

git rebase -i -p --exec 'git commit --amend --reset-author --no-edit'

This will create a todo-list that looks like this:

pick ef11092 Blah blah blah
exec git commit --amend --reset-author --no-edit
pick 52d6391 Blah bloh bloo
exec git commit --amend --reset-author --no-edit
pick 30ebbfe Blah bluh bleh
exec git commit --amend --reset-author --no-edit
...

and this will work all automatically, which works when you have hundreds of commits.

If the commits you want to fix are the latest ones, and just a couple of them, you can use a combination of git reset and git stash to go back an commit them again after configuring the right name and email.

The sequence will be something like this (for 2 wrong commits, no pending changes):

git config user.name <good name>
git config user.email <good email>
git reset HEAD^
git stash
git reset HEAD^
git commit -a
git stash pop
git commit -a

If you are using Eclipse with EGit, then there is a quite easy solution.
Assumption: you have commits in a local branch 'local_master_user_x' which cannot be pushed to a remote branch 'master' because of the invalid user.

  1. Checkout the remote branch 'master'
  2. Select the projects/folders/files for which 'local_master_user_x' contains changes
  3. Right-click - Replace with - Branch - 'local_master_user_x'
  4. Commit these changes again, this time as the correct user and into the local branch 'master'
  5. Push to remote 'master'

Using interactive rebase, you can place an amend command after each commit you want to alter. For instance:

pick a07cb86 Project tile template with full details and styling
x git commit --amend --reset-author -Chead

Note that git stores two different e-mail addresses, one for the committer (the person who committed the change) and another one for the author (the person who wrote the change).

The committer information isn't displayed in most places, but you can see it with git log -1 --format=%cn,%ce (or use show instead of log to specify a particular commit).

While changing the author of your last commit is as simple as git commit --amend --author "Author Name <email@example.com>", there is no one-liner or argument to do the same to the committer information.

The solution is to (temporarily, or not) change your user information, then amend the commit, which will update the committer to your current information:

git config user.email my_other_email@example.com 
git commit --amend

We have experienced an issue today where a UTF8 character in an author name was causing trouble on the build server, so we had to rewrite the history to correct this. The steps taken were:

Step 1: Change your username in git for all future commits, as per instructions here: https://help.github.com/articles/setting-your-username-in-git/

Step 2: Run the following bash script:

#!/bin/sh

REPO_URL=ssh://path/to/your.git
REPO_DIR=rewrite.tmp

# Clone the repository
git clone ${REPO_URL} ${REPO_DIR}

# Change to the cloned repository
cd ${REPO_DIR}

# Checkout all the remote branches as local tracking branches
git branch --list -r origin/* | cut -c10- | xargs -n1 git checkout

# Rewrite the history, use a system that will preseve the eol (or lack of in commit messages) - preferably Linux not OSX
git filter-branch --env-filter '
OLD_EMAIL="me@something.com"
CORRECT_NAME="New Me"

if [ "$GIT_COMMITTER_EMAIL" = "$OLD_EMAIL" ]
then
    export GIT_COMMITTER_NAME="$CORRECT_NAME"
fi
if [ "$GIT_AUTHOR_EMAIL" = "$OLD_EMAIL" ]
then
    export GIT_AUTHOR_NAME="$CORRECT_NAME"
fi
' --tag-name-filter cat -- --branches --tags

# Force push the rewritten branches + tags to the remote
git push -f

# Remove all knowledge that we did something
rm -rf ${REPO_DIR}

# Tell your colleagues to `git pull --rebase` on all their local remote tracking branches

Quick overview: Checkout your repository to a temp file, checkout all the remote branches, run the script which will rewrite the history, do a force push of the new state, and tell all your colleagues to do a rebase pull to get the changes.

We had trouble with running this on OS X because it somehow messed up line endings in commit messages, so we had to re-run it on a Linux machine afterwards.

Your problem is really common. See "Using Mailmap to Fix Authors List in Git"

For the sake of simplicity, I have created a script to ease the process: git-changemail

After putting that script on your path, you can issue commands like:

  • Change author matchings on current branch

    $ git changemail -a old@email.com -n newname -m new@email.com
    
  • Change author and committer matchings on <branch> and <branch2>. Pass -f to filter-branch to allow rewriting backups

    $ git changemail -b old@email.com -n newname -m new@email.com -- -f &lt;branch> &lt;branch2>
    
  • Show existing users on repo

    $ git changemail --show-both
    

By the way, after making your changes, clean the backup from the filter-branch with: git-backup-clean

If you are the only user of this repo or you don't care about possibly breaking the repo for other users, then yes. If you've pushed these commits and they exist where somewhere else can access them, then no, unless you don't care about breaking other people's repos. The problem is by changing these commits you will be generating new SHAs which will cause them to be treated as different commits. When someone else tries to pull in these changed commits, the history is different and kaboom.

This page http://inputvalidation.blogspot.com/2008/08/how-to-change-git-commit-author.html describes how to do it. (I haven't tried this so YMMV)

I want to add my Example too. I want to create a bash_function with given parameter.

this works in mint-linux-17.3

# $1 => email to change, $2 => new_name, $3 => new E-Mail

function git_change_user_config_for_commit {

 # defaults
 WRONG_EMAIL=${1:-"you_wrong_mail@hello.world"}
 NEW_NAME=${2:-"your name"}
 NEW_EMAIL=${3:-"new_mail@hello.world"}

 git filter-branch -f --env-filter "
  if [ \$GIT_COMMITTER_EMAIL = '$WRONG_EMAIL' ]; then
    export GIT_COMMITTER_NAME='$NEW_NAME'
    export GIT_COMMITTER_EMAIL='$NEW_EMAIL'
  fi
  if [ \$GIT_AUTHOR_EMAIL = '$WRONG_EMAIL' ]; then
    export GIT_AUTHOR_NAME='$NEW_NAME'
    export GIT_AUTHOR_EMAIL='$NEW_EMAIL'
  fi
 " --tag-name-filter cat -- --branches --tags;
}
git rebase -i YOUR_FIRTS_COMMIT_SHA^

while true; do git commit --amend --author="Name Surname <email@example.com>" --no-edit && git rebase --continue; done

Press ^C # after the rebase is done (the loop will keep updating last commit)

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