diff options
Diffstat (limited to 'git-filter-branch.sh')
-rwxr-xr-x | git-filter-branch.sh | 79 |
1 files changed, 35 insertions, 44 deletions
diff --git a/git-filter-branch.sh b/git-filter-branch.sh index ffcc408ee5..49e13f0bb1 100755 --- a/git-filter-branch.sh +++ b/git-filter-branch.sh @@ -8,6 +8,9 @@ # a new branch. You can specify a number of filters to modify the commits, # files and trees. +# The following functions will also be available in the commit filter: + +functions=$(cat << \EOF warn () { echo "$*" >&2 } @@ -46,6 +49,10 @@ die() echo "$*" >&2 exit 1 } +EOF +) + +eval "$functions" # When piped a commit, output a script to set the ident of either # "author" or "committer @@ -59,17 +66,17 @@ set_ident () { h s/^'$lid' \([^<]*\) <[^>]*> .*$/\1/ s/'\''/'\''\'\'\''/g - s/.*/export GIT_'$uid'_NAME='\''&'\''/p + s/.*/GIT_'$uid'_NAME='\''&'\''; export GIT_'$uid'_NAME/p g s/^'$lid' [^<]* <\([^>]*\)> .*$/\1/ s/'\''/'\''\'\'\''/g - s/.*/export GIT_'$uid'_EMAIL='\''&'\''/p + s/.*/GIT_'$uid'_EMAIL='\''&'\''; export GIT_'$uid'_EMAIL/p g s/^'$lid' [^<]* <[^>]*> \(.*\)$/\1/ s/'\''/'\''\'\'\''/g - s/.*/export GIT_'$uid'_DATE='\''&'\''/p + s/.*/GIT_'$uid'_DATE='\''&'\''; export GIT_'$uid'_DATE/p q } @@ -77,14 +84,9 @@ set_ident () { LANG=C LC_ALL=C sed -ne "$pick_id_script" # Ensure non-empty id name. - echo "[ -n \"\$GIT_${uid}_NAME\" ] || export GIT_${uid}_NAME=\"\${GIT_${uid}_EMAIL%%@*}\"" + echo "case \"\$GIT_${uid}_NAME\" in \"\") GIT_${uid}_NAME=\"\${GIT_${uid}_EMAIL%%@*}\" && export GIT_${uid}_NAME;; esac" } -# This script can be sourced by the commit filter to get the functions -test "a$SOURCE_FUNCTIONS" = a1 && return -this_script="$(cd "$(dirname "$0")"; pwd)"/$(basename "$0") -export this_script - USAGE="[--env-filter <command>] [--tree-filter <command>] \ [--index-filter <command>] [--parent-filter <command>] \ [--msg-filter <command>] [--commit-filter <command>] \ @@ -92,10 +94,11 @@ USAGE="[--env-filter <command>] [--tree-filter <command>] \ [--original <namespace>] [-d <directory>] [-f | --force] \ [<rev-list options>...]" +OPTIONS_SPEC= . git-sh-setup git diff-files --quiet && - git diff-index --cached --quiet HEAD || + git diff-index --cached --quiet HEAD -- || die "Cannot rewrite branch(es) with a dirty working directory." tempdir=.git-rewrite @@ -111,7 +114,6 @@ orig_namespace=refs/original/ force= while : do - test $# = 0 && usage case "$1" in --) shift @@ -155,7 +157,7 @@ do filter_msg="$OPTARG" ;; --commit-filter) - filter_commit='SOURCE_FUNCTIONS=1 . "$this_script";'" $OPTARG" + filter_commit="$functions; $OPTARG" ;; --tag-name-filter) filter_tag_name="$OPTARG" @@ -186,6 +188,9 @@ cd "$tempdir/t" && workdir="$(pwd)" || die "" +# Remove tempdir on exit +trap 'cd ../..; rm -rf "$tempdir"' 0 + # Make sure refs/original is empty git for-each-ref > "$tempdir"/backup-refs while read sha1 type name @@ -203,32 +208,18 @@ done < "$tempdir"/backup-refs ORIG_GIT_DIR="$GIT_DIR" ORIG_GIT_WORK_TREE="$GIT_WORK_TREE" ORIG_GIT_INDEX_FILE="$GIT_INDEX_FILE" -export GIT_DIR GIT_WORK_TREE=. - -# These refs should be updated if their heads were rewritten - -git rev-parse --revs-only --symbolic "$@" | -while read ref -do - # normalize ref - case "$ref" in - HEAD) - ref="$(git symbolic-ref "$ref")" - ;; - refs/*) - ;; - *) - ref="$(git for-each-ref --format='%(refname)' | - grep /"$ref")" - esac +GIT_WORK_TREE=. +export GIT_DIR GIT_WORK_TREE - git check-ref-format "$ref" && echo "$ref" -done > "$tempdir"/heads +# The refs should be updated if their heads were rewritten +git rev-parse --no-flags --revs-only --symbolic-full-name --default HEAD "$@" | +sed -e '/^^/d' >"$tempdir"/heads test -s "$tempdir"/heads || die "Which ref do you want to rewrite?" -export GIT_INDEX_FILE="$(pwd)/../index" +GIT_INDEX_FILE="$(pwd)/../index" +export GIT_INDEX_FILE git read-tree || die "Could not seed the index" ret=0 @@ -264,7 +255,8 @@ while read commit parents; do git read-tree -i -m $commit:"$filter_subdir" esac || die "Could not initialize the index" - export GIT_COMMIT=$commit + GIT_COMMIT=$commit + export GIT_COMMIT git cat-file commit "$commit" >../commit || die "Cannot read commit $commit" @@ -284,10 +276,11 @@ while read commit parents; do 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 + ( + git diff-index -r --name-only $commit + git ls-files --others + ) | + git update-index --add --replace --remove --stdin fi eval "$filter_index" < /dev/null || @@ -336,7 +329,6 @@ done < "$tempdir"/heads _x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]' _x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40" -count=0 echo while read ref do @@ -374,7 +366,6 @@ do ;; esac git update-ref -m "filter-branch: backup" "$orig_namespace$ref" $sha1 - count=$(($count+1)) done < "$tempdir"/heads # TODO: This should possibly go, with the semantics that all positive given @@ -398,7 +389,8 @@ if [ "$filter_tag_name" ]; then [ -f "../map/$sha1" ] || continue new_sha1="$(cat "../map/$sha1")" - export GIT_COMMIT="$sha1" + GIT_COMMIT="$sha1" + export GIT_COMMIT new_ref="$(echo "$ref" | eval "$filter_tag_name")" || die "tag name filter failed: $filter_tag_name" @@ -416,9 +408,8 @@ fi cd ../.. rm -rf "$tempdir" -echo -test $count -gt 0 && echo "These refs were rewritten:" -git show-ref | grep ^"$orig_namespace" + +trap - 0 unset GIT_DIR GIT_WORK_TREE GIT_INDEX_FILE test -z "$ORIG_GIT_DIR" || GIT_DIR="$ORIG_GIT_DIR" && export GIT_DIR |