Skip to content

Commit

Permalink
Add git reauthor (tj#548)
Browse files Browse the repository at this point in the history
  • Loading branch information
tardypad authored and nicolaiskogheim committed Aug 2, 2016
1 parent f3954e1 commit 9b3e25f
Show file tree
Hide file tree
Showing 9 changed files with 683 additions and 0 deletions.
1 change: 1 addition & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ Patches and Suggestions
- Carl Casbolt <[email protected]>
- Ciro Nunes <[email protected]>
- Craig MacGregor <[email protected]>
- Damien Tardy-Panis <[email protected]>
- Dan Jackson <[email protected]>
- Daniel Schildt <[email protected]>
- Dave James Miller <[email protected]>
Expand Down
38 changes: 38 additions & 0 deletions Commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
- [`git psykorebase`](#git-psykorebase)
- [`git pull-request`](#git-pull-request)
- [`git rebase-patch`](#git-rebase-patch)
- [`git reauthor`](#git-reauthor)
- [`git release`](#git-release)
- [`git rename-tag`](#git-rename-tag)
- [`git repl`](#git-repl)
Expand Down Expand Up @@ -347,6 +348,7 @@ Does the following:
- Push the branch / tags
- Executes _.git/hooks/post-release.sh_ (if present)


## git rename-tag

Rename a tag (locally and remotely).
Expand All @@ -370,6 +372,42 @@ $ git tag
test2
```


## git reauthor

Rewrite history to change author's identity.

Replace the personal email and name of Jack to his work ones
```bash
$ git reauthor --old-email [email protected] --correct-email [email protected] --correct-name 'Jack Foobar'
```

Replace the email and name of Jack to the ones defined in the Git config
```bash
$ git reauthor --old-email [email protected] --use-config
```

Replace only the email of Jack (keep the name already used)
```bash
$ git reauthor --old-email jack@perso --correct-email [email protected]
```

Change only the committer email of Jack (keep the author email already used)
```bash
$ git reauthor --old-email [email protected] --correct-email [email protected] --type committer
```

Set Jack's identity as the only one of the whole repository
```bash
$ git reauthor --all --correct-email [email protected] --correct-name Jack
```

Set Jack as the only committer of the whole repository (keeps authors)
```bash
$ git reauthor --all --correct-email [email protected] --correct-name Jack --type committer
```


## git alias

Define, search and show aliases.
Expand Down
161 changes: 161 additions & 0 deletions bin/git-reauthor
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
#!/usr/bin/env bash


init_variables() {
COMMAND=${0#*-}

CONFIG=false
ALL=false
unset OLD_EMAIL
unset CORRECT_EMAIL
unset CORRECT_NAME
TYPE='both'
}


usage() {
cat << EOF
usage: git ${COMMAND} [<options>]
Options
-a, --all rewrite all identities in commits and tags
-c, --use-config define correct values from user Git config
-e, --correct-email <email> define the correct email to set
-n, --correct-name <name> define the correct name to set
-o, --old-email <email> rewrite identities matching old email in commits and tags
-t, --type <id> define the type of identities affected by the rewrite
author, committer, both (default)
EOF
}


error() {
if [[ -n "$1" ]]; then
local msg=$( echo "error: $1" | sed 's/\\n/\\n /g' )
echo -e "${msg}" >&2
fi
usage
exit 1
}


reauthor() {
local author='
if ${ALL} || [ "${GIT_AUTHOR_EMAIL}" = "${OLD_EMAIL}" ]; then
[ -z "${CORRECT_EMAIL+x}" ] || export GIT_AUTHOR_EMAIL="${CORRECT_EMAIL}"
[ -z "${CORRECT_NAME+x}" ] || export GIT_AUTHOR_NAME="${CORRECT_NAME}"
fi
'
local committer='
if ${ALL} || [ "${GIT_COMMITTER_EMAIL}" = "${OLD_EMAIL}" ]; then
[ -z "${CORRECT_EMAIL+x}" ] || export GIT_COMMITTER_EMAIL="${CORRECT_EMAIL}"
[ -z "${CORRECT_NAME+x}" ] || export GIT_COMMITTER_NAME="${CORRECT_NAME}"
fi
'
local filter

case "${TYPE}" in
author) filter="${author}" ;;
committer) filter="${committer}" ;;
both) filter="${author} ${committer}" ;;
esac

export ALL
export OLD_EMAIL
export CORRECT_EMAIL
export CORRECT_NAME

git filter-branch --force --env-filter "${filter}" \
--tag-name-filter cat -- --branches --tags
}


parse_options() {
while [[ "$#" -gt 0 ]]; do
case "$1" in
--all|-a)
ALL=true
shift
;;
--correct-email|-e)
[[ -n "${2+x}" ]] || error 'Missing correct-email value'
CORRECT_EMAIL="$2"
shift 2
;;
-h)
usage
exit 0
;;
--correct-name|-n)
[[ -n "${2+x}" ]] || error 'Missing correct-name value'
CORRECT_NAME="$2"
shift 2
;;
--old-email|-o)
[[ -n "${2+x}" ]] || error 'Missing old-email value'
OLD_EMAIL="$2"
shift 2
;;
--type|-t)
[[ -n "${2+x}" ]] || error 'Missing type value'
TYPE="$2"
shift 2
;;
--use-config|-c)
CONFIG=true
shift
;;
*)
error "invalid option '$1'"
;;
esac
done

if ${CONFIG}; then
# use config values if not explicitly already defined
[[ -n "${CORRECT_EMAIL+x}" ]] || CORRECT_EMAIL=$( git config user.email )
[[ -n "${CORRECT_NAME+x}" ]] || CORRECT_NAME=$( git config user.name )
fi
}


validate_options() {
# Either OLD_EMAIL should be set or ALL should be true
if [[ -z "${OLD_EMAIL+x}" ]] && ! ${ALL}; then
msg="missing target of the rewrite"
msg="${msg}\nuse either --old-email option or --all flag"
error "${msg}"
fi

# OLD_EMAIL shouldn't be set if ALL is true as well to prevent misuse
if [[ -n "${OLD_EMAIL+x}" ]] && ${ALL}; then
msg="ambiguous target of the rewrite"
msg="${msg}\nuse either --old-email option or --all flag"
error "${msg}"
fi

# CORRECT_NAME should be either unset or set to non-empty string
[[ -n "${CORRECT_NAME-x}" ]] || error "empty name is not allowed"

# Either CORRECT_EMAIL or CORRECT_NAME should be set
if [[ -z "${CORRECT_EMAIL+x}" ]] && [[ -z "${CORRECT_NAME+x}" ]]; then
msg="missing correct email and/or name to set"
msg="${msg}\nuse --correct-email and/or --correct-name options"
msg="${msg}\nor --use-config flag with user values set in Git config"
error "${msg}"
fi

# TYPE should be a valid identifier
if [[ "${TYPE}" != 'both' ]] \
&& [[ "${TYPE}" != 'author' ]] \
&& [[ "${TYPE}" != 'committer' ]]; then
error "invalid type '${TYPE}'"
fi
}


init_variables
parse_options "$@"
validate_options

reauthor
13 changes: 13 additions & 0 deletions etc/bash_completion.sh
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,19 @@ _git_psykorebase(){
__gitcomp "$(__git_heads) --continue --no-ff"
}

_git_reauthor(){
local prev="${COMP_WORDS[COMP_CWORD-1]}"
local comp

if [[ "${prev}" == '--type' ]] || [[ "${prev}" == '-t' ]]; then
comp='author committer full'
else
comp='--all --correct-email --correct-name --old-email --type --use-config'
fi

__gitcomp "${comp}"
}

_git_refactor(){
__git_extras_workflow "refactor"
}
Expand Down
1 change: 1 addition & 0 deletions man/git-extras.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ git-extras(1) -- Awesome GIT utilities
- **git-missing(1)** Show commits missing from another branch
- **git-pr(1)** Checks out a pull request locally
- **git-psykorebase(1)** Rebase a branch with a merge commit
- **git-reauthor(1)** Rewrite history to change author's identity
- **git-rebase-patch(1)** Rebases a patch
- **git-refactor(1)** Create refactor branch
- **git-release(1)** Commit, tag and push changes to the repository
Expand Down
Loading

0 comments on commit 9b3e25f

Please sign in to comment.