blob: dc1cf4e920041ae3da02e7e6cc5333c090af0fb3 [file] [log] [blame]
b.liue9582032025-04-17 19:18:16 +08001#!/bin/bash
2set -e
3get_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
7if [ -z "$1" ]; then
8 echo "Usage: `basename "$0"` branch_to_auto_pick_from"
9 exit
10fi
11FROM_BRANCH="$1"
12TO_BRANCH="$(git rev-parse --abbrev-ref HEAD)"
13if [ -z "$TO_BRANCH" ]; then
14 echo "Please git checkout to a branch first"
15 exit 1
16fi
17
18echo "Computing merge base from $FROM_BRANCH to $TO_BRANCH ..."
19MERGE_BASE="$(git merge-base --all "$FROM_BRANCH" "$TO_BRANCH")"
20if [ -z "$MERGE_BASE" ]; then
21 echo "Failed to get merge base"
22 exit 1
23elif [ $(wc -l <<< "$MERGE_BASE") -gt 1 ]; then
24 echo "Git tree with cross merge not supported"
25 exit 1
26fi
27echo "Merge base is $(get_patch_id_commit_id_pairs $MERGE_BASE^..$MERGE_BASE)"
28
29echo -n "Getting patch list on $FROM_BRANCH ... "
30declare -A MAP_FROM_PATCHES
31REV_LIST_FROM_PATCHES=
32while 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"
40done < <(get_patch_id_commit_id_pairs "$MERGE_BASE..$FROM_BRANCH")
41echo "${#MAP_FROM_PATCHES[@]} patches"
42
43echo -n "Getting patch list on $TO_BRANCH ... "
44declare -A MAP_TO_PATCHES
45declare -A MAP_TO_PATCHES_DUP
46while 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"
53done < <(get_patch_id_commit_id_pairs "$MERGE_BASE..$TO_BRANCH")
54echo "${#MAP_TO_PATCHES[@]} patches"
55for d in ${MAP_TO_PATCHES_DUP[@]}; do
56 HASH="$(git diff --binary $d^..$d | sha1sum | cut -d ' ' -f 1)"
57 eval "HAS_$HASH=true"
58done
59
60echo "Computing patches to cherry-pick ..."
61PATCHES_TO_PICK=
62while 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
97done <<< "$REV_LIST_FROM_PATCHES"
98while 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"
105done <<< "$PATCHES_TO_PICK"
106
107echo "Done"