1#!/bin/sh 2 3#- 4# SPDX-License-Identifier: BSD-2-Clause 5# 6# Copyright 2022 The FreeBSD Foundation 7# 8# This software was developed by Ed Maste 9# under sponsorship from the FreeBSD Foundation. 10# 11# Redistribution and use in source and binary forms, with or without 12# modification, are permitted providing that the following conditions 13# are met: 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. 19# 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 30# SUCH DAMAGE. 31 32from_branch=freebsd/main 33author="${USER}" 34 35# Get the FreeBSD repository 36repo=$(basename "$(git remote get-url freebsd 2>/dev/null)" 2>/dev/null) 37 38if [ "${repo}" = "ports.git" ]; then 39 year=$(date '+%Y') 40 month=$(date '+%m') 41 qtr=$(((month-1) / 3 + 1)) 42 to_branch="freebsd/${year}Q${qtr}" 43elif [ "${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) 47 case $cur_branch in 48 stable/*) 49 to_branch=$cur_branch 50 ;; 51 releng/*) 52 to_branch=$cur_branch 53 major=${cur_branch#releng/} 54 major=${major%.*} 55 from_branch=freebsd/stable/$major 56 esac 57else 58 echo "pwd is not under a ports or src repository." 59 exit 0 60fi 61 62params() 63{ 64 echo "from: $from_branch" 65 echo "to: $to_branch" 66 if [ -n "$author" ]; then 67 echo "author/committer: $author" 68 else 69 echo "author/committer: <all>" 70 fi 71} 72 73usage() 74{ 75 echo "usage: $(basename $0) [-ah] [-f from_branch] [-t to_branch] [-u user] [-X exclude_file] [path ...]" 76 echo 77 params 78 exit 0 79} 80 81while getopts "af:ht:u:vX:" opt; do 82 case $opt in 83 a) 84 # All authors/committers 85 author= 86 ;; 87 f) 88 from_branch=$OPTARG 89 ;; 90 h) 91 usage 92 ;; 93 t) 94 to_branch=$OPTARG 95 ;; 96 u) 97 author=$OPTARG 98 ;; 99 v) 100 verbose=1 101 ;; 102 X) 103 if [ ! -r "$OPTARG" ]; then 104 echo "Exclude file $OPTARG not readable" >&2 105 exit 1 106 fi 107 exclude_file=$OPTARG 108 ;; 109 esac 110done 111shift $(($OPTIND - 1)) 112 113if [ $verbose ]; then 114 params 115 echo 116fi 117 118authorarg= 119if [ -n "$author" ]; then 120 # Match user ID in the email portion of author or committer 121 authorarg="--committer <${author}@" 122fi 123 124# Commits in from_branch after branch point 125commits_from() 126{ 127 git rev-list --first-parent $authorarg $to_branch..$from_branch "$@" |\ 128 sort 129} 130 131# "cherry picked from" hashes from commits in to_branch after branch point 132commits_to() 133{ 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' |\ 136 sort 137} 138 139# Turn a list of short hashes (and optional descriptions) into a list of full 140# hashes. 141canonicalize_hashes() 142{ 143 while read hash rest; do 144 if ! git show --pretty=%H --no-patch $hash; then 145 echo "error parsing hash list" >&2 146 exit 1 147 fi 148 done | sort 149} 150 151workdir=$(mktemp -d /tmp/find-mfc.XXXXXXXXXX) 152from_list=$workdir/commits-from 153to_list=$workdir/commits-to 154candidate_list=$workdir/candidates 155 156if [ -n "$exclude_file" ]; then 157 exclude_list=$workdir/commits-exclude 158 canonicalize_hashes < $exclude_file > $exclude_list 159fi 160 161commits_from "$@" > $from_list 162commits_to "$@" > $to_list 163 164comm -23 $from_list $to_list > $candidate_list 165 166if [ -n "$exclude_file" ]; then 167 mv $candidate_list $candidate_list.bak 168 comm -23 $candidate_list.bak $exclude_list > $candidate_list 169fi 170 171# Sort by (but do not print) commit time 172while read hash; do 173 git show --pretty='%ct %h %s' --no-patch $hash 174done < $candidate_list | sort -n | cut -d ' ' -f 2- 175 176rm -rf "$workdir" 177