I would like to create a git script which replaces author "A" with author "B" in a specified commit range (abcd..dcba). How can I do that? Here is what I have so far:
#!/bin/sh
#
# git-myCommand
#
#
git filter-branch --commit-filter '
if [ git rev-list --boundary 02e60c8..dc4c65f ]; then
if [ "$GIT_AUTHOR_NAME" = "A" ];then
GIT_AUTHOR_NAME="B";
fi;
fi;
git commit-tree "$@"'
problem is that git says
Rewrite $SHA1-Number git commit-tree: line 48: [: too many arguments
Is the git rev-list --boundary command even legal in an if statement? if i remove the if [git rev-list ... ] statement it'll work.
Ideal would be if I can add input variables. So the command would look like
git myCommand $AuthorExpression $AuthorReplace $CommitA..$CommitB
Edit: Some thinks that this question has already been asked. for those please read the problem above again and compare it wit the previously asked questions. AFAIK THIS question (test if commits are between commit A and commit B) has not been asked yet. If i'm wrong, sorry for wasting your time. Thanks to those who have tried to answer that question!
If you want to use parameters for the script, simply do
#!/bin/sh
#
# git-myCommand
#
#
AuthorExpression=$1
AuthorReplace=$2
CommitA=$3
CommitB=$4
git filter-branch --commit-filter "
if git rev-list --boundary '$CommitA'..'$CommitB'; then
if [ \"\$GIT_AUTHOR_NAME\" = '$AuthorExpression' ];then
GIT_AUTHOR_NAME='$AuthorReplace';
fi;
fi;
git commit-tree \"\$@\""
However, note that you will probably want to edit GIT_COMMITTER_NAME
, GIT_COMMITTER_EMAIL
and GIT_AUTHOR_EMAIL
as well. See this answer .
You can substitute variables from your shell script into the script that you pass in to git filter-branch
. You just need to be careful to get the quoting right. Since you're in single quotes, you can't substitute the variable directly, but you can end the single quotes and open a double quoted string for the substitution, then close the double quoted string and open the single quoted string back up again; the strings will be appended after expansion. And within the single quoted string, you should include quotes that will surround the expanded string from the variable, in case it contains spaces or other characters.
Rather than trying to limit the revisions within the filter script, it's better to just pass the revisions in to git filter-branch
so that it will only ever do anything to those commits. git filter-branch
takes the same arguments as git rev-list
at the end of the command (though you have to delimit them with a --
in order for it to interpret --boundary
as an rev-list
argument).
#!/bin/sh
#
# git-myCommand
#
#
AuthorExpression=$1
AuthorReplace=$2
CommitA=$3
CommitB=$4
git filter-branch --commit-filter '
if [ "$GIT_AUTHOR_NAME" = "'"$AuthorExpression"'" ];then
GIT_AUTHOR_NAME="'"$AuthorReplace"'";
fi;
git commit-tree "$@"' -- --boundary "$CommitA".."$CommitB"
edit : Missed the problem with git rev-list
when first answering.
Others have addressed parameter quoting. The big remaining problem is the test:
if [ git-rev-list ... ]
The commit filter is just a shell script fragment, so this tells the shell to run the command:
[ git-rev-list ... ]
and test whether the exit status of that command is zero (true) or not (false). The [
command, also known as test
, does not have any git
built-ins.
What you seem to want is to tell whether the original commit being filtered is a member of the range A
.. B
inclusive. Let's first note this, from the filter-branch documentation:
The filters are applied in the order as listed below. The <command> argument is always evaluated in the shell context using the eval command (with the notable exception of the commit filter, for technical reasons). Prior to that, the
$GIT_COMMIT
environment variable will be set to contain the id of the commit being rewritten.
Thus, you could write something like this:
A=$(git rev-parse $3) || exit 1
B=$(git rev-parse $4) || exit 1
git filter-branch --commit-filter "
if git merge-base --is-ancestor \$GIT_COMMIT $B &&
! git merge-base --is-ancestor \$GIT_COMMIT $A^; then
The first merge-base
tests whether $GIT_COMMIT
is an ancestor of the higher rev (is equal to $B
or comes "before" it topologically). The second excludes commits that come before the lower rev ( $A
), using the hat-suffix to avoid excluding $A
itself.
Here's a variant of Brian Campbell's script using this technique (well, I also changed the quote expansion technique too).
#! /bin/sh
case $# in
4) ;;
*) echo "usage: $0 oldauthor newauthor firstrev lastrev" >&2; exit 1;;
esac
AuthorExpression=$1
AuthorReplace=$2
A=$(git rev-parse --verify $3^{commit}) || exit 1
B=$(git rev-parse --verify $4^{commit}) || exit 1
git filter-branch --commit-filter "
if git merge-base --is-ancestor \$GIT_COMMIT $B &&
! git merge-base --is-ancestor \$GIT_COMMIT $A^; then
if [ \"\$GIT_AUTHOR_NAME\" = '$AuthorExpression' ]; then
GIT_AUTHOR_NAME='$AuthorReplace'
fi
fi
git commit-tree \"\$@\""
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.