Browse Source

filter-branch: fail gracefully when a filter fails

A common mistake is to provide a filter which fails unwantedly. For
example, this will stop in the middle:

	git filter-branch --env-filter '
		test $GIT_COMMITTER_EMAIL = xyz &&
		export GIT_COMMITTER_EMAIL = abc' rewritten

When $GIT_COMMITTER_EMAIL is not "xyz", the test fails, and consequently
the whole filter has a non-zero exit status. However, as demonstrated
in this example, filter-branch would just stop, and the user would be
none the wiser.

Also, a failing msg-filter would not have been caught, as was the
case with one of the tests.

This patch fixes both issues, by paying attention to the exit status
of msg-filter, and by saying what failed before exiting.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
maint
Johannes Schindelin 18 years ago committed by Junio C Hamano
parent
commit
8c1ce0f46b
  1. 39
      git-filter-branch.sh
  2. 8
      t/t7003-filter-branch.sh

39
git-filter-branch.sh

@ -28,6 +28,16 @@ map() @@ -28,6 +28,16 @@ map()
fi
}

# override die(): this version puts in an extra line break, so that
# the progress is still visible

die()
{
echo >&2
echo "$*" >&2
exit 1
}

# When piped a commit, output a script to set the ident of either
# "author" or "committer

@ -181,23 +191,29 @@ while read commit parents; do @@ -181,23 +191,29 @@ while read commit parents; do
export GIT_COMMIT=$commit
git cat-file commit "$commit" >../commit

eval "$(set_ident AUTHOR <../commit)"
eval "$(set_ident COMMITTER <../commit)"
eval "$filter_env" < /dev/null
eval "$(set_ident AUTHOR <../commit)" ||
die "setting author failed for commit $commit"
eval "$(set_ident COMMITTER <../commit)" ||
die "setting committer failed for commit $commit"
eval "$filter_env" < /dev/null ||
die "env filter failed: $filter_env"

if [ "$filter_tree" ]; then
git checkout-index -f -u -a
# files that $commit removed are now still in the working tree;
# remove them, else they would be added again
git ls-files -z --others | xargs -0 rm -f
eval "$filter_tree" < /dev/null
eval "$filter_tree" < /dev/null ||
die "tree filter failed: $filter_tree"

git diff-index -r $commit | cut -f 2- | tr '\n' '\0' | \
xargs -0 git update-index --add --replace --remove
git ls-files -z --others | \
xargs -0 git update-index --add --replace --remove
fi

eval "$filter_index" < /dev/null
eval "$filter_index" < /dev/null ||
die "index filter failed: $filter_index"

parentstr=
for parent in $parents; do
@ -206,13 +222,15 @@ while read commit parents; do @@ -206,13 +222,15 @@ while read commit parents; do
done
done
if [ "$filter_parent" ]; then
parentstr="$(echo "$parentstr" | eval "$filter_parent")"
parentstr="$(echo "$parentstr" | eval "$filter_parent")" ||
die "parent filter failed: $filter_parent"
fi

sed -e '1,/^$/d' <../commit | \
eval "$filter_msg" | \
sh -c "$filter_commit" "git commit-tree" $(git write-tree) \
$parentstr > ../map/$commit
eval "$filter_msg" > ../message ||
die "msg filter failed: $filter_msg"
sh -c "$filter_commit" "git commit-tree" \
$(git write-tree) $parentstr < ../message > ../map/$commit
done <../revs

src_head=$(tail -n 1 ../revs | sed -e 's/ .*//')
@ -249,7 +267,8 @@ if [ "$filter_tag_name" ]; then @@ -249,7 +267,8 @@ if [ "$filter_tag_name" ]; then
[ -f "../map/$sha1" ] || continue
new_sha1="$(cat "../map/$sha1")"
export GIT_COMMIT="$sha1"
new_ref="$(echo "$ref" | eval "$filter_tag_name")"
new_ref="$(echo "$ref" | eval "$filter_tag_name")" ||
die "tag name filter failed: $filter_tag_name"

echo "$ref -> $new_ref ($sha1 -> $new_sha1)"


8
t/t7003-filter-branch.sh

@ -107,13 +107,19 @@ test_expect_success 'use index-filter to move into a subdirectory' ' @@ -107,13 +107,19 @@ test_expect_success 'use index-filter to move into a subdirectory' '
mv \$GIT_INDEX_FILE.new \$GIT_INDEX_FILE" directorymoved &&
test -z "$(git diff HEAD directorymoved:newsubdir)"'

test_expect_success 'stops when msg filter fails' '
! git-filter-branch --msg-filter false nonono &&
rm -rf .git-rewrite &&
! git rev-parse nonono
'

test_expect_success 'author information is preserved' '
: > i &&
git add i &&
test_tick &&
GIT_AUTHOR_NAME="B V Uips" git commit -m bvuips &&
git-filter-branch --msg-filter "cat; \
test \$GIT_COMMIT = $(git rev-parse master) && \
test \$GIT_COMMIT != $(git rev-parse master) || \
echo Hallo" \
preserved-author &&
test 1 = $(git rev-list --author="B V Uips" preserved-author | wc -l)

Loading…
Cancel
Save