A script that helps you rewrite git history (but doesn't do it for you!)
Use this at your own risk
(but is should be rather safe to do so)
Editing GIT_AUTHOR
and GIT_COMMITTER
data for multiple commits can be a pain.
Editing dates even more so.
This script tries to make the process somewhat easier. It works by creating a new branch, applying the changes there and letting the user to actually decide if he wants to keep the branch or throw it away.
The supported fields are:
AUTHOR_NAME
AUTHOR_EMAIL
AUTHOR_DATE
COMMITTER_NAME
COMMITTER_EMAIL
COMMITTER_DATE
Let's assume that we have the following repo and that we want to change the AUTHOR data
for commits C
and D
HEAD
|
*
A ---> B ---> C ---> D ---> E ---> F
Running this script will:
- checkout
B
- create a new branch
- cherry-pick commits:
C
,D
,E
andF
- edit
AUTHOR
andCOMMITER
data on each commit withgit commit --amend
So, after running the script our repo should look like this:
A ---> B ---> C ---> D ---> E ---> F (original-branch)
|
-----> C' --> D' --> E' --> F' (new-branch)
It is now up to us to ensure that everything is looking OK and actually overwrite history with e.g.:
git checkout original-branch
git reset --hard new-branch
git push
The recommended installation method is pipx. More
specifically, you can install git-rewrite
for your user with:
pipx install --spec https://github.com/pmav99/git-rewrite/archive/master.zip git-rewrite
The above command will create a virtual environment in ~/.local/pipx/venvs/git-rewrite
and add the git-rewrite
script in ~/.local/bin
.
The script has two subcommands:
git-rewrite dump
git-rewrite apply
Both are required.
The dump
step saves the commit data of the current history to a JSON file.
You are supposed to manually edit the file and make any changes you need (e.g. using sed
).
After you are done, you just apply
the changes to the repo.
The dump
script
- generates a list of commit hashes since the root commit using:
git rev-list --ancestry-path a84477f..HEAD
- parses the commit data of each commit using
git show --format=fuller
and saves them to a JSON file.
The end result is something like this:
{
"root_hash": "a84477f",
"commits": [
{
"commit_hash": "6726ad10be585c21c38726630f7dadf85833f10f",
"author_name": "John Doe",
"author_email": "john_doe@gmail.com",
"author_date": "Thu Jun 6 15:51:30 2019 +0300",
"committer_name": "john Doe",
"committer_email": "john_doe@gmail.com",
"committer_date": "Thu Jun 6 15:53:56 2019 +0300"
},
{
"commit_hash": "4bf077761d21090b46f178b5da534fb9a9da0ca9",
"author_name": "John Doe",
"author_email": "john_doe@gmail.com",
"author_date": "Thu Jun 6 18:12:34 2019 +0300",
"committer_name": "John Doe",
"committer_email": "john_doe@gmail.com",
"committer_date": "Thu Jun 6 18:12:34 2019 +0300"
}
]
}
-
the script checkouts the root commit and creates a new branch.
-
For each commit in the JSON file the script runs:
git cherry-pick
it in order to bring the changeset into the new branchgit commit --amend ...
in order to update theAUTHOR
and theCOMMITTER
data.