HBASE-12207 A script to help keep your Git repo fresh
This commit is contained in:
parent
1d6c4678bb
commit
66b6dd1941
|
@ -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
|
|
@ -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>
|
||||
|
|
Loading…
Reference in New Issue