diff options
Diffstat (limited to 'scripts')
| -rwxr-xr-x | scripts/cronjob | 4 | ||||
| -rwxr-xr-x | scripts/filter.sh | 6 | ||||
| -rwxr-xr-x | scripts/git-filter-branch | 673 | 
3 files changed, 678 insertions, 5 deletions
| diff --git a/scripts/cronjob b/scripts/cronjob index f01166b8e4e7..6cc1373284d7 100755 --- a/scripts/cronjob +++ b/scripts/cronjob @@ -6,7 +6,7 @@ cd $(dirname $0)/..  UPSTREAM_GIT="git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git" -BRANCHES="master filter-state upstream/master upstream/dts" +BRANCHES="master filter-state-split upstream/master upstream/dts"  if [ ! -f scripts/filter.sh ] ; then      echo "`pwd`: does not appear to be a device-tree.git" 1>&2 @@ -75,7 +75,7 @@ echo "Filtering"  echo  ) 2>&1 ` -#git push --dry-run origin filter-state upstream/dts upstream/master +#git push --dry-run origin filter-state-split upstream/dts upstream/master  #git push --dry-run origin --tags  #echo diff --git a/scripts/filter.sh b/scripts/filter.sh index 5e10ff417766..998b8f0a144c 100755 --- a/scripts/filter.sh +++ b/scripts/filter.sh @@ -1,6 +1,6 @@  #!/bin/sh -# git branch -D upstream/rewritten-prev upstream/master upstream/rewritten filter-state       +# git branch -D upstream/rewritten-prev upstream/master upstream/rewritten filter-state-split  set -e @@ -29,12 +29,12 @@ rm -f .git/refs/original/refs/heads/${UPSTREAM_REWRITTEN}  git branch -f $UPSTREAM_REWRITTEN FETCH_HEAD -git filter-branch --force \ +PATH=$(git --exec-path):$PATH $SCRIPTS/git-filter-branch --force \  	--index-filter ${SCRIPTS}/index-filter.sh \  	--msg-filter 'cat && /bin/echo -e "\n[ upstream commit: $GIT_COMMIT ]"' \  	--tag-name-filter 'while read t ; do /bin/echo -n $t-dts-raw ; done' \  	--parent-filter 'sed "s/-p //g" | xargs -r git show-branch --independent | sed "s/\</-p /g"' \ -	--prune-empty --state-branch refs/heads/filter-state \ +	--prune-empty --state-branch refs/heads/filter-state-split \  	-- $RANGE  git branch -f $UPSTREAM_MASTER FETCH_HEAD diff --git a/scripts/git-filter-branch b/scripts/git-filter-branch new file mode 100755 index 000000000000..690497cb4d51 --- /dev/null +++ b/scripts/git-filter-branch @@ -0,0 +1,673 @@ +#!/bin/sh +# +# Rewrite revision history +# Copyright (c) Petr Baudis, 2006 +# Minimal changes to "port" it to core-git (c) Johannes Schindelin, 2007 +# +# Lets you rewrite the revision history of the current branch, creating +# 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 +EMPTY_TREE=$(git hash-object -t tree /dev/null) + +warn () { +	echo "$*" >&2 +} + +map() +{ +	# if it was not rewritten, take the original +	if test -r "$workdir/../map/$1" +	then +		cat "$workdir/../map/$1" +	else +		echo "$1" +	fi +} + +# if you run 'skip_commit "$@"' in a commit filter, it will print +# the (mapped) parents, effectively skipping the commit. + +skip_commit() +{ +	shift; +	while [ -n "$1" ]; +	do +		shift; +		map "$1"; +		shift; +	done; +} + +# if you run 'git_commit_non_empty_tree "$@"' in a commit filter, +# it will skip commits that leave the tree untouched, commit the other. +git_commit_non_empty_tree() +{ +	if test $# = 3 && test "$1" = $(git rev-parse "$3^{tree}"); then +		map "$3" +	elif test $# = 1 && test "$1" = $EMPTY_TREE; then +		: +	else +		git commit-tree "$@" +	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 +} +EOF +) + +eval "$functions" + +finish_ident() { +	# Ensure non-empty id name. +	echo "case \"\$GIT_$1_NAME\" in \"\") GIT_$1_NAME=\"\${GIT_$1_EMAIL%%@*}\" && export GIT_$1_NAME;; esac" +	# And make sure everything is exported. +	echo "export GIT_$1_NAME" +	echo "export GIT_$1_EMAIL" +	echo "export GIT_$1_DATE" +} + +set_ident () { +	parse_ident_from_commit author AUTHOR committer COMMITTER +	finish_ident AUTHOR +	finish_ident COMMITTER +} + +if test -z "$FILTER_BRANCH_SQUELCH_WARNING$GIT_TEST_DISALLOW_ABBREVIATED_OPTIONS" +then +	cat <<EOF +WARNING: git-filter-branch has a glut of gotchas generating mangled history +	 rewrites.  Hit Ctrl-C before proceeding to abort, then use an +	 alternative filtering tool such as 'git filter-repo' +	 (https://github.com/newren/git-filter-repo/) instead.  See the +	 filter-branch manual page for more details; to squelch this warning, +	 set FILTER_BRANCH_SQUELCH_WARNING=1. +EOF +	sleep 10 +	printf "Proceeding with filter-branch...\n\n" +fi + +USAGE="[--setup <command>] [--subdirectory-filter <directory>] [--env-filter <command>] +	[--tree-filter <command>] [--index-filter <command>] +	[--parent-filter <command>] [--msg-filter <command>] +	[--commit-filter <command>] [--tag-name-filter <command>] +	[--original <namespace>] +	[-d <directory>] [-f | --force] [--state-branch <branch>] +	[--] [<rev-list options>...]" + +OPTIONS_SPEC= +. git-sh-setup + +if [ "$(is_bare_repository)" = false ]; then +	require_clean_work_tree 'rewrite branches' +fi + +tempdir=.git-rewrite +filter_setup= +filter_env= +filter_tree= +filter_index= +filter_parent= +filter_msg=cat +filter_commit= +filter_tag_name= +filter_subdir= +state_branch= +orig_namespace=refs/original/ +force= +prune_empty= +remap_to_ancestor= +while : +do +	case "$1" in +	--) +		shift +		break +		;; +	--force|-f) +		shift +		force=t +		continue +		;; +	--remap-to-ancestor) +		# deprecated ($remap_to_ancestor is set now automatically) +		shift +		remap_to_ancestor=t +		continue +		;; +	--prune-empty) +		shift +		prune_empty=t +		continue +		;; +	-*) +		;; +	*) +		break; +	esac + +	# all switches take one argument +	ARG="$1" +	case "$#" in 1) usage ;; esac +	shift +	OPTARG="$1" +	shift + +	case "$ARG" in +	-d) +		tempdir="$OPTARG" +		;; +	--setup) +		filter_setup="$OPTARG" +		;; +	--subdirectory-filter) +		filter_subdir="$OPTARG" +		remap_to_ancestor=t +		;; +	--env-filter) +		filter_env="$OPTARG" +		;; +	--tree-filter) +		filter_tree="$OPTARG" +		;; +	--index-filter) +		filter_index="$OPTARG" +		;; +	--parent-filter) +		filter_parent="$OPTARG" +		;; +	--msg-filter) +		filter_msg="$OPTARG" +		;; +	--commit-filter) +		filter_commit="$functions; $OPTARG" +		;; +	--tag-name-filter) +		filter_tag_name="$OPTARG" +		;; +	--original) +		orig_namespace=$(expr "$OPTARG/" : '\(.*[^/]\)/*$')/ +		;; +	--state-branch) +		state_branch="$OPTARG" +		;; +	*) +		usage +		;; +	esac +done + +case "$prune_empty,$filter_commit" in +,) +	filter_commit='git commit-tree "$@"';; +t,) +	filter_commit="$functions;"' git_commit_non_empty_tree "$@"';; +,*) +	;; +*) +	die "Cannot set --prune-empty and --commit-filter at the same time" +esac + +case "$force" in +t) +	rm -rf "$tempdir" +;; +'') +	test -d "$tempdir" && +		die "$tempdir already exists, please remove it" +esac +orig_dir=$(pwd) +mkdir -p "$tempdir/t" && +tempdir="$(cd "$tempdir"; pwd)" && +cd "$tempdir/t" && +workdir="$(pwd)" || +die "" + +# Remove tempdir on exit +trap 'cd "$orig_dir"; rm -rf "$tempdir"' 0 + +ORIG_GIT_DIR="$GIT_DIR" +ORIG_GIT_WORK_TREE="$GIT_WORK_TREE" +ORIG_GIT_INDEX_FILE="$GIT_INDEX_FILE" +ORIG_GIT_AUTHOR_NAME="$GIT_AUTHOR_NAME" +ORIG_GIT_AUTHOR_EMAIL="$GIT_AUTHOR_EMAIL" +ORIG_GIT_AUTHOR_DATE="$GIT_AUTHOR_DATE" +ORIG_GIT_COMMITTER_NAME="$GIT_COMMITTER_NAME" +ORIG_GIT_COMMITTER_EMAIL="$GIT_COMMITTER_EMAIL" +ORIG_GIT_COMMITTER_DATE="$GIT_COMMITTER_DATE" + +GIT_WORK_TREE=. +export GIT_DIR GIT_WORK_TREE + +# Make sure refs/original is empty +git for-each-ref > "$tempdir"/backup-refs || exit +while read sha1 type name +do +	case "$force,$name" in +	,$orig_namespace*) +		die "Cannot create a new backup. +A previous backup already exists in $orig_namespace +Force overwriting the backup with -f" +	;; +	t,$orig_namespace*) +		git update-ref -d "$name" $sha1 +	;; +	esac +done < "$tempdir"/backup-refs + +# The refs should be updated if their heads were rewritten +git rev-parse --no-flags --revs-only --symbolic-full-name \ +	--default HEAD "$@" > "$tempdir"/raw-refs || exit +while read ref +do +	case "$ref" in ^?*) continue ;; esac + +	if git rev-parse --verify "$ref"^0 >/dev/null 2>&1 +	then +		echo "$ref" +	else +		warn "WARNING: not rewriting '$ref' (not a committish)" +	fi +done >"$tempdir"/heads <"$tempdir"/raw-refs + +test -s "$tempdir"/heads || +	die "You must specify a ref to rewrite." + +GIT_INDEX_FILE="$(pwd)/../index" +export GIT_INDEX_FILE + +# map old->new commit ids for rewriting parents +mkdir ../map || die "Could not create map/ directory" + +state_prefixes="0 1 2 3 4 5 6 7 8 9 a b c d e f" + +if test -n "$state_branch" +then +	state_commit=$(git rev-parse --no-flags --revs-only "$state_branch") +	if test -n "$state_commit" +	then +		echo "Populating map from $state_branch ($state_commit)" 1>&2 +		for prefix in $state_prefixes ; do +			perl -e'open(MAP, "-|", "git show $ARGV[0]:$ARGV[1]") or die; +				while (<MAP>) { +					m/(.*):(.*)/ or die; +					open F, ">../map/$1" or die; +					print F "$2" or die; +					close(F) or die; +				} +				close(MAP) or die;' "$state_commit" "filter_${prefix}.map" \ +					|| die "Unable to load state from $state_branch:filter_${prefix}.map" +		done +	else +		echo "Branch $state_branch does not exist. Will create" 1>&2 +	fi +fi + +# we need "--" only if there are no path arguments in $@ +nonrevs=$(git rev-parse --no-revs "$@") || exit +if test -z "$nonrevs" +then +	dashdash=-- +else +	dashdash= +	remap_to_ancestor=t +fi + +git rev-parse --revs-only "$@" >../parse + +case "$filter_subdir" in +"") +	eval set -- "$(git rev-parse --sq --no-revs "$@")" +	;; +*) +	eval set -- "$(git rev-parse --sq --no-revs "$@" $dashdash \ +		"$filter_subdir")" +	;; +esac + +git rev-list --reverse --topo-order --default HEAD \ +	--parents --simplify-merges --stdin "$@" <../parse >../revs || +	die "Could not get the commits" +commits=$(wc -l <../revs | tr -d " ") + +test $commits -eq 0 && die_with_status 2 "Found nothing to rewrite" + +# Rewrite the commits +report_progress () +{ +	if test -n "$progress" && +		test $git_filter_branch__commit_count -gt $next_sample_at +	then +		count=$git_filter_branch__commit_count + +		now=$(date +%s) +		elapsed=$(($now - $start_timestamp)) +		remaining=$(( ($commits - $count) * $elapsed / $count )) +		if test $elapsed -gt 0 +		then +			next_sample_at=$(( ($elapsed + 1) * $count / $elapsed )) +		else +			next_sample_at=$(($next_sample_at + 1)) +		fi +		progress=" ($elapsed seconds passed, remaining $remaining predicted)" +	fi +	printf "\rRewrite $commit ($count/$commits)$progress    " +} + +git_filter_branch__commit_count=0 + +progress= start_timestamp= +if date '+%s' 2>/dev/null | grep -q '^[0-9][0-9]*$' +then +	next_sample_at=0 +	progress="dummy to ensure this is not empty" +	start_timestamp=$(date '+%s') +fi + +if test -n "$filter_index" || +   test -n "$filter_tree" || +   test -n "$filter_subdir" +then +	need_index=t +else +	need_index= +fi + +eval "$filter_setup" < /dev/null || +	die "filter setup failed: $filter_setup" + +while read commit parents; do +	git_filter_branch__commit_count=$(($git_filter_branch__commit_count+1)) + +	report_progress +	test -f "$workdir"/../map/$commit && continue + +	case "$filter_subdir" in +	"") +		if test -n "$need_index" +		then +			GIT_ALLOW_NULL_SHA1=1 git read-tree -i -m $commit +		fi +		;; +	*) +		# The commit may not have the subdirectory at all +		err=$(GIT_ALLOW_NULL_SHA1=1 \ +		      git read-tree -i -m $commit:"$filter_subdir" 2>&1) || { +			if ! git rev-parse -q --verify $commit:"$filter_subdir" +			then +				rm -f "$GIT_INDEX_FILE" +			else +				echo >&2 "$err" +				false +			fi +		} +	esac || die "Could not initialize the index" + +	GIT_COMMIT=$commit +	export GIT_COMMIT +	git cat-file commit "$commit" >../commit || +		die "Cannot read commit $commit" + +	eval "$(set_ident <../commit)" || +		die "setting author/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 || +			die "Could not checkout the index" +		# files that $commit removed are now still in the working tree; +		# remove them, else they would be added again +		git clean -d -q -f -x +		eval "$filter_tree" < /dev/null || +			die "tree filter failed: $filter_tree" + +		( +			git diff-index -r --name-only --ignore-submodules $commit -- && +			git ls-files --others +		) > "$tempdir"/tree-state || exit +		git update-index --add --replace --remove --stdin \ +			< "$tempdir"/tree-state || exit +	fi + +	eval "$filter_index" < /dev/null || +		die "index filter failed: $filter_index" + +	parentstr= +	for parent in $parents; do +		for reparent in $(map "$parent"); do +			case "$parentstr " in +			*" -p $reparent "*) +				;; +			*) +				parentstr="$parentstr -p $reparent" +				;; +			esac +		done +	done +	if [ "$filter_parent" ]; then +		parentstr="$(echo "$parentstr" | eval "$filter_parent")" || +				die "parent filter failed: $filter_parent" +	fi + +	{ +		while IFS='' read -r header_line && test -n "$header_line" +		do +			# skip header lines... +			:; +		done +		# and output the actual commit message +		cat +	} <../commit | +		eval "$filter_msg" > ../message || +			die "msg filter failed: $filter_msg" + +	if test -n "$need_index" +	then +		tree=$(git write-tree) +	else +		tree=$(git rev-parse "$commit^{tree}") +	fi +	workdir=$workdir /bin/sh -c "$filter_commit" "git commit-tree" \ +		"$tree" $parentstr < ../message > ../map/$commit || +			die "could not write rewritten commit" +done <../revs + +# If we are filtering for paths, as in the case of a subdirectory +# filter, it is possible that a specified head is not in the set of +# rewritten commits, because it was pruned by the revision walker. +# Ancestor remapping fixes this by mapping these heads to the unique +# nearest ancestor that survived the pruning. + +if test "$remap_to_ancestor" = t +then +	while read ref +	do +		sha1=$(git rev-parse "$ref"^0) +		test -f "$workdir"/../map/$sha1 && continue +		ancestor=$(git rev-list --simplify-merges -1 "$ref" "$@") +		test "$ancestor" && echo $(map $ancestor) >"$workdir"/../map/$sha1 +	done < "$tempdir"/heads +fi + +# Finally update the refs + +echo +while read ref +do +	# avoid rewriting a ref twice +	test -f "$orig_namespace$ref" && continue + +	sha1=$(git rev-parse "$ref"^0) +	rewritten=$(map $sha1) + +	test $sha1 = "$rewritten" && +		warn "WARNING: Ref '$ref' is unchanged" && +		continue + +	case "$rewritten" in +	'') +		echo "Ref '$ref' was deleted" +		git update-ref -m "filter-branch: delete" -d "$ref" $sha1 || +			die "Could not delete $ref" +	;; +	*) +		echo "Ref '$ref' was rewritten" +		if ! git update-ref -m "filter-branch: rewrite" \ +					"$ref" $rewritten $sha1 2>/dev/null; then +			if test $(git cat-file -t "$ref") = tag; then +				if test -z "$filter_tag_name"; then +					warn "WARNING: You said to rewrite tagged commits, but not the corresponding tag." +					warn "WARNING: Perhaps use '--tag-name-filter cat' to rewrite the tag." +				fi +			else +				die "Could not rewrite $ref" +			fi +		fi +	;; +	esac +	git update-ref -m "filter-branch: backup" "$orig_namespace$ref" $sha1 || +		 exit +done < "$tempdir"/heads + +# TODO: This should possibly go, with the semantics that all positive given +#       refs are updated, and their original heads stored in refs/original/ +# Filter tags + +if [ "$filter_tag_name" ]; then +	git for-each-ref --format='%(objectname) %(objecttype) %(refname)' refs/tags | +	while read sha1 type ref; do +		ref="${ref#refs/tags/}" +		# XXX: Rewrite tagged trees as well? +		if [ "$type" != "commit" -a "$type" != "tag" ]; then +			continue; +		fi + +		if [ "$type" = "tag" ]; then +			# Dereference to a commit +			sha1t="$sha1" +			sha1="$(git rev-parse -q "$sha1"^{commit})" || continue +		fi + +		[ -f "../map/$sha1" ] || continue +		new_sha1="$(cat "../map/$sha1")" +		GIT_COMMIT="$sha1" +		export GIT_COMMIT +		new_ref="$(echo "$ref" | eval "$filter_tag_name")" || +			die "tag name filter failed: $filter_tag_name" + +		echo "$ref -> $new_ref ($sha1 -> $new_sha1)" + +		if [ "$type" = "tag" ]; then +			new_sha1=$( ( printf 'object %s\ntype commit\ntag %s\n' \ +						"$new_sha1" "$new_ref" +				git cat-file tag "$ref" | +				sed -n \ +				    -e '1,/^$/{ +					  /^object /d +					  /^type /d +					  /^tag /d +					}' \ +				    -e '/^-----BEGIN PGP SIGNATURE-----/q' \ +				    -e 'p' ) | +				git hash-object -t tag -w --stdin) || +				die "Could not create new tag object for $ref" +			if git cat-file tag "$ref" | \ +			   grep '^-----BEGIN PGP SIGNATURE-----' >/dev/null 2>&1 +			then +				warn "gpg signature stripped from tag object $sha1t" +			fi +		fi + +		git update-ref "refs/tags/$new_ref" "$new_sha1" || +			die "Could not write tag $new_ref" +	done +fi + +unset GIT_DIR GIT_WORK_TREE GIT_INDEX_FILE +unset GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_AUTHOR_DATE +unset GIT_COMMITTER_NAME GIT_COMMITTER_EMAIL GIT_COMMITTER_DATE +test -z "$ORIG_GIT_DIR" || { +	GIT_DIR="$ORIG_GIT_DIR" && export GIT_DIR +} +test -z "$ORIG_GIT_WORK_TREE" || { +	GIT_WORK_TREE="$ORIG_GIT_WORK_TREE" && +	export GIT_WORK_TREE +} +test -z "$ORIG_GIT_INDEX_FILE" || { +	GIT_INDEX_FILE="$ORIG_GIT_INDEX_FILE" && +	export GIT_INDEX_FILE +} +test -z "$ORIG_GIT_AUTHOR_NAME" || { +	GIT_AUTHOR_NAME="$ORIG_GIT_AUTHOR_NAME" && +	export GIT_AUTHOR_NAME +} +test -z "$ORIG_GIT_AUTHOR_EMAIL" || { +	GIT_AUTHOR_EMAIL="$ORIG_GIT_AUTHOR_EMAIL" && +	export GIT_AUTHOR_EMAIL +} +test -z "$ORIG_GIT_AUTHOR_DATE" || { +	GIT_AUTHOR_DATE="$ORIG_GIT_AUTHOR_DATE" && +	export GIT_AUTHOR_DATE +} +test -z "$ORIG_GIT_COMMITTER_NAME" || { +	GIT_COMMITTER_NAME="$ORIG_GIT_COMMITTER_NAME" && +	export GIT_COMMITTER_NAME +} +test -z "$ORIG_GIT_COMMITTER_EMAIL" || { +	GIT_COMMITTER_EMAIL="$ORIG_GIT_COMMITTER_EMAIL" && +	export GIT_COMMITTER_EMAIL +} +test -z "$ORIG_GIT_COMMITTER_DATE" || { +	GIT_COMMITTER_DATE="$ORIG_GIT_COMMITTER_DATE" && +	export GIT_COMMITTER_DATE +} + +if test -n "$state_branch" +then +	echo "Saving rewrite state to $state_branch" 1>&2 +	for prefix in $state_prefixes ; do +		state_blob=$( +			perl -e'opendir D, "../map" or die; +				open H, "|-", "git hash-object -w --stdin" or die; +				foreach (sort readdir(D)) { +					next if m/^\.\.?$/; +					next unless m/^$ARGV[0]/; +					open F, "<../map/$_" or die; +					chomp($f = <F>); +					print H "$_:$f\n" or die; +				} +				close(H) or die;' "$prefix" || die "Unable to save state") +		printf '100644 blob %s\tfilter_%s.map\n' "$state_blob" "$prefix" >> $tempdir/state-branch-tree +	done +	state_tree=$(cat $tempdir/state-branch-tree | git mktree) + +	if test -n "$state_commit" +	then +		state_commit=$(echo "Sync" | git commit-tree "$state_tree" -p "$state_commit") +	else +		state_commit=$(echo "Sync" | git commit-tree "$state_tree" ) +	fi +	git update-ref "$state_branch" "$state_commit" +fi + +cd "$orig_dir" +rm -rf "$tempdir" + +trap - 0 + +if [ "$(is_bare_repository)" = false ]; then +	git read-tree -u -m HEAD || exit +fi + +exit 0 | 
