HBASE-12207 A script to help keep your Git repo fresh

This commit is contained in:
Misty Stanley-Jones 2014-10-09 09:38:24 +10:00
parent 1d6c4678bb
commit 66b6dd1941
2 changed files with 242 additions and 3 deletions

View File

@ -0,0 +1,204 @@
#!/bin/bash
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# This script assumes that your remote is called "origin"
# and that your local master branch is called "master".
# I am sure it could be made more abstract but these are the defaults.
# Edit this line to point to your default directory,
# or always pass a directory to the script.
DEFAULT_DIR="EDIT_ME"
function print_usage {
cat << __EOF
$0: A script to manage your Apache HBase Git repository.
If run with no arguments, it reads the DEFAULT_DIR variable, which you
can specify by editing the script.
Usage: $0 [-d <dir>]
$0 -h
-h Show this screen.
-d <dir> The absolute or relative directory of your Git repository.
__EOF
}
function get_all_branches {
# Gets all git branches present locally
all_branches=()
for i in `git branch --list | sed -e "s/\*//g"`; do
all_branches+=("$(echo $i | awk '{print($1)}')")
done
}
function get_tracking_branches {
# Gets all branches with a remote tracking branch
tracking_branches=()
for i in `git branch -lvv | grep "\[origin/" | sed -e 's/\*//g' | awk {'print $1'}`; do
tracking_branches+=("$(echo $i | awk '{print($1)}')")
done
}
function check_git_branch_status {
# Checks the current Git branch to see if it's dirty
# Returns 1 if the branch is dirty
git_dirty=$(git diff --shortstat 2> /dev/null | wc -l|awk {'print $1'})
if [ "$git_dirty" -ne 0 ]; then
echo "Git status is dirty. Commit locally first." >&2
exit 1
fi
}
function get_jira_status {
# This function expects as an argument the JIRA ID,
# and returns 99 if resolved and 1 if it couldn't
# get the status.
# The JIRA status looks like this in the HTML:
# span id="resolution-val" class="value resolved" >
# The following is a bit brittle, but filters for lines with
# resolution-val returns 99 if it's resolved
jira_url='https://issues.apache.org/jira/browse'
jira_id="$1"
status="$(curl -s $jira_url/$jira_id | \
grep resolution-val | \
sed -e "s/.*class=\"value\ //" | \
cut -d'"' -f 1)"
if [ $? -ne 0 ]; then
echo "Could not get JIRA status. Check your network." >&2
exit 1
fi
if [ "$status" = "resolved" ]; then
return 99
fi
}
# Process the arguments
while getopts ":hd:" opt; do
case $opt in
d)
# A directory was passed in
dir="$OPTARG"
if [ ! -d "$dir/.git/" ]; then
echo "$dir does not exist or is not a Git repository." >&2
exit 1
fi
;;
h)
# Print usage instructions
print_usage
exit 0
;;
*)
echo "Invalid argument: $OPTARG" >&2
print_usage >&2
exit 1
;;
esac
done
if [ -z "$dir" ]; then
# No directory was passed in
dir="$DEFAULT_DIR"
if [ "$dir" = "EDIT_ME" ]; then
echo "You need to edit the DEFAULT_DIR in $0." >&2
$0 -h
exit 1
elif [ ! -d "$DEFAULT_DIR/.git/" ]; then
echo "Default directory $DEFAULT_DIR is not a Git repository." >&2
exit 1
fi
fi
cd "$dir"
# For each tracking branch, check it out and make sure it's fresh
# This function creates tracking_branches array and stores the tracking branches in it
get_tracking_branches
for i in "${tracking_branches[@]}"; do
git checkout -q "$i"
# Exit if git status is dirty
check_git_branch_status
git pull -q --rebase
status=$?
if [ "$status" -ne 0 ]; then
echo "Unable to pull changes in $i: $status Exiting." >&2
exit 1
fi
echo "Refreshed $i from remote."
done
# Run the function to get the list of all branches
# The function creates array all_branches and stores the branches in it
get_all_branches
# Declare array to hold deleted branch info
deleted_branches=()
for i in "${all_branches[@]}"; do
# Check JIRA status to see if we still need this branch
# JIRA expects uppercase
jira_id="$(echo $i | awk '{print toupper($0)'})"
if [[ "$jira_id" == HBASE-* ]]; then
# Returns 1 if the JIRA is closed, 0 otherwise
get_jira_status "$jira_id"
jira_status=$?
if [ $jira_status -eq 99 ]; then
# the JIRA seems to be resolved or is at least not unresolved
deleted_branches+=("$i")
fi
fi
git checkout -q "$i"
# Exit if git status is dirty
check_git_branch_status
# If this branch has a remote, don't rebase it
# If it has a remote, it has a log with at least one entry
git log -n 1 origin/"$i" > /dev/null 2>&1
status=$?
if [ $status -eq 128 ]; then
# Status 128 means there is no remote branch
# Try to rebase against master
echo "Rebasing $i on origin/master"
git rebase -q origin/master > /dev/null 2>&1
if [ $? -ne 0 ]; then
echo "Failed. Rolling back. Rebase $i manually."
git rebase --abort
fi
elif [ $status -ne 0 ]; then
# If status is 0 it means there is a remote branch, we already took care of it
echo "Unknown error: $?" >&2
exit 1
fi
done
# Offer to clean up all deleted branches
for i in "${deleted_branches[@]}"; do
read -p "$i's JIRA is resolved. Delete? " yn
case $yn in
[Yy])
git branch -D $i
;;
*)
echo "To delete it manually, run git branch -D $deleted_branches"
;;
esac
done
git checkout -q master
exit 0

View File

@ -1780,6 +1780,40 @@ justification="I know what I'm doing")</programlisting>
</section>
</section>
<section xml:id="git.best.practices">
<title>Git Best Practices</title>
<itemizedlist>
<listitem>
<para>Use the correct method to create patches. See <xref
linkend="submitting.patches"/>.</para>
</listitem>
<listitem>
<para>Avoid git merges. Use <code>git pull --rebase</code> or <code>git
fetch</code> followed by <code>git rebase</code>.</para>
</listitem>
<listitem>
<para>Do not use <code>git push --force</code>. If the push does not work, fix
the problem or ask for help.</para>
</listitem>
</itemizedlist>
<para>Please contribute to this document if you think of other Git best
practices.</para>
<section>
<title><code>rebase_all_git_branches.sh</code></title>
<para>The <filename>dev-support/rebase_all_git_branches.sh</filename> script is
provided to help keep your Git repository clean. Use the <code>-h</code>
parameter to get usage instructions. The script automatically refreshes your
tracking branches, attempts an automatic rebase of each local branch against its
remote branch, and gives you the option to delete any branch which represents a
closed <literal>HBASE-</literal> JIRA. The script has one optional configuration
option, the location of your Git directory. You can set a default by editing the
script. Otherwise, you can pass the git directory manually by using the
<code>-d</code> parameter, followed by an absolute or relative directory
name, or even '.' for the current working directory. The script checks the
directory for sub-directory called <filename>.git/</filename>, before
proceeding.</para>
</section>
</section>
<section xml:id="submitting.patches">
<title>Submitting Patches</title>
@ -1787,7 +1821,8 @@ justification="I know what I'm doing")</programlisting>
contribute patches in our new GIT context, caveat the fact that we have a different
branching model and that we don't currently do the merge practice described in the
following, the <link xlink:href="http://accumulo.apache.org/git.html">accumulo doc
on how to contribute and develop</link> after our move to GIT is worth a read. </para>
on how to contribute and develop</link> after our move to GIT is worth a read.
See also <xref linkend="git.best.practices"/>.</para>
<para>If you are new to submitting patches to open source or new to submitting patches
to Apache, start by reading the <link
@ -1898,8 +1933,8 @@ justification="I know what I'm doing")</programlisting>
<term>Git</term>
<listitem>
<para><code>git format-patch</code> is preferred because it preserves
commit messages. Use <code>git squash</code> first, to combine
smaller commits into a single larger one.</para>
commit messages. Use <code>git rebase -i</code> first, to combine
(squash) smaller commits into a single larger one.</para>
<note>
<para>Do not use <code>--no-prefix</code>, even if you were in the
habit of doing it previously.</para>