diff --git a/git-backport-diff b/git-backport-diff index 2ae090f..31a3e97 100755 --- a/git-backport-diff +++ b/git-backport-diff @@ -44,6 +44,10 @@ def_pause='y' def_sensitivity=0 def_summary='n' +if [ -z "${DIFFOPTS+x}" ]; then + DIFFOPTS= +fi + upstream=`git config backport-diff.upstream || true` diffprog=`git config backport-diff.diffprog || true` range=`git config backport-diff.range || true` @@ -126,7 +130,9 @@ usage() { echo " git config backport-diff.summary" } -while getopts ":r:u:nd:phs:S" opt +declare -A aliases + +while getopts ":r:u:nd:phs:Sa:" opt do case $opt in r) range=$OPTARG @@ -149,6 +155,9 @@ do ;; S) summary='y' ;; + a) IFS='=' read -ra a <<< "$OPTARG" + aliases[${a[0]}]=${a[1]} + ;; h) usage exit ;; @@ -205,7 +214,7 @@ elif git show-ref --quiet --verify refs/remotes/${upstream} then upstream_valid='y' # commit id -elif git rev-list --max-count=1 --quiet $upstream >/dev/null 2>&1 +elif git rev-list --max-count=1 --quiet $upstream -- >/dev/null 2>&1 then upstream_valid='y' fi @@ -225,13 +234,27 @@ compare_git() while read hashsubj do let cnt=$cnt+1; - subj=${hashsubj:40} + newsubj=${hashsubj:40} + subj=$newsubj + if [ -n "${aliases[$subj]+_}" ] + then + subj=${aliases[$subj]} + fi + + # We need to direct the git-log output through a FIFO so we + # get a git-log job that we can kill once we have found our + # match + git_fifo=$(mktemp -u --tmpdir 'backport-diff.XXXXXX') + mkfifo "$git_fifo" + downhash=${hashsubj:0:40} # A little bit hackish, but find the match by looking at upstream # subject lines, and using the newest one. Not all backports contain # the phrase "cherry-pick", so we can't really try and find the # upstream hash from that... uphash="" + git log $upstream --pretty=tformat:"%H%s" --fixed-strings --grep="${subj}" -- >"$git_fifo" & + job_id=$(jobs -l | grep "\<$!\>" | sed -e 's/[^\[]*\[\([^\]]*\)\].*/\1/') while read uphashsubj do if [[ "${uphashsubj:40}" == "$subj" ]] @@ -239,17 +262,22 @@ compare_git() uphash=${uphashsubj:0:40} break fi - done < <(git log $upstream --pretty=tformat:"%H%s" --fixed-strings --grep="${subj}") + done <"$git_fifo" + + # Ignore errors + kill %$job_id &>/dev/null || true + wait &> /dev/null + rm -f "$git_fifo" if [[ -n "$uphash" ]] then - numdiff=`diff -u <(git diff $uphash^! |egrep ^[-+])\ - <(git diff $downhash^! |egrep ^[-+])\ - | egrep '^[-+]' | egrep -v '^[-+]{3}' |wc -l || true` + numdiff=`diff -u <(git diff --diff-algorithm=patience $DIFFOPTS $uphash^! |grep -E ^[-+])\ + <(git diff --diff-algorithm=patience $DIFFOPTS $downhash^! |grep -E ^[-+])\ + | grep -E '^[-+]' | grep -E -v '^[-+]{3}' |wc -l || true` # for contextual diff checking, we will ignore hashes and line number offsets - condiff=`diff -u <(git diff $uphash^\! |sed -e s/^@@.*@@//g |egrep -v ^index |egrep -v ^diff)\ - <(git diff $downhash^\!|sed -e s/^@@.*@@//g |egrep -v ^index |egrep -v ^diff)\ - | egrep '^[-+]' | egrep -v '^[-+]{3}'|wc -l || true` + condiff=`diff -u <(git diff --diff-algorithm=patience $DIFFOPTS $uphash^\! |sed -e s/^@@.*@@//g |grep -E -v ^index |grep -E -v ^diff)\ + <(git diff --diff-algorithm=patience $DIFFOPTS $downhash^\!|sed -e s/^@@.*@@//g |grep -E -v ^index |grep -E -v ^diff)\ + | grep -E '^[-+]' | grep -E -v '^[-+]{3}'|wc -l || true` f="-" c="-" if [[ $sensitivity -gt 1 ]] @@ -270,22 +298,22 @@ compare_git() then f=${bold}F${reset} showdiff=1 - printf "%03d/${total}:[${bold}%04d${reset}] [${f}${c}] ${bold}${color4}'%s'${reset}\n" $cnt $numdiff "$subj" + printf "%03d/${total}:[${bold}%04d${reset}] [${f}${c}] ${bold}${color4}'%s'${reset}\n" $cnt $numdiff "$newsubj" else - printf "%03d/$total:[----] [${f}${c}] '%s'\n" $cnt "$subj" + printf "%03d/$total:[----] [${f}${c}] '%s'\n" $cnt "$newsubj" fi if [[ $showdiff -eq 1 ]] then if [[ $diffprog == "meld" ]] then - label="--label=\"Patch #$cnt: $subj\" --label=\" \"" + label="--label=\"Patch #$cnt: $newsubj\" --label=\" \"" fi - subjlist[$cnt]=$subj - exe[$cnt]="${label} <(git show $uphash^!) <(git show $downhash^!) 2>/dev/null" + subjlist[$cnt]=$newsubj + exe[$cnt]="${label} <(git show $DIFFOPTS $uphash^!) <(git show $DIFFOPTS $downhash^!) 2>/dev/null" shortexe[$cnt]="<(git show ${uphash:0:7}^\!) <(git show ${downhash:0:7}^\!)" fi else - printf "%03d/$total:[${bold}${color1}down${reset}] ${bold}${color4}'%s'${reset}\n" $cnt "$subj" + printf "%03d/$total:[${bold}${color1}down${reset}] ${bold}${color4}'%s'${reset}\n" $cnt "$newsubj" fi done < <(git log --pretty=tformat:"%H%s" --reverse $range) } diff --git a/git-submit b/git-submit new file mode 100755 index 0000000..507a2de --- /dev/null +++ b/git-submit @@ -0,0 +1,90 @@ +#!/usr/bin/ruby + +require 'shellwords' + +def die(msg, hint=nil) + $stderr.puts("\033[31;1m#{msg}\033[0m") + if hint + $stderr.puts("\033[1mHint: #{hint}\033[0m") + end + exit 1 +end + +def run(cmd) + puts("\033[1m$ #{cmd}\033[0m") + $stdout.write("OK? [y/n] ") + $stdout.flush + if gets.strip.downcase != 'y' + puts('(Aborting)') + exit 0 + end + system(cmd) +end + +def branch_exists?(name) + !`git branch --list #{name.shellescape}`.strip.empty? +end + +upstream_branch = 'main' +if !branch_exists?(upstream_branch) + upstream_branch = 'master' +end +if !branch_exists?(upstream_branch) + die('Found neither “main” nor “master”') +end + +next_branch = `git branch --show-current`.strip +if next_branch.empty? + die('Not on any branch') +end + +m = next_branch.match(/^(.*)-next$/) +if !m + die("Current branch (#{next_branch}) does not match the pattern `${topic}-next`") +end +base_branch = m[1] + +if !system("git merge-base --is-ancestor #{upstream_branch} #{next_branch}") + die("Upstream base branch #{upstream_branch} is not an ancestor of #{next_branch}") +end + +remote = `git config get branch.#{base_branch.shellescape}.remote`.strip +if remote.empty? + die("Base topic branch #{base_branch} has no remote info set", "Use git branch --set-upstream-to=${remote}/#{base_branch}") +end + +max_topic_ver = `git branch --color=never --list #{"#{base_branch}-v*".shellescape} | sort | tail -n 1`.strip.sub("#{base_branch}-v", '') +if max_topic_ver.empty? + max_topic_ver = 0 +else + max_topic_ver = Integer(max_topic_ver) +end +new_topic_ver = max_topic_ver + 1 + +puts < [remote]" >&2 + exit 1 +fi + +if [ -n "$2" ]; then + infix="$2-" +else + infix="" +fi + +max_ver=$(git branch --list "mr-$infix$mr-v*" | sort | tail -n 1 | sed -e "s/^\*\? *mr-$infix$mr-v//") +branch="mr-$infix$mr-v$((max_ver + 1))" +cmd="git fetch $remote pull/$mr/head:$branch" + +echo "\$ $cmd" +$cmd + +git checkout $branch diff --git a/gitlab-fetch-mr.sh b/gitlab-fetch-mr.sh new file mode 100755 index 0000000..889d938 --- /dev/null +++ b/gitlab-fetch-mr.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +set -e + +mr=$1 +remote="${2:-origin}" + +if [[ ! $mr =~ ^[0-9]+$ || $3 != "" ]]; then + echo "Usage: $0 [remote]" >&2 + exit 1 +fi + +max_ver=$(git branch --list "mr-$mr-v*" | grep "mr-$mr-v[0-9]\\+$" | sort | tail -n 1 | sed -e "s/^\*\? *mr-$mr-v//") +branch="mr-$mr-v$((max_ver + 1))" +cmd="git fetch $remote merge-requests/$mr/head:$branch" + +echo "\$ $cmd" +$cmd + +git checkout $branch