filter-branch: stop depending on Perl

While git-filter-branch(1) is written as a shell script, the `--state-branch` feature depends on Perl to save and extract the object ID mappings. This can lead to subtle breakage though: - We execute `perl` directly without respecting the `PERL_PATH` configured by the distribution. As such, it may happen that we use the wrong version of Perl. - We install the script unchanged even if Perl isn't available at all on the system, so using `--state-branch` would lead to failure altogether in that case. Fix this by dropping Perl and instead implementing the feature with shell scripting exclusively. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Patrick Steinhardt committed Apr 16, 2025 at 14:16 UTC f6d855091e73fdab8a39185a8392b9d0df7ed46f
1 file changed +19 -18
git-filter-branch.sh
+19 -18
@@ -295,15 +295,18 @@ then
295 if test -n "$state_commit"
296 then
297 echo "Populating map from $state_branch ($state_commit)" 1>&2
298 - perl -e'open(MAP, "-|", "git show $ARGV[0]:filter.map") or die;
299 - while (<MAP>) {
300 - m/(.*):(.*)/ or die;
301 - open F, ">../map/$1" or die;
302 - print F "$2" or die;
303 - close(F) or die;
304 - }
305 - close(MAP) or die;' "$state_commit" \
306 - || die "Unable to load state from $state_branch:filter.map"
298 +
299 + git show "$state_commit:filter.map" >"$tempdir"/filter-map ||
300 + die "Unable to load state from $state_branch:filter.map"
301 + while read line
302 + do
303 + case "$line" in
304 + *:*)
305 + echo "${line%:*}" >../map/"${line#*:}";;
306 + *)
307 + die "Unable to load state from $state_branch:filter.map";;
308 + esac
309 + done <"$tempdir"/filter-map
310 else
311 echo "Branch $state_branch does not exist. Will create" 1>&2
312 fi
@@ -633,15 +636,13 @@ if test -n "$state_branch"
636 then
637 echo "Saving rewrite state to $state_branch" 1>&2
638 state_blob=$(
636 - perl -e'opendir D, "../map" or die;
637 - open H, "|-", "git hash-object -w --stdin" or die;
638 - foreach (sort readdir(D)) {
639 - next if m/^\.\.?$/;
640 - open F, "<../map/$_" or die;
641 - chomp($f = <F>);
642 - print H "$_:$f\n" or die;
643 - }
644 - close(H) or die;' || die "Unable to save state")
639 + for file in ../map/*
640 + do
641 + from_commit=$(basename "$file")
642 + to_commit=$(cat "$file")
643 + echo "$from_commit:$to_commit"
644 + done | git hash-object -w --stdin || die "Unable to save state"
645 + )
646 state_tree=$(printf '100644 blob %s\tfilter.map\n' "$state_blob" | git mktree)
647 if test -n "$state_commit"
648 then