threads / discuss / 3113

"git push" logic changed?

Subject: "git push" logic changed?

## tl;dr

13 messages between Jan 20, 2006 and Jan 24, 2006.

replies: 12people: 4as markdown or json

Greg KH· Jan 20, 2006, 22:53 UTC · lore

As of the git development tree from last night, 'git push' seems to work a bit differently now.

When I do:
	$ git push parent
it responds with
	No refs given to be pushed.
This used to work before.
Now I have to do:
	$ git push --all parent
to get things to be pushed.
Or should I always be doing --all?
thanks,
greg k-h
Junio C Hamano· Jan 21, 2006, 00:03 UTC · re: Greg KH · lore

Re: "git push" logic changed?

Greg KH <greg@kroah.com> writes:
> As of the git development tree from last night, 'git push' seems to work
> a bit differently now.

The change was 9e9b267. I suspect the earlier way was a bit more friendly to savvier people (especially the subsystem maintainers and the project lead), but it was found to be confusing for people who clone from an upstream and then use that as a shared repository. Their developers further clone from that shared repository, and as needed pull from the true upstream. When they push their changes back, "git push central:/shared.git/" would trigger a "remote origin does not fast forward" error, depending on when these developers fetched from the shared repository the last time, and whether they stored what they fetched from the shared repository in their "origin" or not. If you do "git pull central:/shared.git/", not "git pull origin" (taking advantage of remotes/origin file), your "origin" branch would become out-of-date. Which is OK for the purpose of maintaining "master" branch properly, but pushing meaningless "origin" back to "origin" at the shared repository (which is also meaningless) was triggering an error and causing confusion in that setup.

> Or should I always be doing --all?

In order to make sure all your local refs are on the "parent", then yes. And this is not new. It used to push all the refs that appear in _both_ your local repo and the "parent" repo, so your new tags and branches did not get propagated so you needed to use '--all' in such a case anyway. We now also have '--tags' to push all tags.

We could probably resurrect the earlier behaviour with a '--matching' option or something if you'd like.

Greg KH· Jan 21, 2006, 00:15 UTC · re: Junio C Hamano · lore

Re: "git push" logic changed?

On Fri, Jan 20, 2006 at 04:03:50PM -0800, Junio C Hamano wrote:
Show 23 quoted lines
> Greg KH <greg@kroah.com> writes:
> 
> > As of the git development tree from last night, 'git push' seems to work
> > a bit differently now.
> 
> The change was 9e9b267.  I suspect the earlier way was a bit
> more friendly to savvier people (especially the subsystem
> maintainers and the project lead), but it was found to be
> confusing for people who clone from an upstream and then use
> that as a shared repository.  Their developers further clone
> from that shared repository, and as needed pull from the true
> upstream.  When they push their changes back, "git push
> central:/shared.git/" would trigger a "remote origin does not
> fast forward" error, depending on when these developers fetched
> from the shared repository the last time, and whether they
> stored what they fetched from the shared repository in their
> "origin" or not.  If you do "git pull central:/shared.git/", not
> "git pull origin" (taking advantage of remotes/origin file),
> your "origin" branch would become out-of-date.  Which is OK for
> the purpose of maintaining "master" branch properly, but pushing
> meaningless "origin" back to "origin" at the shared repository
> (which is also meaningless) was triggering an error and causing
> confusion in that setup.
Well what should I do then to push to "orgin"?
	$ git push
	Where would you want to push today?
	Usage: /home/greg/bin/git-push [--all] [--tags] [--force] <repository> [<refspec>...]
	$ git push origin
	No refs given to be pushed.
Show 8 quoted lines
> > Or should I always be doing --all?
> 
> In order to make sure all your local refs are on the "parent",
> then yes.  And this is not new.  It used to push all the refs
> that appear in _both_ your local repo and the "parent" repo, so
> your new tags and branches did not get propagated so you needed
> to use '--all' in such a case anyway.  We now also have '--tags'
> to push all tags.

Yes, but "git push origin" used to push my local changes there, and that's all I really want.

Someone off-list told me I could edit my .git/branches/parent file to fix this issue for that branch. Since I hand-created that file in the first place, that's not a bit deal. But I was relying on git to get the "origin" branch right, as I didn't edit it at all :)

So, what I'm really just looking for is a simple way to push back to the repository that I cloned this one from, as I only have one "repo" here.

> We could probably resurrect the earlier behaviour with a
> '--matching' option or something if you'd like.
It would be nicer not to break a previously working command :)

Or at least show me how to change it so I can just easily push back to where I cloned the original from...

thanks,
greg k-h
Junio C Hamano· Jan 21, 2006, 00:54 UTC · re: Greg KH · lore

Re: "git push" logic changed?

Greg KH <greg@kroah.com> writes:
Show 9 quoted lines
> Well what should I do then to push to "orgin"?
>...
> Yes, but "git push origin" used to push my local changes there, and
> that's all I really want.
>
> Someone off-list told me I could edit my .git/branches/parent file to
> fix this issue for that branch.  Since I hand-created that file in the
> first place, that's not a bit deal.  But I was relying on git to get the
> "origin" branch right, as I didn't edit it at all :)

If you cloned from "origin", then you would have gotton something like:

	URL: that.machine:/this/directory.git
        Pull: master:origin

in your ".git/remotes/origin". Since there are more downloaders and individual developers than subsystem maintainers, this is a good default for the former class of people.

You as the tree owner would then add "Push:" line(s) to push back from your local repository. For example:

	$ cat .git/remotes/origin	
	URL: that.machine:/this/directory.git
        Pull: master:origin
	Push: master:master
With this,
	$ git push origin

would push master branch to that.machine:/this/directory.git/ repository. With --tags or --all:

	$ git push --tags origin
        $ git push --all origin

These "Push:" lines are for people who have write access to the other side (which is a minority compared to downloaders), so git does not create them by default when you clone the repository.

Junio C Hamano· Jan 21, 2006, 00:59 UTC · re: Greg KH · lore

Re: "git push" logic changed?

Greg KH <greg@kroah.com> writes:
> It would be nicer not to break a previously working command :)

Well the change was not about breaking things but the command's natural way of "working" (which was fine for you and other people, me included) was not so helpful to the shared repository people, and unfortunately I couldn't have it both ways X-<.

Junio C Hamano· Jan 21, 2006, 07:46 UTC · re: Greg KH · lore

[RFC] Reverting "git push logic change"?

The change introduced by 9e9b267 commit broke "correct" usage of git push to push matching refs, to work around a problem observed in a usage pattern on a shared repository.

I think I made a bad judgement in evaluating the scenario, and made a bad change to "fix" a problem that did not exist. I apologize for having caused this confusion.

My conclusion after thinking about the problem again is that we would be better of if we reverted that commit. This message is to make my intention clear, and solicit objections or comments from the list.

The use case that prompted this change was this:
 - A shared repository is created by cloning Linus repository.
   This repository gets "origin" (then-current Linus master) and
   "master" (the same).
	$ git clone --naked \
          git://git.kernel.org/.../linux-2.6.git/ project.git
 - Two developers use this as their shared repository.  They
   first start out by cloning from it, do their development in
   their "master" branch and pushing back to the "master" branch
   of the shared repository.  Their workflow is:
	0. Clone it (once per developer):
        $ git clone ssh://pub.example.com/project.git/ work
	1. To make sure the developers are in sync:
	$ git pull ssh://pub.example.com/project.git/ ;# (a) or
	$ git pull origin			      ;# (b)
        2. His own development:
	$ edit;compile;test;git commit
	3. Pull from upstream, to avoid conflicts with it (only when needed):
	$ git pull git://git.kernel.org/.../linux-2.6.git/
	4. Push back the result to shared repository:
        $ git push ssh://pub.example.com/project.git/

With this workflow, in the two developer repositories, "origin" branch is not really well maintained. If "git pull origin" was used with the remotes/origin file "git clone" initially gave him, it would have kept track of the latest push into the shared "master" closely, but if the explicit URL was used, "origin" of the developer repository would have been left behind.

This is not problem as far as the correctness of the "master" branch is concerned. The fast-forward check when pushing into the shared repository "master" branch prevents the two developers from losing commits. In other words, either way to pull from the shared repository is legal/valid.

However, the push done in step 4. triggers the default "push all matching refs" behaviour. All three repositories have "origin" and "master", which means this results in "origin" being updated in the shared repository. But one developer repository has a stale "origin" while the other developer has an up-to-date "origin". This triggers a "not a fast forward" error, which does not cause the push of "master" to fail, but still looks worrisome.

I think the correct thing to do in this workflow is to simply remove "origin" branch from the shared repository.

Using or not using "origin" as a reference branch to keep track of what was fetched from the shared repository is a matter of personal taste for each developer, and there is no reason to enforce either (1-a) or (1-b). This means that the branch is not maintained the same way in developer repositories, and there is no point pushing into it --- there is no point to have "origin" in the shared repository.

Once "origin" branch is removed from that shared repository, then, either "push all matching refs", or "push 'master' explicitly" would work well for these developers.

Daniel Barkalow· Jan 22, 2006, 19:09 UTC · re: Junio C Hamano · lore

Re: [RFC] Reverting "git push logic change"?

On Fri, 20 Jan 2006, Junio C Hamano wrote:
Show 64 quoted lines
> The change introduced by 9e9b267 commit broke "correct" usage of
> git push to push matching refs, to work around a problem
> observed in a usage pattern on a shared repository.
> 
> I think I made a bad judgement in evaluating the scenario, and
> made a bad change to "fix" a problem that did not exist.  I
> apologize for having caused this confusion.
> 
> My conclusion after thinking about the problem again is that we
> would be better of if we reverted that commit.  This message is
> to make my intention clear, and solicit objections or comments
> from the list.
> 
> The use case that prompted this change was this:
> 
>  - A shared repository is created by cloning Linus repository.
>    This repository gets "origin" (then-current Linus master) and
>    "master" (the same).
> 
> 	$ git clone --naked \
>           git://git.kernel.org/.../linux-2.6.git/ project.git
> 
>  - Two developers use this as their shared repository.  They
>    first start out by cloning from it, do their development in
>    their "master" branch and pushing back to the "master" branch
>    of the shared repository.  Their workflow is:
> 
> 	0. Clone it (once per developer):
>         $ git clone ssh://pub.example.com/project.git/ work
> 
> 	1. To make sure the developers are in sync:
> 	$ git pull ssh://pub.example.com/project.git/ ;# (a) or
> 	$ git pull origin			      ;# (b)
> 
>         2. His own development:
> 	$ edit;compile;test;git commit
> 
> 	3. Pull from upstream, to avoid conflicts with it (only when needed):
> 	$ git pull git://git.kernel.org/.../linux-2.6.git/
> 
> 	4. Push back the result to shared repository:
>         $ git push ssh://pub.example.com/project.git/
> 
> With this workflow, in the two developer repositories, "origin"
> branch is not really well maintained.  If "git pull origin" was
> used with the remotes/origin file "git clone" initially gave
> him, it would have kept track of the latest push into the shared
> "master" closely, but if the explicit URL was used, "origin" of
> the developer repository would have been left behind.
> 
> This is not problem as far as the correctness of the "master"
> branch is concerned.  The fast-forward check when pushing into
> the shared repository "master" branch prevents the two
> developers from losing commits.  In other words, either way to
> pull from the shared repository is legal/valid.
> 
> However, the push done in step 4. triggers the default "push all
> matching refs" behaviour.  All three repositories have "origin"
> and "master", which means this results in "origin" being updated
> in the shared repository.  But one developer repository has a
> stale "origin" while the other developer has an up-to-date
> "origin".  This triggers a "not a fast forward" error, which
> does not cause the push of "master" to fail, but still looks
> worrisome.
I think there are a number of good solutions:
 - Make the case of a pure rewind (i.e., pushing something that would be a 
   fast-forward in the other direction) have no effect and give a more 
   positive message like 'Remote "origin" is already ahead of your 
   version.' I expect that something of that sort would comfort the users 
   and distinguish branches that you're not actively using and have fallen 
   behind on from branches that you are using, but someone else is also 
   using. This seems like a good idea even if we do other stuff.
 - Have a command to write, report, and modify remotes files, so Greg can 
   tell it exactly what he actually wants without mucking around with the 
   files by hand. Also generally nice.
 - Require --all in push, but, if none are given, produce a summary of 
   what you could specify instead of assuming you mean to push nothing. 
   Then Greg would see master:master as the obvious thing, and do that.
 - Maybe "git clone" should add "Push: master:master" by default if the 
   URL permits pushing?

I think that having it default to matching branches isn't really ideal, since that seems to me to work for practically everybody only by coincidence: master:master is by far the most common case; then there are some people who use multiple branches, but they must have done something other than the default to create this situation, anyway; then there's the case where "master" isn't a head on both sides, but (at least in my experience), master:master is still what the user means (case happens when pushing a first commit from a clone of an empty repository).

Maybe the default should be master:master? It seems to fit the general pattern of defaulting to master. Or maybe (what HEAD points to):(matching branch), or (but I'm not too comfortable with this one) HEAD:master.

	-Daniel
*This .sig left intentionally blank*
Junio C Hamano· Jan 22, 2006, 20:31 UTC · re: Daniel Barkalow · lore

Re: [RFC] Reverting "git push logic change"?

Daniel Barkalow <barkalow@iabervon.org> writes:
>  - Make the case of a pure rewind (i.e., pushing something that would be a 
>    fast-forward in the other direction) have no effect and give a more 
>    positive message like 'Remote "origin" is already ahead of your 
>    version.'

If the remote is not behind you, you would not be able to tell if it is ahead of you or totally unrelated, unless you fetch from them. So I am afraid this is unpractical.

>  - Have a command to write, report, and modify remotes files, so Greg can 
>    tell it exactly what he actually wants without mucking around with the 
>    files by hand. Also generally nice.

For the record, it was somebody else. Greg has the repositories on both ends set up correctly, and does not suffer from this "left behind origin" error message. He has every right to expect the "all the matching refs" semantics to keep working.

I think in this case, it was not the lack of tool to "tell it exactly what he actually wants", but "what he actually wants" was not quite well understood by the developers who experienced this problem (again, not Greg). This is a user error but that is not their fault. It means that we need to document this better:

	A typical "cloned" repository has an "origin" branch to
	record the head commit of the upstream repository when
	the repository was cloned, and the branch is used to
	keep track of further development at the upstream.  But
	in a shared repository, it usually is not used for
	further development by your developers who clone from it
	and then push their changes back to it (for that they
	would use the "master" branch).  Your developers may
	occasionally need to sync with the upstream, but that is
	done by pulling from the upstream directly, and the
	"origin" branch at the shared repository is not
	involved.  In other words, that branch is useless and
	tends to be left behind.  If you are preparing a
	repository by first cloning from somewhere else, remove
	branches that your developers and people who download
	from your shared repository do not use, including
	"origin".
	"git push", without telling the tool which branches to
        push explicitly, pushes the branches that exist on both
        ends.  Culling unused branches, especially "origin",
        from the shared repository helps your developers because
        they do not have to do anything special to prevent their
        "origin" from being pushed back to the shared repository.
or something like that.
>  - Require --all in push, but, if none are given, produce a summary of 
>    what you could specify instead...

This is essentially what the "fix" did, except giving a summary. The effect to the end user was that we were robbing "matching refs" option from them.

>  - Maybe "git clone" should add "Push: master:master" by default if the 
>    URL permits pushing?

This might be a good thing to have. I suspect majority of users would benefit from this.

Show 5 quoted lines
> I think that having it default to matching branches isn't really ideal, 
> since that seems to me to work for practically everybody only by 
> coincidence: master:master is by far the most common case; then 
> there are some people who use multiple branches, but they must have done 
> something other than the default to create this situation, anyway;

Actually I started to think matching is a very good default for everyday use.

 - In the recommended "topic branches" workflow, a developer
   repository has more branches than his public repository he
   pushes into.  A typical public repository on kernel.org has
   either "master" alone, or "test" and "release" pair.  In
   either case, I expect the set of branches on these public
   repositories have "matching" ones in the owners' development
   repositories.  "matching" push lets them updated without
   pushing topic branch heads _unless_ the developer also wants
   to push topic branches to public, which reduces the clutter
   on the public repository.
 - In a shared repository setup, a developer still can employ
   topic branches workflow for himself.  The same "matching
   semantics prevents unneeded exposure of private topic
   branches" applies here.
 - In a non-default developer repository that has more than one,
   they must have done something other than the default.  For
   example:
	$ git branch test
        $ git branch release
        $ git push public:myrepo test release
   We _could_ require (or strongly suggest) them to keep a
   remotes/ shorthand for push destination and have:
	URL: public:myrepo
        Push: test
        Push: release
   so that next push would be "git push public".  Another
   possibility is that "git push public test release"
   (i.e. using a "remotes/public" shorthand) _could_ offer to
   update the remotes/ file when it sees these branches do not
   appear on Push: lines.
   But the "matching ones" push has the same effect.  It
   remembers which ones have been pushed out before, without
   mucking with remotes/ file, as long as the branch names are
   the same on the both ends (which I suspect is the most common
   usage).
   Also we need to remember there are people who push into more
   than one repositories, and they would need to keep and
   maintain separate remotes/ file per destination if there is
   no "matching ones" option.

If we add "Push: master" upon clone from host:repo (or local), then these new repositories would push master into master and nothing else with "git push origin", and "git push URL" to the same remote repository without using remotes/ shorthand would result in the matching behaviour. That may be a good default.

Junio C Hamano· Jan 22, 2006, 21:31 UTC · re: Junio C Hamano · lore

Re: [RFC] Reverting "git push logic change"?

Junio C Hamano <junkio@cox.net> writes:
> ...  This is a user error but that is not their fault.  It
> means that we need to document this better:
I hope something like this is clear enough?

-- >8 -- [PATCH] Recommend to remove unused `origin` in a shared repository

It is a common mistake to leave an unsed `origin` branch behind if a shared public repository was created by first cloning from somewhere else. Subsequent `git push` into it with the default "push all the matching ref" would push the `origin` branch from the developer repository uselessly.

Signed-off-by: Junio C Hamano <junkio@cox.net>
---
diff --git a/Documentation/tutorial.txt b/Documentation/tutorial.txt
index b8fa299..35579cc 100644
--- a/Documentation/tutorial.txt
+++ b/Documentation/tutorial.txt
@@ -1667,6 +1667,26 @@ complain, telling you that the remote `m
 fast forward.  You need to pull and merge those other changes
 back before you push your work when it happens.
 
+The `git push` command without any explicit refspec parameter
+pushes the refs that exist both in the local repository and the
+remote repository.  So the last `push` can be done with either
+one of these:
+------------
+$ git push origin
+$ git push repo.shared.xz:/pub/scm/project.git/
+------------
+as long as the shared repository does not have any branches
+other than `master`.
+[NOTE]
+============
+If you created your shared repository by cloning from somewhere
+else, you may have the `origin` branch.  Your developers
+typically do not use that branch; remove it.  Otherwise, that
+would be pushed back by the `git push origin` because your
+developers' repository would surely have `origin` branch to keep
+track of the shared repository, and would be counted as "exist
+on both ends".
+============
 
 Advanced Shared Repository Management
 -------------------------------------
sean· Jan 22, 2006, 21:42 UTC · re: Junio C Hamano · lore

Re: [RFC] Reverting "git push logic change"?

On Sun, 22 Jan 2006 13:31:00 -0800 Junio C Hamano <junkio@cox.net> wrote:

Show 7 quoted lines
> +If you created your shared repository by cloning from somewhere
> +else, you may have the `origin` branch.  Your developers
> +typically do not use that branch; remove it.  Otherwise, that
> +would be pushed back by the `git push origin` because your
> +developers' repository would surely have `origin` branch to keep
> +track of the shared repository, and would be counted as "exist
> +on both ends".

What about just always excluding the origin branch from being implicitly pushed; even if it does exist in both repositories? In the rare cases where it is actually desired to be pushed, it can be done explicitly.

Sean
Junio C Hamano· Jan 22, 2006, 23:09 UTC · re: sean · lore

Re: [RFC] Reverting "git push logic change"?

sean <seanlkml@sympatico.ca> writes:
> What about just always excluding the origin branch from being 
> implicitly pushed; even if it does exist in both repositories?
> In the rare cases where it is actually desired to be pushed,
> it can be done explicitly.

The problem is "origin" is just a Porcelain convention and we would not want to teach that to the core level, so that will not fly.

Junio C Hamano· Jan 23, 2006, 01:31 UTC · re: Junio C Hamano · lore

Re: [RFC] Reverting "git push logic change"?

Junio C Hamano <junkio@cox.net> writes:
Show 10 quoted lines
> sean <seanlkml@sympatico.ca> writes:
>
>> What about just always excluding the origin branch from being 
>> implicitly pushed; even if it does exist in both repositories?
>> In the rare cases where it is actually desired to be pushed,
>> it can be done explicitly.
>
> The problem is "origin" is just a Porcelain convention and we
> would not want to teach that to the core level, so that will not
> fly.

One improvement that can be done is to update "git clone --bare" so that it does not create "origin", which is more or less pointless for such a "distribution point" repository.

This reminds me that I need to deprecate --naked and introduce --bare to the clone command...

Greg KH· Jan 24, 2006, 05:05 UTC · re: Junio C Hamano · lore

Re: [RFC] Reverting "git push logic change"?

On Fri, Jan 20, 2006 at 11:46:23PM -0800, Junio C Hamano wrote:
> The change introduced by 9e9b267 commit broke "correct" usage of
> git push to push matching refs, to work around a problem
> observed in a usage pattern on a shared repository.
<snip>
Thanks, I think this makes a bit more sense.

If nothing else, the documentation should be updated to reflect the change in 9e9b267 :)

thanks,
greg k-h

← back to recent threads