b.liu | e958203 | 2025-04-17 19:18:16 +0800 | [diff] [blame] | 1 | #!/bin/bash |
| 2 | set -e |
| 3 | get_patch_id_commit_id_pairs() { |
| 4 | 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()}' |
| 5 | } |
| 6 | |
| 7 | if [ -z "$1" ]; then |
| 8 | echo "Usage: `basename "$0"` branch_to_auto_pick_from" |
| 9 | exit |
| 10 | fi |
| 11 | FROM_BRANCH="$1" |
| 12 | TO_BRANCH="$(git rev-parse --abbrev-ref HEAD)" |
| 13 | if [ -z "$TO_BRANCH" ]; then |
| 14 | echo "Please git checkout to a branch first" |
| 15 | exit 1 |
| 16 | fi |
| 17 | |
| 18 | echo "Computing merge base from $FROM_BRANCH to $TO_BRANCH ..." |
| 19 | MERGE_BASE="$(git merge-base --all "$FROM_BRANCH" "$TO_BRANCH")" |
| 20 | if [ -z "$MERGE_BASE" ]; then |
| 21 | echo "Failed to get merge base" |
| 22 | exit 1 |
| 23 | elif [ $(wc -l <<< "$MERGE_BASE") -gt 1 ]; then |
| 24 | echo "Git tree with cross merge not supported" |
| 25 | exit 1 |
| 26 | fi |
| 27 | echo "Merge base is $(get_patch_id_commit_id_pairs $MERGE_BASE^..$MERGE_BASE)" |
| 28 | |
| 29 | echo -n "Getting patch list on $FROM_BRANCH ... " |
| 30 | declare -A MAP_FROM_PATCHES |
| 31 | REV_LIST_FROM_PATCHES= |
| 32 | while read c d; do |
| 33 | if [ -n "$(exec 2>/dev/null; echo ${MAP_FROM_PATCHES[$c]})" ]; then |
| 34 | echo "Duplicate patch name found for $c $d ${MAP_FROM_PATCHES[$c]}" |
| 35 | d="$d ${MAP_FROM_PATCHES[$c]}" |
| 36 | fi |
| 37 | MAP_FROM_PATCHES[$c]="$d" |
| 38 | REV_LIST_FROM_PATCHES="$c |
| 39 | $REV_LIST_FROM_PATCHES" |
| 40 | done < <(get_patch_id_commit_id_pairs "$MERGE_BASE..$FROM_BRANCH") |
| 41 | echo "${#MAP_FROM_PATCHES[@]} patches" |
| 42 | |
| 43 | echo -n "Getting patch list on $TO_BRANCH ... " |
| 44 | declare -A MAP_TO_PATCHES |
| 45 | declare -A MAP_TO_PATCHES_DUP |
| 46 | while read c d; do |
| 47 | if [ -n "$(exec 2>/dev/null; echo ${MAP_TO_PATCHES[$c]})" ]; then |
| 48 | echo "Duplicate patch name found for $c $d ${MAP_TO_PATCHES[$c]}" |
| 49 | d="$d ${MAP_TO_PATCHES[$c]}" |
| 50 | MAP_TO_PATCHES_DUP[$c]="$d" |
| 51 | fi |
| 52 | MAP_TO_PATCHES[$c]="$d" |
| 53 | done < <(get_patch_id_commit_id_pairs "$MERGE_BASE..$TO_BRANCH") |
| 54 | echo "${#MAP_TO_PATCHES[@]} patches" |
| 55 | for d in ${MAP_TO_PATCHES_DUP[@]}; do |
| 56 | HASH="$(git diff --binary $d^..$d | sha1sum | cut -d ' ' -f 1)" |
| 57 | eval "HAS_$HASH=true" |
| 58 | done |
| 59 | |
| 60 | echo "Computing patches to cherry-pick ..." |
| 61 | PATCHES_TO_PICK= |
| 62 | while read c; do |
| 63 | if [ -z "$c" ]; then |
| 64 | continue |
| 65 | fi |
| 66 | if [ -z "$(exec 2>/dev/null; echo ${MAP_TO_PATCHES[$c]})" ] || [ ${#MAP_FROM_PATCHES[$c]} -ne ${#MAP_TO_PATCHES[$c]} ]; then |
| 67 | echo -ne "$c\t" |
| 68 | if [[ "${MAP_FROM_PATCHES[$c]}" == *" "* ]]; then |
| 69 | if [ -z "$(exec 2>/dev/null; echo ${MAP_TO_PATCHES_DUP[$c]})" ]; then |
| 70 | for d in ${MAP_TO_PATCHES[$c]}; do |
| 71 | HASH="$(git diff --binary $d^..$d | sha1sum | cut -d ' ' -f 1)" |
| 72 | eval "HAS_$HASH=true" |
| 73 | done |
| 74 | fi |
| 75 | for d in ${MAP_FROM_PATCHES[$c]}; do |
| 76 | if [ -z "$(eval echo "\${VISITED_$d}")" ]; then |
| 77 | break |
| 78 | fi |
| 79 | done |
| 80 | if [ -n "$(eval echo "\${VISITED_$d}")" ]; then |
| 81 | echo "All patches visited for $c: ${MAP_FROM_PATCHES[$c]}" |
| 82 | exit 1 |
| 83 | fi |
| 84 | eval "VISITED_$d=true" |
| 85 | HASH="$(git diff --binary $d^..$d | sha1sum | cut -d ' ' -f 1)" |
| 86 | if [ -n "$(eval echo "\${HAS_$HASH}")" ]; then |
| 87 | echo "$d skipped" |
| 88 | continue |
| 89 | fi |
| 90 | c="$c-$HASH" |
| 91 | MAP_FROM_PATCHES[$c]="$d" |
| 92 | fi |
| 93 | echo "${MAP_FROM_PATCHES[$c]}" |
| 94 | PATCHES_TO_PICK="$PATCHES_TO_PICK |
| 95 | $c" |
| 96 | fi |
| 97 | done <<< "$REV_LIST_FROM_PATCHES" |
| 98 | while read c; do |
| 99 | if [ -z "$c" ]; then |
| 100 | continue |
| 101 | fi |
| 102 | d="${MAP_FROM_PATCHES[$c]}" |
| 103 | echo "Cherry-picking $d for $c ..." |
| 104 | git cherry-pick "$d" |
| 105 | done <<< "$PATCHES_TO_PICK" |
| 106 | |
| 107 | echo "Done" |