|
| 1 | +#!/bin/bash |
| 2 | +set -euo pipefail |
| 3 | + |
| 4 | +HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" |
| 5 | + |
| 6 | +if [ $# -ne 1 ]; then |
| 7 | + echo "Usage: $0 [<upstream-commit-hash> | --continue | --abort]" |
| 8 | + exit 1 |
| 9 | +fi |
| 10 | + |
| 11 | +CMD=$1 |
| 12 | + |
| 13 | +if [[ "$CMD" == "--continue" ]] || [[ "$CMD" == "--abort" ]]; then |
| 14 | + GIT_DIR="$HERE/../.git" |
| 15 | + if [ -f "$GIT_DIR/CHERRY_PICK_HEAD" ] && [ -f "$GIT_DIR/CHERRY_COMMIT_EDITMSG" ]; then |
| 16 | + if [[ "$CMD" == "--continue" ]]; then |
| 17 | + git commit -F "$GIT_DIR/CHERRY_COMMIT_EDITMSG" --author "$(cat $GIT_DIR/COMMIT_AUTHOR_NAME) <$(cat $GIT_DIR/COMMIT_AUTHOR_EMAIL)>)" --date "$(cat $GIT_DIR/COMMIT_AUTHOR_DATE)" |
| 18 | + else |
| 19 | + git reset --hard HEAD |
| 20 | + fi |
| 21 | + rm -f $GIT_DIR/CHERRY_PICK_HEAD $GIT_DIR/CHERY_COMMIT_EDITMSG $GIT_DIR/COMMIT_AUTHOR_NAME $GIT_DIR/COMMIT_AUTHOR_EMAIL $GIT_DIR/COMMIT_AUTHOR_DATE |
| 22 | + exit 0 |
| 23 | + else |
| 24 | + echo "No cherry-pick in progress." |
| 25 | + exit 1 |
| 26 | + fi |
| 27 | +fi |
| 28 | + |
| 29 | +UPSTREAM_COMMIT=$1 |
| 30 | + |
| 31 | +PATCH_FILE=$(mktemp) |
| 32 | +TMP_REWRITTEN=$(mktemp) |
| 33 | + |
| 34 | +cleanup() { |
| 35 | + rm -f "$PATCH_FILE" "$TMP_REWRITTEN" |
| 36 | +} |
| 37 | +trap cleanup EXIT |
| 38 | + |
| 39 | +# Step 1: Generate patch from upstream commit (only src/) |
| 40 | +git diff-tree -p "$UPSTREAM_COMMIT" -- src/ > "$PATCH_FILE" |
| 41 | + |
| 42 | +# Step 2: Rewrite and filter paths |
| 43 | +awk ' |
| 44 | + function is_cpp_or_header(path) { |
| 45 | + return path ~ /\.(cpp|cc|cxx|h|hpp)$/ |
| 46 | + } |
| 47 | + function is_api_java(path) { |
| 48 | + return path ~ /^src\/api\/.*\.java$/ |
| 49 | + } |
| 50 | + function translate_path(path) { |
| 51 | + if (is_cpp_or_header(path)) { |
| 52 | + sub(/^src\//, "ddprof-lib/src/main/cpp/", path) |
| 53 | + return path |
| 54 | + } else if (is_api_java(path)) { |
| 55 | + sub(/^src\/api\//, "ddprof-lib/src/main/java/", path) |
| 56 | + return path |
| 57 | + } |
| 58 | + return "" |
| 59 | + } |
| 60 | +
|
| 61 | + BEGIN { |
| 62 | + skip = 0 |
| 63 | + } |
| 64 | +
|
| 65 | + /^diff --git a\// { |
| 66 | + a = substr($3, 3) |
| 67 | + b = substr($4, 3) |
| 68 | + a_new = translate_path(a) |
| 69 | + b_new = translate_path(b) |
| 70 | + if (a_new == "" || b_new == "") { |
| 71 | + skip = 1 |
| 72 | + next |
| 73 | + } |
| 74 | + print "diff --git a/" a_new " b/" b_new |
| 75 | + skip = 0 |
| 76 | + next |
| 77 | + } |
| 78 | +
|
| 79 | + /^--- a\// { |
| 80 | + if (skip) next |
| 81 | + path = substr($0, 7) |
| 82 | + newpath = translate_path(path) |
| 83 | + if (newpath == "") { skip = 1; next } |
| 84 | + print "--- a/" newpath |
| 85 | + next |
| 86 | + } |
| 87 | +
|
| 88 | + /^\+\+\+ b\// { |
| 89 | + if (skip) next |
| 90 | + path = substr($0, 7) |
| 91 | + newpath = translate_path(path) |
| 92 | + if (newpath == "") { skip = 1; next } |
| 93 | + print "+++ b/" newpath |
| 94 | + next |
| 95 | + } |
| 96 | +
|
| 97 | + { |
| 98 | + if (!skip) print |
| 99 | + } |
| 100 | +' "$PATCH_FILE" > "$TMP_REWRITTEN" |
| 101 | + |
| 102 | +# Step 3: Apply the rewritten patch if it's not empty |
| 103 | +if ! grep -q '^diff --git' "$TMP_REWRITTEN"; then |
| 104 | + echo "No applicable changes after path filtering. Skipping commit $UPSTREAM_COMMIT" |
| 105 | + exit 0 |
| 106 | +fi |
| 107 | + |
| 108 | +# Step 4: Commit using original metadata |
| 109 | +tree=$(git write-tree) |
| 110 | +parent=$(git rev-parse HEAD) |
| 111 | +author_name=$(git show -s --format='%an' "$UPSTREAM_COMMIT") |
| 112 | +author_email=$(git show -s --format='%ae' "$UPSTREAM_COMMIT") |
| 113 | +author_date=$(git show -s --format='%aI' "$UPSTREAM_COMMIT") |
| 114 | +commit_message=$(git show -s --format='%s%n%n%b' "$UPSTREAM_COMMIT") |
| 115 | + |
| 116 | +if ! grep -q "$UPSTREAM_COMMIT" <<< "$commit_message"; then |
| 117 | + commit_message="$commit_message |
| 118 | +
|
| 119 | +(cherry picked from commit $UPSTREAM_COMMIT)" |
| 120 | +fi |
| 121 | + |
| 122 | +if ! git apply --3way "$TMP_REWRITTEN"; then |
| 123 | + echo "Patch had conflicts. Please resolve manually, then run:" |
| 124 | + echo "./utils/cherry.sh --continue" |
| 125 | + echo " or " |
| 126 | + echo " git add <resolved files>" |
| 127 | + echo " git commit --author=\"$author_name <$author_email>\" --date=\"$author_date\" -m \"$commit_message\"" |
| 128 | + echo |
| 129 | + echo "$author_date" > .git/COMMIT_AUTHOR_DATE |
| 130 | + echo "$author_email" > .git/COMMIT_AUTHOR_EMAIL |
| 131 | + echo "$author_name" > .git/COMMIT_AUTHOR_NAME |
| 132 | + echo "$UPSTREAM_COMMIT" > .git/CHERRY_PICK_HEAD |
| 133 | + echo "$commit_message" > .git/CHERRY_COMMIT_EDITMSG |
| 134 | + exit 1 |
| 135 | +fi |
| 136 | + |
| 137 | +GIT_AUTHOR_NAME="$author_name" \ |
| 138 | +GIT_AUTHOR_EMAIL="$author_email" \ |
| 139 | +GIT_AUTHOR_DATE="$author_date" \ |
| 140 | +git commit-tree "$tree" -p "$parent" -m "$commit_message" | xargs git reset --hard |
0 commit comments