tools: Add git utility scripts.
ADD
tools/clean-branches
+#!/usr/bin/env bash
+set -e
+
+# usage: clean-branches
+# Deletes any local branches which are ancestors of origin/master,
+# and also any branches in origin which are ancestors of
+# origin/master and are named like $USER-*.
+
+# usage: clean-branches --reviews
+# Deletes all the above mentioned branches as well as branches
+# created by the scripts like `fetch-rebase-pull-request`. Be careful
+# as this would also remove other branches woth names like review-*
+
+review=0
+if [ $# -ne 0 ] && [ "$1" == "--reviews" ]; then
+ review=1
+fi
+push_args=()
+
+function is_merged {
+ ! git rev-list -n 1 origin/master.."$1" | grep -q .
+}
+
+function clean_ref {
+ ref="$1"
+ case "$ref" in
+ */master | */HEAD)
+ return
+ ;;
+
+ refs/heads/review-*)
+ if [ $review -ne 0 ]; then
+ echo -n "Deleting local branch $(echo "$ref" | sed 's!^refs/heads/!!')"
+ echo " (was $(git rev-parse --short "$ref"))"
+ git update-ref -d "$ref"
+ fi
+ ;;
+
+ refs/heads/*)
+ if is_merged "$ref"; then
+ echo -n "Deleting local branch $(echo "$ref" | sed 's!^refs/heads/!!')"
+ echo " (was $(git rev-parse --short "$ref"))"
+ git update-ref -d "$ref"
+ fi
+ ;;
+
+ refs/remotes/origin/$USER-*)
+ if is_merged "$ref"; then
+ remote_name="$(echo "$ref" | sed 's!^refs/remotes/origin/!!')"
+ echo -n "Deleting remote branch $remote_name"
+ echo " (was $(git rev-parse --short "$ref"))"
+ # NB: this won't handle spaces in ref names
+ push_args=("${push_args[@]}" ":$remote_name")
+ fi
+ ;;
+ esac
+}
+
+if [ "$(git symbolic-ref HEAD)" != 'refs/heads/master' ]; then
+ echo "Check out master before you run this script." >&2
+ exit 1
+fi
+
+git fetch --prune origin
+
+eval "$(git for-each-ref --shell --format='clean_ref %(refname);')"
+
+if [ "${#push_args}" -ne 0 ]; then
+ git push origin "${push_args[@]}"
+fi

ADD
tools/clean-repo
+#!/usr/bin/env bash
+set -e
+
+# Remove .pyc files to prevent loading stale code.
+#
+# You can run it automatically on checkout:
+#
+# echo ./tools/clean-repo > .git/hooks/post-checkout
+# chmod +x .git/hooks/post-checkout
+
+cd "$(dirname "$0")/.."
+find . -name "*.pyc" -exec rm -f {} \;
+find . -name "__pycache__" -prune -exec rm -rf {} \;

ADD
tools/deploy-branch
+#!/bin/bash
+
+function error_out {
+ echo -en '\e[0;31m'
+ echo "$1"
+ echo -en '\e[0m'
+ exit 1
+}
+
+status=$(git status --porcelain | grep -v '^??')
+[ ! -z "$status" ] && error_out "Working directory or index not clean"
+
+old_ref=$(git rev-list --max-count=1 HEAD)
+branch=$1
+branch_ref=$(git rev-list --max-count=1 "$branch")
+
+[ $? -ne 0 ] && error_out "Unknown branch: $branch"
+
+if [ "$old_ref" == "$branch_ref" ]; then
+ new_ref=master
+else
+ ref_name=$(git describe --all --exact "$old_ref")
+ if [ $? -eq 0 ]; then
+ new_ref=$(echo "$ref_name" | perl -pe 's{^(heads|remotes)/}{}')
+ else
+ new_ref=$old_ref
+ fi
+fi
+
+[ -z "$branch" ] && error_out "You must specify a branch name to deploy"
+
+git fetch -p
+
+git rebase origin/master "$branch"
+[ $? -ne 0 ] && error_out "Rebase onto origin/master failed"
+
+git push . HEAD:master
+git push origin master
+[ $? -ne 0 ] && error_out "Push of master to origin/master failed"
+
+git checkout "$new_ref"
+git branch -D "$branch"
+git push origin ":$branch"

ADD
tools/fetch-pull-request
+#!/bin/bash
+set -e
+set -x
+
+if ! git diff-index --quiet HEAD; then
+ set +x
+ echo "There are uncommitted changes:"
+ git status --short
+ echo "Doing nothing to avoid losing your work."
+ exit 1
+fi
+request_id="$1"
+remote=${2:-"upstream"}
+git fetch "$remote" "pull/$request_id/head"
+git checkout -B "review-original-${request_id}"
+git reset --hard FETCH_HEAD

ADD
tools/fetch-rebase-pull-request
+#!/bin/bash
+set -e
+set -x
+
+if ! git diff-index --quiet HEAD; then
+ set +x
+ echo "There are uncommitted changes:"
+ git status --short
+ echo "Doing nothing to avoid losing your work."
+ exit 1
+fi
+request_id="$1"
+remote=${2:-"upstream"}
+git fetch "$remote" "pull/$request_id/head"
+git checkout -B "review-${request_id}" $remote/master
+git reset --hard FETCH_HEAD
+git pull --rebase

ADD
tools/reset-to-pull-request
+#!/bin/bash
+set -e
+set -x
+
+if ! git diff-index --quiet HEAD; then
+ set +x
+ echo "There are uncommitted changes:"
+ git status --short
+ echo "Doing nothing to avoid losing your work."
+ exit 1
+fi
+request_id="$1"
+remote=${2:-"upstream"}
+git fetch "$remote" "pull/$request_id/head"
+git reset --hard FETCH_HEAD

ADD
tools/review
+#!/usr/bin/env python
+
+from __future__ import print_function
+import subprocess
+import sys
+
+def exit(message):
+ # type: (str) -> None
+ print('PROBLEM!')
+ print(message)
+ sys.exit(1)
+
+def run(command):
+ # type: (str) -> None
+ print('\n>>> ' + command)
+ subprocess.check_call(command.split())
+
+def check_output(command):
+ # type: (str) -> str
+ return subprocess.check_output(command.split()).decode('ascii')
+
+def get_git_branch():
+ # type: () -> str
+ command = 'git rev-parse --abbrev-ref HEAD'
+ output = check_output(command)
+ return output.strip()
+
+def check_git_pristine():
+ # type: () -> None
+ command = 'git status --porcelain'
+ output = check_output(command)
+ if output.strip():
+ exit('Git is not pristine:\n' + output)
+
+def ensure_on_clean_master():
+ # type: () -> None
+ branch = get_git_branch()
+ if branch != 'master':
+ exit('You are still on a feature branch: %s' % (branch,))
+ check_git_pristine()
+ run('git fetch upstream master')
+ run('git rebase upstream/master')
+
+def create_pull_branch(pull_id):
+ # type: (int) -> None
+ run('git fetch upstream pull/%d/head' % (pull_id,))
+ run('git checkout -B review-%s FETCH_HEAD' % (pull_id,))
+ run('git rebase upstream/master')
+ run('git log upstream/master.. --oneline')
+ run('git diff upstream/master.. --name-status')
+
+ print()
+ print('PR: %d' % (pull_id,))
+ print(subprocess.check_output(['git', 'log', 'HEAD~..',
+ '--pretty=format:Author: %an']))
+
+def review_pr():
+ # type: () -> None
+ try:
+ pull_id = int(sys.argv[1])
+ except Exception:
+ exit('please provide an integer pull request id')
+
+ ensure_on_clean_master()
+ create_pull_branch(pull_id)
+
+if __name__ == '__main__':
+ review_pr()

tools: Add git utility scripts.