summaryrefslogtreecommitdiff
path: root/util/scripts/gerrit-rebase
diff options
context:
space:
mode:
authorPatrick Georgi <pgeorgi@chromium.org>2016-09-22 12:46:45 +0200
committerPatrick Georgi <pgeorgi@google.com>2016-10-10 20:18:57 +0200
commit519c4b7298516c849b4a510ad2fd691d662de7d6 (patch)
tree08eaae4cfa81c8f6539391cae131ab0039f8cb2f /util/scripts/gerrit-rebase
parent0de17e74ff428cefc95d8788e58ad11ec5f70085 (diff)
util/scripts: add gerrit-rebase script
gerrit-rebase is a gerrit-context aware rebase script. Given a source and a target branch (that need to have a common ancestor), it prepares a rebase todo list that applies all commits from source that aren't already found on target. It matches commits using Reviewed-on lines in the commit message that are added by gerrit when submitting commits using the "cherry-pick" strategy. This has been shown to be the best preserved meta data to work from in existing data (Change-Id was mangled in all kinds of ways). Change-Id: I9618c1b66ebc1fb7ed006efbc1665fb08386e1a5 Signed-off-by: Patrick Georgi <pgeorgi@chromium.org> Reviewed-on: https://review.coreboot.org/16695 Tested-by: build bot (Jenkins) Reviewed-by: Paul Menzel <paulepanter@users.sourceforge.net> Reviewed-by: Martin Roth <martinroth@google.com>
Diffstat (limited to 'util/scripts/gerrit-rebase')
-rwxr-xr-xutil/scripts/gerrit-rebase61
1 files changed, 61 insertions, 0 deletions
diff --git a/util/scripts/gerrit-rebase b/util/scripts/gerrit-rebase
new file mode 100755
index 0000000000..002c499f8c
--- /dev/null
+++ b/util/scripts/gerrit-rebase
@@ -0,0 +1,61 @@
+#!/bin/bash
+# $0 from-branch to-branch
+# applies all commits that from-branch has over to-branch,
+# based on a common ancestor and gerrit meta-data
+from=$1
+to=$2
+
+# match string: this is the git commit line that is used to
+# identify commits that were already copied over.
+#
+# Must not contain spaces except for leading and trailing.
+#
+# The first pick was Change-Id, but it was lost too often,
+# so go for Reviewed-on instead. It's also unique because it
+# contains the gerrit instance's host name and the change's number
+# on that system.
+match_string='^ [-A-Za-z]*[Rr]eviewed-on: '
+
+# fetch common ancestor
+common_base=$(git merge-base ${from} ${to} 2>/dev/null)
+
+if [ -z "${common_base}" ]; then
+ echo \"${from}\" or \"${to}\" is not a valid branch name.
+ exit 1
+fi
+
+# collect matches that are present on the target side
+to_matches="$(git log ${common_base}..${to} | \
+ grep "${match_string}" | \
+ cut -d: -f2-)"
+
+# start rebase process, but fail immediately by enforcing an invalid todo
+GIT_SEQUENCE_EDITOR="echo foo >" \
+ git rebase -i --onto ${to} ${from} ${to} 2>/dev/null
+
+# write new rebase todo
+# the appended "commit" line triggers handling of the last log entry
+commit=""
+(git log --reverse ${common_base}..${from} | \
+ grep -E "(^commit [0-9a-f]{40}\$|${match_string})"; \
+ echo "commit") | \
+while read key value; do
+ if [ "${key}" = "commit" ]; then
+ if [ -n "${commit}" ]; then
+ git log -n 1 --pretty="pick %h %s" ${commit}
+ fi
+ commit="${value}"
+ else
+ # if value was already found on the "to" side, skip this
+ # commit
+ if [[ ${to_matches} == *"${value}"* ]]; then
+ commit=""
+ fi
+ fi
+done | GIT_SEQUENCE_EDITOR="cat >" git rebase --edit-todo
+
+# allow user to edit todo
+git rebase --edit-todo
+
+# start processing todo to mimick git rebase -i behavior
+git rebase --continue