1

All answers I see regarding this question (here, here) only ever offer ways to either change the most recent commit(s) or all commits, however I want to change the author of only past commits that match a certain predicate. I have looked at git filter-branch (deprecated), git-filter-repo (its replacement), and bfg, but can't figure out how to make this change.

The way I intuitively tried to approach this is:

  1. First find all commits that I'm trying to change.
  2. Change author of those commits.

I have other commits in the history with the same author that I do not want to change, I only want to change commits that match a certain predicate.

So for step 1, find all commits whose commit messages have a specific substring:

git log --pretty=format:'%H %s' | grep 'My Commit Message' | awk '{print $1}'

Then for step 2, I expected to be able to do something like:

step1command | xargs -I@ git commit --amend --author "New Name <name@email.com>" @

But it doesn't seem to be so simple. How should I go about this?

Thanks!

torek
  • 448,244
  • 59
  • 642
  • 775
Daniel Porteous
  • 5,536
  • 3
  • 25
  • 44
  • The same answers as you already have seen: https://stackoverflow.com/a/750182/7976758 and https://stackoverflow.com/a/4982271/7976758 — just use a different predicate in `if`. – phd Sep 04 '21 at 22:18
  • Perhaps I'm not looking properly but I looked in the git man pages and there doesn't seem to be an environment variable that I can use in the `if` that will give me the commit message. – Daniel Porteous Sep 04 '21 at 22:21
  • 1
    You have commit ID in `$GIT_COMMIT` so you can use [`git show --format="%s" $GIT_COMMIT | grep`](https://git-scm.com/docs/git-show#Documentation/git-show.txt---formatltformatgt). You can also try [`--commit-filter`](https://stackoverflow.com/a/870367/7976758); it gives you every commit for inspection and modification; please be warned it's **very** slow 'cause it checks out every commit to a temporary directory. – phd Sep 04 '21 at 22:47
  • Third option to look at is [`git filter-repo`](https://github.com/newren/git-filter-repo); see [examples](https://github.com/newren/git-filter-repo/blob/main/Documentation/converting-from-filter-branch.md). – phd Sep 04 '21 at 22:49
  • 1
    Thanks! `git show` with a slight modification (`-s `) worked a treat! – Daniel Porteous Sep 04 '21 at 23:12

1 Answers1

2

Thanks to @phd's help, I was able to figure out a working solution:

git filter-branch --env-filter '
if git show -s --format="%s" $GIT_COMMIT | grep "My commit message";
then
    export GIT_AUTHOR_NAME="New Name"
    export GIT_AUTHOR_EMAIL="new@email.com"
fi
' --tag-name-filter cat -- --branches --tags

Then run git push -f to force change the existing commits in the remote repo.

Note, this only changes the author name and email, not the committer. For that, you'd want to change GIT_COMMITTER_NAME and GIT_COMMITTER_EMAIL also, like in this answer.

Daniel Porteous
  • 5,536
  • 3
  • 25
  • 44
  • 1
    This is the right answer. :-) Since filter-branch literally runs your shell fragments (with `eval` in this case), it makes it easy(ish) to do arbitrarily fancy stuff. It's too bad that filter-branch itself is so klunky and is officially deprecated, as it really is powerful. – torek Sep 05 '21 at 01:24