Newer
Older
#
# dim - drm inglorious maintainer script
#
# Copyright © 2012-2018 Intel Corporation
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice (including the next
# paragraph) shall be included in all copies or substantial portions of the
# Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
#
# Authors:
# Jani Nikula <jani.nikula@intel.com>
# User configuration. Global DIM_ prefixed uppercase variables. Set in
# environment or configuration file. See dimrc.sample for an example.
DIM_CACHE_DIR=${XDG_CACHE_HOME:-$HOME/.cache}/dim
DIM_CONF_DIR=${XDG_CONFIG_HOME:-$HOME/.config}/dim
function load_config() {
if [[ -v DIM_CONFIG ]] && [[ -z "$DIM_CONFIG" ]]; then
return
fi
# dim configuration file
if [[ -n $DIM_CONFIG ]] && [ -r $DIM_CONFIG ]; then
# shellcheck source=/dev/null
. $DIM_CONFIG
elif [ -r $DIM_CONF_DIR/dimrc ]; then
# shellcheck source=/dev/null
. $DIM_CONF_DIR/dimrc
elif [ -r $HOME/.dimrc ]; then
# shellcheck source=/dev/null
. $HOME/.dimrc
fi
}
load_config
# prefix for repo directories
DIM_PREFIX=${DIM_PREFIX:-$HOME/linux}
# location of another dim setup used to speedup clones; default
# to something that doesn't exist so no cache is used
DIM_KERNEL_REFERENCE=${DIM_KERNEL_REFERENCE:-}
# main maintainer repo under $DIM_PREFIX
# mail user agent. must support a subset of mutt(1) command line options:
# usage: $DIM_MUA [-s subject] [-i file] [-c cc-addr] to-addr [...]
DIM_MUA=${DIM_MUA:-mutt}
# b4 binary
DIM_B4=${DIM_B4:-b4}
# make options (not used for C=1)
DIM_MAKE_OPTIONS=${DIM_MAKE_OPTIONS:--j20}
Ander Conselvan de Oliveira
committed
# command to run after dim apply
DIM_POST_APPLY_ACTION=${DIM_POST_APPLY_ACTION:-}
# greetings pull request template
DIM_TEMPLATE_HELLO=${DIM_TEMPLATE_HELLO:-$HOME/.dim.template.hello}
# signature pull request template
DIM_TEMPLATE_SIGNATURE=${DIM_TEMPLATE_SIGNATURE:-$HOME/.dim.template.signature}
# preferred protocol when adding remotes
DIM_PREFERRED_PROTOCOL=${DIM_PREFERRED_PROTOCOL:-}
# Internal configuration. Global dim_ prefixed variables.
dim=$(basename $0)
dim_timestamp="$(date --utc +%Yy-%mm-%dd-%Hh-%Mm-%Ss) UTC"
dim_fdo_cookie="--push-option fdo.pushedWithDim=this-was-pushed-with-dim-and-not-manually"
dim_fdo_patchwork_linkmask="https://patchwork.freedesktop.org/patch/msgid/%s"
maintainer_tools_https=https://gitlab.freedesktop.org/drm/maintainer-tools.git
# Recipients for all dim based pull requests.
# Add To: lines to the end, Cc: lines in the beginning with -c.
dim_pull_request_recipients=(
-c "Jani Nikula <jani.nikula@linux.intel.com>"
-c "Joonas Lahtinen <joonas.lahtinen@linux.intel.com>"
-c "Tvrtko Ursulin <tursulin@ursulin.net>"
-c "Rodrigo Vivi <rodrigo.vivi@intel.com>"
-c "Thomas Zimmermann <tzimmermann@suse.de>"
-c "Maarten Lankhorst <maarten.lankhorst@linux.intel.com>"
-c "Thomas Hellström <thomas.hellstrom@linux.intel.com>"
-c "Oded Gabbay <ogabbay@kernel.org>"
-c "Lucas De Marchi <lucas.demarchi@intel.com>"
-c "dri-devel@lists.freedesktop.org"
-c "intel-gfx@lists.freedesktop.org"
-c "intel-xe@lists.freedesktop.org"
-c "dim-tools@lists.freedesktop.org"
"Dave Airlie <airlied@gmail.com>"
dim_integration_config=nightly.conf
dim_last_path_file=$DIM_CACHE_DIR/last-path
dim_extract_tags_marker="# *** extracted tags ***"
#
# Only function and alias definitions until the command line argument parsing
# and subcommand handling at the end.
#
function read_integration_config
{
# clear everything first to allow configuration reload
unset drm_tip_repos drm_old_urls drm_tip_config
declare -g -A drm_old_urls
declare -g -A drm_tip_repos
declare -g -a drm_tip_config
if [ -r $DIM_PREFIX/drm-rerere/$dim_integration_config ]; then
# shellcheck source=/dev/null
source $DIM_PREFIX/drm-rerere/$dim_integration_config
if [[ "${#drm_tip_repos[@]}" = "0" ]] || [[ "${#drm_tip_config[@]}" = "0" ]]; then
echoerr "$dim_integration_config not set up correctly, please fix manually"
echoerr "$dim_integration_config is missing, please check your configuration and/or run dim setup"
fi
dim_branches=
for conf in "${drm_tip_config[@]}"; do
local repo branch override
if [[ $repo = drm-* ]] || [[ $branch = topic/* ]]; then
dim_branches="$dim_branches $branch"
fi
done
}
function warn_or_fail
{
if [[ $FORCE ]] ; then
echoerr "WARNING: $1, but continuing"
elif [[ $DRY ]] ; then
echoerr "WARNING: $1, but continuing dry-run"
echoerr "ERROR: $1, aborting"
function pause
{
read -rsp "Press any key to continue..." -n1 key2
echo
}
function ask_user
{
if [ $ASK_USER_ASSUME_YES -eq 1 ]; then
return 0
fi
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
return 0
else
return 1
fi
}
#
# Variable naming convetion:
#
# repo:
# symbolic git repository name from $dim_integration_config
# remote:
# local remote name in the git repository for the current path
# branch:
# git branch name - dim assumes that the remote and local name match
# url:
# url to a repo, using ssh:// protocol
# git_url:
# url to a repo, but using anonymous git:// protocol
#
# The below functions map between these.
#
for repo in "${!drm_tip_repos[@]}"; do
for repo_url in ${drm_tip_repos[$repo]}; do
if [ "$url" == "$repo_url" ]; then
echo $repo
return
fi
done
function url_to_remote_from_git # url
local url remote
url="$1"
remote=$(git remote -v | grep -m 1 "$url/\? (" | cut -f 1)
echo "$remote"
return 0
}
function url_to_remote # url [url ...]
{
local url remote old_url repo url_list
if [[ "$#" = "0" ]]; then
echoerr "url_to_remote without URLs"
return 1
for url; do
remote=$(url_to_remote_from_git "$url")
if [[ -n "$remote" ]]; then
echo "$remote"
return 0
fi
done
repo=$(url_to_repo "$url")
url_list="$*"
url=$1
for old_url in ${drm_old_urls[$repo]} ; do
remote=$(url_to_remote_from_git "$old_url")
if [[ -n "$remote" ]]; then
if [[ -n "$DIM_PREFERRED_PROTOCOL" ]]; then
url=$(pick_protocol_url "$DIM_PREFERRED_PROTOCOL" ${url_list})
fi
if ! ask_user "Update $remote to new $url?"; then
echoerr "Old branch setup found but not updated, aborting"
return 1
fi
git remote set-url $remote $url
echo "$remote"
return 0
fi
done
# When bootstrapping the repo, there's no manifest yet. Hence there's
# no "repo", no "remote". Repo to cause this is known: drm-tip.
# Hardcode there's no repo above since default remote to the repo name, but fallback for when bootstrapping
# the environment: we may still not have drm-rerere to get the repo
# name. In that case, rely on the url
if [[ -z "$repo" ]]; then
# let's assert we are indeed dealing with drm-tip
# special case drm-tip
if [[ $url != *drm/tip.git ]]; then
echoerr "Unknown repo for urls $url_list"
return 1
fi
remote="drm-tip"
repo="drm-tip"
else
remote="$repo"
# possibly amend the passed in URLs if any matched a repo
url_list=${drm_tip_repos[$repo]}
echoerr "Adding remote for ${repo} repo from URLs: $url_list"
if [[ -n "$DIM_PREFERRED_PROTOCOL" ]]; then
url=$(pick_protocol_url "$DIM_PREFERRED_PROTOCOL" $url_list)
fi
if [ $ASK_USER_ASSUME_YES -ne 1 ]; then
read -r -i "$remote" -e -p "Enter a name to auto-add this remote, leave blank to abort: " remote
fi
if [[ -z "$remote" ]]; then
echoerr "Please set it up yourself using:"
echoerr " $ git remote add <name> $url"
echoerr "with a name of your choice."
git remote add $remote $url
echo $remote
return 0
function pick_protocol_url # (git|ssh|https|whatever) url [url ...]
{
local url protocol protocol_url
if [[ "$#" -lt "2" ]]; then
echoerr "pick_protocol_url without protocol or URLs"
return 1
fi
protocol=$1
shift
# Find the URL that has given protocol
for url; do
case $url in
${protocol}://*)
protocol_url=$url
break
;;
esac
done
if [[ -z "$protocol_url" ]]; then
echoerr "No $protocol URL in any of the URLs: $*"
return 1
fi
echo $protocol_url
}
function branch_to_remote # branch
{
repo=$(branch_to_repo $branch)
if [[ -z "$repo" ]] ; then
# fallback for special branches like rerere-cache
remote=$(git rev-parse --abbrev-ref --symbolic-full-name "$branch@{upstream}")
remote=${remote%%/*}
else
remote=$(repo_to_remote $repo)
fi
local repo url_list
repo=$1
url_list=${drm_tip_repos[$repo]}
if [[ -z "$url_list" ]]; then
echoerr "unknown repo $repo"
return 1
fi
url_to_remote $url_list
function branch_to_repo # branch
{
for conf in "${drm_tip_config[@]}"; do
local repo branch override
if [[ "$branch" == "$1" ]] ; then
echo $repo
fi
done
echo ""
}
function dim_version
{
local using
using="${BASH_SOURCE[0]}"
if [[ ! -e "$using" ]]; then
echoerr "could not figure out the version being used ($using)."
fi
if [[ ! -e "$DIM_PREFIX/maintainer-tools/.git" ]]; then
echoerr "could not find the upstream repo for $dim."
git --git-dir=$DIM_PREFIX/maintainer-tools/.git fetch -q
if ! git --git-dir=$DIM_PREFIX/maintainer-tools/.git show "@{upstream}:dim" |\
diff "$using" - >& /dev/null; then
echoerr "not running upstream version of the script."
function git_fetch_helper # remote
{
local remote
remote=$1
# old git versions returned 128 if there was nothing to fetch
if [[ $? -ne "128" ]] ; then
echoerr "Failed to fetch $remote"
return 1
fi
fi
}
function git_current_branch
{
git symbolic-ref -q --short HEAD
}
function git_is_current_branch # branch
{
test "$(git_current_branch)" = "$1"
function git_branch_exists # branch
{
if [[ "$(git branch --list $1)" == "" ]] ; then
false
else
true
fi
}
# $1: branch
# $2: upstream
function git_unmerged_tags
{
local branch upstream
branch=$1
upstream=$2
# assume branch based tag names, ensure space separated list
git log --decorate --pretty=%D "$branch@{upstream}" ^$upstream |\
grep -o "tag: $branch-[0-9-]\+" |\
sed -e "s/^tag: //" |\
tr "\n" " "
}
function git_committer_email
{
if ! committer_email=$(git config --get user.email) ; then
fi
echo $committer_email
}
function git_push
{
git push $dim_fdo_cookie $DRY_RUN "$@"
}
function check_for_updates
{
local stamp stampfile
stampfile=$DIM_CACHE_DIR/update-check-timestamp
mkdir -p $(dirname $stampfile)
# daily check for updates based on file timestamp
stamp=$(stat --printf=%Y $stampfile 2>/dev/null || echo -n 0)
if [[ $((stamp + 24*60*60)) -lt $(date +%s) ]]; then
dim_uptodate || true
touch $stampfile
fi
}
function check_git_version
{
local min_version="git version 2.8"
if ! echo -e "$min_version\n$(git version)" | sort -VC; then
echoerr "WARNING: recommended minimum $min_version, you have $(git version)"
fi
}
function check_dim_version
{
if [[ -n "$DIM_MIN_VERSION" ]] && [[ "$(dim_version)" < "$DIM_MIN_VERSION" ]]; then
echoerr "ERROR: required minimum dim version $DIM_MIN_VERSION, you have $(dim_version)"
exit 1
fi
}
function check_dim_config
{
if [[ "$DIM_REPO" == "drm-tip" || "$DIM_REPO" == "drm-rerere" || "$DIM_REPO" == "maintainer-tools" ]]; then
echoerr "WARNING: setting $DIM_REPO for DIM_REPO not allowed"
exit 1
fi
}
# get message id from file
# $1 = file
message_get_id ()
{
import email
f = open('$1', 'rb')
msg = email.message_from_binary_file(f)
message_id = msg['message-id']
if message_id is not None:
print(message_id.strip('<> \n'))
msg = email.message_from_binary_file(file)
for part in msg.walk():
if part.get_content_type() == 'text/plain':
print(part.get_payload(decode=True).decode(part.get_content_charset(failobj='us-ascii'), 'replace'))
# append all arguments as tags at the end of the commit message of HEAD
function dim_commit_add_tag
for arg; do
# the first sed deletes all trailing blank lines at the end
git log -1 --pretty=%B | \
sed -e :a -e '/^\n*$/{$d;N;ba' -e '}' | \
sed "\$a${arg}" | \
git commit --amend -F-
done
# $1: branch [optional]
function git_find_tip
{
git log $1 -1 --format=%H --grep="^drm-tip: .* integration manifest$"
}
# $1: branch [optional]
function dim_retip
{
local branch upstream new_upstream
if [[ -n "$branch" ]] && [[ "$branch" != -* ]] ; then
shift
else
branch=$(git symbolic-ref --short HEAD)
fi
if repo_to_remote drm-tip &> /dev/null ; then
new_upstream=$(repo_to_remote drm-tip)/drm-tip
else
new_upstream=$(git branch -r | grep '/drm-tip$')
upstream=$(git_find_tip "$branch")
if [[ -z "$upstream" ]]; then
echoerr "$branch is not based on drm-tip"
return 1
fi
git rebase --onto $new_upstream $upstream $branch "$@"
function dim_range_diff
{
local branch
branch=${1:-@\{1\}}
if [[ $(git rev-parse $branch | wc -l) -eq 1 ]] ; then
if [[ $(git rev-parse $branch) == "$branch" ]] ; then
branch="@{1}"
else
shift || true
fi
git range-diff $branch...HEAD "$@"
else
git range-diff "$@"
fi
}
# update for-linux-next* branches
function update_linux_next # branch next next-fixes fixes [for-linux-next] [for-linux-next-fixes]
local branch linux_next linux_next_fixes linux_fixes for_linux_next for_linux_next_fixes repo remote
branch=$1
linux_next=$2
linux_next_fixes=$3
linux_fixes=$4
for_linux_next=${5:-for-linux-next}
for_linux_next_fixes=${6:-for-linux-next-fixes}
if [[ $repo != $(branch_to_repo $linux_next) ]] ; then
if [ -n "$for_linux_next_fixes" ] ; then
echo -n "Pushing $linux_fixes to $for_linux_next_fixes... "
git_push $remote +$remote/$linux_fixes:$for_linux_next_fixes
if git merge-base --is-ancestor $remote/$linux_next_fixes $remote/$linux_fixes ; then
# -fixes has caught up to dinf, i.e. we're out of the merge
# window. Push the next queue.
echo -n "Out of merge window. Pushing $linux_next to $for_linux_next... "
git_push $remote +$remote/$linux_next:$for_linux_next
# dinf is ahead of -fixes, i.e. drm-next has already closed for
# the next merge window and we've started to gather new fixes
# for the current -next cycle. Push dinf
echo -n "Pushing $linux_next_fixes to $for_linux_next... "
git_push $remote +$remote/$linux_next_fixes:$for_linux_next
function check_conflicts # tree
if git diff | grep -q '\(<<<<<<<\|=======\|>>>>>>>\||||||||\)' ; then
# we need an empty line to make it look pretty
echoerr ""
echoerr "FAILURE: Could not merge $1"
git -C ${1:-$PWD} rev-parse --absolute-git-dir
if ! git_is_current_branch rerere-cache; then
echo "Fail: Branch setup for the rerere-cache is borked."
exit 1
fi
if ! git pull -q ; then
# We raced with someone else hitting the same conflict, or the
# erratic git gc for rr-cache entries nuke a few entries we
# still want to keep. Clean up and try, but only when the
# initial pull fails since otherwise there's no way to keep new
# resolutions around.
echo "Conflict in the rr-cache, cleaning up"
git clean -fdx rr-cache/
git checkout -f ':(glob)rr-cache/**'
if ! git pull -q ; then
echoerr "Failed to update the rerere cache."
echoerr "Please manually run"
echoerr " $ cd $DIM_PREFIX/drm-rerere ; git pull"
echoerr "and fixup any issues."
cd - > /dev/null
}
function update_rerere_cache
{
echo -n "Updating rerere cache... "
pull_rerere_cache
cd $DIM_PREFIX/drm-tip/
rr_cache_dir=$(git rev-parse --git-common-dir)/rr-cache
if [ ! -L $rr_cache_dir ] ; then
if [ -d $rr_cache_dir ] ; then
rm -Rf $rr_cache_dir
ln -s "$DIM_PREFIX/drm-rerere/rr-cache" $rr_cache_dir
echo "Done."
}
function commit_rerere_cache
{
local remote file commit_message
cd $DIM_PREFIX/drm-rerere/
remote=$(branch_to_remote rerere-cache)
git add ./*.patch >& /dev/null || true
git add fixups/*.patch >& /dev/null || true
for file in $(git ls-files -- rr-cache); do
if ! git log --since="60 days ago" --name-only -- $file | grep $file &> /dev/null; then
git rm $file &> /dev/null || true
find rr-cache/ -mtime -1 -type f -not -name "thisimage*" -print0 | xargs -0 git add &> /dev/null || true
git rm rr-cache/rr-cache &> /dev/null || true
commit_message=$(mktemp)
cat > $commit_message <<-EOF
$dim_timestamp: $integration_branch rerere cache update
$(git --version)
EOF
if git commit -F $commit_message >& /dev/null; then
echo -n "Pushing rerere cache... "
git_push $remote HEAD >& /dev/null && echo "$DONE_OR_SKIP"
function fetch_all
{
for repo in "${!drm_tip_repos[@]}"; do
remote=$(repo_to_remote $repo)
if [[ "$repo" = "$remote" ]]; then
echo -n "Fetching $repo... "
else
echo -n "Fetching $repo (local remote $remote)... "
fi
git_fetch_helper $remote
echo "Done."
done
}
function find_fixup_file # repo branch
{
local file_paths repo branch rerere
repo=$1
branch=$2
rerere=$DIM_PREFIX/drm-rerere
file_paths="$rerere/${repo}-${branch//\//-}-fixup.patch
$rerere/fixups/${branch//\//-}.patch"
for file_path in $file_paths; do
[ -f "$file_path" ] && break
done
echo "$file_path"
}
function dim_rebuild_tip # local_branch
local integration_branch specfile first rerere repo remote local_branch
local_branch=$1
integration_branch=drm-tip
first=1
rerere=$DIM_PREFIX/drm-rerere
if git status --porcelain | grep -v "^.. rr-cache" | grep -q -v "^[ ?][ ?]"; then
warn_or_fail "integration configuration file $dim_integration_config not committed"
echo -n "Reloading $dim_integration_config... "
read_integration_config
cd $DIM_PREFIX/$integration_branch
if ! git_is_current_branch $integration_branch ; then
echo "Branch setup for the integration repo is borked"
exit 1
fi
# rerere uses sha1 of the diff to identify conflicts, we must ensure
# that they look the same for everyone
git config merge.conflictstyle merge
for conf in "${drm_tip_config[@]}"; do
local branch override sha1 fixup_file
remote=$(repo_to_remote $repo)
sha1=$remote/$branch
if [[ $DRY_RUN ]] && [[ "$local_branch" = "$branch" ]]; then
echo -n "Merging (local) $branch... "
sha1=$(git rev-parse $branch)
elif [[ "$repo" = "$remote" ]]; then
echo -n "Merging $repo/$branch... "
else
echo -n "Merging $repo/$branch (local remote $remote)... "
fi
if [[ -n "$override" ]]; then
sha1=$override
echo -n "Using override sha1: $sha1... "
git reset --hard $sha1 &> /dev/null
elif git merge --rerere-autoupdate --ff-only $sha1 >& /dev/null ; then
# nothing to do if just fast-forward
fixup_file=$(find_fixup_file $repo $branch)
echo $branch > .fixup_branch
git merge --rerere-autoupdate --no-commit $sha1 >& /dev/null || true
# normalize conflict markers
if git grep -l '^>>>>>>> ' &> /dev/null ; then
git grep -l '^>>>>>>> ' | xargs sed -e "s|^>>>>>>> .*$|>>>>>>> $repo\/$branch|" -i
echo -n "Applying manual fixup patch for $integration_branch merge... "
if ! check_conflicts "$repo/$branch" ; then
echoerr "See the section \"Resolving Conflicts when Rebuilding drm-tip\""
echoerr "in the drm-tip.rst documentation for how to handle this situation."
return 1
fi
# because we filter out fast-forward merges there will
# always be something to commit
if ! git commit --no-edit --quiet --no-verify ; then
echoerr "Commit failed, missing topic branch?"
return 1
fi
echo -e "$repo $branch $(git rev-parse $sha1)\n\t$(git log -1 $sha1 --pretty=format:%s)" >> $specfile
echo -n "Adding integration manifest $integration_branch: $dim_timestamp... "
mv $specfile integration-manifest
git add integration-manifest
git commit --quiet -m "$integration_branch: $dim_timestamp integration manifest"
remote=$(repo_to_remote drm-tip)
echo -n "Pushing $integration_branch... "
git_push $remote +HEAD >& /dev/null && echo "$DONE_OR_SKIP"
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
function checkpatch_fixes_tag
{
local sha1 fixes_lines cite rv fline
sha1=$1
rv=0
fixes_lines=$(git log -1 --format='%B' "$sha1" | grep -i '^[[:space:]]*Fixes:')
cite=$(dim_cite $sha1)
echo "$fixes_lines" | ( local rv; rv=0 ; while read -r fline; do
local fixes_sha1 fixes_subject orig_subject
if [[ -z "$fline" ]] ; then
continue
fi
[[ "$fline" =~ ^[[:space:]]*[Ff][Ii][Xx][Ee][Ss]:[[:space:]]*(.*)$ ]]
fline="${BASH_REMATCH[1]}"
if [[ ! "$fline" =~ ^[[:space:]]*([[:xdigit:]]{5,})[[:space:]]*(.*)$ ]]; then
echoerr "$cite: Malformed fixes line:"
echoerr " $fline"
rv=1
continue
fi
fixes_sha1="${BASH_REMATCH[1]}"
fixes_subject="${BASH_REMATCH[2]}"
if ! git rev-parse --verify -q $fixes_sha1 > /dev/null ; then
echoerr "$cite: SHA1 in fixes line not found:"
echoerr " $fline"
rv=1
continue
fi
if ! git merge-base --is-ancestor $fixes_sha1 $sha1 ; then
echoerr "$cite: Fixes: SHA1 in not pointing at an ancestor:"
echoerr " $fline"
rv=1
continue
fi
if ! echo $fixes_sha1 | grep -q '[[:xdigit:]]\{12\}' ; then
echoerr "$cite: Fixes: SHA1 needs at least 12 digits:"
echoerr " $fline"
rv=1
continue
fi
orig_subject=$(git show -s $fixes_sha1 --format="format:%s")
if [[ "$fixes_subject" != "(\"$orig_subject\")" ]] ; then
echoerr "$cite: Subject in fixes line doesn't match referenced commit:"
echoerr " $fline"
rv=1
continue
fi
done ; exit $rv )
rv=$?