git-push: avoid falling back on pushing "matching" refs.
authorJunio C Hamano <junkio@cox.net>
Thu, 12 Jan 2006 23:29:12 +0000 (15:29 -0800)
committerJunio C Hamano <junkio@cox.net>
Sat, 14 Jan 2006 00:53:35 +0000 (16:53 -0800)
The underlying "git send-pack remote.host:path" pushes all the
matching refs that both local and remote have, and "git push"
blindly inherits this property.  Which probably was a mistake.

A typical cloned repository (e.g. a subsystem repository cloned
from Linus repository) has at least two branches, "master" to
keep the subsystem and "origin" that records tip of Linus
"master" when the repository was cloned.  If this is the public
repository for the subsystem, then subsystem developers would
clone it, and then cloned ones have "master" and "origin".  When
developers use this public subsystem repository as a shared
repository, pushing into it via "git push subsys:/path/name"
would try to push the matching refs, "master" and "origin", from
the developers' repositories.  The "origin" in the public shared
repository does not have much relevance, yet pushing into
"origin" would cause "not a fast forward" checks to be
triggered.  Arguably "git push subsys:/path/name master" would
work it around, but having them to say it explicitly to avoid
pushing into "origin" as well is bad.

This commit requires you to give at least one refspec to
git-push.  You could "give" by either:

 (1) Listing the refspec(s) explicitly on the command line.
     E.g. "git push subsys:/path/name master".

 (2) Using --all or --tags on the command line.
     E.g. "git push --tags subsys:/path/name".

 (3) Using a $GIT_DIR/remotes shorthand with 'Push: refspec'
     line in it.

Unlike pull that can happen pretty much promiscuously, people
will push into the same set of a limited number of remote
repositories repeatedly over the life of the project, so it is
reasonable to assume they would want to keep a $GIT_DIR/remotes/
entry for those repositories even only to save typing the URL,
so keeping the default 'Push: refspec' line in such is a
sensible thing to do.

It was suggested to further fall back on pushing the current
branch, but this commit does not implement it.  If developers
adopt topic branch workflow, pushing to public while on a topic
branch by mistake would expose the topic branch to the public
repository.  Not falling back to the current branch prevents
that mistake from happening.

Signed-off-by: Junio C Hamano <junkio@cox.net>
git-push.sh

index 1c5cf80..136093b 100755 (executable)
@@ -9,12 +9,15 @@ has_all=
 has_force=
 has_exec=
 remote=
+do_tags=
 
 while case "$#" in 0) break ;; esac
 do
        case "$1" in
        --all)
                has_all=--all ;;
+       --tags)
+               do_tags=yes ;;
        --force)
                has_force=--force ;;
        --exec=*)
@@ -33,6 +36,10 @@ case "$#" in
        echo "Where would you want to push today?"
         usage ;;
 esac
+if test ",$has_all,$do_tags," = ",--all,yes,"
+then
+       do_tags=
+fi
 
 . git-parse-remote
 remote=$(get_remote_url "$@")
@@ -42,6 +49,20 @@ case "$has_all" in
 esac
 shift
 
+case "$do_tags" in
+yes)
+       set "$@" $(cd "$GIT_DIR/refs" && find tags -type f -print) ;;
+esac
+
+# Now we have explicit refs from the command line or from remotes/
+# shorthand, or --tags.  Falling back on the current branch if we still
+# do not have any may be an alternative, but prevent mistakes for now.
+
+case "$#,$has_all" in
+0,)
+       die "No refs given to be pushed." ;;
+esac
+
 case "$remote" in
 git://*)
        die "Cannot use READ-ONLY transport to push to $remote" ;;