165 lines
5.5 KiB
Bash
Executable File
165 lines
5.5 KiB
Bash
Executable File
#!/bin/bash
|
|
#/**
|
|
# * Licensed to the Apache Software Foundation (ASF) under one
|
|
# * or more contributor license agreements. See the NOTICE file
|
|
# * distributed with this work for additional information
|
|
# * regarding copyright ownership. The ASF licenses this file
|
|
# * to you 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.
|
|
# */
|
|
|
|
# Make a patch for the current branch based on its tracking branch
|
|
|
|
patch_version=''
|
|
|
|
# Process args
|
|
while getopts "ahtd:b:" opt; do
|
|
case "${opt}" in
|
|
a) addendum='-addendum'
|
|
;;
|
|
d)
|
|
patch_dir=$OPTARG
|
|
;;
|
|
b)
|
|
tracking_branch=$OPTARG
|
|
;;
|
|
t)
|
|
patch_version=".$(date -u +%Y%m%d-%H%M%S)"
|
|
;;
|
|
*)
|
|
echo -e "Usage: $0 [-h] [-a] [-t] [-d] <directory> \n\
|
|
Must be run from within the git branch to make the patch against.\n\
|
|
-h - display these instructions.\n\
|
|
-a - Add an 'addendum' prefix to the patch name.\n\
|
|
-t - Use the current timestamp as the version indicator.\n\
|
|
-b - Specify the base branch to diff from. (defaults to the tracking branch or origin master)\n\
|
|
-d - specify a patch directory (defaults to ~/patches/)"
|
|
exit 0
|
|
;;
|
|
esac
|
|
done
|
|
|
|
# Find what branch we are on
|
|
branch=$(git branch | grep '^\*' | cut -d' ' -f2- )
|
|
if [ ! "${branch}" ]; then
|
|
echo "Can't determine the git branch. Exiting." >&2
|
|
exit 1
|
|
fi
|
|
|
|
# Exit if git status is dirty
|
|
git_dirty=$(git diff --shortstat 2> /dev/null | wc -l)
|
|
echo "git_dirty is ${git_dirty}"
|
|
if [ "${git_dirty}" -ne 0 ]; then
|
|
echo "Git status is dirty. Commit locally first.">&2
|
|
exit 1
|
|
fi
|
|
|
|
# Determine the tracking branch if needed.
|
|
# If it was passed in from the command line
|
|
# with -b then use dthat no matter what.
|
|
if [ ! "${tracking_branch}" ]; then
|
|
git log -n 1 "origin/${branch}" > /dev/null 2>&1
|
|
status=$?
|
|
if [ "${status}" -eq 128 ]; then
|
|
# Status 128 means there is no remote branch
|
|
tracking_branch='origin/master'
|
|
elif [ "${status}" -eq 0 ]; then
|
|
# Status 0 means there is a remote branch
|
|
tracking_branch="origin/${branch}"
|
|
else
|
|
echo "Unknown error: $?" >&2
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
|
|
# Deal with invalid or missing ${patch_dir}
|
|
if [ ! "${patch_dir}" ]; then
|
|
echo -e "Patch directory not specified. Falling back to ~/patches/."
|
|
patch_dir=~/patches
|
|
fi
|
|
|
|
if [ ! -d "${patch_dir}" ]; then
|
|
echo "${patch_dir} does not exist. Creating it."
|
|
mkdir "${patch_dir}"
|
|
fi
|
|
|
|
# If this is against a tracking branch other than master
|
|
# include it in the patch name
|
|
tracking_suffix=""
|
|
if [[ "${tracking_branch}" != "origin/master" \
|
|
&& "${tracking_branch}" != "master" ]]; then
|
|
tracking_suffix=".${tracking_branch#origin/}"
|
|
fi
|
|
|
|
# Determine what to call the patch
|
|
if [[ "${patch_version}" == "" ]]; then
|
|
# If we do NOT have the timestamp we must find the version to use
|
|
version=0
|
|
# Check to see if any patch exists that includes the branch name
|
|
status=$(find "${patch_dir}" -maxdepth 1 -type f -name "${branch}${tracking_suffix}.v[0-9][0-9].patch" 2>/dev/null|grep -c -v addendum)
|
|
if [[ "${status}" -eq 0 ]]; then
|
|
# This is the first patch we are making for this release
|
|
version=1
|
|
elif [[ "${status}" -ge 1 ]]; then
|
|
# At least one patch already exists -- find the last one
|
|
for i in {99..1}; do
|
|
# Check to see the maximum version of patch that exists
|
|
versionfiles=$(find "${patch_dir}" -maxdepth 1 -type f -name "${branch}${tracking_suffix}.v$(printf "%02d" "$i").patch" 2> /dev/null | wc -l)
|
|
if [ 0 -lt "${versionfiles}" ]; then
|
|
version=$((i+1))
|
|
break
|
|
fi
|
|
done
|
|
fi
|
|
if [ -n "${addendum}" ]; then
|
|
# Don't increment the patch # if it is an addendum
|
|
echo "Creating an addendum"
|
|
if [ "${version}" -ge 1 ]; then
|
|
# We are making an addendum to a different version of the patch
|
|
version=$((version-1))
|
|
fi
|
|
fi
|
|
patch_version=".v$(printf "%02d" "${version}")"
|
|
fi
|
|
|
|
|
|
patch_name="${branch}${tracking_suffix}${patch_version}${addendum}.patch"
|
|
|
|
# Do we need to make a diff?
|
|
git diff --quiet "${tracking_branch}"
|
|
status=$?
|
|
if [ "${status}" -eq 0 ]; then
|
|
echo "There is no difference between ${branch} and ${tracking_branch}."
|
|
echo "No patch created."
|
|
exit 0
|
|
fi
|
|
|
|
# Check whether we need to squash or not
|
|
local_commits=$(git log "${tracking_branch}..${branch}" | grep -c 'Author:')
|
|
if [ "$local_commits" -gt 1 ]; then
|
|
read -p "$local_commits commits exist only in your local branch. Interactive rebase?" yn
|
|
case $yn in
|
|
[Yy]* )
|
|
git rebase -i "${tracking_branch}"
|
|
;;
|
|
[Nn]* )
|
|
echo "Creating ${patch_dir}/${patch_name} using git diff."
|
|
git diff "${tracking_branch}" > "${patch_dir}/${patch_name}"
|
|
exit 0
|
|
;;
|
|
esac
|
|
fi
|
|
|
|
echo "Creating patch ${patch_dir}/${patch_name} using git format-patch"
|
|
git format-patch --no-prefix --stdout "${tracking_branch}" > "${patch_dir}/${patch_name}"
|