Pruning a Git Repository
August 03, 2024
Removing Entire Files
Did you ever want to delete files entirely from the history of a Git repo, while preserving the commit attributes? Such as time stamps and committer info? Of course, you did!
Run the following command to delete files entirely and to prune empty commits:
# Delete *.term files:
FILTER_BRANCH_SQUELCH_WARNING=1 git filter-branch -f --prune-empty \
--index-filter 'git rm -rf --cached --ignore-unmatch \*\*/\*.term' \
--env-filter 'GIT_COMMITTER_NAME="$GIT_COMMITTER_NAME"; GIT_COMMITTER_EMAIL="$GIT_COMMITTER_EMAIL";' HEAD
--index-filter
: removes all files matching the pattern**/*.term
.--env-filter
: preserves the commiter name and email.
Rebasing to Clean out Merge Commits
Never loved merge commits? Don't worry, we can dissolve them.
Save this file as amend_head_commit.sh
:
#!/bin/bash
# https://git-scm.com/book/en/v2/Git-Internals-Environment-Variables
GIT_AUTHOR_NAME=$(git show --no-patch --format=%an "$1") \
GIT_AUTHOR_EMAIL=$(git show --no-patch --format=%ae "$1") \
GIT_AUTHOR_DATE=$(git show --no-patch --format=%ad "$1") \
GIT_COMMITTER_NAME=$(git show --no-patch --format=%cn "$1") \
GIT_COMMITTER_EMAIL=$(git show --no-patch --format=%ce "$1") \
GIT_COMMITTER_DATE=$(git show --no-patch --format=%cd "$1") \
git commit --amend --no-edit
Run:
git rebase -i --exec ./amend_head_commit.sh "$UNTIL_COMMIT_HASH"
The todo file needs some adjusting. Run in a different shell:
gawk -i inplace '/^pick /{hash=$2} /^exec /{print $0 " " hash; next} {print}' .git/rebase-merge/git-rebase-todo
The script matches each pick
line, remembers the hash
...
pick 3874d2ac Something nice
exec ./amend_head_commit.sh
...and appends it to the next exec
line:
pick 3874d2ac Something nice
exec ./amend_head_commit.sh 3874d2ac
Exit the editor called by git rebase
and let it do its magic. 🪄✨
Yay! 🙌 No more knots (in your stomach)! 😌
Patching E-Mail
Made commits with the wrong email address? I got you covered!
FILTER_BRANCH_SQUELCH_WARNING=1 git filter-branch -f --env-filter '
CORRECT_EMAIL="aziz.koeksal@gmail.com"
if [ "$GIT_COMMITTER_EMAIL" = "aziz.koeksal@wrong.com" ]; then GIT_COMMITTER_EMAIL=$CORRECT_EMAIL; fi
if [ "$GIT_AUTHOR_EMAIL" = "aziz.koeksal@wrong.com" ]; then GIT_AUTHOR_EMAIL=$CORRECT_EMAIL; fi
export GIT_COMMITTER_EMAIL GIT_AUTHOR_EMAIL
' $FROM_COMMIT_HASH..HEAD