git/git-request-pull.sh

161 lines
3.6 KiB
Bash
Raw Normal View History

#!/bin/sh
# Copyright 2005, Ryan Anderson <ryan@michonline.com>
#
# This file is licensed under the GPL v2, or a later version
# at the discretion of Linus Torvalds.
SUBDIRECTORY_OK='Yes'
OPTIONS_KEEPDASHDASH=
OPTIONS_STUCKLONG=
OPTIONS_SPEC='git request-pull [options] start url [end]
--
p show patch text as well
'
. git-sh-setup
GIT_PAGER=
export GIT_PAGER
patch=
while case "$#" in 0) break ;; esac
do
case "$1" in
-p)
patch=-p ;;
--)
shift; break ;;
-*)
usage ;;
*)
break ;;
esac
shift
done
request-pull: more strictly match local/remote branches The current 'request-pull' will try to find matching commit on the given remote, and rewrite the "please pull" line to match that remote ref. That may be very helpful if your local tree doesn't match the layout of the remote branches, but for the common case it's been a recurring disaster, when "request-pull" is done against a delayed remote update, and it rewrites the target branch randomly to some other branch name that happens to have the same expected SHA1 (or more commonly, leaves it blank). To avoid that recurring problem, this changes "git request-pull" so that it matches the ref name to be pulled against the *local* repository, and then warns if the remote repository does not have that exact same branch or tag name and content. This means that git request-pull will never rewrite the ref-name you gave it. If the local branch name is "xyzzy", that is the only branch name that request-pull will ask the other side to fetch. If the remote has that branch under a different name, that's your problem and git request-pull will not try to fix it up (but git request-pull will warn about the fact that no exact matching branch is found, and you can edit the end result to then have the remote name you want if it doesn't match your local one). The new "find local ref" code will also complain loudly if you give an ambiguous refname (eg you have both a tag and a branch with that same name, and you don't specify "heads/name" or "tags/name"). Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-01-23 04:32:30 +08:00
base=$1 url=$2 status=0
test -n "$base" && test -n "$url" || usage
baserev=$(git rev-parse --verify --quiet "$base"^0)
if test -z "$baserev"
then
die "fatal: Not a valid revision: $base"
fi
request-pull: more strictly match local/remote branches The current 'request-pull' will try to find matching commit on the given remote, and rewrite the "please pull" line to match that remote ref. That may be very helpful if your local tree doesn't match the layout of the remote branches, but for the common case it's been a recurring disaster, when "request-pull" is done against a delayed remote update, and it rewrites the target branch randomly to some other branch name that happens to have the same expected SHA1 (or more commonly, leaves it blank). To avoid that recurring problem, this changes "git request-pull" so that it matches the ref name to be pulled against the *local* repository, and then warns if the remote repository does not have that exact same branch or tag name and content. This means that git request-pull will never rewrite the ref-name you gave it. If the local branch name is "xyzzy", that is the only branch name that request-pull will ask the other side to fetch. If the remote has that branch under a different name, that's your problem and git request-pull will not try to fix it up (but git request-pull will warn about the fact that no exact matching branch is found, and you can edit the end result to then have the remote name you want if it doesn't match your local one). The new "find local ref" code will also complain loudly if you give an ambiguous refname (eg you have both a tag and a branch with that same name, and you don't specify "heads/name" or "tags/name"). Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-01-23 04:32:30 +08:00
#
# $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'.
request-pull: more strictly match local/remote branches The current 'request-pull' will try to find matching commit on the given remote, and rewrite the "please pull" line to match that remote ref. That may be very helpful if your local tree doesn't match the layout of the remote branches, but for the common case it's been a recurring disaster, when "request-pull" is done against a delayed remote update, and it rewrites the target branch randomly to some other branch name that happens to have the same expected SHA1 (or more commonly, leaves it blank). To avoid that recurring problem, this changes "git request-pull" so that it matches the ref name to be pulled against the *local* repository, and then warns if the remote repository does not have that exact same branch or tag name and content. This means that git request-pull will never rewrite the ref-name you gave it. If the local branch name is "xyzzy", that is the only branch name that request-pull will ask the other side to fetch. If the remote has that branch under a different name, that's your problem and git request-pull will not try to fix it up (but git request-pull will warn about the fact that no exact matching branch is found, and you can edit the end result to then have the remote name you want if it doesn't match your local one). The new "find local ref" code will also complain loudly if you give an ambiguous refname (eg you have both a tag and a branch with that same name, and you don't specify "heads/name" or "tags/name"). Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-01-23 04:32:30 +08:00
#
local=${3%:*}
local=${local:-HEAD}
remote=${3#*:}
pretty_remote=${remote#refs/}
pretty_remote=${pretty_remote#heads/}
head=$(git symbolic-ref -q "$local")
head=${head:-$(git show-ref --heads --tags "$local" | cut -d' ' -f2)}
head=${head:-$(git rev-parse --quiet --verify "$local")}
request-pull: more strictly match local/remote branches The current 'request-pull' will try to find matching commit on the given remote, and rewrite the "please pull" line to match that remote ref. That may be very helpful if your local tree doesn't match the layout of the remote branches, but for the common case it's been a recurring disaster, when "request-pull" is done against a delayed remote update, and it rewrites the target branch randomly to some other branch name that happens to have the same expected SHA1 (or more commonly, leaves it blank). To avoid that recurring problem, this changes "git request-pull" so that it matches the ref name to be pulled against the *local* repository, and then warns if the remote repository does not have that exact same branch or tag name and content. This means that git request-pull will never rewrite the ref-name you gave it. If the local branch name is "xyzzy", that is the only branch name that request-pull will ask the other side to fetch. If the remote has that branch under a different name, that's your problem and git request-pull will not try to fix it up (but git request-pull will warn about the fact that no exact matching branch is found, and you can edit the end result to then have the remote name you want if it doesn't match your local one). The new "find local ref" code will also complain loudly if you give an ambiguous refname (eg you have both a tag and a branch with that same name, and you don't specify "heads/name" or "tags/name"). Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-01-23 04:32:30 +08:00
# None of the above? Bad.
test -z "$head" && die "fatal: Not a valid revision: $local"
request-pull: more strictly match local/remote branches The current 'request-pull' will try to find matching commit on the given remote, and rewrite the "please pull" line to match that remote ref. That may be very helpful if your local tree doesn't match the layout of the remote branches, but for the common case it's been a recurring disaster, when "request-pull" is done against a delayed remote update, and it rewrites the target branch randomly to some other branch name that happens to have the same expected SHA1 (or more commonly, leaves it blank). To avoid that recurring problem, this changes "git request-pull" so that it matches the ref name to be pulled against the *local* repository, and then warns if the remote repository does not have that exact same branch or tag name and content. This means that git request-pull will never rewrite the ref-name you gave it. If the local branch name is "xyzzy", that is the only branch name that request-pull will ask the other side to fetch. If the remote has that branch under a different name, that's your problem and git request-pull will not try to fix it up (but git request-pull will warn about the fact that no exact matching branch is found, and you can edit the end result to then have the remote name you want if it doesn't match your local one). The new "find local ref" code will also complain loudly if you give an ambiguous refname (eg you have both a tag and a branch with that same name, and you don't specify "heads/name" or "tags/name"). Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-01-23 04:32:30 +08:00
# This also verifies that the resulting head is unique:
# "git show-ref" could have shown multiple matching refs..
headrev=$(git rev-parse --verify --quiet "$head"^0)
test -z "$headrev" && die "fatal: Ambiguous revision: $local"
request-pull: more strictly match local/remote branches The current 'request-pull' will try to find matching commit on the given remote, and rewrite the "please pull" line to match that remote ref. That may be very helpful if your local tree doesn't match the layout of the remote branches, but for the common case it's been a recurring disaster, when "request-pull" is done against a delayed remote update, and it rewrites the target branch randomly to some other branch name that happens to have the same expected SHA1 (or more commonly, leaves it blank). To avoid that recurring problem, this changes "git request-pull" so that it matches the ref name to be pulled against the *local* repository, and then warns if the remote repository does not have that exact same branch or tag name and content. This means that git request-pull will never rewrite the ref-name you gave it. If the local branch name is "xyzzy", that is the only branch name that request-pull will ask the other side to fetch. If the remote has that branch under a different name, that's your problem and git request-pull will not try to fix it up (but git request-pull will warn about the fact that no exact matching branch is found, and you can edit the end result to then have the remote name you want if it doesn't match your local one). The new "find local ref" code will also complain loudly if you give an ambiguous refname (eg you have both a tag and a branch with that same name, and you don't specify "heads/name" or "tags/name"). Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-01-23 04:32:30 +08:00
# Was it a branch with a description?
branch_name=${head#refs/heads/}
if test "z$branch_name" = "z$headref" ||
! git config "branch.$branch_name.description" >/dev/null
then
request-pull: more strictly match local/remote branches The current 'request-pull' will try to find matching commit on the given remote, and rewrite the "please pull" line to match that remote ref. That may be very helpful if your local tree doesn't match the layout of the remote branches, but for the common case it's been a recurring disaster, when "request-pull" is done against a delayed remote update, and it rewrites the target branch randomly to some other branch name that happens to have the same expected SHA1 (or more commonly, leaves it blank). To avoid that recurring problem, this changes "git request-pull" so that it matches the ref name to be pulled against the *local* repository, and then warns if the remote repository does not have that exact same branch or tag name and content. This means that git request-pull will never rewrite the ref-name you gave it. If the local branch name is "xyzzy", that is the only branch name that request-pull will ask the other side to fetch. If the remote has that branch under a different name, that's your problem and git request-pull will not try to fix it up (but git request-pull will warn about the fact that no exact matching branch is found, and you can edit the end result to then have the remote name you want if it doesn't match your local one). The new "find local ref" code will also complain loudly if you give an ambiguous refname (eg you have both a tag and a branch with that same name, and you don't specify "heads/name" or "tags/name"). Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-01-23 04:32:30 +08:00
branch_name=
fi
merge_base=$(git merge-base $baserev $headrev) ||
Improve request-pull to handle non-rebased branches This is actually a few different changes to request-pull, making it slightly smarter: 1) Minor cleanup of revision->base variable names, making it follow the head/headrev naming convention that is already in use. 2) Compute the merge-base between the two revisions upfront and reuse that selected merge-base to create the diffstat. 3) Refuse to generate a pull request for branches that have no existing relationship. These aren't very common and would mess up our diffstat generation. 4) Disable the PAGER when running shortlog and diff, as these would otherwise activate the pager for each command when git-request-pull is run on a tty. Instead users can get the entire output paged (if desired) using `git -p request-pull`. 5) Use shortlog rather than `git log | git shortlog` now that recent shortlog versions are able to run the revision listing internally. 6) Attempt to resolve the input URL using the user's configured remotes. This is useful if the URL you want the recipient to see is also the one you used to push your changes. If not a config-file remote could easily be setup for the public URL and request-pull could be passed that name instead. 7) Automatically guess and include the remote branch name in the body of the message. We list the branch name immediately after the URL, making it easy for the recipient to copy and paste the entire line onto a `git pull` command line. Rumor has it Linus likes this format, for exactly that reason. If multiple branches at the remote match $headrev we take the first one returned by peek-remote and assume it is suitable. If no branches are available we warn the user about the problem, but insert a static string that is not a valid branch name and would be obvious to anyone reading the message as being totally incorrect. This allows users to still generate a template message without network access (for example) and hand-correct the bits that cannot be verified. Signed-off-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-05-01 14:08:23 +08:00
die "fatal: No commits in common between $base and $head"
request-pull: more strictly match local/remote branches The current 'request-pull' will try to find matching commit on the given remote, and rewrite the "please pull" line to match that remote ref. That may be very helpful if your local tree doesn't match the layout of the remote branches, but for the common case it's been a recurring disaster, when "request-pull" is done against a delayed remote update, and it rewrites the target branch randomly to some other branch name that happens to have the same expected SHA1 (or more commonly, leaves it blank). To avoid that recurring problem, this changes "git request-pull" so that it matches the ref name to be pulled against the *local* repository, and then warns if the remote repository does not have that exact same branch or tag name and content. This means that git request-pull will never rewrite the ref-name you gave it. If the local branch name is "xyzzy", that is the only branch name that request-pull will ask the other side to fetch. If the remote has that branch under a different name, that's your problem and git request-pull will not try to fix it up (but git request-pull will warn about the fact that no exact matching branch is found, and you can edit the end result to then have the remote name you want if it doesn't match your local one). The new "find local ref" code will also complain loudly if you give an ambiguous refname (eg you have both a tag and a branch with that same name, and you don't specify "heads/name" or "tags/name"). Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-01-23 04:32:30 +08:00
# $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.
find_matching_ref='
my ($head,$headrev) = (@ARGV);
my ($found);
while (<STDIN>) {
chomp;
request-pull: more strictly match local/remote branches The current 'request-pull' will try to find matching commit on the given remote, and rewrite the "please pull" line to match that remote ref. That may be very helpful if your local tree doesn't match the layout of the remote branches, but for the common case it's been a recurring disaster, when "request-pull" is done against a delayed remote update, and it rewrites the target branch randomly to some other branch name that happens to have the same expected SHA1 (or more commonly, leaves it blank). To avoid that recurring problem, this changes "git request-pull" so that it matches the ref name to be pulled against the *local* repository, and then warns if the remote repository does not have that exact same branch or tag name and content. This means that git request-pull will never rewrite the ref-name you gave it. If the local branch name is "xyzzy", that is the only branch name that request-pull will ask the other side to fetch. If the remote has that branch under a different name, that's your problem and git request-pull will not try to fix it up (but git request-pull will warn about the fact that no exact matching branch is found, and you can edit the end result to then have the remote name you want if it doesn't match your local one). The new "find local ref" code will also complain loudly if you give an ambiguous refname (eg you have both a tag and a branch with that same name, and you don't specify "heads/name" or "tags/name"). Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-01-23 04:32:30 +08:00
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) {
request-pull: more strictly match local/remote branches The current 'request-pull' will try to find matching commit on the given remote, and rewrite the "please pull" line to match that remote ref. That may be very helpful if your local tree doesn't match the layout of the remote branches, but for the common case it's been a recurring disaster, when "request-pull" is done against a delayed remote update, and it rewrites the target branch randomly to some other branch name that happens to have the same expected SHA1 (or more commonly, leaves it blank). To avoid that recurring problem, this changes "git request-pull" so that it matches the ref name to be pulled against the *local* repository, and then warns if the remote repository does not have that exact same branch or tag name and content. This means that git request-pull will never rewrite the ref-name you gave it. If the local branch name is "xyzzy", that is the only branch name that request-pull will ask the other side to fetch. If the remote has that branch under a different name, that's your problem and git request-pull will not try to fix it up (but git request-pull will warn about the fact that no exact matching branch is found, and you can edit the end result to then have the remote name you want if it doesn't match your local one). The new "find local ref" code will also complain loudly if you give an ambiguous refname (eg you have both a tag and a branch with that same name, and you don't specify "heads/name" or "tags/name"). Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-01-23 04:32:30 +08:00
$found = $sha1;
}
}
if ($found) {
print "$found\n";
}
'
ref=$(git ls-remote "$url" | @@PERL@@ -e "$find_matching_ref" "${remote:-HEAD}" "$headrev")
request-pull: more strictly match local/remote branches The current 'request-pull' will try to find matching commit on the given remote, and rewrite the "please pull" line to match that remote ref. That may be very helpful if your local tree doesn't match the layout of the remote branches, but for the common case it's been a recurring disaster, when "request-pull" is done against a delayed remote update, and it rewrites the target branch randomly to some other branch name that happens to have the same expected SHA1 (or more commonly, leaves it blank). To avoid that recurring problem, this changes "git request-pull" so that it matches the ref name to be pulled against the *local* repository, and then warns if the remote repository does not have that exact same branch or tag name and content. This means that git request-pull will never rewrite the ref-name you gave it. If the local branch name is "xyzzy", that is the only branch name that request-pull will ask the other side to fetch. If the remote has that branch under a different name, that's your problem and git request-pull will not try to fix it up (but git request-pull will warn about the fact that no exact matching branch is found, and you can edit the end result to then have the remote name you want if it doesn't match your local one). The new "find local ref" code will also complain loudly if you give an ambiguous refname (eg you have both a tag and a branch with that same name, and you don't specify "heads/name" or "tags/name"). Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-01-23 04:32:30 +08:00
if test -z "$ref"
then
echo "warn: No match for commit $headrev found at $url" >&2
echo "warn: Are you sure you pushed '${remote:-HEAD}' there?" >&2
request-pull: more strictly match local/remote branches The current 'request-pull' will try to find matching commit on the given remote, and rewrite the "please pull" line to match that remote ref. That may be very helpful if your local tree doesn't match the layout of the remote branches, but for the common case it's been a recurring disaster, when "request-pull" is done against a delayed remote update, and it rewrites the target branch randomly to some other branch name that happens to have the same expected SHA1 (or more commonly, leaves it blank). To avoid that recurring problem, this changes "git request-pull" so that it matches the ref name to be pulled against the *local* repository, and then warns if the remote repository does not have that exact same branch or tag name and content. This means that git request-pull will never rewrite the ref-name you gave it. If the local branch name is "xyzzy", that is the only branch name that request-pull will ask the other side to fetch. If the remote has that branch under a different name, that's your problem and git request-pull will not try to fix it up (but git request-pull will warn about the fact that no exact matching branch is found, and you can edit the end result to then have the remote name you want if it doesn't match your local one). The new "find local ref" code will also complain loudly if you give an ambiguous refname (eg you have both a tag and a branch with that same name, and you don't specify "heads/name" or "tags/name"). Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-01-23 04:32:30 +08:00
status=1
fi
# Special case: turn "for_linus" to "tags/for_linus" when it is correct
if test "$ref" = "refs/tags/$pretty_remote"
then
pretty_remote=tags/$pretty_remote
fi
url=$(git ls-remote --get-url "$url")
Improve request-pull to handle non-rebased branches This is actually a few different changes to request-pull, making it slightly smarter: 1) Minor cleanup of revision->base variable names, making it follow the head/headrev naming convention that is already in use. 2) Compute the merge-base between the two revisions upfront and reuse that selected merge-base to create the diffstat. 3) Refuse to generate a pull request for branches that have no existing relationship. These aren't very common and would mess up our diffstat generation. 4) Disable the PAGER when running shortlog and diff, as these would otherwise activate the pager for each command when git-request-pull is run on a tty. Instead users can get the entire output paged (if desired) using `git -p request-pull`. 5) Use shortlog rather than `git log | git shortlog` now that recent shortlog versions are able to run the revision listing internally. 6) Attempt to resolve the input URL using the user's configured remotes. This is useful if the URL you want the recipient to see is also the one you used to push your changes. If not a config-file remote could easily be setup for the public URL and request-pull could be passed that name instead. 7) Automatically guess and include the remote branch name in the body of the message. We list the branch name immediately after the URL, making it easy for the recipient to copy and paste the entire line onto a `git pull` command line. Rumor has it Linus likes this format, for exactly that reason. If multiple branches at the remote match $headrev we take the first one returned by peek-remote and assume it is suitable. If no branches are available we warn the user about the problem, but insert a static string that is not a valid branch name and would be obvious to anyone reading the message as being totally incorrect. This allows users to still generate a template message without network access (for example) and hand-correct the bits that cannot be verified. Signed-off-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-05-01 14:08:23 +08:00
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
then
git cat-file tag "$head" |
sed -n -e '1,/^$/d' -e '/^-----BEGIN PGP /q' -e p
echo
echo "----------------------------------------------------------------"
fi &&
if test -n "$branch_name"
then
echo "(from the branch description for $branch_name local branch)"
echo
git config "branch.$branch_name.description"
echo "----------------------------------------------------------------"
fi &&
git shortlog ^$baserev $headrev &&
git diff -M --stat --summary $patch $merge_base..$headrev || status=1
Improve request-pull to handle non-rebased branches This is actually a few different changes to request-pull, making it slightly smarter: 1) Minor cleanup of revision->base variable names, making it follow the head/headrev naming convention that is already in use. 2) Compute the merge-base between the two revisions upfront and reuse that selected merge-base to create the diffstat. 3) Refuse to generate a pull request for branches that have no existing relationship. These aren't very common and would mess up our diffstat generation. 4) Disable the PAGER when running shortlog and diff, as these would otherwise activate the pager for each command when git-request-pull is run on a tty. Instead users can get the entire output paged (if desired) using `git -p request-pull`. 5) Use shortlog rather than `git log | git shortlog` now that recent shortlog versions are able to run the revision listing internally. 6) Attempt to resolve the input URL using the user's configured remotes. This is useful if the URL you want the recipient to see is also the one you used to push your changes. If not a config-file remote could easily be setup for the public URL and request-pull could be passed that name instead. 7) Automatically guess and include the remote branch name in the body of the message. We list the branch name immediately after the URL, making it easy for the recipient to copy and paste the entire line onto a `git pull` command line. Rumor has it Linus likes this format, for exactly that reason. If multiple branches at the remote match $headrev we take the first one returned by peek-remote and assume it is suitable. If no branches are available we warn the user about the problem, but insert a static string that is not a valid branch name and would be obvious to anyone reading the message as being totally incorrect. This allows users to still generate a template message without network access (for example) and hand-correct the bits that cannot be verified. Signed-off-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-05-01 14:08:23 +08:00
exit $status