4 # SPDX-License-Identifier: BSD-2-Clause
6 # Copyright 2022 The FreeBSD Foundation
8 # This software was developed by Ed Maste
9 # under sponsorship from the FreeBSD Foundation.
11 # Redistribution and use in source and binary forms, with or without
12 # modification, are permitted providing that the following conditions
14 # 1. Redistributions of source code must retain the above copyright
15 # notice, this list of conditions and the following disclaimer.
16 # 2. Redistributions in binary form must reproduce the above copyright
17 # notice, this list of conditions and the following disclaimer in the
18 # documentation and/or other materials provided with the distribution.
20 # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24 # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 from_branch=freebsd/main
35 # Get the FreeBSD repository
36 repo=$(basename "$(git remote get-url freebsd 2>/dev/null)" 2>/dev/null)
38 if [ "${repo}" = "ports.git" ]; then
41 qtr=$(((month-1) / 3 + 1))
42 to_branch="freebsd/${year}Q${qtr}"
43 elif [ "${repo}" = "src.git" ]; then
44 to_branch=freebsd/stable/13
45 # If pwd is a stable or release branch tree, default to it.
46 cur_branch=$(git symbolic-ref --short HEAD 2>/dev/null)
53 major=${cur_branch#releng/}
55 from_branch=freebsd/stable/$major
58 echo "pwd is not under a ports or src repository."
64 echo "from: $from_branch"
66 if [ -n "$author" ]; then
67 echo "author/committer: $author"
69 echo "author/committer: <all>"
75 echo "usage: $(basename $0) [-ah] [-f from_branch] [-t to_branch] [-u user] [-X exclude_file] [path ...]"
81 while getopts "af:ht:u:vX:" opt; do
84 # All authors/committers
103 if [ ! -r "$OPTARG" ]; then
104 echo "Exclude file $OPTARG not readable" >&2
111 shift $(($OPTIND - 1))
113 if [ $verbose ]; then
119 if [ -n "$author" ]; then
120 # Match user ID in the email portion of author or committer
121 authorarg="--author <${author}@ --committer <${author}@"
124 # Commits in from_branch after branch point
127 git rev-list --first-parent $authorarg $to_branch..$from_branch "$@" |\
131 # "cherry picked from" hashes from commits in to_branch after branch point
134 git log $from_branch..$to_branch --grep 'cherry picked from' "$@" |\
135 sed -E -n 's/^[[:space:]]*\(cherry picked from commit ([0-9a-f]+)\)[[:space:]]*$/\1/p' |\
139 # Turn a list of short hashes (and optional descriptions) into a list of full
141 canonicalize_hashes()
143 while read hash rest; do
144 if ! git show --pretty=%H --no-patch $hash; then
145 echo "error parsing hash list" >&2
151 workdir=$(mktemp -d /tmp/find-mfc.XXXXXXXXXX)
152 from_list=$workdir/commits-from
153 to_list=$workdir/commits-to
154 candidate_list=$workdir/candidates
156 if [ -n "$exclude_file" ]; then
157 exclude_list=$workdir/commits-exclude
158 canonicalize_hashes < $exclude_file > $exclude_list
161 commits_from "$@" > $from_list
162 commits_to "$@" > $to_list
164 comm -23 $from_list $to_list > $candidate_list
166 if [ -n "$exclude_file" ]; then
167 mv $candidate_list $candidate_list.bak
168 comm -23 $candidate_list.bak $exclude_list > $candidate_list
171 # Sort by (but do not print) commit time
173 git show --pretty='%ct %h %s' --no-patch $hash
174 done < $candidate_list | sort -n | cut -d ' ' -f 2-