4 >&2 echo "Usage: ghmerge <options including prnum and reviewer(s)>
5 or ghmerge [<options>] -- <prnum> <reviewer>...
6 Options may include addrev options and gitaddrev filter args.
8 Option style arguments:
10 --help Print this help and exit
11 --tools Merge a tools PR (rather than openssl PR)
12 --web Merge a web PR (rather than openssl PR)
13 --remote <remote> Repo to merge with (rather than git.openssl.org), usually 'upstream'
14 --target <branch> Merge target (rather than current branch), usually 'master'
15 --ref <branch> A synonym for --target
16 --cherry-pick [<n>] Cherry-pick the last n (1 <= n <= 99, default: 1) commits, rather than rebasing
17 --squash Squash new commits non-interactively (allows editing msg)
18 --noautosquash Do not automatically squash fixups in interactive rebase
19 --nobuild Do not call 'openssbuild' before merging
23 ghmerge 12345 mattcaswell
24 ghmerge 12345 paulidale t8m --nobuild --myemail=dev@ddvo.net
25 ghmerge edd05b7^^^^..19692bb2c32 --squash -- 12345 levitte
26 ghmerge 12345 slontis --target openssl-3.0
27 ghmerge --nobuild --target openssl-3.0 --cherry-pick 3 16051 paulidale"
36 AUTOSQUASH="--autosquash"
40 [ -z ${CC+x} ] && CC="ccache gcc" # opensslbuild will otherwise use "ccache clang-3.6"
42 if [ ! -d .git ] ; then
43 echo Not at a top-level git directory
52 while [ $# -ne 0 ]; do
58 WHAT=tools ; BUILD=no ; shift
61 WHAT=web ; BUILD=no ; shift
66 if [ "$1" != "" ] && [ $1 -ge 1 ] 2>/dev/null && [ $1 -le 99 ]; then
74 INTERACTIVE=no ; shift
80 if [ $# -lt 2 ] ; then
81 echo "Missing argument of '$1'"
84 shift; REMOTE=$1; shift
87 if [ $# -lt 2 ] ; then
88 echo "Missing argument of '$1'"
91 shift; TARGET=$1; shift
94 if [ $# -lt 3 ] ; then
95 echo "Missing <prnum> <reviewer>... after '--'"
98 shift; PRNUM=$1 ; shift
102 -*) # e.g., --verbose, --trivial, --myemail=...
103 ADDREVOPTS="$ADDREVOPTS $1"
106 +([[:digit:]]) ) # e.g., 1453
110 TEAM="$TEAM $1"; shift
112 +([[:alnum:]-]) ) # e.g., levitte
113 if [[ $1 =~ ^[0-9a-f]{7,}+$ ]]; then # e.g., edd05b7
114 ADDREVOPTS="$ADDREVOPTS $1"
120 *) # e.g., edd05b7^^^^..19692bb2c32
121 ADDREVOPTS="$ADDREVOPTS $1"; shift
126 if [ "$WHAT" = "" ] ; then
129 ADDREVOPTS="$ADDREVOPTS --$WHAT"
131 ADDREVOPTS=${ADDREVOPTS# } # chop any leading ' '
133 [ "$REMOTE" = "" ] && REMOTE=`git remote -v | awk '/git.openssl.org.*(push)/{ print $1; }' | head -n 1` # usually this will be 'upstream'
134 if [ "$REMOTE" = "" ] ; then
135 echo Cannot find git remote with URL including 'git.openssl.org'
139 if [ "$PRNUM" = "" -o "$TEAM" = "" ] ; then
143 PR_URL=https://api.github.com/repos/openssl/$WHAT/pulls/$PRNUM
144 if ! wget --quiet $PR_URL -O /tmp/gh$$; then
145 echo "Error getting $PR_URL"
149 from __future__ import print_function
151 input = json.load(sys.stdin)
152 print(str(input["head"]["label"]).replace(":", " "),
153 str(input["head"]["repo"]["ssh_url"]))' </tmp/gh$$`
159 if [ -z "$WHO" -o -z "$BRANCH" -o -z "$REPO" ]; then
160 echo "Could not determine from $PR_URL which branch of whom to fetch from where"
164 ORIG_REF=`git rev-parse --abbrev-ref HEAD` # usually this will be 'master'
165 STASH_OUT=`git stash`
166 WORK="copy-of-${WHO}-${BRANCH}"
168 (git branch | grep -q "$WORK") && (echo "Branch already exists: $WORK"; exit 1)
172 echo # make sure to enter new line, needed, e.g., after Ctrl-C
173 [ $rv -ne 0 ] && echo -e "\nghmerge failed"
174 if [ "$REBASING" == 1 ] ; then
175 git rebase --abort 2>/dev/null || true
177 if [ "$CHERRYPICKING" == 1 ] ; then
178 echo "Hint: maybe --cherry-pick was not given a suitable <n> parameter."
179 git cherry-pick --abort 2>/dev/null || true
181 if [ "$ORIG_TARGET_HEAD" != "" ]; then
182 echo Restoring original commit HEAD of $TARGET
183 git reset --hard "$ORIG_TARGET_HEAD"
185 if [ "$TARGET" != "$ORIG_REF" ] || [ "$WORK_USED" != "" ]; then
186 echo Returning to previous branch $ORIG_REF
187 git checkout -q $ORIG_REF
189 if [ "$WORK_USED" != "" ]; then
190 git branch -qD $WORK_USED
192 if [ "$STASH_OUT" != "No local changes to save" ]; then
193 git stash pop -q # restore original state of $ORIG_REF, pruning any leftover commits added locally
198 [ "$TARGET" = "" ] && TARGET=$ORIG_REF
199 if [ "$TARGET" != "$ORIG_REF" ]; then
200 echo -n "Press Enter to checkout $TARGET: "; read foo
204 echo -n "Press Enter to pull the latest $REMOTE/$TARGET: "; read foo
206 git pull $REMOTE $TARGET || exit 1
209 # append new commits from $REPO/$BRANCH
210 if [ "$PICK" == "no" ]; then
211 echo Rebasing $REPO/$BRANCH on $TARGET...
212 git fetch $REPO $BRANCH && git checkout -b $WORK FETCH_HEAD
215 git rebase $TARGET || (echo 'Fix or Ctrl-d to abort' ; read || exit 1)
218 echo Cherry-picking $REPO/$BRANCH to $TARGET...
219 git checkout -b $WORK $TARGET
222 git fetch $REPO $BRANCH && (git cherry-pick FETCH_HEAD~$PICK..FETCH_HEAD || exit 1)
226 echo Diff against $REMOTE/$TARGET
227 git diff $REMOTE/$TARGET
229 if [ "$INTERACTIVE" == "yes" ] ; then
230 echo -n "Press Enter to interactively rebase $AUTOSQUASH on $REMOTE/$TARGET: "; read foo
232 git rebase -i $AUTOSQUASH $REMOTE/$TARGET || exit 1
234 echo "Calling addrev $ADDREVOPTS --prnum=$PRNUM $TEAM $REMOTE/$TARGET.."
235 addrev $ADDREVOPTS --prnum=$PRNUM $TEAM $REMOTE/$TARGET..
239 echo Log since $REMOTE/$TARGET
240 git log $REMOTE/$TARGET..
243 if [ "$INTERACTIVE" != "yes" ] ; then
244 echo -n "Press Enter to non-interactively merge --squash $BRANCH to $REMOTE/$TARGET: "; read foo
245 ORIG_TARGET_HEAD=`git show -s --format="%H"`
246 git merge --ff-only --no-commit --squash $WORK
247 AUTHOR=`git show --no-patch --pretty="format:%an <%ae>" $WORK`
248 git commit --author="$AUTHOR"
249 addrev $ADDREVOPTS --prnum=$PRNUM $TEAM $REMOTE/${TARGET}..
251 # echo -n "Press Enter to merge to $TARGET: "; read foo
253 echo "Merging to $TARGET"
254 ORIG_TARGET_HEAD=`git show -s --format="%H"`
255 git merge --ff-only $WORK
258 echo New log since $REMOTE/$TARGET
259 git log $REMOTE/$TARGET..
261 if [ "$BUILD" == "yes" ] ; then
263 CC="$CC" opensslbuild >/dev/null # any STDERR output will be shown
267 echo -n "Enter 'y'/'yes' to push to $REMOTE/$TARGET or 'n'/'no' to abort: "
269 x="`echo $x | tr A-Z a-z`"
270 if [ "$x" = "y" -o "$x" = "yes" -o "$x" = "n" -o "$x" = "no" ] ; then
275 if [ "$x" = "y" -o "$x" = "yes" ] ; then
276 git push -v $REMOTE $TARGET