On Mon, Apr 02, 2012 at 09:40:22AM +0200, Matthieu Moy wrote:
quoted
For the others, they already have to learn about the "upstream"
semantics. And making argumentless "git pull" and "git push" purposely
asymetric to make it simple for the user sounds like an oxymoron to me.
We can make the operations technically symmetric in terms of the actual
sources and destinations from which commits are moved, but they are not
necessarily symmetric in the user's workflow.
It seems rather natural to me to have "asymetric workflow, asymetric
commands" by default. So, if one wants to push to a place other than
upstream, say "git push public-repo branch", or set your upstream to
where you want to push (simple with "git push -u"), and say explicitely
"git pull repo branch".
I can hardly imagine someone knowing what "git pull" does, and
_surprised_ to see that "git push" sends commits to the same place. I
agree that sending commits to upstream may be a mistake, but I don't
think it can happen "by surprise".
There are also ways to shoot yourself in the foot with when setting
upstream to something other that where you usually push. For example,
run "git rebase -i" without argument, and it will offer you to rewrite
some published history. "git pull --rebase" also becomes a potentially
dangerous operation, while it's normally harmless with
'push.default=upstream'.
And I still have my concern with real beginners: what advice would you
give to a user whose "git push" is denied because of non-fast forward. I
raised this concern already:
http://thread.gmane.org/gmane.comp.version-control.git/192547/focus=193196
and I essentially had the answer "telling the user to pull is wrong"
(with which I disagree), but no one managed to give another advice.
With real-real-newbies, this is my number 1 issue (they don't even do
branches, they just run push, git tells them to pull, and they come to
me saying "git is broken, we can't work"). With not-so-newbies, I have
less experience ;-).
quoted
The discussion seems to focuse on 'let's make "git push" easy to
explain', but I think the right thing to do is to make _Git_ easy to
explain. With "push.default = current", we'll have a hard time
explaining how "git pull" works.
Do we have a hard time explaining how "git pull" works now?
I don't think so, but Junio's argument is that explaining what push
would do with 'upstream' would be too complex, and that 'current' is
easier to explain. If 'git pull' is simple, then 'git -c
push.current=upstream push' is equally simple.
--
Matthieu Moy
http://www-verimag.imag.fr/~moy/
From: Jeff King <hidden> Date: 2016-06-15 22:53:28
On Thu, Apr 05, 2012 at 06:46:51PM +0200, Matthieu Moy wrote:
It seems rather natural to me to have "asymetric workflow, asymetric
commands" by default. So, if one wants to push to a place other than
upstream, say "git push public-repo branch", or set your upstream to
where you want to push (simple with "git push -u"), and say explicitely
"git pull repo branch".
That makes sense _if_ the user is thinking about pull and push as
symmetric commands. That may be immediately obvious for some people's
mental models. But I suspect it is not for others (it is not for mine,
though I obviously do not count as a beginner).
I can hardly imagine someone knowing what "git pull" does, and
_surprised_ to see that "git push" sends commits to the same place. I
agree that sending commits to upstream may be a mistake, but I don't
think it can happen "by surprise".
You are asking the new user to make a logical inference about the
relationship between push and pull. That inference may seem obvious to
you, and it may even be obvious to a large portion of new users. But
keep in mind that we are not debating whether "upstream" is a reasonable
thing for git to have, but rather whether it is a good default. My
concern is that upstream as a default would have negligible benefit for
people who do make the inference, but be dangerous for the group who do
not. We don't know the size of the latter, but my feeling is that it is
non-trivial.
There are also ways to shoot yourself in the foot with when setting
upstream to something other that where you usually push. For example,
run "git rebase -i" without argument, and it will offer you to rewrite
some published history.
Yes, although that is often what you want in such a setup (e.g., you are
rebasing on top of the upstream branch, but publishing your work in
progress). However, I do agree that it can potentially be dangerous.
Two helpful saving graces are:
1. The first thing you see upon "git rebase -i" is a giant list of the
commits from your upstream branch. It is usually quite obvious that
you are rebasing more than you want in this case, and you can abort
before doing anything.
2. Even if you do rebase, you have made a _local_ error. You are not
hurting anyone until you push, at which point you will get a
non-fast-forward error, and you have a chance to fix things before
disrupting other people.
And I still have my concern with real beginners: what advice would you
give to a user whose "git push" is denied because of non-fast forward. I
raised this concern already:
http://thread.gmane.org/gmane.comp.version-control.git/192547/focus=193196
and I essentially had the answer "telling the user to pull is wrong"
(with which I disagree), but no one managed to give another advice.
It _is_ wrong unless the destination branch is also the configured
upstream. Which yes, it probably is if push.default is "upstream".
Unless you actually specified a push destination, in which case it may
not be. Or if you were pushing something besides HEAD.
If the push destination was $remote:$branch, it seems the only correct
thing is to suggest "git pull $remote $branch" in the general case, and
possibly simplify that to "git pull" if $remote:$branch is the
configured upstream. And if the source was HEAD, of course; otherwise
you would need to checkout.
So shouldn't the advice for a non-fast-forward push be:
if $source_ref is currently checked out
advise "git checkout $source_ref, and then..."
fi
if $dest_remote == branch.$source_ref.remote &&
$dest_ref == branch.$source_ref.merge
advise "git pull"
else
advise "git pull $dest_remote $dest_ref"
fi
That handles only one ref, of course. If you get multiple non-ff
failures, I'm not sure what we should advise.
quoted
quoted
The discussion seems to focuse on 'let's make "git push" easy to
explain', but I think the right thing to do is to make _Git_ easy to
explain. With "push.default = current", we'll have a hard time
explaining how "git pull" works.
Do we have a hard time explaining how "git pull" works now?
I don't think so, but Junio's argument is that explaining what push
would do with 'upstream' would be too complex, and that 'current' is
easier to explain. If 'git pull' is simple, then 'git -c
push.current=upstream push' is equally simple.
You wrote above that we'll have a hard time explaining how "git pull"
works. But I don't think so; if it hasn't been a problem with
"matching", then why would it with "current"?
I agree that your symmetry explanation is reasonably simple for
explaining what "git push" will do for new users (though I also think
"current" is quite easy to explain). I'm less concerned with explaining
and more concerned about safe defaults.
-Peff
On Thu, Apr 5, 2012 at 8:46 PM, Matthieu Moy
[off-list ref] wrote:
I can hardly imagine someone knowing what "git pull" does, and
_surprised_ to see that "git push" sends commits to the same place.
It seems you assume that people use in a _centralized_ workflow.
In this case, 'upstream' does largely the right thing, so no one
will be surprised.
However, many of those who got used to a distributed workflow will find
that surprising, because when they created a new branch that meant it
to push as a _new_ branch. So other people could take a look, or they
may need the maintainer ACK to push anything to 'master'. Also they may
have a policy nothing should be fast-forwarded to master, but only to
be merged with a merge commit.
And then it is more natural for people to think in terms of names that
are immediately obvious to anyone, while 'upstream' behavior depends on
the state that is not immediately obvious. You may start a new topic
branch based on 'master' or some the latest release to have a more
stable base. And 'upstream' will work differently in this case. If you
know about 'tracking' then it may be obvious to you, but it is not so
obvious to those who only start to use git for short time...
And I still have my concern with real beginners: what advice would you
give to a user whose "git push" is denied because of non-fast forward. I
raised this concern already:
Don't use a central workflow, because it sucks :)
Seriously, why do you care about beginners who use a centralized workflow
and not beginners who have to use with existing projects that use more or
less distributed workflow, where pushing to 'master' is more likely to be
the wrong thing to do than otherwise... And when push is denied, they may
ask someone whether they are doing something wrong. In case when master
is fast-forwarded silently, they are not likely to notice that they did
something wrong, and the fact that happens only sometimes (depending on
some "tracking" feature which they have not heard) is not very helpful.
Dmitry
On 6 April 2012 13:38, Dmitry Potapov [off-list ref] wrote:
Seriously, why do you care about beginners who use a centralized workflow
and not beginners who have to use with existing projects that use more or
less distributed workflow,
Because the former are unlikely to be self-selected users of git and
instead are likely to be forced to use git because their $work has
dictated it to be so. The self-selected users of git IMO would tend to
both have the motivation and the basic skills to learn whatever they
need and are unlikely to blame their mistakes on git. The ones forced
to use git are *very* likely to say "git is broken", or "git doesn't
work" and then start arguing that "cvs never had that problem". Do you
really want a bunch of users of your software thinking CVS was
superior?
I would say the right default is the one that keeps idiot users happy,
and has the least "out of the box surprises" for them. The smart ones
will figure things out anyway and configure their tools appropriately.
cheers
Yves
--
perl -Mre=debug -e "/just|another|perl|hacker/"
On Fri, Apr 6, 2012 at 5:36 PM, demerphq [off-list ref] wrote:
On 6 April 2012 13:38, Dmitry Potapov [off-list ref] wrote:
quoted
Seriously, why do you care about beginners who use a centralized workflow
and not beginners who have to use with existing projects that use more or
less distributed workflow,
Because the former are unlikely to be self-selected users of git and
instead are likely to be forced to use git because their $work has
dictated it to be so.
Any decision is made by people. On its own, $work does not dictate what
VCS or what workflow should be used. There are many ways for those who
are in charge to screw up things. And a centralized workflow is not very
scalable and many bad practices associated with it. While it is not easy
to to convert a CVS/SVN repository to git that alone does not bring most
of git advantages, because those advantages come from the workflow.
The self-selected users of git IMO would tend to
both have the motivation and the basic skills to learn whatever they
need and are unlikely to blame their mistakes on git. The ones forced
to use git are *very* likely to say "git is broken", or "git doesn't
work" and then start arguing that "cvs never had that problem". Do you
really want a bunch of users of your software thinking CVS was
superior?
Git is a distributed version control system. There is another VCS whose
whole designed was dictated by being a better CVS. It's called SVN and
if someone is happy with it, why do not use it?
I think git default settings should respect the main goal of git design:
a good support of a distributed workflow. Certainly git can be used in
many other ways: some people use it with a centralized workflow, some
use it to back up their configuration files, etc.. But those usage
should not dictate the default settings for git.
Dmitry
On 6 April 2012 20:03, Dmitry Potapov [off-list ref] wrote:
On Fri, Apr 6, 2012 at 5:36 PM, demerphq [off-list ref] wrote:
quoted
On 6 April 2012 13:38, Dmitry Potapov [off-list ref] wrote:
quoted
Seriously, why do you care about beginners who use a centralized workflow
and not beginners who have to use with existing projects that use more or
less distributed workflow,
Because the former are unlikely to be self-selected users of git and
instead are likely to be forced to use git because their $work has
dictated it to be so.
Any decision is made by people. On its own, $work does not dictate what
VCS or what workflow should be used. There are many ways for those who
are in charge to screw up things. And a centralized workflow is not very
scalable and many bad practices associated with it. While it is not easy
to to convert a CVS/SVN repository to git that alone does not bring most
of git advantages, because those advantages come from the workflow.
Pretty well every project that uses git has a "canonical upstream
repository". Including for instance this one. Which basically means at
some point there is a centralized master repo. It is either owned by
someone like Linus or Junio, or it is owned by a company. Companies
tend to like to know that their valuable data is properly backed up,
and etc. This basically means central repos are inevitable. And git
works just fine like that thank you very much.
quoted
The self-selected users of git IMO would tend to
both have the motivation and the basic skills to learn whatever they
need and are unlikely to blame their mistakes on git. The ones forced
to use git are *very* likely to say "git is broken", or "git doesn't
work" and then start arguing that "cvs never had that problem". Do you
really want a bunch of users of your software thinking CVS was
superior?
Git is a distributed version control system. There is another VCS whose
whole designed was dictated by being a better CVS. It's called SVN and
if someone is happy with it, why do not use it?
Because it sucks.
I think git default settings should respect the main goal of git design:
a good support of a distributed workflow. Certainly git can be used in
many other ways: some people use it with a centralized workflow, some
use it to back up their configuration files, etc.. But those usage
should not dictate the default settings for git.
I stick to my original point, it should be aimed at making dumb people
happy. The rest will sort themselves out.
Yves
--
perl -Mre=debug -e "/just|another|perl|hacker/"
On Fri, Apr 6, 2012 at 10:48 PM, demerphq [off-list ref] wrote:
On 6 April 2012 20:03, Dmitry Potapov [off-list ref] wrote:
quoted
On Fri, Apr 6, 2012 at 5:36 PM, demerphq [off-list ref] wrote:
quoted
On 6 April 2012 13:38, Dmitry Potapov [off-list ref] wrote:
quoted
Seriously, why do you care about beginners who use a centralized workflow
and not beginners who have to use with existing projects that use more or
less distributed workflow,
Because the former are unlikely to be self-selected users of git and
instead are likely to be forced to use git because their $work has
dictated it to be so.
Any decision is made by people. On its own, $work does not dictate what
VCS or what workflow should be used. There are many ways for those who
are in charge to screw up things. And a centralized workflow is not very
scalable and many bad practices associated with it. While it is not easy
to to convert a CVS/SVN repository to git that alone does not bring most
of git advantages, because those advantages come from the workflow.
Pretty well every project that uses git has a "canonical upstream
repository". Including for instance this one. Which basically means at
some point there is a centralized master repo. It is either owned by
someone like Linus or Junio, or it is owned by a company. Companies
tend to like to know that their valuable data is properly backed up,
and etc. This basically means central repos are inevitable. And git
works just fine like that thank you very much.
It seems you confuse a centralized workflow with existence of an official
(central) repository. It is not same...
Dmitry
From: Christopher Tiwald <hidden> Date: 2016-06-15 22:53:33
On Fri, Apr 06, 2012 at 03:15:20AM -0400, Jeff King wrote:
So shouldn't the advice for a non-fast-forward push be:
if $source_ref is currently checked out
advise "git checkout $source_ref, and then..."
fi
if $dest_remote == branch.$source_ref.remote &&
$dest_ref == branch.$source_ref.merge
advise "git pull"
else
advise "git pull $dest_remote $dest_ref"
fi
That handles only one ref, of course. If you get multiple non-ff
failures, I'm not sure what we should advise.
Hmmm. Maybe something like this? Note to reviewers: This is necessarily
based on ct/advise-push-default.
Assuming this logic is sound and the patch is a reasonable change, I'm not
wedded to "pushNonFFCurrentUntracked" and "pushNonFFCurrentTracked". I'm
concerned both config options are a bit too long. Is there a better, more
concise way to specify those config options?
---- >8 ----
Suppose a user configured a local branch to track an upstream branch by
a different name or didn't set an upstream branch at all. In these
cases, issuing 'git pull' without specifying a remote repository or
refspec can be dangerous. In the first case, 'git pull --rebase' could
rewrite published history. In the second, 'git pull' without argument
will fail.
Modify 'git push's non-fast-forward advice to account for these cases.
Instruct users who push a non-fast-forward update to their current
branch to 'git pull <repository> <refspec>' when the branch is untracked
or tracks to a different repo or refspec then the one they specified.
Otherwise, instruct users to 'git pull'. Make both types of advice
configurable, so that users who disable one won't disable the other on
accident. Finally, offer users who configure a branch for octopus
merges, i.e. where 'branch->merge_nr > 1', the simple 'git pull' advice.
Signed-off-by: Christopher Tiwald <redacted>
---
Documentation/config.txt | 9 +++++++--
advice.c | 6 ++++--
advice.h | 3 ++-
builtin/push.c | 48 +++++++++++++++++++++++++++++++++++++++++-----
4 files changed, 56 insertions(+), 10 deletions(-)
@@ -141,9 +141,14 @@ advice.*:: Set this variable to 'false' if you want to disable 'pushNonFFCurrent', 'pushNonFFDefault', and 'pushNonFFMatching' simultaneously.- pushNonFFCurrent::+ pushNonFFCurrentUntracked:: Advice shown when linkgit:git-push[1] fails due to a- non-fast-forward update to the current branch.+ non-fast-forward update to the current branch and that+ branch doesn't match the tracked remote and refspec.+ pushNonFFCurrentTracked::+ Advice shown when linkgit:git-push[1] fails due to a+ non-fast-forward update to the current branch and that+ branch matches the tracked remote and refspec. pushNonFFDefault:: Advice to set 'push.default' to 'upstream' or 'current' when you ran linkgit:git-push[1] and pushed 'matching
@@ -118,12 +118,18 @@ static void setup_default_push_refspecs(struct remote *remote)}}-staticconstcharmessage_advice_pull_before_push[]=+staticconstcharmessage_advice_tracked_pull_before_push[]=N_("Updates were rejected because the tip of your current branch is behind\n""its remote counterpart. Merge the remote changes (e.g. 'git pull')\n""before pushing again.\n""See the 'Note about fast-forwards' in 'git push --help' for details.");+staticconstcharmessage_advice_untracked_pull_before_push[]=+N_("Updates were rejected because the tip of your current branch is behind\n"+"its remote counterpart. Merge the remote changes to your local branch\n"+"(e.g. 'git pull <repository> <refspec>') before pushing again.\n"+"See the 'Note about fast-forwards' in 'git push --help' for details.");+staticconstcharmessage_advice_use_upstream[]=N_("Updates were rejected because a pushed branch tip is behind its remote\n""counterpart. If you did not intend to push that branch, you may want to\n"
@@ -136,11 +142,20 @@ static const char message_advice_checkout_pull_push[] ="(e.g. 'git pull') before pushing again.\n""See the 'Note about fast-forwards' in 'git push --help' for details.");-staticvoidadvise_pull_before_push(void)+staticvoidadvise_tracked_pull_before_push(void)+{+if(!advice_push_non_ff_current_tracked||+!advice_push_nonfastforward)+return;+advise(_(message_advice_tracked_pull_before_push));+}++staticvoidadvise_untracked_pull_before_push(void){-if(!advice_push_non_ff_current||!advice_push_nonfastforward)+if(!advice_push_non_ff_current_untracked||+!advice_push_nonfastforward)return;-advise(_(message_advice_pull_before_push));+advise(_(message_advice_untracked_pull_before_push));}staticvoidadvise_use_upstream(void)
@@ -161,6 +176,16 @@ static int push_with_options(struct transport *transport, int flags){interr;intnonfastforward;+structbranch*branch;+structstrbufbuf=STRBUF_INIT;++branch=branch_get(NULL);++if(branch){+strbuf_addstr(&buf,transport->remote->name);+strbuf_addstr(&buf,"/");+strbuf_addstr(&buf,branch->name);+}transport_set_verbosity(transport,verbosity,progress);
@@ -185,7 +210,18 @@ static int push_with_options(struct transport *transport, int flags)default:break;caseNON_FF_HEAD:-advise_pull_before_push();+/* Branches configured for octopus merges should advise+*just'gitpull'*/+if(branch->remote_name&&+branch->merge&&+branch->merge_nr==1&&+!strcmp(transport->remote->name,branch->remote_name)&&+!strcmp(strbuf_detach(&buf,NULL),+prettify_refname(branch->merge[0]->dst))){+advise_tracked_pull_before_push();+}+else+advise_untracked_pull_before_push();break;caseNON_FF_OTHER:if(default_matching_used)
@@ -195,6 +231,8 @@ static int push_with_options(struct transport *transport, int flags)break;}+strbuf_release(&buf);+return1;}