mirror of
https://github.com/zulip/zulip.git
synced 2025-10-23 04:52:12 +00:00
The commit hashes that appear in the `pull/12345/head` ref are the ones _before_ any final rebase occurs, and as such may not match to any commit hashes which exist in `main`. Use the GitHub GraphQL API to pull the last "merge commit" on the PR, which is post-rebase, and use that as the target commit when cherry-picking. Then walk backwards from that commit, including every sequential commit which is still associated with the PR; we do this because during the merge, commits may be added or removed, so the PR is not reliable in the commit count.
103 lines
2.4 KiB
Bash
Executable File
103 lines
2.4 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
set -e
|
|
|
|
usage() {
|
|
cat >&2 <<EOF
|
|
usage: $0 PULL_REQUEST_ID COMMIT_COUNT [REMOTE]
|
|
|
|
Fetch the given GitHub pull request branch and backport it to
|
|
the current branch using 'git cherry-pick -x'.
|
|
|
|
Typical usage is:
|
|
git fetch upstream
|
|
git checkout -b 8.x upstream/8.x
|
|
$0 FIRST_PR_ID
|
|
$0 SECOND_PR_ID
|
|
git push origin +HEAD:backport-changes
|
|
EOF
|
|
exit 1
|
|
}
|
|
|
|
pr_id="$1"
|
|
|
|
if [ -z "$pr_id" ]; then
|
|
usage
|
|
fi
|
|
|
|
fail() {
|
|
echo "$1"
|
|
exit 1
|
|
}
|
|
|
|
type gh >/dev/null 2>&1 \
|
|
|| fail "The 'gh' CLI tool is not installed; see https://cli.github.com/"
|
|
gh auth status 2>/dev/null || fail "Not authenticated to github"
|
|
|
|
# Find the last commit that was merged. We will look back in `main`
|
|
# for other commits from the same PR.
|
|
# shellcheck disable=SC2016
|
|
merge_commit="$(
|
|
gh api graphql \
|
|
-q '.data.repository.pullRequest.timelineItems.nodes[0].commit.oid' \
|
|
-F pr_id="$1" \
|
|
-f query='
|
|
query($pr_id:Int!) {
|
|
repository(name: "zulip", owner: "zulip") {
|
|
pullRequest(number:$pr_id) {
|
|
timelineItems(last:1, itemTypes: [MERGED_EVENT]) {
|
|
nodes {
|
|
... on MergedEvent {
|
|
commit {
|
|
oid
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
'
|
|
)"
|
|
|
|
# We cannot trust the "commits" count on the PR, since only part of it
|
|
# may get merged, or it may have commits squashed during the merge.
|
|
# Walk backwards on `main` from the merge commit we found, checking
|
|
# that each of those commits is still associated with the same PR.
|
|
commit_id="$merge_commit"
|
|
while true; do
|
|
# shellcheck disable=SC2016
|
|
this_pr="$(gh api graphql -F "commit_id=$commit_id 0" \
|
|
--jq '.data.repository.ref.target.history.edges[].node.associatedPullRequests.nodes[].number' \
|
|
-f query='
|
|
query($commit_id: String!) {
|
|
repository(owner: "zulip", name:"zulip") {
|
|
ref(qualifiedName:"main") {
|
|
target {
|
|
... on Commit {
|
|
history(first:1, after: $commit_id) {
|
|
edges {
|
|
node {
|
|
oid
|
|
associatedPullRequests(first: 1) {
|
|
nodes {
|
|
number
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}')"
|
|
if [ "$this_pr" != "$pr_id" ]; then
|
|
break
|
|
fi
|
|
commit_id="$(git rev-parse "$commit_id"~)"
|
|
done
|
|
|
|
set -x
|
|
git cherry-pick -x "$commit_id~..$merge_commit"
|