Files
secp256k1-zkp/contrib/sync-upstream.sh
Tim Ruffing 349a94b169 sync-upstream: Remove "select" mode and simplify
I believe it was introduced to cherry-pick upstream PRs, but that simply
doesn't work. Assume upstream is two PRs A and B ahead, and A has been
merged before B. Then trying to cherry-picking B by merging the state of
upstream's master after the merge-B commit won't do what we expect. In
particular, the merge result will *include A's changes* because A had
already been merged in upstream's master when B was merged.

(One could think that merging the PR branch of B instead works, but this
will yield the same result if B was rebased on master before it was
merged.)

The proper way to cherry-pick B is to create a PR that cherry-picks all
commits that had been included in B. This could be done automatically,
but the need to cherry-pick a PR is rare enough that we don't need tool
support for it. In fact, because we want to keep cherry-picking at a
minimum, there's a good chance that we'd anyway want to pick only a
subset of the commits in a upstream PR, and that would need manual work
anyway.
2026-03-05 14:42:33 +01:00

144 lines
4.3 KiB
Bash
Executable File

#!/usr/bin/env bash
set -eou pipefail
help() {
echo "Sync merge commits from bitcoin-core/secp256k1 into secp256k1-zkp."
echo
echo "Usage:"
echo " $0 [-b <branch>] [end]"
echo " Merges every merge commit present in upstream/master and missing in <branch>"
echo " (default: master). If the optional [end] commit is provided, only merges"
echo " up to and including [end]."
echo
echo "This tool creates a temporary branch and attempts to merge the upstream commits."
echo "If there are merge conflicts, resolve them and run tests, then use the generated"
echo "script contrib/gh-pr-create.sh to create the PR (requires the gh tool)."
echo
echo "Setup:"
echo " Requires a remote named 'upstream' pointing to bitcoin-core/secp256k1."
echo " The script will fetch it automatically, and offer to create it if missing."
echo " To add manually: git remote add upstream git@github.com:bitcoin-core/secp256k1.git"
echo
echo "Listing upstream merge commits:"
echo " To list merge commits in upstream/master that are missing from <branch> (oldest first):"
echo " git log --oneline --merges \$(git merge-base upstream/master <branch>)..upstream/master | tac"
echo " These are candidates for [end]."
exit 1
}
REMOTE=upstream
REMOTE_BRANCH="$REMOTE/master"
LOCAL_BRANCH="master"
# Makes sure you have a remote "upstream" that is up-to-date
setup() {
ret=0
git fetch "$REMOTE" &> /dev/null || ret="$?"
if [ ${ret} == 0 ]; then
return
fi
echo "Adding remote \"$REMOTE\" with URL git@github.com:bitcoin-core/secp256k1.git. Continue with y"
read -r yn
case $yn in
[Yy]* ) ;;
* ) exit 1;;
esac
git remote add "$REMOTE" git@github.com:bitcoin-core/secp256k1.git &> /dev/null
git fetch "$REMOTE" &> /dev/null
}
range() {
RANGESTART_COMMIT=$(git merge-base "$REMOTE_BRANCH" "$LOCAL_BRANCH")
RANGEEND_COMMIT=$(git rev-parse "$REMOTE_BRANCH")
if [ "$#" = 1 ]; then
RANGEEND_COMMIT=$1
fi
COMMITS=$(git --no-pager log --oneline --merges "$RANGESTART_COMMIT".."$RANGEEND_COMMIT")
COMMITS=$(echo "$COMMITS" | tac | awk '{ print $1 }' ORS=' ')
echo "Merging $COMMITS. Continue with y"
read -r yn
case $yn in
[Yy]* ) ;;
* ) exit 1;;
esac
}
# Process -b <branch> and -h arguments
while getopts "b:h" opt; do
case $opt in
b)
LOCAL_BRANCH=$OPTARG
;;
h)
help
;;
*)
echo
help
;;
esac
done
# Shift off the processed options
shift $((OPTIND -1))
setup
range "$@"
TITLE="Upstream PRs"
REPRODUCE_COMMAND="$0 -b $LOCAL_BRANCH $RANGEEND_COMMIT"
BODY=""
for COMMIT in $COMMITS
do
PRNUM=$(git log -1 "$COMMIT" --pretty=format:%s | sed s/'Merge \(bitcoin-core\/secp256k1\)\?#\([0-9]*\).*'/'\2'/)
TITLE="$TITLE $PRNUM,"
BODY=$(printf "%s\n%s" "$BODY" "$(git log -1 "$COMMIT" --pretty=format:%s | sed s/'Merge \(bitcoin-core\/secp256k1\)\?#\([0-9]*\)'/'[bitcoin-core\/secp256k1#\2]'/)")
done
# Remove trailing ","
TITLE=${TITLE%?}
BODY+=$(cat <<EOF
This PR can be recreated with \`$REPRODUCE_COMMAND\`.
Tips:
* Use \`git show --remerge-diff <pr-branch>\` to show the conflict resolution in the merge commit.
* Use \`git read-tree --reset -u <pr-branch>\` to replay these resolutions during the conflict resolution stage when recreating the PR branch locally.
Be aware that this may discard your index as well as the uncommitted changes and untracked files in your worktree.
EOF
)
echo "-----------------------------------"
echo "$TITLE"
echo "-----------------------------------"
echo "$BODY"
echo "-----------------------------------"
# Create branch from PR commit and create PR
git checkout "$LOCAL_BRANCH"
git pull --autostash
git checkout -b temp-merge-"$PRNUM"
# Escape single quote
# ' -> '\''
quote() {
local quoted=${1//\'/\'\\\'\'}
printf "%s" "$quoted"
}
TITLE=$(quote "$TITLE")
BODY=$(quote "$BODY")
BASEDIR=$(dirname "$0")
FNAME="$BASEDIR/gh-pr-create.sh"
cat <<EOT > "$FNAME"
#!/bin/sh
gh pr create -t '$TITLE' -b '$BODY' --web
# Remove temporary branch
git checkout "$LOCAL_BRANCH"
git branch -D temp-merge-"$PRNUM"
EOT
chmod +x "$FNAME"
echo Run "$FNAME" after solving the merge conflicts
git merge --no-edit -m "Merge commits '$COMMITS' into temp-merge-$PRNUM" $COMMITS