#!/bin/sh # Copyright 2005, Ryan Anderson # # This file is licensed under the GPL v2, or a later version # at the discretion of Linus Torvalds. global USAGE := '' []'' global LONG_USAGE := ''Summarizes the changes between two commits to the standard output, and includes the given URL in the generated summary.'' global SUBDIRECTORY_OK := ''Yes'' global OPTIONS_KEEPDASHDASH := '' global OPTIONS_STUCKLONG := '' global OPTIONS_SPEC := ''git request-pull [options] start url [end] -- p show patch text as well '' source git-sh-setup global GIT_PAGER := '' export GIT_PAGER global patch := '' while case "$#" in 0) break ;; esac { matchstr $1 { -p { global patch := '-p' } -- { shift; break } -* { usage } * { break } } shift } global base := $1, url := $2, status := '0' test -n $base && test -n $url || usage global baserev := $[git rev-parse --verify --quiet "$base"^0] if test -z $baserev { die "fatal: Not a valid revision: $base" } # # $3 must be a symbolic ref, a unique ref, or # a SHA object expression. It can also be of # the format 'local-name:remote-name'. # global local := $(3%:*) global local := $(local:-HEAD) global remote := $(3#*:) global pretty_remote := $(remote#refs/) global pretty_remote := $(pretty_remote#heads/) global head := $[git symbolic-ref -q $local] global head := $(head:-$(git show-ref --heads --tags "$local" | cut -d' ' -f2)) global head := $(head:-$(git rev-parse --quiet --verify "$local")) # None of the above? Bad. test -z $head && die "fatal: Not a valid revision: $local" # This also verifies that the resulting head is unique: # "git show-ref" could have shown multiple matching refs.. global headrev := $[git rev-parse --verify --quiet "$head"^0] test -z $headrev && die "fatal: Ambiguous revision: $local" # Was it a branch with a description? global branch_name := $(head#refs/heads/) if test "z$branch_name" = "z$headref" || ! git config "branch.$branch_name.description" >/dev/null { global branch_name := '' } global merge_base := $[git merge-base $baserev $headrev] || die "fatal: No commits in common between $base and $head" # $head is the refname from the command line. # If a ref with the same name as $head exists at the remote # and their values match, use that. # # Otherwise find a random ref that matches $headrev. global find_matching_ref := '' my ($head,$headrev) = (@ARGV); my ($found); while () { chomp; my ($sha1, $ref, $deref) = /^(\S+)\s+([^^]+)(\S*)$/; my ($pattern); next unless ($sha1 eq $headrev); $pattern="/$head\$"; if ($ref eq $head) { $found = $ref; } if ($ref =~ /$pattern/) { $found = $ref; } if ($sha1 eq $head) { $found = $sha1; } } if ($found) { print "$found\n"; } '' global ref := $[git ls-remote $url | @@PERL@@ -e $find_matching_ref $(remote:-HEAD) $headrev] if test -z $ref { echo "warn: No match for commit $headrev found at $url" > !2 echo "warn: Are you sure you pushed '$(remote:-HEAD)' there?" > !2 global status := '1' } # Special case: turn "for_linus" to "tags/for_linus" when it is correct if test $ref = "refs/tags/$pretty_remote" { global pretty_remote := "tags/$pretty_remote" } global url := $[git ls-remote --get-url $url] git show -s --format='The following changes since commit %H: %s (%ci) are available in the git repository at: ' $merge_base && echo " $url $pretty_remote" && git show -s --format=' for you to fetch changes up to %H: %s (%ci) ----------------------------------------------------------------' $headrev && if test $[git cat-file -t $head] = tag { git cat-file tag $head | sed -n -e '1,/^$/d' -e '/^-----BEGIN PGP /q' -e p echo echo "----------------------------------------------------------------" } && if test -n $branch_name { echo "(from the branch description for $branch_name local branch)" echo git config "branch.$branch_name.description" echo "----------------------------------------------------------------" } && git shortlog ^$baserev $headrev && git diff -M --stat --summary $patch $merge_base..$headrev || global status := '1' exit $status (CommandList children: [ (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:USAGE) op: Equal rhs: {(SQ <" []">)} spids: [16] ) ] spids: [16] ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:LONG_USAGE) op: Equal rhs: { (SQ <"Summarizes the changes between two commits to the standard output,\n"> <"and includes the given URL in the generated summary."> ) } spids: [21] ) ] spids: [21] ) (Assignment keyword: Assign_None pairs: [(assign_pair lhs:(LhsName name:SUBDIRECTORY_OK) op:Equal rhs:{(SQ )} spids:[27])] spids: [27] ) (Assignment keyword: Assign_None pairs: [(assign_pair lhs:(LhsName name:OPTIONS_KEEPDASHDASH) op:Equal rhs:{(SQ )} spids:[32])] spids: [32] ) (Assignment keyword: Assign_None pairs: [(assign_pair lhs:(LhsName name:OPTIONS_STUCKLONG) op:Equal rhs:{(SQ )} spids:[34])] spids: [34] ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:OPTIONS_SPEC) op: Equal rhs: { (SQ <"git request-pull [options] start url [end]\n"> <"--\n"> <"p show patch text as well\n"> ) } spids: [36] ) ] spids: [36] ) (C {(.)} {(git-sh-setup)}) (Assignment keyword: Assign_None pairs: [(assign_pair lhs:(LhsName name:GIT_PAGER) op:Equal rhs:{(SQ )} spids:[49])] spids: [49] ) (C {(export)} {(GIT_PAGER)}) (Assignment keyword: Assign_None pairs: [(assign_pair lhs:(LhsName name:patch) op:Equal rhs:{(SQ )} spids:[56])] spids: [56] ) (While cond: [ (Case to_match: {(DQ ($ VSub_Pound "$#"))} arms: [ (case_arm pat_list: [{(0)}] action: [(ControlFlow token:)] spids: [68 69 73 -1] ) ] spids: [60 66 75] ) ] body: (DoGroup children: [ (Case to_match: {(DQ ($ VSub_Number "$1"))} arms: [ (case_arm pat_list: [{(-p)}] action: [ (Assignment keyword: Assign_None pairs: [(assign_pair lhs:(LhsName name:patch) op:Equal rhs:{(-p)} spids:[93])] spids: [93] ) ] spids: [89 90 96 -1] ) (case_arm pat_list: [{(--)}] action: [ (Sentence child:(C {(shift)}) terminator:) (ControlFlow token:) ] spids: [99 100 108 -1] ) (case_arm pat_list: [{(-) (Lit_Other "*")}] action: [(C {(usage)})] spids: [111 113 118 -1] ) (case_arm pat_list: [{(Lit_Other "*")}] action: [(ControlFlow token:)] spids: [121 122 127 -1] ) ] spids: [80 86 130] ) (C {(shift)}) ] spids: [77 135] ) ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs:(LhsName name:base) op:Equal rhs:{($ VSub_Number "$1")} spids:[138]) (assign_pair lhs:(LhsName name:url) op:Equal rhs:{($ VSub_Number "$2")} spids:[141]) (assign_pair lhs:(LhsName name:status) op:Equal rhs:{(0)} spids:[144]) ] spids: [138] ) (AndOr children: [ (C {(test)} {(-n)} {(DQ ($ VSub_Name "$base"))}) (AndOr children: [(C {(test)} {(-n)} {(DQ ($ VSub_Name "$url"))}) (C {(usage)})] op_id: Op_DPipe ) ] op_id: Op_DAmp ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:baserev) op: Equal rhs: { (CommandSubPart command_list: (CommandList children: [ (C {(git)} {(rev-parse)} {(--verify)} {(--quiet)} {(DQ ($ VSub_Name "$base")) (Lit_Other "^") (0)} ) ] ) left_token: spids: [172 186] ) } spids: [171] ) ] spids: [171] ) (If arms: [ (if_arm cond: [(C {(test)} {(-z)} {(DQ ($ VSub_Name "$baserev"))})] action: [(C {(die)} {(DQ ("fatal: Not a valid revision: ") ($ VSub_Name "$base"))})] spids: [-1 198] ) ] spids: [-1 208] ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:local) op: Equal rhs: { (BracedVarSub token: suffix_op: (StringUnary op_id:VOp1_Percent arg_word:{(":*")}) spids: [227 231] ) } spids: [226] ) ] spids: [226] ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:local) op: Equal rhs: { (BracedVarSub token: suffix_op: (StringUnary op_id:VTest_ColonHyphen arg_word:{(HEAD)}) spids: [234 238] ) } spids: [233] ) ] spids: [233] ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:remote) op: Equal rhs: { (BracedVarSub token: suffix_op: (StringUnary op_id:VOp1_Pound arg_word:{("*:")}) spids: [241 245] ) } spids: [240] ) ] spids: [240] ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:pretty_remote) op: Equal rhs: { (BracedVarSub token: suffix_op: (StringUnary op_id:VOp1_Pound arg_word:{(refs) (Lit_Slash /)}) spids: [248 253] ) } spids: [247] ) ] spids: [247] ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:pretty_remote) op: Equal rhs: { (BracedVarSub token: suffix_op: (StringUnary op_id:VOp1_Pound arg_word:{(heads) (Lit_Slash /)}) spids: [256 261] ) } spids: [255] ) ] spids: [255] ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:head) op: Equal rhs: { (CommandSubPart command_list: (CommandList children: [(C {(git)} {(symbolic-ref)} {(-q)} {(DQ ($ VSub_Name "$local"))})] ) left_token: spids: [264 274] ) } spids: [263] ) ] spids: [263] ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:head) op: Equal rhs: { (BracedVarSub token: suffix_op: (StringUnary op_id: VTest_ColonHyphen arg_word: { (CommandSubPart command_list: (CommandList children: [ (Pipeline children: [ (C {(git)} {(show-ref)} {(--heads)} {(--tags)} {(DQ ($ VSub_Name "$local"))} ) (C {(cut)} {(-d) (SQ <" ">)} {(-f2)}) ] negated: False ) ] ) left_token: spids: [280 303] ) } ) spids: [277 304] ) } spids: [276] ) ] spids: [276] ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:head) op: Equal rhs: { (BracedVarSub token: suffix_op: (StringUnary op_id: VTest_ColonHyphen arg_word: { (CommandSubPart command_list: (CommandList children: [ (C {(git)} {(rev-parse)} {(--quiet)} {(--verify)} {(DQ ($ VSub_Name "$local"))} ) ] ) left_token: spids: [310 322] ) } ) spids: [307 323] ) } spids: [306] ) ] spids: [306] ) (AndOr children: [ (C {(test)} {(-z)} {(DQ ($ VSub_Name "$head"))}) (C {(die)} {(DQ ("fatal: Not a valid revision: ") ($ VSub_Name "$local"))}) ] op_id: Op_DAmp ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:headrev) op: Equal rhs: { (CommandSubPart command_list: (CommandList children: [ (C {(git)} {(rev-parse)} {(--verify)} {(--quiet)} {(DQ ($ VSub_Name "$head")) (Lit_Other "^") (0)} ) ] ) left_token: spids: [354 368] ) } spids: [353] ) ] spids: [353] ) (AndOr children: [ (C {(test)} {(-z)} {(DQ ($ VSub_Name "$headrev"))}) (C {(die)} {(DQ ("fatal: Ambiguous revision: ") ($ VSub_Name "$local"))}) ] op_id: Op_DAmp ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:branch_name) op: Equal rhs: { (BracedVarSub token: suffix_op: (StringUnary op_id: VOp1_Pound arg_word: {(refs) (Lit_Slash /) (heads) (Lit_Slash /)} ) spids: [392 399] ) } spids: [391] ) ] spids: [391] ) (If arms: [ (if_arm cond: [ (AndOr children: [ (C {(test)} {(DQ (z) ($ VSub_Name "$branch_name"))} {(Lit_Other "=")} {(DQ (z) ($ VSub_Name "$headref"))} ) (Pipeline children: [ (SimpleCommand words: [ {(git)} {(config)} {(DQ (branch.) ($ VSub_Name "$branch_name") (.description))} ] redirects: [(Redir op_id:Redir_Great fd:-1 arg_word:{(/dev/null)} spids:[432])] ) ] negated: True ) ] op_id: Op_DPipe ) ] action: [ (Assignment keyword: Assign_None pairs: [(assign_pair lhs:(LhsName name:branch_name) op:Equal rhs:{(SQ )} spids:[438])] spids: [438] ) ] spids: [-1 435] ) ] spids: [-1 440] ) (AndOr children: [ (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:merge_base) op: Equal rhs: { (CommandSubPart command_list: (CommandList children: [ (C {(git)} {(merge-base)} {($ VSub_Name "$baserev")} {($ VSub_Name "$headrev")}) ] ) left_token: spids: [444 452] ) } spids: [443] ) ] spids: [443] ) (C {(die)} { (DQ ("fatal: No commits in common between ") ($ VSub_Name "$base") (" and ") ($ VSub_Name "$head") ) } ) ] op_id: Op_DPipe ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:find_matching_ref) op: Equal rhs: { (SQ <"\n"> <"\tmy ($head,$headrev) = (@ARGV);\n"> <"\tmy ($found);\n"> <"\n"> <"\twhile () {\n"> <"\t\tchomp;\n"> <"\t\tmy ($sha1, $ref, $deref) = /^(\\S+)\\s+([^^]+)(\\S*)$/;\n"> <"\t\tmy ($pattern);\n"> <"\t\tnext unless ($sha1 eq $headrev);\n"> <"\n"> <"\t\t$pattern=\"/$head\\$\";\n"> <"\t\tif ($ref eq $head) {\n"> <"\t\t\t$found = $ref;\n"> <"\t\t}\n"> <"\t\tif ($ref =~ /$pattern/) {\n"> <"\t\t\t$found = $ref;\n"> <"\t\t}\n"> <"\t\tif ($sha1 eq $head) {\n"> <"\t\t\t$found = $sha1;\n"> <"\t\t}\n"> <"\t}\n"> <"\tif ($found) {\n"> <"\t\tprint \"$found\\n\";\n"> <"\t}\n"> ) } spids: [481] ) ] spids: [481] ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:ref) op: Equal rhs: { (CommandSubPart command_list: (CommandList children: [ (Pipeline children: [ (C {(git)} {(ls-remote)} {(DQ ($ VSub_Name "$url"))}) (C {(Lit_Other "@") (Lit_Other "@") (PERL) (Lit_Other "@") (Lit_Other "@")} {(-e)} {(DQ ($ VSub_Name "$find_matching_ref"))} { (DQ (BracedVarSub token: suffix_op: (StringUnary op_id:VTest_ColonHyphen arg_word:{(HEAD)}) spids: [535 539] ) ) } {(DQ ($ VSub_Name "$headrev"))} ) ] negated: False ) ] ) left_token: spids: [511 545] ) } spids: [510] ) ] spids: [510] ) (If arms: [ (if_arm cond: [(C {(test)} {(-z)} {(DQ ($ VSub_Name "$ref"))})] action: [ (SimpleCommand words: [ {(echo)} { (DQ ("warn: No match for commit ") ($ VSub_Name "$headrev") (" found at ") ($ VSub_Name "$url") ) } ] redirects: [(Redir op_id:Redir_GreatAnd fd:-1 arg_word:{(2)} spids:[570])] ) (SimpleCommand words: [ {(echo)} { (DQ ("warn: Are you sure you pushed '") (BracedVarSub token: suffix_op: (StringUnary op_id:VTest_ColonHyphen arg_word:{(HEAD)}) spids: [578 582] ) ("' there?") ) } ] redirects: [(Redir op_id:Redir_GreatAnd fd:-1 arg_word:{(2)} spids:[586])] ) (Assignment keyword: Assign_None pairs: [(assign_pair lhs:(LhsName name:status) op:Equal rhs:{(1)} spids:[590])] spids: [590] ) ] spids: [-1 558] ) ] spids: [-1 593] ) (If arms: [ (if_arm cond: [ (C {(test)} {(DQ ($ VSub_Name "$ref"))} {(Lit_Other "=")} {(DQ (refs/tags/) ($ VSub_Name "$pretty_remote"))} ) ] action: [ (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:pretty_remote) op: Equal rhs: {(tags/) ($ VSub_Name "$pretty_remote")} spids: [617] ) ] spids: [617] ) ] spids: [-1 614] ) ] spids: [-1 621] ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:url) op: Equal rhs: { (CommandSubPart command_list: (CommandList children: [(C {(git)} {(ls-remote)} {(--get-url)} {(DQ ($ VSub_Name "$url"))})] ) left_token: spids: [625 635] ) } spids: [624] ) ] spids: [624] ) (AndOr children: [ (C {(git)} {(show)} {(-s)} {(--format) (Lit_Other "=") (SQ <"The following changes since commit %H:\n"> <"\n"> <" %s (%ci)\n"> <"\n"> <"are available in the git repository at:\n"> ) } {($ VSub_Name "$merge_base")} ) (AndOr children: [ (C {(echo)} {(DQ (" ") ($ VSub_Name "$url") (" ") ($ VSub_Name "$pretty_remote"))}) (AndOr children: [ (C {(git)} {(show)} {(-s)} {(--format) (Lit_Other "=") (SQ <"\n"> <"for you to fetch changes up to %H:\n"> <"\n"> <" %s (%ci)\n"> <"\n"> <----------------------------------------------------------------> ) } {($ VSub_Name "$headrev")} ) (AndOr children: [ (If arms: [ (if_arm cond: [ (C {(test)} { (CommandSubPart command_list: (CommandList children: [ (C {(git)} {(cat-file)} {(-t)} {(DQ ($ VSub_Name "$head"))}) ] ) left_token: spids: [695 705] ) } {(Lit_Other "=")} {(tag)} ) ] action: [ (Pipeline children: [ (C {(git)} {(cat-file)} {(tag)} {(DQ ($ VSub_Name "$head"))}) (C {(sed)} {(-n)} {(-e)} {(SQ <"1,/^$/d">)} {(-e)} {(SQ <"/^-----BEGIN PGP /q">)} {(-e)} {(p)} ) ] negated: False ) (C {(echo)}) (C {(echo)} { (DQ ( ---------------------------------------------------------------- ) ) } ) ] spids: [-1 711] ) ] spids: [-1 757] ) (AndOr children: [ (If arms: [ (if_arm cond: [(C {(test)} {(-n)} {(DQ ($ VSub_Name "$branch_name"))})] action: [ (C {(echo)} { (DQ ("(from the branch description for ") ($ VSub_Name "$branch_name") (" local branch)") ) } ) (C {(echo)}) (C {(git)} {(config)} {(DQ (branch.) ($ VSub_Name "$branch_name") (.description))} ) (C {(echo)} { (DQ ( ---------------------------------------------------------------- ) ) } ) ] spids: [-1 772] ) ] spids: [-1 804] ) (AndOr children: [ (C {(git)} {(shortlog)} {(Lit_Other "^") ($ VSub_Name "$baserev")} {($ VSub_Name "$headrev")} ) (AndOr children: [ (C {(git)} {(diff)} {(-M)} {(--stat)} {(--summary)} {($ VSub_Name "$patch")} {($ VSub_Name "$merge_base") (..) ($ VSub_Name "$headrev")} ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:status) op: Equal rhs: {(1)} spids: [838] ) ] spids: [838] ) ] op_id: Op_DPipe ) ] op_id: Op_DAmp ) ] op_id: Op_DAmp ) ] op_id: Op_DAmp ) ] op_id: Op_DAmp ) ] op_id: Op_DAmp ) ] op_id: Op_DAmp ) (C {(exit)} {($ VSub_Name "$status")}) ] )