threads / patch / 16104

patchRe: [PATCH] Documentation: add a planning document for the next CLI revamp

Subject: Re: [PATCH] Documentation: add a planning document for the next CLI revamp

## tl;dr

25 messages between Oct 31, 2008 and Nov 5, 2008. Diffs are folded; open one to read it.

replies: 24people: 9as markdown or json

Jeff King· Oct 31, 2008, 00:31 UTC · lore
On Wed, Oct 29, 2008 at 05:22:00PM -0700, Sam Vilain wrote:
>  Some suggestions, which have been briefly scanned over by some of the
>  (remaining) GitTogether attendees.  Please keep it constructive!  :)
Thanks for putting this together.
> +  * 'git stage' would do what 'git add' does now.
> +
> +  * 'git unstage' would do what 'git reset --' does now
These seem reasonable.
> +  * 'git status' would encourage the user to use
> +    'git diff --staged' to see staged changes as a patch

I notice the commit template message getting longer and longer. Maybe it is time for status.verbosetemplate (which could default to true, I just want to be able to turn it off).

> +  * 'git commit' with no changes should give useful information about
> +    using 'git stage', 'git commit -a' or 'git commit filename ...'

There is already infrastructure that figures out exactly what the situation is (no changes versus changes in untracked files versus changes in unstaged files), so it should just be a matter of tweaking the messages.

> +  * 'git add' and 'git rm': no change
> +
> +  * 'git update-index' considered plumbing, not changed
Definitely.
> +  * 'git revert' deprecated in favour of 'git cherry-pick --revert'

I think I would make it "-R, --reverse", since it really is analagous to "git diff -R".

> +  * 'git undo' would do what 'git checkout HEAD --' does now

This is an awful name, IMHO. It doesn't point out _what_ you're undoing, so it leaves me with the feeling that you can undo arbitrary things. I think the name needs to be considered along with related operations.

So think of us as having three "spots": the HEAD (H), the "stage"[1] (S), and the working tree (W). And we want commands for moving content between them. Now we have:

  W->S: add
  H->S: reset --
  S->W: checkout --
  S->H: commit (no paths)
And if you want to include things that jump the staging area:
  W->H: commit (paths or -a)
  H->W: checkout HEAD --
So I think with your stage/unstage, we have:
  W->S: stage
  H->S: unstage
  S->W: ?
  S->H: commit (no paths)
  W->H: commit (paths or -a)
  H->W: ?

So I think we can note something: movement commands are related based on their _destination_. So since both of the missing ones impact the working tree, they should have a related name.

But do note the difference between "stage vs unstage" as opposed to "commit versus commit -a". I think this is because the stage sits in the middle. So it is mentally "which direction are changes coming from" and not "how _far_ are changes coming from".

So by that rationale, we should have a single command which says "put stuff in the working tree", with a flag for "from HEAD" versus "from the staging area." And that's what we have right now with "git checkout". The real problem with it is that it is an overload of checkout's other behavior of switching branches.

So what I am saying is "git undo" _must_ support both "put index content into working tree" as well as "put HEAD content into working tree", or it will be a step backwards in consistency.

So I guess that doesn't really suggest a name. But "undo" is awful. ;P

Side note: there are actually _other_ places you might want to move content. Like a stash. So now you can think of it as:

                 stash
                  ^  ^
                 /    \
                /      \
               v        v
  HEAD <--> stage <--> working tree

So maybe we just need a "git content" command. And then you can "git content --from=HEAD --to=tree <paths>" or "git content --from=tree --to=stash", with all equally supporting "--interactive". And of course I am kidding, because typing that would be awful. But I think conceptually, it makes sense. To me, anyway.

> +  * 'git branch --switch' : alternative to checkout

Blech. I think switching branches is the one thing that checkout does unconfusedly. And this is much more typing. Not to mention that So I would rather see "git switch" if checkout is somehow unpalatable.

But I don't know that it is. This seems like an attempt to say "branch operations should all be part of 'git branch'". But checkout isn't necessarily a branch operation. Consider detaching HEAD to a tag. Should it be "git tag --switch"?

> +  * 'git push --matching' does what 'git push' does today (without
> +    explicit configuration)

I think this is reasonable even without other changes, just to override any configuration.

Show 7 quoted lines
> +  * 'git push' with no ref args and no 'push =' configuration does
> +    what:
> +    'git push origin $(git symbolic-ref HEAD | sed "s!refs/heads/!!")'
> +    does today.  ie, it only pushes the current branch.
> +    If a branch was defined in branch.<name>.push, push to that ref
> +    instead of the matching one.  If there is no matching ref, and
> +    there is a branch.<name>.merge, push back there.

There was a thread between me and Junio some months ago that touched on this. I don't remember all of the arguments, but it was resolved to keep the current behavior. Any proposal along these lines should at least revisit and respond to those arguments.

> +  * 'git push' to checked out branch of non-bare repository not
> +    allowed without special configuration.  Configuration available

I have this patch done and sitting in my repo, but I need to add the "without special configuration" bit and add tests and docs.

> +Informational
> +-------------
> +
> +  * 'git branch' should default to '--color=auto -v'

This should at least be configurable (even if it defaults to "on"). "-v" is more expensive, and not always wanted.

I, for one, just use "git branch" to get the current branch. I don't know of a more obvious way to ask for it (and please don't mention an ever-changing bash prompt).

> +  * 'git tag -l' should show more information

I remember somebody talking about this, but not the details. Which information?

> +  * 'git am -3' the default; with global option to make it not the
> +    default for those that prefer the speed of -2

I would prefer that personally. I think Linus has been very reasonable in the past about recognizing that his workflow and speed requirements aren't always typical, and being willing to accept setting a configuration flag in those cases. So I think if he ack'd such a patch, nobody else would complain.

> +  * 'git export' command that does what
> +    'git archive --format=tar --prefix=dir | tar x' does now

I agree, if you mean "does what ... does now" means "looks to the user like ... is happening". This is much more sanely done using git-checkout-index (though somebody suggested "remote export", which would need to use tar itself).

Show 10 quoted lines
> +  * 'git init --server' (or similar) should do everything required for
> +    exporting::
> +----
> +chmod -R a+rX
> +touch git-daemon-export-ok
> +git gc
> +git update-server-info
> +chmod u+x .git/hooks/post-update
> +git config core.sharedrepository=1
> +----

But not all of those things are necessarily related, and some of them have security implications. I would hate to get a bug report like "I used --server because I wanted to share my content via dumb http, but my repo was p0wned because of too-loose group permissions."

-Peff
Sam Vilain· Oct 31, 2008, 06:40 UTC · re: Jeff King · lore
On Thu, 2008-10-30 at 20:31 -0400, Jeff King wrote:
> >  Some suggestions, which have been briefly scanned over by some of the
> >  (remaining) GitTogether attendees.  Please keep it constructive!  :)
> Thanks for putting this together.

No problem! Thanks for responding. I've been amazed that it seems to have been largely taken well :) But there are still very important changes required.

Show 6 quoted lines
> > +  * 'git status' would encourage the user to use
> > +    'git diff --staged' to see staged changes as a patch
> 
> I notice the commit template message getting longer and longer. Maybe it
> is time for status.verbosetemplate (which could default to true, I just
> want to be able to turn it off).

Right. We'll have to work through that when we look at how 'git status' output is displayed. There may be some people who parse the existing output, but they should get to read the release notes about the proper ways to do that. I think the whole output could do with a shake-up.

> > +  * 'git undo' would do what 'git checkout HEAD --' does now
> This is an awful name, IMHO. It doesn't point out _what_ you're undoing,
As others have said, yes.
Show 12 quoted lines
> So I think with your stage/unstage, we have:
> 
>   W->S: stage
>   H->S: unstage
>   S->W: ?
>   S->H: commit (no paths)
>   W->H: commit (paths or -a)
>   H->W: ?
> 
> So I think we can note something: movement commands are related based on
> their _destination_. So since both of the missing ones impact the
> working tree, they should have a related name.
An interesting observation.

I still think it's OK to use 'git revert-files' for this; it just seems so long. Switches could specify where to and from.

Show 15 quoted lines
> Side note: there are actually _other_ places you might want to move
> content. Like a stash. So now you can think of it as:
> 
>                  stash
>                   ^  ^
>                  /    \
>                 /      \
>                v        v
>   HEAD <--> stage <--> working tree
> 
> So maybe we just need a "git content" command. And then you can "git
> content --from=HEAD --to=tree <paths>" or "git content --from=tree
> --to=stash", with all equally supporting "--interactive".  And of course
> I am kidding, because typing that would be awful. But I think
> conceptually, it makes sense. To me, anyway.

Again interesting, you could look at the stash as a whole bunch of staged commits yet to happen. Of course, adding a file when the version in HEAD doesn't match the version in the base of the stash is a bit insane, so should probably be an error.

I'll have a ponder over this and whether there is a simple word for this all.

Show 10 quoted lines
> > +  * 'git branch --switch' : alternative to checkout
> 
> Blech. I think switching branches is the one thing that checkout does
> unconfusedly. And this is much more typing. Not to mention that So I
> would rather see "git switch" if checkout is somehow unpalatable.
>
> But I don't know that it is. This seems like an attempt to say "branch
> operations should all be part of 'git branch'". But checkout isn't
> necessarily a branch operation. Consider detaching HEAD to a tag. Should
> it be "git tag --switch"?

You're right with all that. I don't think that it is necessarily wrong to have two ways to get at functionality, depending on whether you start with the noun or the verb first; so long as it doesn't introduce confusion. And if anything, I think --switch is wrong; --checkout is probably more consistent.

I think I might have to mark this one as [maybe], and make it --checkout
- as you say, it would need to go on all the other commands that are
nouns and able to be checked out to be consistent.  Let's see how that
looks in round 2.
Show 5 quoted lines
> > +  * 'git push --matching' does what 'git push' does today (without
> > +    explicit configuration)
> 
> I think this is reasonable even without other changes, just to override
> any configuration.
Excellent, I have another vote towards this push sanity!  :)
Show 12 quoted lines
> > +  * 'git push' with no ref args and no 'push =' configuration does
> > +    what:
> > +    'git push origin $(git symbolic-ref HEAD | sed "s!refs/heads/!!")'
> > +    does today.  ie, it only pushes the current branch.
> > +    If a branch was defined in branch.<name>.push, push to that ref
> > +    instead of the matching one.  If there is no matching ref, and
> > +    there is a branch.<name>.merge, push back there.
> 
> There was a thread between me and Junio some months ago that touched on
> this. I don't remember all of the arguments, but it was resolved to keep
> the current behavior. Any proposal along these lines should at least
> revisit and respond to those arguments.

Right. So, before round 2, I'll read and attempt to summarise that thread - assuming I can find it! :)

> > +  * 'git push' to checked out branch of non-bare repository not
> > +    allowed without special configuration.  Configuration available
> I have this patch done and sitting in my repo, but I need to add the
> "without special configuration" bit and add tests and docs.
Looking forward to that!  Thanks.
Show 7 quoted lines
> > +  * 'git branch' should default to '--color=auto -v'
> This should at least be configurable (even if it defaults to "on"). "-v"
> is more expensive, and not always wanted.
> 
> I, for one, just use "git branch" to get the current branch. I don't
> know of a more obvious way to ask for it (and please don't mention an
> ever-changing bash prompt).
What's wrong with 'git symbolic-ref HEAD' ?  *ducks*

Of course 'git branch -q' would then be the quick version, or 'git br' (after git config --global alias.br 'branch -q')

Another command people often want is 'git info' to tell them stuff like they might get from 'git status' or 'git remote' but without all the file details...

> > +  * 'git tag -l' should show more information
> 
> I remember somebody talking about this, but not the details. Which
> information?

Oh, good point. Basically the same stuff that 'git branch -v' shows; in any case, its behaviour should be relatively consistent compared to 'git branch'.

Show 15 quoted lines
> > +  * 'git init --server' (or similar) should do everything required for
> > +    exporting::
> > +----
> > +chmod -R a+rX
> > +touch git-daemon-export-ok
> > +git gc
> > +git update-server-info
> > +chmod u+x .git/hooks/post-update
> > +git config core.sharedrepository=1
> > +----
> 
> But not all of those things are necessarily related, and some of them
> have security implications. I would hate to get a bug report like "I
> used --server because I wanted to share my content via dumb http, but my
> repo was p0wned because of too-loose group permissions."

ok. That should come down to the detail of how '--server' is specified, I think. I'll expand on that during round 2.

Sam.
Pierre Habouzit· Oct 31, 2008, 08:20 UTC · re: Sam Vilain · lore
On Fri, Oct 31, 2008 at 06:40:38AM +0000, Sam Vilain wrote:
Show 8 quoted lines
> On Thu, 2008-10-30 at 20:31 -0400, Jeff King wrote:
> > >  Some suggestions, which have been briefly scanned over by some of the
> > >  (remaining) GitTogether attendees.  Please keep it constructive!  :)
> > Thanks for putting this together.
> 
> No problem!  Thanks for responding.  I've been amazed that it seems to
> have been largely taken well :)  But there are still very important
> changes required.
Well, most of it we discussed IRL, that helps tremendously ;)
> I still think it's OK to use 'git revert-files' for this; it just seems
> so long.  Switches could specify where to and from.

Well the point is we will probably just deprecate git-revert and remove it alltogether in git 2.6. At that time you will be able to define git-revert as an alias to git cherry-pick -R if you're an old fart, or git revert-files if you're an svn user ;)

But I see no convincing name that hasn't "revert" in them, hence will be long :/

> Of course 'git branch -q' would then be the quick version, or 'git
> br' (after git config --global alias.br 'branch -q')

oh no, not -q please, -q is quiet, -h is help, -v is verbose. I mean POSIX should define these. Do not give those switch any other kind of sementics anymore, we've done that, and it hurts. -Q is fine with me though.

> Another command people often want is 'git info' to tell them stuff like
> they might get from 'git status' or 'git remote' but without all the
> file details...

And to say to them if they're in the midle of a merge, of a rebase, an am, on a detached, head, .... what is in the __git_ps1 of bash actually.

Show 18 quoted lines
> > > +  * 'git init --server' (or similar) should do everything required for
> > > +    exporting::
> > > +----
> > > +chmod -R a+rX
> > > +touch git-daemon-export-ok
> > > +git gc
> > > +git update-server-info
> > > +chmod u+x .git/hooks/post-update
> > > +git config core.sharedrepository=1
> > > +----
> > 
> > But not all of those things are necessarily related, and some of them
> > have security implications. I would hate to get a bug report like "I
> > used --server because I wanted to share my content via dumb http, but my
> > repo was p0wned because of too-loose group permissions."
> 
> ok.  That should come down to the detail of how '--server' is specified,
> I think.  I'll expand on that during round 2.
What about git init --svn-like ? /me *ducks*
-- 
·O·  Pierre Habouzit
··O                                                madcoder@debian.org
OOO                                                http://www.madism.org
Jeff King· Nov 2, 2008, 04:18 UTC · re: Sam Vilain · lore
On Thu, Oct 30, 2008 at 11:40:38PM -0700, Sam Vilain wrote:
Show 7 quoted lines
> > I notice the commit template message getting longer and longer. Maybe it
> > is time for status.verbosetemplate (which could default to true, I just
> > want to be able to turn it off).
> Right.  We'll have to work through that when we look at how 'git status'
> output is displayed.  There may be some people who parse the existing
> output, but they should get to read the release notes about the proper
> ways to do that.  I think the whole output could do with a shake-up.

Maybe I am wrong, but I thought at some point we decided that parsing the output of "git status" was insane and wrong, since it's porcelain. OTOH, it is also an easy way for editors to see what is happening in a commit whose message you are editing (and to do, for example, syntax highlighting on it). So it may be that it is getting parsed anyway.

> [moving content from HEAD or index to working tree]
> I still think it's OK to use 'git revert-files' for this; it just seems
> so long.  Switches could specify where to and from.

Yeah, revert-files is pretty painful to type. And I'm not looking forward to fielding UI questions about "why isn't it just revert?" :)

Somebody suggested "clobber", which I think is a bit _too_ intense.

I guess something like "retrieve" is too ambiguous. You really need something that implies movement of content, and something that implies the working directory. "Checkout" is actually not a bad name; if only we had "git switch" instead of "git checkout" for switching branches, it would be perfect.

So I am a bit stumped. Maybe "clobber" is not so bad. ;)
Show 7 quoted lines
> Again interesting, you could look at the stash as a whole bunch of
> staged commits yet to happen.  Of course, adding a file when the version
> in HEAD doesn't match the version in the base of the stash is a bit
> insane, so should probably be an error.
> 
> I'll have a ponder over this and whether there is a simple word for this
> all.

Whether or not we come up with a simple word, I think it makes sense to expose this through "git stash -i" (since, after all, we are just putting stuff into an index there).

Show 5 quoted lines
> You're right with all that.  I don't think that it is necessarily wrong
> to have two ways to get at functionality, depending on whether you start
> with the noun or the verb first; so long as it doesn't introduce
> confusion.  And if anything, I think --switch is wrong; --checkout is
> probably more consistent.

Agreed on --checkout. I think your "noun or verb" comment hits the nail right on the head. I wonder if there are other places where functionality can be exposed in either direction (I think we already have some in "git fetch <remote>" versus "git remote update").

Show 7 quoted lines
> > There was a thread between me and Junio some months ago that touched on
> > this. I don't remember all of the arguments, but it was resolved to keep
> > the current behavior. Any proposal along these lines should at least
> > revisit and respond to those arguments.
> 
> Right.  So, before round 2, I'll read and attempt to summarise that
> thread - assuming I can find it!  :)

I think it was "Minor annoyance with git push" from this past February. Quite a long thread, but there is some in this subthread:

http://thread.gmane.org/gmane.comp.version-control.git/73038/focus=73208
> Another command people often want is 'git info' to tell them stuff like
> they might get from 'git status' or 'git remote' but without all the
> file details...

Yeah, I don't know if you have followed the other threads in the past month or so, but I think there is some desire for a "new" status with a nicer format.

And I think it might be nice to structure it as a long list of things it _can_ report on, and then let you tweak those with command-line options and config settings. E.g., I might set info.currentbranch, info.staged, and info.untracked because that is what _I_ like to see to get a sense of what is happening in the repo.

And I will get around to designing that after I clear the other 100 things off my todo list. ;)

Show 6 quoted lines
> > > +  * 'git tag -l' should show more information
> > I remember somebody talking about this, but not the details. Which
> > information?
> Oh, good point.  Basically the same stuff that 'git branch -v' shows; in
> any case, its behaviour should be relatively consistent compared to 'git
> branch'.

OK, that makes sense to me. I think of "git tag -l" as plumbing-ish, though, so we might be breaking people's scripts (yes, I know the "real" plumbing for this is for-each-ref, but it really is a pain to parse the tags out of that versus "for i in `git tag -l`").

-Peff
Theodore Tso· Nov 2, 2008, 09:56 UTC · re: Jeff King · lore
On Sun, Nov 02, 2008 at 12:18:33AM -0400, Jeff King wrote:
> 
> Yeah, revert-files is pretty painful to type. And I'm not looking
> forward to fielding UI questions about "why isn't it just revert?" :)
> 

At least for me, I don't use it *that* often, so it's not that painful for me (I have it as an "git revert-file" as an alias already).

And the answer, "because 'git revert' used to do something else" is I think a perfectly reasonable answer. I probably do "git revert-files" about 3-5 times more often than I do "git revert", so it's a bit strange from a character count perspective, but history is history.

Show 7 quoted lines
> Somebody suggested "clobber", which I think is a bit _too_ intense.
> 
> I guess something like "retrieve" is too ambiguous. You really need
> something that implies movement of content, and something that implies
> the working directory. "Checkout" is actually not a bad name; if only we
> had "git switch" instead of "git checkout" for switching branches, it
> would be perfect.

If people really want a shorter name, how about bk's "unedit"? I'd still worry about people being able to find it, since the reality is that most of the world knows this command as revert, though.

     	     	       	     	  	     	     - Ted
Johannes Schindelin· Oct 31, 2008, 16:46 UTC · re: Jeff King · lore
Hi,
On Thu, 30 Oct 2008, Jeff King wrote:
Show 7 quoted lines
> On Wed, Oct 29, 2008 at 05:22:00PM -0700, Sam Vilain wrote:
> 
> > +  * 'git branch --switch' : alternative to checkout
> 
> Blech. I think switching branches is the one thing that checkout does 
> unconfusedly. And this is much more typing. Not to mention that So I 
> would rather see "git switch" if checkout is somehow unpalatable.

You know, I asked for this because a _user_ told me "Guess how long it took me to find out how to check out a branch!".

I think if you are not confused by CVS/SVN, the name "checkout" is utterly unintuitive.

Ciao, Dscho

Jeff King· Nov 2, 2008, 03:42 UTC · re: Johannes Schindelin · lore
On Fri, Oct 31, 2008 at 05:46:35PM +0100, Johannes Schindelin wrote:
Show 11 quoted lines
> > > +  * 'git branch --switch' : alternative to checkout
> > 
> > Blech. I think switching branches is the one thing that checkout does 
> > unconfusedly. And this is much more typing. Not to mention that So I 
> > would rather see "git switch" if checkout is somehow unpalatable.
> 
> You know, I asked for this because a _user_ told me "Guess how long it 
> took me to find out how to check out a branch!".
> 
> I think if you are not confused by CVS/SVN, the name "checkout" is utterly 
> unintuitive.
OK. I am not opposed to such a change as long as:
 - this is not just _a_ user, but a _common_ user confusion. IOW, I
   don't recall this complaint coming up a lot (or at least not nearly
   as often as other ones do). But maybe you have more data.
 - it is done consistently.
   My initial "blech" was a little premature, as I was thinking "instead
   of checkout", though it does clearly say "alternative" there.
   However, (and somebody else in the thread very cleverly came up with
   this analysis, not me), this is basically going from "verb the noun"
   to "noun --verb". And that's reasonable, if users think in terms of
   nouns. But we should be consistent in applying that transformation,
   and make it available for other nouns that match that verb. In other
   words, "git tag --switch". And however one might manipulate remote
   tracking branches ("git branch -r --switch", I guess).
   Personally I find it somewhat backwards, but I think CVS rotted my
   brain long ago.
-Peff
Jeff King· Nov 2, 2008, 03:53 UTC · re: Jeff King · lore
On Thu, Oct 30, 2008 at 08:31:54PM -0400, Jeff King wrote:
> So think of us as having three "spots": the HEAD (H), the "stage"[1] (S),
> and the working tree (W). And we want commands for moving content

Re-reading this, I realized I forgot to fill in my footnote. But it was going to be:

 [1] Actually, the term "the stage" is growing on me.
-Peff
Junio C Hamano· Nov 2, 2008, 22:27 UTC · re: Jeff King · lore
Jeff King <peff@peff.net> writes:
Show 5 quoted lines
>> +  * 'git push --matching' does what 'git push' does today (without
>> +    explicit configuration)
>
> I think this is reasonable even without other changes, just to override
> any configuration.

I don't. Can't you say "git push $there HEAD" these days? I vaguely recall that there is a way to configure push that way for people too lazy to type "origin HEAD" after "git push".

Show 7 quoted lines
>> +  * 'git export' command that does what
>> +    'git archive --format=tar --prefix=dir | tar x' does now
>
> I agree, if you mean "does what ... does now" means "looks to the user
> like ... is happening". This is much more sanely done using
> git-checkout-index (though somebody suggested "remote export", which
> would need to use tar itself).

I think I was neutral in the discussion that led to the removal of "git-export", but the rationale IIRC was exactly because "git-export" can be done by simply piping "git-tar" to tar. On the other hand, if all you had was "export" and you wanted to create a release tar/zip ball, you have to first create a (potentially huge) hierarchy in the filesystem only to archive it. This change needs to defend that the benefit of being able to create a new non-git checkout elsewhere on the filesystem far outweighs the downside of addition of another command (i.e. "eek, why does git have that many commands" from new people).

Sam Vilain· Nov 3, 2008, 05:59 UTC · re: Junio C Hamano · lore
On Sun, 2008-11-02 at 14:27 -0800, Junio C Hamano wrote:
Show 11 quoted lines
> Jeff King <peff@peff.net> writes:
> 
> >> +  * 'git push --matching' does what 'git push' does today (without
> >> +    explicit configuration)
> >
> > I think this is reasonable even without other changes, just to override
> > any configuration.
> 
> I don't.  Can't you say "git push $there HEAD" these days?  I vaguely
> recall that there is a way to configure push that way for people too lazy
> to type "origin HEAD" after "git push".

I don't think it's about laziness, it's more about making sure that without specifying behaviour, the action of the command is conservative. Pushing all matching refs is not conservative; it's "magic". And in my experience, people get bitten by it, because they think, "ok, time to push this branch", type "git push" and then a lot more than they expected gets pushed.

I can see that some people want this behaviour by default; but to me "push the current branch back to where it came from" seems like far more a rational default for at least 90% of users.

Sam.
Jakub Narebski· Nov 3, 2008, 09:48 UTC · re: Sam Vilain · lore
Sam Vilain wrote:
Show 23 quoted lines
> On Sun, 2008-11-02 at 14:27 -0800, Junio C Hamano wrote:
>> Jeff King <peff@peff.net> writes:
>> 
>>>> +  * 'git push --matching' does what 'git push' does today (without
>>>> +    explicit configuration)
>>>
>>> I think this is reasonable even without other changes, just to override
>>> any configuration.
>> 
>> I don't.  Can't you say "git push $there HEAD" these days?  I vaguely
>> recall that there is a way to configure push that way for people too lazy
>> to type "origin HEAD" after "git push".
> 
> I don't think it's about laziness, it's more about making sure that
> without specifying behaviour, the action of the command is conservative.
> Pushing all matching refs is not conservative; it's "magic".  And in my
> experience, people get bitten by it, because they think, "ok, time to
> push this branch", type "git push" and then a lot more than they
> expected gets pushed.
> 
> I can see that some people want this behaviour by default; but to me
> "push the current branch back to where it came from" seems like far more
> a rational default for at least 90% of users.
"git remote <remote> push" for push matching?
-- 
Jakub Narebski
Warsaw, Poland
ShadeHawk on #git
Sverre Rabbelier· Nov 3, 2008, 09:53 UTC · re: Jakub Narebski · lore
On Mon, Nov 3, 2008 at 10:48, Jakub Narebski <jnareb@gmail.com> wrote:
> "git remote <remote> push" for push matching?

Not another command that is made to perform yet another piece of funcionality. Let's let remote handle (configuring, and maintaining of) remote related things, not also make it do push stuff. Unless ofcourse, you mean that "git remote push <remote>" (certainly not the other way around) is for configuration only.

-- 
Cheers,

Sverre Rabbelier
Dmitry Potapov· Nov 4, 2008, 09:18 UTC · re: Sam Vilain · lore
On Mon, Nov 03, 2008 at 06:59:20PM +1300, Sam Vilain wrote:
> 
> I can see that some people want this behaviour by default; but to me
> "push the current branch back to where it came from" seems like far more
> a rational default for at least 90% of users.

I think it depends on one's workflow. If you use a centralized workflow as with CVS then yes, 90% cases you want to push the current branch. On the other hand, if people push their changes to the server only for review, it means that accidentally pushing more than one intended is not a big deal. The only one who does publishing to the official repository is the maintainer, and the maintainer is most likely to run some tests after merging all changes, which takes some time. So, it is rarely push the current branch, it is usually the branch that has been tested, so the name of the branch should be specified explicitly anyway.

Dmitry
Sam Vilain· Nov 4, 2008, 18:10 UTC · re: Dmitry Potapov · lore
On Tue, 2008-11-04 at 12:18 +0300, Dmitry Potapov wrote:
Show 9 quoted lines
> > I can see that some people want this behaviour by default; but to me
> > "push the current branch back to where it came from" seems like far more
> > a rational default for at least 90% of users.
> 
> I think it depends on one's workflow. If you use a centralized workflow
> as with CVS then yes, 90% cases you want to push the current branch. On
> the other hand, if people push their changes to the server only for
> review, it means that accidentally pushing more than one intended is not
> a big deal.

Perhaps not, but it was still unintended. I really can't understand the opposition to making this command make many people less angry at it.

Show 5 quoted lines
>  The only one who does publishing to the official repository
> is the maintainer, and the maintainer is most likely to run some tests
> after merging all changes, which takes some time. So, it is rarely push
> the current branch, it is usually the branch that has been tested, so
> the name of the branch should be specified explicitly anyway.

Why is that relevant? That person can still use the explicit version of the command.

Sam.
Junio C Hamano· Nov 4, 2008, 19:46 UTC · re: Sam Vilain · lore
Sam Vilain <sam@vilain.net> writes:
Show 10 quoted lines
> On Tue, 2008-11-04 at 12:18 +0300, Dmitry Potapov wrote:
> ...
>>  The only one who does publishing to the official repository
>> is the maintainer, and the maintainer is most likely to run some tests
>> after merging all changes, which takes some time. So, it is rarely push
>> the current branch, it is usually the branch that has been tested, so
>> the name of the branch should be specified explicitly anyway.
>
> Why is that relevant?  That person can still use the explicit version of
> the command.

Back when "git push $there :" were not available, the default matching behaviour was the _only_ way to say "I know the set of branches I want to publish, and I have many more private branches in my primary work repository. I do not want to list the set of branches to publish every time when I type 'git push', nor I want to configure it --- Heck, I shouldn't have to list them, the public repository I am pushing to already has that list, and it is the set of branches that exist there".

These days, people who would want the maching behaviour can explicitly ask for it, so there is one less reason to resist changing the default (i.e. earlier explicitly askinf for "matching" was impossible, but now we can). The remaining reason of resistance is pure inertia (i.e. not changing the behaviour of the command only because you upgraded your git), and the only way to address it is to start issuing the warning when "git push" or "git push $there" is used and the matching behaviour was chosen without configuration (i.e. no "remote.<there>.push = :"), and keep it that way for two release cycles, and finally change the default.

Jeff King· Nov 5, 2008, 03:05 UTC · re: Junio C Hamano · lore
On Tue, Nov 04, 2008 at 11:46:36AM -0800, Junio C Hamano wrote:
Show 9 quoted lines
> These days, people who would want the maching behaviour can explicitly ask
> for it, so there is one less reason to resist changing the default
> (i.e. earlier explicitly askinf for "matching" was impossible, but now we
> can).  The remaining reason of resistance is pure inertia (i.e. not
> changing the behaviour of the command only because you upgraded your git),
> and the only way to address it is to start issuing the warning when "git
> push" or "git push $there" is used and the matching behaviour was chosen
> without configuration (i.e. no "remote.<there>.push = :"), and keep it
> that way for two release cycles, and finally change the default.

Hmm. It really seems to me that there are two desires for push behavior, based on particular workflows. I.e., some people seem to want the matching behavior by default, and others want to push the current branch.

And we already can control that via configuration of the refspec. So any argument that "git push should do the same thing even on somebody else's setup" is already wrong. But I do think Junio has a good point, which is that there is going to be confusion if upgrading git suddenly causes "git push" to do something else.

So why not take one step back in the behavior change? We can set up the "push just this branch" refspec during clone, which will leave existing repositories untouched. And to make things even gentler, we can start with opt-in to the clone feature, notify users via the release notes (which, as we have established, EVERYONE reads), and then decide if and when to switch the option on by default.

So something like a "remote.push" config option, the value of which gets added to newly created remotes (including those created on clone). It would default to ":", but you could easily set "git config remote.push HEAD" to get the other behavior.

No, this doesn't get rid of the eventual need to choose whether to switch the default. But I think it eases us into it a little more. And I think such an option is a lot more generally applicable than a "default push to matching versus HEAD" option.

-Peff
Junio C Hamano· Nov 5, 2008, 06:40 UTC · re: Jeff King · lore
Jeff King <peff@peff.net> writes:
> So why not take one step back in the behavior change? We can set up the
> "push just this branch" refspec during clone, which will leave existing
> repositories untouched.
That is not good enough.

People who (think) know what an unconfigured "git push" would do would suddenly see "git push" start misbehaving in their new repositories.

Here is a patch to do what I suggested earlier.  It
 * Adds "--matching" option; if we ever change the default to "current
   branch only", then "git push $there :" forces people to type $there.
   "git push --matching" allows us to honor "branch.<name>.remote".
 * Issues a deprecation warning when "git push" and "git push $there" is
   used to trigger the "matching" behaviour, without configuration or
   explicit command line refspec ":".

Whoever wants to change the default to "current branch only" can change the part that calls push_deprecation_warning().

I'll leave it up to people who want to change the default to implement the same for non native transports and document the transition plan, as I am not very keen on changing the default myself.

---
 builtin-push.c      |   11 +++++++----
 builtin-send-pack.c |    2 ++
 remote.c            |    8 ++++++++
 remote.h            |    1 +
 send-pack.h         |    1 +
 transport.c         |    1 +
 transport.h         |    1 +
 7 files changed, 21 insertions(+), 4 deletions(-)
Show changes to diff +21 −4
diff --git c/builtin-push.c w/builtin-push.c
index 122fdcf..21418ab 100644
--- c/builtin-push.c
+++ w/builtin-push.c
@@ -10,7 +10,7 @@
 #include "parse-options.h"
 
 static const char * const push_usage[] = {
-	"git push [--all | --mirror] [--dry-run] [--tags] [--receive-pack=<git-receive-pack>] [--repo=<repository>] [-f | --force] [-v] [<repository> <refspec>...]",
+	"git push [--all | --mirror] [--dry-run] [--matching] [--tags] [--receive-pack=<git-receive-pack>] [--repo=<repository>] [-f | --force] [-v] [<repository> <refspec>...]",
 	NULL,
 };
 
@@ -71,9 +71,11 @@ static int do_push(const char *repo, int flags)
 		return error("--mirror can't be combined with refspecs");
 	}
 
-	if ((flags & (TRANSPORT_PUSH_ALL|TRANSPORT_PUSH_MIRROR)) ==
-				(TRANSPORT_PUSH_ALL|TRANSPORT_PUSH_MIRROR)) {
-		return error("--all and --mirror are incompatible");
+	if (HAS_MULTI_BITS(flags &
+			   (TRANSPORT_PUSH_ALL|
+			    TRANSPORT_PUSH_MIRROR|
+			    TRANSPORT_PUSH_MATCHING))) {
+		return error("--all, --mirror, --matching are incompatible");
 	}
 
 	if (!refspec
@@ -123,6 +125,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)
 		OPT_BOOLEAN( 0 , "tags", &tags, "push tags"),
 		OPT_BIT( 0 , "dry-run", &flags, "dry run", TRANSPORT_PUSH_DRY_RUN),
 		OPT_BIT('f', "force", &flags, "force updates", TRANSPORT_PUSH_FORCE),
+		OPT_BIT( 0 , "matching", &flags, "push matching", TRANSPORT_PUSH_MATCHING),
 		OPT_BOOLEAN( 0 , "thin", &thin, "use thin pack"),
 		OPT_STRING( 0 , "receive-pack", &receivepack, "receive-pack", "receive pack program"),
 		OPT_STRING( 0 , "exec", &receivepack, "receive-pack", "receive pack program"),
diff --git c/builtin-send-pack.c w/builtin-send-pack.c
index d68ce2d..f5dda88 100644
--- c/builtin-send-pack.c
+++ w/builtin-send-pack.c
@@ -402,6 +402,8 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest
 		flags |= MATCH_REFS_ALL;
 	if (args.send_mirror)
 		flags |= MATCH_REFS_MIRROR;
+	if (args.send_matching)
+		flags |= MATCH_REFS_MATCHING;
 
 	/* No funny business with the matcher */
 	remote_tail = get_remote_heads(in, &remote_refs, 0, NULL, REF_NORMAL,
diff --git c/remote.c w/remote.c
index e530a21..ce4f54c 100644
--- c/remote.c
+++ w/remote.c
@@ -1017,6 +1017,12 @@ static const struct refspec *check_pattern_match(const struct refspec *rs,
 		return NULL;
 }
 
+static void push_deprecation_warning(void)
+{
+	warning("'git push [$remote]' will stop pushing 'matching refs' in a future release");
+	warning("please train your fingers to say 'git push --matching' instead.");
+}
+
 /*
  * Note. This is used only by "push"; refspec matching rules for
  * push and fetch are subtly different, so do not try to reuse it
@@ -1031,6 +1037,8 @@ int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,
 	static const char *default_refspec[] = { ":", 0 };
 
 	if (!nr_refspec) {
+		if (!(flags & MATCH_REFS_MATCHING))
+			push_deprecation_warning();
 		nr_refspec = 1;
 		refspec = default_refspec;
 	}
diff --git c/remote.h w/remote.h
index d2e170c..2a702cb 100644
--- c/remote.h
+++ w/remote.h
@@ -124,6 +124,7 @@ enum match_refs_flags {
 	MATCH_REFS_NONE		= 0,
 	MATCH_REFS_ALL 		= (1 << 0),
 	MATCH_REFS_MIRROR	= (1 << 1),
+	MATCH_REFS_MATCHING	= (1 << 2),
 };
 
 /* Reporting of tracking info */
diff --git c/send-pack.h w/send-pack.h
index 8ff1dc3..133cb67 100644
--- c/send-pack.h
+++ w/send-pack.h
@@ -6,6 +6,7 @@ struct send_pack_args {
 	unsigned verbose:1,
 		send_all:1,
 		send_mirror:1,
+		send_matching:1,
 		force_update:1,
 		use_thin_pack:1,
 		dry_run:1;
diff --git c/transport.c w/transport.c
index 56831c5..4057d27 100644
--- c/transport.c
+++ w/transport.c
@@ -680,6 +680,7 @@ static int git_transport_push(struct transport *transport, int refspec_nr, const
 	args.receivepack = data->receivepack;
 	args.send_all = !!(flags & TRANSPORT_PUSH_ALL);
 	args.send_mirror = !!(flags & TRANSPORT_PUSH_MIRROR);
+	args.send_matching = !!(flags & TRANSPORT_PUSH_MATCHING);
 	args.force_update = !!(flags & TRANSPORT_PUSH_FORCE);
 	args.use_thin_pack = data->thin;
 	args.verbose = !!(flags & TRANSPORT_PUSH_VERBOSE);
diff --git c/transport.h w/transport.h
index 6bbc1a8..fb98128 100644
--- c/transport.h
+++ w/transport.h
@@ -34,6 +34,7 @@ struct transport {
 #define TRANSPORT_PUSH_DRY_RUN 4
 #define TRANSPORT_PUSH_MIRROR 8
 #define TRANSPORT_PUSH_VERBOSE 16
+#define TRANSPORT_PUSH_MATCHING 32
 
 /* Returns a transport suitable for the url */
 struct transport *transport_get(struct remote *, const char *);
Dmitry Potapov· Nov 5, 2008, 22:53 UTC · re: Sam Vilain · lore
On Wed, Nov 05, 2008 at 07:10:31AM +1300, Sam Vilain wrote:
Show 12 quoted lines
> On Tue, 2008-11-04 at 12:18 +0300, Dmitry Potapov wrote:
> > > I can see that some people want this behaviour by default; but to me
> > > "push the current branch back to where it came from" seems like far more
> > > a rational default for at least 90% of users.
> > 
> > I think it depends on one's workflow. If you use a centralized workflow
> > as with CVS then yes, 90% cases you want to push the current branch. On
> > the other hand, if people push their changes to the server only for
> > review, it means that accidentally pushing more than one intended is not
> > a big deal.
> 
> Perhaps not, but it was still unintended.

Even if it were unintended, it will be noticed and corrected immediately, while forgetting to push some changes is not so obvious... Anyway, your workflow assumes that one wants to push changes immediately before switching to another branch, while there are many people who do that later (after some additional testing or just at the end of their workday).

> I really can't understand the
> opposition to making this command make many people less angry at it.

Because it breaks how this command works now. So I don't think it is a good idea to make some people less angry while enraging many others over breaking their workflow. Compatibility should not be taken lightly.

Dmitry
Jeff King· Nov 3, 2008, 06:56 UTC · re: Junio C Hamano · lore
On Sun, Nov 02, 2008 at 02:27:57PM -0800, Junio C Hamano wrote:
Show 9 quoted lines
> >> +  * 'git push --matching' does what 'git push' does today (without
> >> +    explicit configuration)
> >
> > I think this is reasonable even without other changes, just to override
> > any configuration.
> 
> I don't.  Can't you say "git push $there HEAD" these days?  I vaguely
> recall that there is a way to configure push that way for people too lazy
> to type "origin HEAD" after "git push".

I think you are reading more into my statement than I intended. I meant that adding an explicit --matching was reasonable, _even if it matches the default_. I can think of two reasons:

 1. Even if it is a no-op, it is more explicit for showing newbies what
    is going on. And it also means that _if_ we wanted to introduce
    new behavior or configurability, we will have already had
    "--matching" for some time. So it will be safe(r) at that point to
    immediately start saying "--matching" in your scripts to specify the
    behavior you want, without as much worry about confusing an older
    version.
 2. Even today, the behavior of push can be modified with configuration
    in remote.*.mirror. I would expect "git push --matching" to override
    this. Though perhaps that is too confusing a behavior, as mirroring
    does more than just ref selection, including force-updating.

So my statement was not anything about "git push $there HEAD", but just that adding "--matching" was reasonable.

Show 9 quoted lines
> I think I was neutral in the discussion that led to the removal of
> "git-export", but the rationale IIRC was exactly because "git-export" can
> be done by simply piping "git-tar" to tar.  On the other hand, if all you
> had was "export" and you wanted to create a release tar/zip ball, you have
> to first create a (potentially huge) hierarchy in the filesystem only to
> archive it.  This change needs to defend that the benefit of being able to
> create a new non-git checkout elsewhere on the filesystem far outweighs
> the downside of addition of another command (i.e. "eek, why does git have
> that many commands" from new people).

I think the complaint is just that it is awkward to have to pipe to tar (and harder to check error status), when "export to directory" is a reasonably common request.

If the concern is about another command, then perhaps rather than "git export" it would be simpler to have "git archive --format=dir" as a convenience (and it could even use the checkout-index optimization in the local case, rather than generating a tar).

-Peff
Jeff King· Nov 3, 2008, 06:59 UTC · re: Jeff King · lore
On Mon, Nov 03, 2008 at 01:56:36AM -0500, Jeff King wrote:
> So my statement was not anything about "git push $there HEAD", but just
> that adding "--matching" was reasonable.

And btw, I am not saying I necessarily disagree with Sam's proposal about bare "git push". I am undecided about the best course of action there.

I just wanted to make clear that it was not what I was talking about in the original mail.

-Peff
Pierre Habouzit· Nov 3, 2008, 09:25 UTC · re: Junio C Hamano · lore
On Sun, Nov 02, 2008 at 10:27:57PM +0000, Junio C Hamano wrote:
Show 11 quoted lines
> Jeff King <peff@peff.net> writes:
> 
> >> +  * 'git push --matching' does what 'git push' does today (without
> >> +    explicit configuration)
> >
> > I think this is reasonable even without other changes, just to override
> > any configuration.
> 
> I don't.  Can't you say "git push $there HEAD" these days?  I vaguely
> recall that there is a way to configure push that way for people too lazy
> to type "origin HEAD" after "git push".

Yes, but it's broken in the sense that if you're in a non matching branch it creates it remotely. The way to configure it is to say remote.push = HEAD in your .gitconfig or sth similar. I removed it because I've created 2 times a new branch remotely that I didn't want to because I was tired and forgot to checkout and merge into the proper one.

I rarely do mistakes with git, but something like more than half of my mistakes are with push. I've argued that in the past, I know most of the other core git developers disagree with the fact that git-push UI is not helping users to not shoot themselves in the foot, I disagree, but there is not much I can do if I'm 1:10 to think that ;)

-- 
·O·  Pierre Habouzit
··O                                                madcoder@debian.org
OOO                                                http://www.madism.org
Junio C Hamano· Nov 3, 2008, 23:33 UTC · re: Pierre Habouzit · lore
Pierre Habouzit <madcoder@debian.org> writes:
Show 15 quoted lines
> On Sun, Nov 02, 2008 at 10:27:57PM +0000, Junio C Hamano wrote:
>> Jeff King <peff@peff.net> writes:
>> 
>> >> +  * 'git push --matching' does what 'git push' does today (without
>> >> +    explicit configuration)
>> >
>> > I think this is reasonable even without other changes, just to override
>> > any configuration.
>> 
>> I don't.  Can't you say "git push $there HEAD" these days?  I vaguely
>> recall that there is a way to configure push that way for people too lazy
>> to type "origin HEAD" after "git push".
>
> Yes, but it's broken in the sense that if you're in a non matching
> branch it creates it remotely.
Ok, I agree that may be a problem.

But that would not change if you only changed the default behaviour from matching to _this branch_. You need to also teach a new mode of operation to send-pack/receive-pack pair, which is to "update the same branch as the one I am on locally, but do not do anything if there is no such branch over there". I do not think we have such a mode of operation currently.

By the way, didn't we add a feature to let you say "git push $there :" which is to do what "git push --matching $there" would do?

Pierre Habouzit· Nov 4, 2008, 00:02 UTC · re: Junio C Hamano · lore
On Mon, Nov 03, 2008 at 11:33:10PM +0000, Junio C Hamano wrote:
Show 25 quoted lines
> Pierre Habouzit <madcoder@debian.org> writes:
> 
> > On Sun, Nov 02, 2008 at 10:27:57PM +0000, Junio C Hamano wrote:
> >> Jeff King <peff@peff.net> writes:
> >> 
> >> >> +  * 'git push --matching' does what 'git push' does today (without
> >> >> +    explicit configuration)
> >> >
> >> > I think this is reasonable even without other changes, just to override
> >> > any configuration.
> >> 
> >> I don't.  Can't you say "git push $there HEAD" these days?  I vaguely
> >> recall that there is a way to configure push that way for people too lazy
> >> to type "origin HEAD" after "git push".
> >
> > Yes, but it's broken in the sense that if you're in a non matching
> > branch it creates it remotely.
> 
> Ok, I agree that may be a problem.
> 
> But that would not change if you only changed the default behaviour from
> matching to _this branch_.  You need to also teach a new mode of operation
> to send-pack/receive-pack pair, which is to "update the same branch as the
> one I am on locally, but do not do anything if there is no such branch
> over there".  I do not think we have such a mode of operation currently.
You're right.
> By the way, didn't we add a feature to let you say "git push $there :"
> which is to do what "git push --matching $there" would do?

I don't know, I thought git push --matching $remote would be the same as git push $remote ?

-- 
·O·  Pierre Habouzit
··O                                                madcoder@debian.org
OOO                                                http://www.madism.org
Junio C Hamano· Nov 4, 2008, 00:44 UTC · re: Pierre Habouzit · lore
Pierre Habouzit <madcoder@debian.org> writes:
Show 9 quoted lines
>> Ok, I agree that may be a problem.
>> 
>> But that would not change if you only changed the default behaviour from
>> matching to _this branch_.  You need to also teach a new mode of operation
>> to send-pack/receive-pack pair, which is to "update the same branch as the
>> one I am on locally, but do not do anything if there is no such branch
>> over there".  I do not think we have such a mode of operation currently.
>
> You're right.
Perhaps "git push --no-create"?

In hindsight, _if_ we did not have to worry about backward compatibility at all, I might agree that the way "git push" ought to work with least surprise would be:

 * "git push" is the same as "git push origin" (override 'origin' with
   branch.$current_branch.remote);
 * "git push $remote" is the same as "git push --no-create $remote HEAD"
   (override 'HEAD' with remote.$remote.push);
 * "git push $remote $any_non_empty_refspec" does what it is told without
   configuration interfering.

Current behaviour satisfies the first one and the third one. Instead of the second, the current behaviour is:

 * "git push $remote" is the same as "git push $remote :" (override ':'
   with remote.$remote.push).
Show 5 quoted lines
>> By the way, didn't we add a feature to let you say "git push $there :"
>> which is to do what "git push --matching $there" would do?
>
> I don't know, I thought git push --matching $remote would be the same as
> git push $remote ?

I think the point of "push --matching" (or an explicit "push $there :") is so that you can defeat what you configured. For example, you could have:

	[branch "master"]
        	remote = gitster
	[remote "gitster"]
        	url = gitster:/pub/git/git.git/
                push = HEAD

And with such a configuration, "git push" or "git push gitster" would only push to the current branch.

You can countermand with "push gitster master next", of course, but you would need a way to ask for the matching from the command line without listing all the names, hence you would say "push gitster :".

I think you meant to give the --matching option the same efffect. My comment is that you do not need a new option, as we already have that feature.

Jeff King· Nov 4, 2008, 05:20 UTC · re: Junio C Hamano · lore
On Mon, Nov 03, 2008 at 03:33:10PM -0800, Junio C Hamano wrote:
> By the way, didn't we add a feature to let you say "git push $there :"
> which is to do what "git push --matching $there" would do?

Oh, indeed: a83619d (add special "matching refs" refspec) from April. So given that, I think my arguments for "--matching" are pointless.

-Peff

← back to recent threads