blob: dc1cf4e920041ae3da02e7e6cc5333c090af0fb3 [file] [log] [blame]
#!/bin/bash
set -e
get_patch_id_commit_id_pairs() {
git log "$@" --pretty=tformat:'COMMITm@g1c %H %al %as %f%n%B' | awk 'function p(){if(h){print(d?d:c?c:g?g:(a":"t":"s)),h}};$1=="COMMITm@g1c"{p();h=$2;a=$3;t=$4;s=$5;c=d=g="";next};$1=="Differential"&&$2=="Revision:"{d=$3;sub("http.*/","",d);next};$1=="Change-Id:"{c=$1$2;next};$1=="git-svn-id:"{g=$2;next};END{p()}'
}
if [ -z "$1" ]; then
echo "Usage: `basename "$0"` branch_to_auto_pick_from"
exit
fi
FROM_BRANCH="$1"
TO_BRANCH="$(git rev-parse --abbrev-ref HEAD)"
if [ -z "$TO_BRANCH" ]; then
echo "Please git checkout to a branch first"
exit 1
fi
echo "Computing merge base from $FROM_BRANCH to $TO_BRANCH ..."
MERGE_BASE="$(git merge-base --all "$FROM_BRANCH" "$TO_BRANCH")"
if [ -z "$MERGE_BASE" ]; then
echo "Failed to get merge base"
exit 1
elif [ $(wc -l <<< "$MERGE_BASE") -gt 1 ]; then
echo "Git tree with cross merge not supported"
exit 1
fi
echo "Merge base is $(get_patch_id_commit_id_pairs $MERGE_BASE^..$MERGE_BASE)"
echo -n "Getting patch list on $FROM_BRANCH ... "
declare -A MAP_FROM_PATCHES
REV_LIST_FROM_PATCHES=
while read c d; do
if [ -n "$(exec 2>/dev/null; echo ${MAP_FROM_PATCHES[$c]})" ]; then
echo "Duplicate patch name found for $c $d ${MAP_FROM_PATCHES[$c]}"
d="$d ${MAP_FROM_PATCHES[$c]}"
fi
MAP_FROM_PATCHES[$c]="$d"
REV_LIST_FROM_PATCHES="$c
$REV_LIST_FROM_PATCHES"
done < <(get_patch_id_commit_id_pairs "$MERGE_BASE..$FROM_BRANCH")
echo "${#MAP_FROM_PATCHES[@]} patches"
echo -n "Getting patch list on $TO_BRANCH ... "
declare -A MAP_TO_PATCHES
declare -A MAP_TO_PATCHES_DUP
while read c d; do
if [ -n "$(exec 2>/dev/null; echo ${MAP_TO_PATCHES[$c]})" ]; then
echo "Duplicate patch name found for $c $d ${MAP_TO_PATCHES[$c]}"
d="$d ${MAP_TO_PATCHES[$c]}"
MAP_TO_PATCHES_DUP[$c]="$d"
fi
MAP_TO_PATCHES[$c]="$d"
done < <(get_patch_id_commit_id_pairs "$MERGE_BASE..$TO_BRANCH")
echo "${#MAP_TO_PATCHES[@]} patches"
for d in ${MAP_TO_PATCHES_DUP[@]}; do
HASH="$(git diff --binary $d^..$d | sha1sum | cut -d ' ' -f 1)"
eval "HAS_$HASH=true"
done
echo "Computing patches to cherry-pick ..."
PATCHES_TO_PICK=
while read c; do
if [ -z "$c" ]; then
continue
fi
if [ -z "$(exec 2>/dev/null; echo ${MAP_TO_PATCHES[$c]})" ] || [ ${#MAP_FROM_PATCHES[$c]} -ne ${#MAP_TO_PATCHES[$c]} ]; then
echo -ne "$c\t"
if [[ "${MAP_FROM_PATCHES[$c]}" == *" "* ]]; then
if [ -z "$(exec 2>/dev/null; echo ${MAP_TO_PATCHES_DUP[$c]})" ]; then
for d in ${MAP_TO_PATCHES[$c]}; do
HASH="$(git diff --binary $d^..$d | sha1sum | cut -d ' ' -f 1)"
eval "HAS_$HASH=true"
done
fi
for d in ${MAP_FROM_PATCHES[$c]}; do
if [ -z "$(eval echo "\${VISITED_$d}")" ]; then
break
fi
done
if [ -n "$(eval echo "\${VISITED_$d}")" ]; then
echo "All patches visited for $c: ${MAP_FROM_PATCHES[$c]}"
exit 1
fi
eval "VISITED_$d=true"
HASH="$(git diff --binary $d^..$d | sha1sum | cut -d ' ' -f 1)"
if [ -n "$(eval echo "\${HAS_$HASH}")" ]; then
echo "$d skipped"
continue
fi
c="$c-$HASH"
MAP_FROM_PATCHES[$c]="$d"
fi
echo "${MAP_FROM_PATCHES[$c]}"
PATCHES_TO_PICK="$PATCHES_TO_PICK
$c"
fi
done <<< "$REV_LIST_FROM_PATCHES"
while read c; do
if [ -z "$c" ]; then
continue
fi
d="${MAP_FROM_PATCHES[$c]}"
echo "Cherry-picking $d for $c ..."
git cherry-pick "$d"
done <<< "$PATCHES_TO_PICK"
echo "Done"