Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Change the commit author of commits starting with a pattern (in message)

Tags:

git

I have a repository where there are some (actually a lot) commits generated by a program that look like:

Adding new domains: example.com

It happened (because of a wrong configuration) that these commits were made in the name of a co-worker. Now, I want to change these commits author:

Some Bot <[email protected]>

Github has a public script posted here to change the commits filtered by an old author. In this case, I want to change the author of commits whom messages start with a pattern: Adding new domains:. How can I do that?

like image 331
Ionică Bizău Avatar asked Jul 02 '15 13:07

Ionică Bizău


2 Answers

You can use the --env-filter and rev-list arguments (--grep=<pattern> in this case) to limit the commits to the ones you want to modify:

#!/bin/sh

git filter-branch --env-filter '

CORRECT_NAME="Your Correct Name"
CORRECT_EMAIL="[email protected]"

export GIT_AUTHOR_NAME="$CORRECT_NAME"
export GIT_AUTHOR_EMAIL="$CORRECT_EMAIL"

' --tag-name-filter cat -- --branches --tags --grep='Adding new domains'

You could save this script with the git- prefix and place it somewhere in your PATH, eg. /usr/local/bin/git-change-author (make sure it's executable) and run it from your repository as:

git change-author

Don't forget to git push --force since you rewrote the history.

like image 179
Calin Avatar answered Sep 30 '22 06:09

Calin


In this case I think you will have to use the --commit-filter filter. This is the only way to get your hands on both the commit message (from stdin) and the environment variables at the same time. The new script will have to completely replicate all the functionality of commit-tree. Fortunately, it won't look all that different from the GitHub script you linked.

First, read the entire commit message into a Bash variable:

commitmsg=$(cat)

Now get the first line of it and test whether it matches:

firstline=$(echo "$commitmsg" | head -n1 | grep "Adding new domains:")
if [ "$firstline" ]; then

We matched the commit message, so do the regular replacement, like in GitHub's script.

    export GIT_AUTHOR_NAME="$CORRECT_NAME"
    export GIT_AUTHOR_EMAIL="$CORRECT_EMAIL"
fi

Now we must call git commit-tree. The commit message is provided on stdin, just like we got it. Since our script is acting as a commit-tree surrogate, we need to pass all arguments on as well. The environment variables we (may have) modified will take care of themselves.

echo "$commitmsg" | git commit-tree "$@"

This will emit the hash onto stdout, just like we are required to do. At this point, we're done!

Here's a copy of the completed script. YMMV, of course, but I tested it and it works fine.

#!/bin/bash

git filter-branch --commit-filter '

CORRECT_NAME="Your Correct Name"
CORRECT_EMAIL="[email protected]"

commitmsg=$(cat)

firstline=$(echo "$commitmsg" | head -n1 | grep "Adding new domains:")
if [ "$firstline" ]; then
    export GIT_AUTHOR_NAME="$CORRECT_NAME"
    export GIT_AUTHOR_EMAIL="$CORRECT_EMAIL"
fi

echo "$commitmsg" | git commit-tree "$@"

' --tag-name-filter cat -- --branches --tags
like image 31
George Hilliard Avatar answered Sep 30 '22 07:09

George Hilliard