diff --git a/tools/tools/git/mfc-candidates.sh b/tools/tools/git/mfc-candidates.sh new file mode 100644 --- /dev/null +++ b/tools/tools/git/mfc-candidates.sh @@ -0,0 +1,163 @@ +#!/bin/sh + +#- +# SPDX-License-Identifier: BSD-2-Clause-FreeBSD +# +# Copyright 2022 The FreeBSD Foundation +# +# This software was developed by Ed Maste +# under sponsorship from the FreeBSD Foundation. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted providing that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. + +from_branch=freebsd/main +to_branch=freebsd/stable/13 +author="${USER}" + +# If pwd is a stable or release branch tree, default to it. +cur_branch=$(git symbolic-ref --short HEAD 2>/dev/null) +case $cur_branch in +stable/*) + to_branch=$cur_branch + ;; +releng/*) + to_branch=$cur_branch + major=${cur_branch#releng/} + major=${major%.*} + from_branch=freebsd/stable/$major +esac + +params() +{ + echo "from: $from_branch" + echo "to: $to_branch" + if [ -n "$author" ]; then + echo "author/committer: $author" + else + echo "author/committer: " + fi +} + +usage() +{ + echo "usage: $(basename $0) [-ah] [-f from_branch] [-t to_branch] [-u user] [-X exclude_file] [path ...]" + echo + params + exit 0 +} + +while getopts "af:ht:u:vX:" opt; do + case $opt in + a) + # All authors/committers + author= + ;; + f) + from_branch=$OPTARG + ;; + h) + usage + ;; + t) + to_branch=$OPTARG + ;; + u) + author=$OPTARG + ;; + v) + verbose=1 + ;; + X) + if [ ! -r "$OPTARG" ]; then + echo "Exclude file $OPTARG not readable" >&2 + exit 1 + fi + exclude_file=$OPTARG + ;; + esac +done +shift $(($OPTIND - 1)) + +if [ $verbose ]; then + params + echo +fi + +authorarg= +if [ -n "$author" ]; then + # Match user ID in the email portion of author or committer + authorarg="--author <${author}@ --committer <${author}@" +fi + +# Commits in from_branch after branch point +commits_from() +{ + git rev-list --first-parent $authorarg $to_branch..$from_branch "$@" |\ + sort +} + +# "cherry picked from" hashes from commits in to_branch after branch point +commits_to() +{ + git log $from_branch..$to_branch --grep 'cherry picked from' "$@" |\ + sed -E -n 's/^[[:space:]]*\(cherry picked from commit ([0-9a-f]+)\)[[:space:]]*$/\1/p' |\ + sort +} + +# Turn a list of short hashes (and optional descriptions) into a list of full +# hashes. +canonicalize_hashes() +{ + while read hash rest; do + if ! git show --pretty=%H --no-patch $hash; then + echo "error parsing hash list" >&2 + exit 1 + fi + done | sort +} + +workdir=$(mktemp -d /tmp/find-mfc.XXXXXXXXXX) +from_list=$workdir/commits-from +to_list=$workdir/commits-to +candidate_list=$workdir/candidates + +if [ -n "$exclude_file" ]; then + exclude_list=$workdir/commits-exclude + canonicalize_hashes < $exclude_file > $exclude_list +fi + +commits_from "$@" > $from_list +commits_to "$@" > $to_list + +comm -23 $from_list $to_list > $candidate_list + +if [ -n "$exclude_file" ]; then + mv $candidate_list $candidate_list.bak + comm -23 $candidate_list.bak $exclude_list > $candidate_list +fi + +# Sort by (but do not print) commit time +while read hash; do + git show --pretty='%ct %h %s' --no-patch $hash +done < $candidate_list | sort -n | cut -d ' ' -f 2- + +rm -rf "$workdir"