Skip to content

Instantly share code, notes, and snippets.

@xkr47

xkr47/README.md

Last active Oct 19, 2020
Embed
What would you like to do?
Script for moving/renaming files/directories arbitrarily in whole git history of single branch, using perl expressions

Install into PATH e.g. $HOME/bin/ as "git-filter-mv" and chmod a+rx git-filter-mv

It works with any special characters in filenames like tabs and linefeeds. It works with empty commits.

Based on example from git-filter-branch manpage.

If you want to print debug messages, use STDERR e.g. print STDERR "File: $_\n";

Examples:

git filter-mv 's!^!subdir/!'

➜ moves all files to a subdirectory "subdir/" in all commits of the current branch

git filter-mv 's!^source/!src/!'

➜ moves all files in "source/" to "src/" in all commits of the current branch

git filter-mv 's!^foo/bar.txt!foo/barbar.txt!'

➜ renames foo/bar.txt to foo/barbar.txt directly below the repository root in all commits of the current branch

git filter-mv 's!(^|/)bar.txt!$1barbar.txt!'

➜ renames bar.txt to barbar.txt in any directory in all commits of the current branch

#!/bin/bash
set -eo pipefail
if [ $# != 1 ]; then
echo "usage: git ${0#*git-} <perl>"
echo "Filter branch by transforming all paths with given perl expression"
echo "Example: git ${0#git-} 's!^!subdir/!' # moves all files to a subdirectory"
exit 1
fi
perl="$1"
shift
if ! git ls-files -z | perl -e 'use strict; use warnings; $/="\0"; $_=<>; '"$perl;" > /dev/null ; then
echo 'ERROR: Given perl script broken, please correct above errors and try again'
exit 1
fi
script='
use strict;
use warnings;
sub ren {
$_ = $_[0];
'"$perl"';
$_
}
$/="\0";
while(<>) {
s/\t(.*)$/"\t".ren($1)/e;
print;
}
'
shellquote () {
perl -e '
use strict;
use warnings;
print "'\''",$ARGV[0] =~ s/'\''/'\''\\'\'''\''/gr,"'\''";
' "$1"
}
git filter-branch --index-filter \
'git ls-files --stage -z |
perl -e '"$(shellquote "$script")"' |
GIT_INDEX_FILE=$GIT_INDEX_FILE.new git update-index -z --index-info &&
touch "$GIT_INDEX_FILE.new" &&
mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"' \
HEAD
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.