Write a shell script or Python code with default arguments for git-filter-repo

59 views Asked by At

Sometimes, I need to change the author/committer email and name (assume author=committer always) for all commits in a repository. I need to do this once for repo, but I may need to do it for multiple repos. I'm using this great answer:

How to amend several commits in Git to change author

git filter-repo --commit-callback '
    if commit.author_email == b"incorrect@email":
        commit.author_email = b"correct@email" 
        commit.author_name = b"Correct Name"
        commit.committer_email = b"correct@email" 
        commit.committer_name = b"Correct Name"
' 

However, every time I want to run this command for a new repository, I need to manually change incorrect@email, correct@email and Correct Name in the command above. I want to put this in a shell script, which:

  • accepts arguments old_email, new_email and author.
  • has default values for these arguments, if one or more is not passed
  • if a different argument is passed, it generates an error

How can I do that?

EDIT: I cooked up a preliminary implementation, but it doesn't work:

#!/bin/bash

# Define default values for email and name
old_email="incorrect@email"
new_email="correct@email"
new_name="Correct Name"

# Parse named arguments with getopts
while getopts ":o:n:e:" opt; do
  case $opt in
    o) old_email="$OPTARG" ;;
    n) new_name="$OPTARG" ;;
    e) new_email="$OPTARG" ;;
    \?) echo "Invalid option: -$OPTARG" >&2; exit 1 ;;
  esac
done

# Shift arguments to remove processed options
shift $((OPTIND-1))

# Check if any remaining arguments (unexpected)
if [ $# -gt 0 ]; then
  echo "Unexpected arguments provided." >&2
  exit 1
fi

# Construct the filter command using here-string
filter_cmd=$(cat << EOF '
if commit.author_email == b"$old_email":
  commit.author_email = b"$new_email"
  commit.author_name = b"$new_name"
  commit.committer_email = b"$new_email"
  commit.committer_name = b"$new_name"
'
EOF
)

# Run git filter-repo with the constructed command
echo "git filter-repo --commit-callback "$filter_cmd""
git filter-repo --commit-callback "$filter_cmd"

# Run git log to confirm that filtering worked
git log

Running this in a git repository gives me:

cat: ''$'\n''if commit.author_email == b"$old_email":'$'\n''  commit.author_email = b"$new_email"'$'\n''  commit.author_name = b"$new_name"'$'\n''  commit.committer_email = b"$new_email"'$'\n''  commit.committer_name = b"$new_name"'$'\n': No such file or directory
1

There are 1 answers

5
TTT On

You can do this all in one shot by using elif and else in the callback, as demonstrated in the git-filter-repo documentation examples, like this:

--------------------------------------------------
git-filter-repo --filename-callback '
  if commit.author_email == b"incorrect1@email"
    # change it
  elif commit.author_email == b"incorrect2@email"
    # change it
  else:
    # put default here
  '
--------------------------------------------------

Add additional swaps in elif blocks and the default in the else block.

Side Note: In the example in your question, you are setting both the Author and Committer based on the Author alone. Perhaps they are always the same in your repo in which case it doesn't matter. If they do ever differ though, you may wish to handle them separately.