threads / discuss / 3058

[RFD] what should "git push remote.host:path" do?

Subject: [RFD] what should "git push remote.host:path" do?

## tl;dr

7 messages between Jan 12, 2006 and Jan 13, 2006.

replies: 6people: 4as markdown or json

Junio C Hamano· Jan 12, 2006, 09:13 UTC · lore

The underlying "git send-pack remote.host:path" pushes all the matching refs that both local and remote has, and "git push" blindly inherits this property.

This is bad. A typical cloned repository (e.g. a subsystem maintainer 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, then subsystem developers would clone from this one, and then cloned ones have "master" and "origin". When developers use this public subsystem repository as a shared repository, "git push subsys:path" would try to push the matching refs, "master" and "origin".

One workaround is to delete "origin" branch from the public repository, because having "origin" there is meaningless. Nobody is supposed to pull directly into it from Linus after cloning; rather, changes in upstream would trickle in by a developer who cloned from this subsystem repository and then pulled from Linus into his repository and then pushed his merge result into this public repository.

Nevertheless, exposing the default behaviour of "git send-pack" to "git push" was probably a mistake. I'd propose to require at least one refspec to be specified, either on the command line or via $GIT_DIR/remotes mechanism. So my answer to the "Subject: " line question is "Barf".

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 to save typing. Then always requiring one or more refspecs for push is not too much to ask for.

Opinions?

BTW, Nick, what does http-push do with "git push http://foo" without refspecs?

Sean· Jan 12, 2006, 10:18 UTC · re: Junio C Hamano · lore

Re: [RFD] what should "git push remote.host:path" do?

On Thu, January 12, 2006 4:13 am, Junio C Hamano said:
> The underlying "git send-pack remote.host:path" pushes all the
> matching refs that both local and remote has, and "git push"
> blindly inherits this property.
[snip]
Show 9 quoted lines
> 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 to save typing.  Then always
> requiring one or more refspecs for push is not too much to ask
> for.
>
> Opinions?

What about assuming a refspec of "current-branch:current-branch" ? That is, if the branch name that is currently checked out locally also exists upstream, push into it (only if fast forward).

This should allow multiple branches to be updated locally, and pushed upstream selectively. If you force all push-refspecs to be listed in a remotes file, they'll all be updated every time you push and you'd lose the ability to push just one branch upstream without resorting to multiple $GIT_DIR/remotes/ entries.

Sean
Junio C Hamano· Jan 12, 2006, 19:00 UTC · re: Sean · lore

Re: [RFD] what should "git push remote.host:path" do?

"Sean" <seanlkml@sympatico.ca> writes:
Show 6 quoted lines
> What about assuming a refspec of  "current-branch:current-branch" ?
> That is, if the branch name that is currently checked out locally
> also exists upstream, push into it (only if fast forward).
>
> This should allow multiple branches to be updated locally, and pushed
> upstream selectively.

Requiring at least one refspec to be given to the command has the same property. Ways to give refspec to the command are:

 (1) give one or more from the command line
 (2) give --all from the command line
 (3) give none from the command line, but in this case you need
     at least one "Push:" the "remotes" file you use.

So it really boils down to "is pushing the current branch a better default"?

Even if a project uses CVS style shared repository setup, individual developers would want to use topic branches to prepare things that they eventually push to the shared common, and I suspect that it would lead to more mistakes if we default the push to push the current branch. "Push: master" in the remotes/ file to publish your results to the shared repository would be safer; "git push" when you are still in your topic branch and have not merged things up into your master branch for publication would be no-op, as opposed to pushing the topic branch, probably resulting in the topic branch in the shared repository, even though the topic was meant to be internal to his repository.

Nick Hengeveld· Jan 12, 2006, 16:31 UTC · re: Junio C Hamano · lore

Re: [RFD] what should "git push remote.host:path" do?

On Thu, Jan 12, 2006 at 01:13:30AM -0800, Junio C Hamano wrote:
> BTW, Nick, what does http-push do with "git push http://foo"
> without refspecs?

It won't push anything unless refspecs are specified. If there are none, it will still verify remote DAV locking is available and then exit quietly.

-- 
For a successful technology, reality must take precedence over public
relations, for nature cannot be fooled.
Linus Torvalds· Jan 12, 2006, 18:10 UTC · re: Junio C Hamano · lore

Re: [RFD] what should "git push remote.host:path" do?

On Thu, 12 Jan 2006, Junio C Hamano wrote:
Show 6 quoted lines
> 
> Nevertheless, exposing the default behaviour of "git send-pack"
> to "git push" was probably a mistake.  I'd propose to require at
> least one refspec to be specified, either on the command line or
> via $GIT_DIR/remotes mechanism.  So my answer to the "Subject: "
> line question is "Barf".

Well, I don't have objections, but from ym usage schenario, I'd at least then want flags for "all tags" (--tags - like "pull") and "all branches" (--all).

Having to list all tags/branches is slightly painful. I currently push out all my tags with

	./push-all $(cd .git/refs ; find -type f tags)

which works but isn't exactly user-friendly ("push-all" is just a script that uses "git push" to push to multiple repositories).

Show 7 quoted lines
> 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 to save typing.  Then always
> requiring one or more refspecs for push is not too much to ask
> for.

Well, especially if you want to use "git push" to basically back up your own repo, you do want the "--all" flag. Otherwise you will then forget to add a branch name to every remotes file whenyou create a new branch.

		Linus
Junio C Hamano· Jan 12, 2006, 18:53 UTC · re: Linus Torvalds · lore

Re: [RFD] what should "git push remote.host:path" do?

Linus Torvalds <torvalds@osdl.org> writes:
> Well, especially if you want to use "git push" to basically back up your 
> own repo, you do want the "--all" flag. Otherwise you will then forget to 
> add a branch name to every remotes file whenyou create a new branch.

Sorry, I was unclear in my original message, but I meant to require at least one refspec to be given to the command. Ways to give refspec to the command are:

 (1) give one or more from the command line
 (2) give --all from the command line
 (3) give none from the command line, but in this case you need
     at least one "Push:" the "remotes" file you use.

We already have --all, but your "git push --tags $remote" makes sense. For backups, "only matching things" is not good enough, and we need --all.

Junio C Hamano· Jan 13, 2006, 01:54 UTC · re: Linus Torvalds · lore

[PATCH] git-push: avoid falling back on pushing "matching" refs.

Linus Torvalds <torvalds@osdl.org> writes:
Show 7 quoted lines
> Having to list all tags/branches is slightly painful. I currently push out 
> all my tags with
>
> 	./push-all $(cd .git/refs ; find -type f tags)
>
> which works but isn't exactly user-friendly ("push-all" is just a script 
> that uses "git push" to push to multiple repositories).

So here it is, to add --tags and avoid falling back to "matching" default.

-- >8 -- 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 |   21 +++++++++++++++++++++
 1 files changed, 21 insertions(+), 0 deletions(-)
85393139981c28a2df93950b00e4712dc4bca56c
diff --git a/git-push.sh b/git-push.sh
index 1c5cf80..2b97e09 100755
--- a/git-push.sh
+++ b/git-push.sh
@@ -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" ;;
-- 
1.1.1-g6009

← back to recent threads