i just had a rather annoying session with git - here's the dump and
commentary, in case anyone is interested in usability fineprint.
it was with git-core-1.5.4.3-2.fc8 - so if it's all fixed/improved in
1.5.5, or if this is blatant user error for which i deserve to be
punished then my apologies!
usually i just have a single git repo that tracks everything
interesting, but this time i did something i rarely do: i tried to merge
one local tree of mine into another local tree of mine. So i had no
commands (or even concepts) cached in my short-term memory that would
achieve this goal, i just tried the commands that i thought to be
'obvious', without applying much (or any) IQ to those commands:
$ cd linux-2.6-sched-devel.git
$ git-remote add ~/linux-2.6-x86.git
$ git-remote show x86
* remote x86
URL: /home/mingo/linux-2.6-x86.git
New remote branches (next fetch will store in remotes/x86)
base for-akpm for-linus latest master testing
$ git-merge x86/latest
x86/latest - not something we can merge
#
# ho hum. Not something 'we' can merge. Do i care? :-) There's no
# actionable reference given to the user about how to resolve this
# problem. So i kept on trying:
#
$ git-fetch x86/latest
fatal: 'x86/latest': unable to chdir or not a git archive
fatal: The remote end hung up unexpectedly
$ git-pull x86/latest
fatal: 'x86/latest': unable to chdir or not a git archive
fatal: The remote end hung up unexpectedly
#
# hm. two fatal messages, suggesting that there's something really
# wrong while there's nothing wrong.
#
what got me going after experimenting around some more was this exact
command:
$ git-pull x86 latest
(that fetch+merge went problem-free.)
but it was a PITA and all of git's messages about the problem were not
only unhelpful, they confused me into looking for problems where there
were none IMO. I was starting to wonder whether i have to have some git
daemon running on that box for example. But ...A helpful message tells the user when a remote was added
without being fetched, and how to fetch it.
Our default of not fetching is breaking the users' workflow
in the common "let me access this repo" use case.
This message alleviates the problem.
Signed-off-by: Gabriel <g2p.code@gmail.com>
---
builtin-remote.c | 12 ++++++++++--
1 files changed, 10 insertions(+), 2 deletions(-)
diff --git a/builtin-remote.c b/builtin-remote.c
index d77f10a..044215a 100644
--- a/builtin-remote.c
+++ b/builtin-remote.c
@@ -111,8 +111,16 @@ static int add(int argc, const char **argv)
return 1;
}
- if (fetch && fetch_remote(name))
- return 1;
+ if (fetch) {
+ if (fetch_remote(name))
+ return 1;
+ }
+ else {
+ printf ("Added remote repository `%s' without fetching it.\n"
+ "Before accessing the branches of this "
+ "remote, run `git fetch %s' "
+ "or `git remote update'.\n", name, name);
+ }
if (master) {
strbuf_reset(&buf);
--
1.5.5.24.geb27
--
Hi, Is this really, really necessary? I was quite happy when a few people made Git less chatty, recently. Ciao, Dscho --
Le Fri, 11 Apr 2008 16:21:45 +0100 (BST), Not necessary, but a real usability improvement. I think the transcript that started the thread makes it clear that having "git remote add" not fetching is not the right default. The user wants to use a remote repository, and has learned these are called "remotes". So he does not have too much trouble finding/remembering the command "git remote add <name> <url>". Now with the user's goal in mind, it makes no sense to add a remote and then not fetch it, because the user definitely wants to do something with the remote. By not fetching it, we are surprising the user (this is apparent in the transcript), maybe we are making him go through some documentation, and he will have to go through a mental checklist "did I add the remote? yes. did I fetch it? yes" later on. The best solution is a patch that makes --fetch default to yes for git remote add and discuss that. In case the remote wasn't fetched, adding some documentation at a place where it _will_ be needed does no harm. This is not an operation as frequent as git status or git checkout, so the three lines it takes in a terminal aren't expensive. A more experienced user that usually runs "git remote add -f", will not see it either. -- Gabriel --
This is what the user wants in 99% of cases.
Signed-off-by: Gabriel <g2p.code@gmail.com>
---
Documentation/git-remote.txt | 4 ++--
builtin-remote.c | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/Documentation/git-remote.txt b/Documentation/git-remote.txt
index 2cbd1f7..04de972 100644
--- a/Documentation/git-remote.txt
+++ b/Documentation/git-remote.txt
@@ -10,7 +10,7 @@ SYNOPSIS
--------
[verse]
'git-remote'
-'git-remote' add [-t <branch>] [-m <master>] [-f] [--mirror] <name> <url>
+'git-remote' add [-t <branch>] [-m <master>] [--no-fetch] [--mirror] <name> <url>
'git-remote' rm <name>
'git-remote' show <name>
'git-remote' prune <name>
@@ -34,7 +34,7 @@ Adds a remote named <name> for the repository at
<url>. The command `git fetch <name>` can then be used to create and
update remote-tracking branches <name>/<branch>.
+
-With `-f` option, `git fetch <name>` is run immediately after
+Without the `--no-fetch` option, `git fetch <name>` is run immediately after
the remote information is set up.
+
With `-t <branch>` option, instead of the default glob
diff --git a/builtin-remote.c b/builtin-remote.c
index 044215a..c0d7d96 100644
--- a/builtin-remote.c
+++ b/builtin-remote.c
@@ -54,7 +54,7 @@ static int fetch_remote(const char *name)
static int add(int argc, const char **argv)
{
- int fetch = 0, mirror = 0;
+ int fetch = 1, mirror = 0;
struct path_list track = { NULL, 0, 0 };
const char *master = NULL;
struct remote *remote;
--
1.5.5.25.g17ee
--
Where did you get these magical statistics? I, for one, have never expected this behaviour. Steve --
Hi, This is wrong, at least in my experience. Do not make up statistics if you want to be taken seriously. Ciao, Dscho --
On Sat, 12 Apr 2008 15:33:30 +0100 (BST), This is obviously not a real statistic, and poor wording on my part. It was meant to summarise the justification that I gave in the parent mail; that justification was certainly up to discussion, and it turns out I was wrong. Which leaves us with the other suggestion of the previous patch, that others have discussed. Now that we have the maintainer's opinion, this is also settled. Anyway, it's easy to get into subjective arguments on usability, and I'll be more careful about this. Which shouldn't prevent us from improving git usability. --
Hi, Thanks for ignoring my opinion. Have a nice life, Dscho --
This is what the user wants in 99% of cases.
Signed-off-by: Gabriel <g2p.code@gmail.com>
---
Also update some tests; disregard the previous patch.
Documentation/git-remote.txt | 4 ++--
builtin-remote.c | 2 +-
t/t5503-tagfollow.sh | 2 +-
t/t5512-ls-remote.sh | 2 +-
4 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/Documentation/git-remote.txt b/Documentation/git-remote.txt
index 2cbd1f7..04de972 100644
--- a/Documentation/git-remote.txt
+++ b/Documentation/git-remote.txt
@@ -10,7 +10,7 @@ SYNOPSIS
--------
[verse]
'git-remote'
-'git-remote' add [-t <branch>] [-m <master>] [-f] [--mirror] <name> <url>
+'git-remote' add [-t <branch>] [-m <master>] [--no-fetch] [--mirror] <name> <url>
'git-remote' rm <name>
'git-remote' show <name>
'git-remote' prune <name>
@@ -34,7 +34,7 @@ Adds a remote named <name> for the repository at
<url>. The command `git fetch <name>` can then be used to create and
update remote-tracking branches <name>/<branch>.
+
-With `-f` option, `git fetch <name>` is run immediately after
+Without the `--no-fetch` option, `git fetch <name>` is run immediately after
the remote information is set up.
+
With `-t <branch>` option, instead of the default glob
diff --git a/builtin-remote.c b/builtin-remote.c
index 044215a..c0d7d96 100644
--- a/builtin-remote.c
+++ b/builtin-remote.c
@@ -54,7 +54,7 @@ static int fetch_remote(const char *name)
static int add(int argc, const char **argv)
{
- int fetch = 0, mirror = 0;
+ int fetch = 1, mirror = 0;
struct path_list track = { NULL, 0, 0 };
const char *master = NULL;
struct remote *remote;
diff --git a/t/t5503-tagfollow.sh b/t/t5503-tagfollow.sh
index 86e5b9b..fd075d9 100755
--- a/t/t5503-tagfollow.sh
+++ b/t/t5503-tagfollow.sh
@@ -134,7 +134,7 @@ test_expect_success 'new clone fetch master and tags' '
mkdir clone2 &&
cd clone2 &&
git init &&
- git remote add origin .. &&
+ git remote add origin .. --no-fetch ...Not sure about that. I often add a remote then push, not fetch. Cheers, Wincent --
Hmm, I'm quite newbie but I have never expected "git remote add" to fetch anything. I wouldn't want it to do it automatically. From the beginning I saw "git remote" as a _configuration_ tool. No doubt it's common to fetch after configuring a remote but in my mind they are two logically different steps (configure, fetch/pull) which I think should be kept separate. Once I have configured something I may want to check that I did the right thing, then configure some more remotes and maybe fetch tomorrow. Maybe I don't want to fetch at all but only pull from that remote. So let's not build ready workflows for users, only convenient, logical tools. That said, I don't mind short messages like "use 'git fetch' to obtain branches" but I don't think that is necessary. --
Good student ;-). Not only that fetch-after-add is _not_ a common nor majority thing at all (contrary to what Gabriel assumed), the "fetch" step is conceptually an unrelated operation from the primary point of "remote add"; "-f" option is a mere convenience feature and we stop at making it conveniently available, never making it a default nor overly advertising it. If the user tells you not to fetch, the command should not bother the user with excess messages, unless the user explicitly asks to, either. --
I fully agree here, but is there a way for the user to do so? Especially the beginning user? Perhaps in the form of a -v(erbose) switch, but for that to be useful it would have to be present across most/all commands and have the same (type of) result. That is, it should provide the user with additional information on what they did wrong/what they likely want to do from here. In this case though I agree that, as Teemu pointed out, 'git remote add' is a config tool. 'man git remote add' points this out more than clearly enough for regular use. Maybe keep it in mind for the to-be "git mind reading" functionality. Cheers, Sverre Rabbelier --
Yeah, I am not sure if that should be called --verbose, but a "training wheel" mode of operation somebody else mentioned the other day that echoes back what the command thinks it was told to do by the user, together with help text that explains what other things the user could have told to the command to enrich its operation, might be an interesting addition. --
Hmmm, I'm not sure about '--verbose' as a name either, but it -is- usually used to display more information about the command(s) being executed. E.g.: -v, --verbose explain what is being done http://unixhelp.ed.ac.uk/CGI/man-cgi?mv Sounds pretty much like what we're doing, explaining what command we thing is being executed. The extra text OTOH with 'possible other workflow suggestions' doesn't quite fit in the '--verbose' picture. Perhaps a different kind of command, like '--newbie' (or, less humiliating, '--explain') would be more appropriate. --
I agree. An automatic fetch would be ... surprising. -Miles -- "Don't just question authority, Don't forget to question me." -- Jello Biafra --
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ I gues that's key here. The remote was added, but you don't actually have fetched the branches yet. Thus the merge fails, but the pull with The syntax is "git pull <repository> <refspec>" So you're trying to fetch/pull from a repository in "x86/latest", that path doesn't exist and that is pretty fatal as you cannot fetch/pull AFAIK merge cannot handle stuff that's outside your repo. To merge stuff from another repo without adding a remote, you have to use pull (or manually do the fetch+merge dance), ie.: git pull ~/linux-2.6-x86.git latest should do. Björn --
As you figured out later, the problem was that "git remote add" doesn't actually fetch the remote's contents: it just sets up the remote. There is a "-f" option which does the fetch automagically after adding. In this case, had "-f" been the default, it would have Just Worked for you. So that's something for us to consider, but I'm not sure if we This is another place where we might have DWYM, by seeing that your repository name started with "<name of a remote>/" and splitting it into "<remote> <branch>". This could affect current usage, but it seems unlikely that people have remote names which are exact prefixes (with trailing slash) of non-remote repositories they are trying to fetch. Reading "git help fetch" should show you the synopsis: git-fetch <options> <repository> <refspec> which maybe gives a clue about the syntax. But I think the problem here is that there are two different syntaxes for what is _almost_ the same thing. The ref refs/remotes/x86/latest, which you can call "x86/latest" Unless you are planning on merging this remote a lot, the common usage is probably to just forget the remote stuff and do: Yes, just showing the remotes would be consistent with what other That is an annoying message. Perhaps we could notice that it looks like a file path (because it begins with '.') and suggest "maybe you wanted to "git pull ..."? -Peff --
Many other commands use the "no arguments" form to show a
list (e.g., git-branch, git-tag). While we did show all
remotes for just "git remote", we displayed a usage error
for "git remote show" with no arguments. This is
counterintuitive, since by giving it _more_ information, we
get _less_ result.
The usage model can now be thought of as:
- "git remote show <remote>": show a remote
- "git remote show": show all remotes
- "git remote": assume "show"; i.e., shorthand for "git remote show"
Signed-off-by: Jeff King <peff@peff.net>
---
And here it is.
builtin-remote.c | 7 ++++++-
1 files changed, 6 insertions(+), 1 deletions(-)
diff --git a/builtin-remote.c b/builtin-remote.c
index d77f10a..06d33e5 100644
--- a/builtin-remote.c
+++ b/builtin-remote.c
@@ -19,6 +19,8 @@ static const char * const builtin_remote_usage[] = {
static int verbose;
+static int show_all(void);
+
static inline int postfixcmp(const char *string, const char *postfix)
{
int len1 = strlen(string), len2 = strlen(postfix);
@@ -380,8 +382,11 @@ static int show_or_prune(int argc, const char **argv, int prune)
argc = parse_options(argc, argv, options, builtin_remote_usage, 0);
- if (argc < 1)
+ if (argc < 1) {
+ if (!prune)
+ return show_all();
usage_with_options(builtin_remote_usage, options);
+ }
memset(&states, 0, sizeof(states));
for (; argc; argc--, argv++) {
--
1.5.5.1.g272c
--
btw., another suggestion: because i use 'git-remote show' rather
frequently, i recently typoed "git-bisect show" and then realized that
it was "git-bisect visualize". Shouldnt there be a "git-bisect show"
alias?
I think using 'show' for all such 'display state' things would be rather
intuitive, if it was applied consistently all across the board.
('visualize' could still remain indefinitely, for compatibility - and
'git-bisect log' would still do the log of the bisection decisions that
were entered.)
Or is there some purpose behind this deviation that i missed?
Ingo
--
Hi, Acked-by: Johannes Schindelin <Johannes.Schindelin@gmx.de> Ciao, Dscho --
I have found this refs/heads/*:refs/remotes/* stuff quite confusing, but I'm starting to understand them. I know my way with them but still they seem quite unnecessary hackerish. Pull and push work pretty nicely without knowing about any refs/* stuff; they can be operated with simple branch names. Fetch is another story. Some ideas: $ git fetch <URL> would be equivalent to $ git fetch <URL> +refs/heads/*:refs/remotes/<name>/* In other words, fetch all the branches from remote repo and store them locally as remote tracking branches to <name>/ hieararchy. The <name> is the last component taken from the <URL> (maybe "origin" if it can't be detected). Currently "git fetch <URL>" does not seem to do anything useful for non-git-hackers. It seems to fetch objects but not create any branches referring to them. As a comparison, let's configure a remote and run similar fetch command without any refspecs explicitly named: $ git remote add <name> <URL> $ git fetch <name> Now this fetch really creates all the branches (as defined in remote.<name>.fetch) which is nice and the way Git currently works. So would it be any good if "git fetch <URL>" without refpecs would use +refs/heads/*:refs/remotes/<name>/* ? In any case the current behaviour seems quite unfriendly. Some more ideas for simple refspecs: $ git fetch <URL|name> <branch> would be equivalent to $ git fetch <URL|name> +refs/heads/<branch>:refs/remotes/<name>/<branch> Again the same behaviour with <URL> and configured remote <name>. In the <URL> case the <name> is the last component of the <URL>. $ git fetch <URL|name> <Rbranch>:<Lbranch> would be equivalent to $ git fetch <URL|name> +refs/heads/<Rbranch>:refs/remotes/<Lbranch> Note that by giving the destination branch (the right side of colon) the new remote tracking branch would be created directly to the refs/remotes/ hierarchy, not to refs/remotes/<name>/ hierarchy like in previous examples. This lets user a bit more ...
This has been discussed before and rejected, because the point of doing
a fetch of a URL (rather than a remote name) is to do a "one-off" thing.
IOW, you don't _want_ the tracking branches, as they will just clutter
your branch space (plus choosing the last component is a bad heuristic;
lots of people must ask Linus to pull from their .../linux-2.6
repository).
Almost nobody says "git fetch <URL>"; it is just a subpart of "git
pull <URL>" which is intended for one-off merges (i.e., you are not
tracking somebody over the long term, you just want to grab their work
It does; it puts the refs into FETCH_HEAD. Maybe a status table like the
usual one would be more informative, like:
From git://host/path/to/repo
* [new branch] foo -> FETCH_HEAD
though again, it would help if we could see a workflow that uses "git
fetch <URL>" for something. I think the simplest answer in your case is
Sure. There is an explicit design decision that "because you gave this
thing a nickname, you are probably interested in keeping its tracking
It would probably be nice if "git fetch name foo" saved the remote
tracking branch remotes/name/foo, which it doesn't currently. But
whether to do it with a URL is orthogonal; it depends on whether we use
We almost have that. It's actually spelled:
git fetch <URL|name> <Rbranch>:remotes/<Lbranch>
But again, what is the workflow? There are generally two ways of
fetching:
1. I am tracking some remote with multiple branches. I give it a
remote name (either by editing the config file or by using
git-remote). When i want to get updates, I do "git fetch <name>",
and then I can work with the <name>/* branches as I want (diffing,
merging, etc).
2. "Somehow" I found out about something interesting in a particular
branch of a particular repo. I want to pull that in to see the
work, so I use "git pull <repo> <branch>". Alternatively, if I
prefer to fetch and examine before pulling (even though the ...First, thank you for such a detailed information and giving somewhat different point of view from mine. Ok, "git fetch <URL>" has its own "point", as you noted, and no doubt it's for good reasons. I just had partially misunderstood its point. See Hmm, maybe. I recently wanted to join two purely local repos together. Both of them had just one branch. Totally different histories so no actual mergin would happen; just two branches in the same repo. I don't know why but "git fetch /the/other/repo/" just happened to be the one I tried first. I saw it fetched something but as no new branch appeared and I had never heard of this FETCH_HEAD thing it was a "didn't work, would be really good. At least to me this would have been enough information. As I'm starting to see the "point of doing fetch <URL>" I take back what I proposed. Just a bit more information would be nice. I have to agree with Ingo Molnar that sometimes Git is a bit un- or even disinformative about what happened. One example is this "git fetch <URL>". Maybe it's not a "sane thing to do" but users are like this. We just try something and learn from it. To me "git fetch <URL>" was a broken command (UI-wise) until I read your message (thanks again!). If Git had told me that it created FETCH_HEAD I had learned fetch's habits myself and likely wouldn't have come up with this "broken command" conclusion. Another thing I spoke of was this refs/ stuff. I know my way around with them now, so maybe they are not actually confusing to me anymore. It's just that I have noticed a pattern: I always use refs/heads/... in certain places and refs/remotes/ in certain places. If such a pattern is very common (well, I don't know if it is) one starts to think that maybe the pattern can/should be hidden and made part of the tool. Just thoughts. --
Ah, OK. In that case, I think the right thing to do would not be to set up a remote, but to fetch explicitly into a local branch. I assume when you say "joining" you mean "so I can get rid of the individual ones". So something like: cd repo1 git fetch ../repo2 master:repo2-topic which creates refs/heads/repo2 in repo1, and you can safely delete repo2. If you _did_ want to keep repo2 around indefinitely, and you are "joining" so that you can do diffs, then you probably do want a remote with tracking branches. cd repo1 git remote add repo2 ../repo2 git fetch repo2 I wonder if people like Linus who do a lot of one-off pulls would find Sure. In my other message I talked about workflows not to imply "how dare you explore the commands!" but rather to see where you were coming from. I agree that a lot of git messages could be improved. So I think the take-away lesson is not that there needs to be some huge change in behavior or what input is accepted, but that git-fetch without tracking I almost never use refs/remotes/ or refs/heads/. Some effort has been put into doing the right thing with partial refnames (which you can of course override by being more specific). Do you have specific examples of where you use the full refname? I suspect it is either not required (and documentation may be out of date), or it is a bug we could fix. :) -Peff --
As it turns out, there is already code to do this very thing, but:
1. it was broken ;)
2. you need to specify "-v"erbose mode to see it
Here is a patch that fixes the breakage, which should be done either
way. If people think this is a good thing to show in general (and I do,
but then I am not a very frequent user of "fetch without tracking
branches"), then there is an obvious one-liner to make it always show.
-- >8 --
git-fetch: fix status output when not storing tracking ref
There was code in update_local_ref for handling this case,
but it never actually got called. It assumed that storing in
FETCH_HEAD meant a blank peer_ref name, but we actually have
a NULL peer_ref in this case, so we never even made it to
the update_local_ref function.
On top of that, the display formatting was different from
all of the other cases, probably owing to the fact that
nobody had ever actually seen the output.
This patch harmonizes the output with the other cases and
moves the detection of this case into store_updated_refs,
where we can actually trigger it.
Signed-off-by: Jeff King <peff@peff.net>
---
builtin-fetch.c | 28 +++++++++++++---------------
1 files changed, 13 insertions(+), 15 deletions(-)
diff --git a/builtin-fetch.c b/builtin-fetch.c
index 5841b3e..139a6b1 100644
--- a/builtin-fetch.c
+++ b/builtin-fetch.c
@@ -215,13 +215,6 @@ static int update_local_ref(struct ref *ref,
if (type < 0)
die("object %s not found", sha1_to_hex(ref->new_sha1));
- if (!*ref->name) {
- /* Not storing */
- if (verbose)
- sprintf(display, "* branch %s -> FETCH_HEAD", remote);
- return 0;
- }
-
if (!hashcmp(ref->old_sha1, ref->new_sha1)) {
if (verbose)
sprintf(display, "= %-*s %-*s -> %s", SUMMARY_WIDTH,
@@ -365,16 +358,21 @@ static int store_updated_refs(const char *url, struct ref *ref_map)
rm->merge ? "" : "not-for-merge",
note);
- if (ref) {
+ if (ref)
update_local_ref(ref, what, verbose, note);
- if (*note) {
- if ...And here is that one-liner, in case there is interest. The only negative
I can think of is that git-pull will now produce two extra lines of
output mentioning FETCH_HEAD (which I actually think is a positive, but
I can see that people might consider it clutter).
-- >8 --
git-fetch: always show status of non-tracking-ref fetches
Previously, a fetch like:
git fetch git://some/url
would show no ref status output (just the object downloading
status, if there was any), leading to some confusion.
With this patch, we now show the usual ref table, with
remote refs going into FETCH_HEAD. Previously this output
was shown only if "-v"erbose was specified.
Signed-off-by: Jeff King <peff@peff.net>
---
builtin-fetch.c | 4 +---
1 files changed, 1 insertions(+), 3 deletions(-)
diff --git a/builtin-fetch.c b/builtin-fetch.c
index 139a6b1..e4486e4 100644
--- a/builtin-fetch.c
+++ b/builtin-fetch.c
@@ -360,12 +360,10 @@ static int store_updated_refs(const char *url, struct ref *ref_map)
if (ref)
update_local_ref(ref, what, verbose, note);
- else if (verbose)
+ else
sprintf(note, "* %-*s %-*s -> FETCH_HEAD",
SUMMARY_WIDTH, *kind ? kind : "branch",
REFCOL_WIDTH, *what ? what : "HEAD");
- else
- *note = '\0';
if (*note) {
if (!shown_url) {
fprintf(stderr, "From %.*s\n",
--
1.5.5.26.g8c565.dirty
--
Thanks for bringing this issue up and proposing a pair of improvements. I am very inclined to apply [1/2] to maint. I am not convinced if [2/2] is a good idea in general but if it is silent on pull and verbose on one-off fetch without local store, it probably is an improvement. --
I think that is the right behavior for 2/2; I was just being a little lazy earlier. I will try to work up an improved 2/2, but I will probably be out of touch for a few days. Maybe we will see some comments from the list in the meantime. -Peff --
In real work I have used refs/heads/...:refs/remotes/... only once or maybe twice (I just quite recently started using Git). But when I studied Git and the workflows it supports I tried all kinds of fetching, pulling and pushing, back and forth, between test repos. There I used refs/ paths a lot, almost all the time actually. At first it was very much just trying to see how they work and this is where I found this common pattern: local refs start with refs/heads/ and remote tracking ones with refs/remotes/ . Thoughts like "why not simplify them, like L: for local and R: for remote" (or something) started to develop. Now it seems that I have been too much attached to the full refspec form. My guide have been the config remote.<name>.fetch as "git remote add" adds those long refspecs. Now I learnt that almost all refspecs can be written as "branch:another" or "branch:remotes/another" for example. So the "friendly refspecs" are pretty much already there! Well, I've been stupid. :) (I understand that in real work when constantly dealing with same remote repos one just adds a remote config and can forget about URLs and probably most of the refspecs too.) Ok, this was partly an RTFM error but even after reading man pages of fetch, pull and push it isn't quite clear how to use these short and nice and friendly refspecs. I thought about it and decided to add some more examples to fetch manual (see my patch in the next message). My English may not be manual-writing quality but I wanted to do something useful anyway. Somebody needs to proof read my text though. Of course there may be some inaccuracies too. Anyway, I think that concrete examples in manuals help people to understand Git better. There is still one thing (at least) that I don't quite understand. It's about "git push". When I do $ git push <remote> <branch> the refs/heads/<branch> is updated or created on the remote side. But if I do $ git push <remote> <branch1>:<branch2> the refs/heads/<branch2> is not ...
This commit adds examples which intend to cover the various ways of using 'git fetch'. Signed-off-by: Teemu Likonen <tlikonen@iki.fi> --- Documentation/git-fetch.txt | 43 ++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 42 insertions(+), 1 deletions(-) diff --git a/Documentation/git-fetch.txt b/Documentation/git-fetch.txt index d982f96..d5b1c9f 100644 --- a/Documentation/git-fetch.txt +++ b/Documentation/git-fetch.txt @@ -37,9 +37,50 @@ include::pull-fetch-param.txt[] include::urls-remotes.txt[] +EXAMPLES +-------- + +git fetch git://host.xz/repo.git/ master:pu:: + Fetch branch `master` from given repository URL and store it locally + as `pu`. + +git fetch git://host.xz/repo.git/ master:remotes/pu:: + Fetch branch `master` from given repository URL and store it locally as + remote tracking branch `pu`. + +git fetch git://host.xz/repo.git/ master:: + Fetch branch `master` from given repository URL but do not create the + branch locally. Only the temporary pointer FETCH_HEAD is set to refer + to the fetched branch. + +git fetch /home/bob/tmp/repo.git:: + Fetch the currently active branch from given local repository and set + the temporary pointer FETCH_HEAD for the fetched branch. + +git fetch alice master:remotes/alice/pu:: + Fetch branch `master` from remote named `alice` and store it locally as + remote tracking branch `alice/pu`. See linkgit:git-remote[1] for more + information on configuring remotes. + +git fetch alice +master:remotes/alice/pu:: + The same as above but the remote tracking branch `alice/pu` is updated + even if it does not result in a fast forward update. + +git fetch alice +master:pu maint:tmp:: + Fetch branches `master` and `maint` from remote named `alice` and store + them locally as `pu` and `tmp` respectively. The branch `pu` is updated + even if it does not result in a fast forward update. + +git fetch origin:: + From the remote named `origin` fetch and store all branches as + configured in ...
While this may technically be correct (and I'll say upfront that all of your "examples" may technically be correct), I would suggest strongly against putting this into EXAMPLES section. People look at examples section to look up something they need to do often; the section should describe the best practices we can suggest them in real life. The above command line is a _great_ way to explain what happens under the hood when you have the matching configuration in .git/config for the remote, so that people would know how to update .git/config entries from what git-clone and "git-remote add" give them by default to suit their needs (e.g. instead of storing all branches in remotes/origin/*, you can configure to only fetch and store a few selected branches). But, fetching from somewhere and storing it explicitly _from the command line_ like your example command line is something you would _never_ do in real life if you And this example is even worse, as the common example is to have remote This one is a fine example of a one-shot command to look at what they have without actually affecting your own history. Use of this form in This is a wrong example on multiple counts (this is one of the worst one in your change, so I'll explain in more detail than for others). First of all, think about the reason _why_ the convention is to use a separate namespace under remotes/ per remote. It is to allow us to use the names that correspond to what the remote repository uses without having to worry about name collisions, and the reason we took pains to implement the mechanism to allow you to use such corresponding names is to avoid having to remember "what she calls master is what I call pu". "I want to make sure I can tell my master and her master apart without confusing myself, so I'd call mine master and call hers alice/master" is the recommended use pattern which "git clone" and "git remote add" give the user. An EXAMPLE that deviates from it without explaining why/when it is a ...
As a recent CVS emigrant, I'm finding the refspecs one of the more confusing areas of git. I think having good, basic examples might be more helpful than experienced users expect. In my case at least, this is a helpful example. --
Thanks for your explanations, they made a lot of sense. I see, I gave examples of various ways of using "git fetch" but they may not reflect real life usage patterns very well. I still feel that refspecs need more explaining (for newbies, that is) so I may later bring another patch hopefully with better examples and applicable to real workflows. --
Perhaps. The basic syntax is "src colon dst" and they are used to copy what's in src to dst, and that is pretty much what's there to it. Some details such as how the wildcard matching works may be missing from the description part of the manual, and filling them in would be a good idea. I however strongly suspect that what new people need to get explained may not be what the mechanism does (e.g. copies the object name recorded as the src ref to the dst ref), nor the syntax you use to tell the mechanism what to copy where (e.g. src is LHS, dst is RHS, copying "emptyness" into dst means deleting dst). I actually think that is an easier part. What is more important is the basic concepts like what a ref is, how they can be used and what you can do with them --- understanding of which would be essential in being able to decide when and how you maywant to keep a copy of ref you get from elsewhere and under what name. I think tutorial is the best place, and then the description section of the manual the second best one, to document that kind of things. --
This happens because "git push <remote> <branch>" is expanded locally to "git push <remote> <branch>:<branch>", but <branch> is first expanded into refs/heads/<branch>. The latter uses the explicit refspec <branch2> which doesn't get expanded, since it doesn't exist at all, and so we can't deduce the type (e.g., refs/heads versus refs/tags). ISTR some discussion in the past few months about using the type of <branch1> to guess the type of <branch2>, but it seems not to have gone anywhere. Daniel, were you working on this? -Peff --
Hmm. Here is a quick patch I worked up, but it causes t5516:14 (push
with ambiguity) to fail. However, I'm not sure the test is right: it
looks like it's trying to find ambiguity between remotes/origin/master
and remotes/frotz/master, but in fact matches _neither_ of them. So it
was failing before as we expected, but for the wrong reason.
---
remote.c | 23 +++++++++++++++++++----
t/t5516-fetch-push.sh | 8 ++++++++
2 files changed, 27 insertions(+), 4 deletions(-)
diff --git a/remote.c b/remote.c
index 08af7f9..2f5d062 100644
--- a/remote.c
+++ b/remote.c
@@ -851,10 +851,25 @@ static int match_explicit(struct ref *src, struct ref *dst,
case 0:
if (!memcmp(dst_value, "refs/", 5))
matched_dst = make_linked_ref(dst_value, dst_tail);
- else
- error("dst refspec %s does not match any "
- "existing ref on the remote and does "
- "not start with refs/.", dst_value);
+ else {
+ /*
+ * We don't have a full ref name for the dst and
+ * it doesn't exist, so let's assume it's the same
+ * type as our src.
+ */
+ struct strbuf tmp = STRBUF_INIT;
+ const char *c;
+ int slashes;
+ for (c = matched_src->name, slashes = 0;
+ *c && slashes < 2; c++) {
+ strbuf_addch(&tmp, *c);
+ if (*c == '/')
+ slashes++;
+ }
+ strbuf_addstr(&tmp, dst_value);
+ dst_value = strbuf_detach(&tmp, NULL);
+ matched_dst = make_linked_ref(dst_value, dst_tail);
+ }
break;
default:
matched_dst = NULL;
diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
index 793ffc6..370f79a 100755
--- a/t/t5516-fetch-push.sh
+++ b/t/t5516-fetch-push.sh
@@ -285,6 +285,14 @@ test_expect_success 'push with colon-less refspec (4)' '
'
+test_expect_success 'push with non-existant, incomplete dest' '
+
+ mk_test &&
+ git push testrepo master:brandnewbranch &&
+ check_push_result $the_commit heads/brandnewbranch
+
+'
+
test_expect_success 'push with HEAD' '
mk_test heads/master &&
-- ...Eh, there is no way unless you force an assumption of a particular workflow to everybody else. What you would say on the second command is not literally "<branch2>" but something like "work-in-progress", or "crap". Even an AI would not be able to guess if you wanted to create a branch on the other side, or wanted to put a lightweight tag to let people know where you are (possibly with the intention of removing it once you are done), and git is not an AI. --
Of course it can't guess all cases. But right now you have the option of: 1. specifying the full destination manually 2. having git complain, and then doing (1) I think changing (2) to "having git make a reasonable guess" is a better behavior. And I think it is a reasonable guess to use the _same_ type, just as we do with "git push <branch>". -Peff --
I was only working on making "HEAD" expand to HEAD:<current branch>. I think that the matching type is only most likely what you want, not certainly enough to just do it. I'd say that push should suggest it, but not actually do it automatically, or possibly require -f to do it without the full name. -Daniel *This .sig left intentionally blank* --
But what should <name> be if you didn't provide it by doing git-remote-add? I think the lack of an obvious name for them is exactly why the branch names don't get created automatically. Avery --
Teemu Likonen <tlikonen@iki.fi> writes:
[By the way, please never redirect the response to your messages away from
you with:
Mail-Followup-To: Jeff King <peff@peff.net>, Ingo Molnar <mingo@elte.hu>,
git@vger.kernel.org
You wasted 30 seconds of my (and anybody who potentially wanted to give
advice to you) time by forcing me fix the To: header while composing this
response. I know Jeff understands what I am going to mention, and I do
I'd suggest you to study:
http://thread.gmane.org/gmane.comp.version-control.git/31351/focus=31634
Not everybody wants remote tracking.
--
Sorry, didn't even know such header existed. After consulting Mutt's manual and some googling I think I understand it now. I'm a subscriber to git list (and my Mutt knows that) and Mail-Followup-To told everyone's MUAs to not include me in recipient list since I get everything through the list. But this is configurable and generating Thanks, and I agree. Me neither always want remote tracking. Git's current behaviour to only create/update FETCH_HEAD seems actually better - now that I know what it does. I think it's a good idea to show "[new branch] foo -> FETCH_HEAD" after fetching. --
My co-workers frequently get confused by this too. The problem is that "x86/latest" is a locally existing remote branch ref, while "x86 latest" is supposed to be a branch ref on a remote system. I think the real problem here is that you can't refer to a remote+branch as a single "word". If you could, then people could just learn to use that everywhere and never get confused. For example, in svn you can talk about svn+ssh://reposerver/path/to/repo/branches/foo@1234; it's a single "word" that refers to a particular revision on a particular branch of a particular server. It therefore makes sense to talk about copying from one branch to another, etc, using exactly one word for the source and one for the destination. Imagine if "git pull ~/linux/2.6-x86.git:latest" would work; then it could mean exactly the same thing as "git merge ~/linux/2.6-x86.git:latest" (which would presumably switch to 'pull' mode automatically). Or even "git diff master..x86:latest", which could diff my local master with an auto-fetched x86:latest. Naturally we'd have to find a new punctuation mark for this, since all the obvious ones are already used :) Have fun, Avery --
Heh, not really. Subversion actually makes this even more confusing than git does. The @rev is called a "peg revision", and is different from the "operative revision" specified with the -r flag. The peg revision is used in conjunction with a path to specify the file (or directory) you want, and the operative revision is used to specify which revision of that file you mean. (This complexity is needed because subversion has a concept of file identity.) So $ svn cp -r 4711 $REPO/foo@1234 somewhere-else means "find the file (or directory) that was called 'foo' in revision 1234, then copy revision 4711 of that file to somewhere-else". See http://svnbook.red-bean.com/en/1.4/svn.advanced.pegrevs.html for the full story. -- Karl Hasselström, kha@treskal.com www.treskal.com/kalle --
Yes, but I believe you get the one from @rev if you don't specify -r. For example, I can ask for an "svn diff svn://blahblah@56 svn://blahblah@59" and it'll feed it to me as expected. This is nearly the same as "svn diff -r56:59 svn://blahblah", except that it might look for blahblah in different places, as you say. I File renames make diffing and merging complicated no matter whether you track them or not. svn's tracking of file identity is additional, but doesn't increase the (UI) complexity in the common case. At least with svn, a newbie can even get real work done without even knowing about -r *or* @notation. Compare that to arbitrary differences in behaviour between "git-fetch" vs "git-fetch a" vs "git-fetch a b", or the difference between HEAD^ and HEAD~1 and HEAD@1. git is very powerful, but also definitely more complex for beginners. Have fun, Avery --
Clearly, I need to use Subversion more, and not fool around with git I don't quite agree with you here. Subversion stores extra state, and that state needs to be considered (in the general case) when predicting what Subversion will do. There are a large number of simple cases where the user doesn't have to care, as you say, but every so often there's a case that's not so simple, and in those cases I Oh, I'm not arguing on that point. I like git because it's beutiful on the _inside_. -- Karl Hasselström, kha@treskal.com www.treskal.com/kalle --
Ok, just in case i dont bore people with "stupid user" experiences and logs of sessions of confusion, here's another session i just had with Git. This time it's with our good friend git-bisect - which i thought to master pretty well and which i already used successfully to bisect kernel bugs up to a hundred times already (at least). The 'v' repository is a vanilla clone of Linus's upstream linux-2.6.git kernel tree with no other modifications done to it. dione:~> git-clone v linux-tmp4 Initialized empty Git repository in /home/mingo/linux-tmp4/.git/ 0 blocks Checking out files: 100% (23809/23809), done. dione:~> cd linux-tmp4/ dione:~/linux-tmp4> ls COPYING MAINTAINERS arch fs kernel samples usr CREDITS Makefile block include lib scripts virt Documentation README crypto init mm security Kbuild REPORTING-BUGS drivers ipc net sound # # ok, so far so good. done this a thousand times before. # # Now lets check out v2.6.24 and check whether the bug i'm interested # in triggers on v2.6.24. I dont create an extra branch for it, because # this is pure temporary work, i use a plain git-checkout as a # throwaway temporary branch: # dione:~/linux-tmp4> git-checkout v2.6.24 Note: moving to "v2.6.24" which isn't a local branch If you want to create a new branch from this checkout, you may do so (now or later) by using -b with the checkout command again. Example: git checkout -b <new_branch_name> HEAD is now at 4991408... Linux 2.6.24 # # i build that kernel and boot it - the bug doesnt trigger - good. # We've got all prerequisites for a bisection session - a 'good' kernel # [v2.6.24] and a 'bad' kernel [HEAD]. # # dione:~/linux-tmp4> git-bisect start fatal: ref HEAD is not a symbolic ref won't bisect on seeked tree # # Hm. It's not a symbolic ref, and git-bisect just wont do it. Ok but # then what, and what can the user do to ...
Yeah, it seems that this is a left over from cogito.
There has been some work on it lately but it seems not enough. See:
This seems to work for me with git 1.5.5 on the git tree:
$ git checkout master
Switched to branch "master"
Your branch is ahead of the tracked remote branch 'origin/master' by 4
commits.
$ git bisect start
$
This is really bad, because, as you can see from the man page or "git
bisect -h" (see also the patch I just sent), "git bisect good" can take
many known good revisions:
git bisect good [<rev>...]
mark <rev>... known-good revisions.
So you marked also "bad" and HEAD as "good".
This is really strange, because here I get for example:
$ git-bisect good bad HEAD
Bad rev input: bad HEAD
So you must have something tagged as "bad" or have a "bad" branch, and
that's why the command works for you but does the wrong thing.
If you wanted to do it all in one command you could have done:
$ git bisect start HEAD v2.6.24
That would have marked HEAD as "bad" and v2.6.24 as "good":
git bisect start [<bad> [<good>...]] [--] [<pathspec>...]
Right, we probably need to have at look at this more closely, maybe warn if
This marked "good" as "bad" and "v2.6.24" as "good".
Again this should "work" only if you have a "good" tag or branch in your
This marked "v2.6.24" as "bad", and "good", "master" and "bad" as "good".
That's much better but you didn't "reset" or "start" again before giving it
correctly the good and bad revs, so there are still some wrong left over
I cannot comment on "git fsck" but I think it has nothing to do with
"git bisect start" also does a "restart" if a bisect is already started.
But yes, we could add "stop" as a synonym for "reset" and "restart" as a
synonym for "start".
Thanks,
--
git-core-1.5.4.3-2.fc8, like for the previous report. and it worked for me too in a later tree - so the condition seems no, there are no 'bad' braches or revisions. and ... if "git-bisect good X bad Y" is invalid syntax it should be detected by the tool ... I did not think up that syntax myself, i think i saw it somewhere else mentioned by someone and found it logical. it probably didnt - i was just grasping at straws because there was no reassuring feedback about what happened so my confidence about my _assumptions_ what was happening in the background gradually eroded so i went in larger and larger circles around the problem dropping more and more assumptions and re-checking them. But i pasted this directly from that session so the "-1" is definitely not imaginery and it is anomalous. Ingo --
Yes, it probably depends on what you have done before. I didn't look at it yet, but I will have a look soon. Anyway as Junio said, there have been some improvements in 1.5.5 so it might You are right, we have got some bugs here I think. In my case bad and HEAD were neither proper revs, that's why I got an error. But I realized that as long as there is one proper rev in what you give to "git bisect good" it will ignore bad revs and mark as good the proper rev you gave it. I just sent a patch to fix this, but I am not sure it's the right fix. More work is probably needed. Ooops I just spotted one bug in my patch. Yes. Thanks again, Christian. --
Enough people were unhappy with this historical wart and we stopped refusing to "bisect on seeked tree" since b577bb9 (Eliminate confusing "won't bisect on seeked tree" failure, 2008-02-23); you should find it as part of the 1.5.5 release. The disturbing "fatal: ref HEAD not a symref" is still there even though it should be harmless. The message should be squelched. --
Another inconsistency:
$ git remote prune
usage: git remote
or: git remote add <name> <url>
or: git remote rm <name>
or: git remote show <name>
or: git remote prune <name>
or: git remote update [group]
show specific options
-n, --dry-run dry run
It took me a while to parse the "show specific options" properly.
Wouldn't "specific options for show" be better?
--=20
Luciano Rocha <luciano@eurotux.com>
Eurotux Inform=E1tica, S.A. <http://www.eurotux.com/>
Yes, or failing that: "show-specific options:" Without the hyphen "show specific options" reads as "verb adjective noun". Cheers, Wincent --
Thanks. It is always enlightening to see this kind of walkthru session to learn where the UI warts are. The ones with concrete suggestions for You told git that "I'll interact with this other repository from now on, so please help me with some extra settings to do so. Namely I do not want to keep typing it in full URL all the time so I want an abbreviated way to tell you I am talking about this remote repository, and also I want to have set of remote tracking branches for this one". Maybe "remote add" is not quite the right name to convey the above You told git "I want to merge a commit into the current branch, and that commit is called x86/latest". Alas, no such commit exists in your repository (yet). Should we be saying "no such commit exists, you need to "Not a git archive" should be clear enough. You already said "remote show x86" correctly above, and it makes me wonder why you are now saying "x86/latest", not "x86" without "latest". In other words, "git fetch x86". With that, you would tell git "Hey, I've already told you what I want you to do with this short-hand name "x86". It is the name for the long URL I've previously given you and I want you to fetch from that repository, and I want its branches to be stored in remote tracking branches in my repository". But you didn't. You are not taking advantage of your previous "git remote add". I am suspecting that a cause of this confusion is partly because earlier in 1.3.0 days we tried to make things easy for CVS migrants where they always interact with a single "upstream" repository and with _the_ single branch, and we were _too_ successful in doing so. That made us allowing the users to type "git pull" and "git fetch" without parameters. This is generally a good thing: shorter to type for doing common things is always good, as long as the user knows what he is doing. But at the same time, this allowed docs and cheat-sheets that mention only the form without parameters and not the normative ...
For me personally, I think this bottom-up approach makes the most sense
to learning (this may look familiar from the commit message to a patch I
sent earlier):
1. here is what "git pull $repo $branch" means
2. here is a way to shorten it to "git pull $repo" (set up remote
$repo)
3. here is a way to shorten it to "git pull" (default to origin)
But I think there are people who will get to the list and say "why
didn't you just tell me 'git pull' in the first place?" That is, the
complaints we have seen in the past reveal _too many_ low level details
too quickly.
Maybe we have stepped too far towards "top down workflow
descriptions" and need to go back. I dunno.
Another way of thinking about it is that we need two sets of
documentation with the same information (heresy, I know!): one bottom-up
and one top-down. I think the manpages tend to be "bottom up"
references. Bruce's user manual is more "top down" describing workflows.
I wonder which one(s) Ingo read, and which helped the most.
-Peff
--
Hey Junio, I'm hearing you here! :-) I think a furtherance of this notion is to teach "git fetch ; git merge" before "git pull". Thanks, jdl --
A possible way it to, by default, make git print the full form of the command when a short form is used. So the user see the concept without having to read the documentation and learn it gradually. I personally like tools that act this way. It permit to make a basic and easy tutorial with short commands that let know the general concept and show the full potential of the tool. A "short form" flag in a user (not repository) configuration file should allow to suppress the long form printout for the comfort of the users that don't want it. -- Jean-Christian de Rivaz --
I think this would be a very nice solution, not only do you allow the user to realize what it is they are doing, you also provide them with an easy way to be more verbose. Perhaps they wish to switch from the default short behavior to a somewhat different form (e.g., change a default 'master' argument to another branch). When writing out the full form each time the user gets an intuitive and gradual introduction into the rest of git, without limiting them or more Or perhaps, as I mentioned in the thread on "friendly refspecs", a "newbie" config option or command that turns on the informative verboseness options. As such, perhaps a "long form" flag would be more desired instead, to prevent existing developers from being spammed with information they do not are interested in. Cheers, Sverre Rabbelier --
Something along the lines of: Error description Why it happened How to solve/Sugestion -- []s, André Goddard --
On Wed, Apr 9, 2008 at 6:56 PM, André Goddard Rosa Hi, This actually touches on one of my main purposes behind Pyrite. I intend to do the following things to help the situation and I was wondering what the git community's reaction is. 1) Since it will be designed for end users I intend to remove the options not designed for end users. This will also shorten up the help so that the entire help can be shown to the user when they encounter an error. 2) No unnamed options. I think this would have helped the above case although it would have required a *bit* more typing. The command would have looked like "pyt pull/fetch -r x86 -b latest" Combined with the above the command would have spit out the help and a message stating what was missing. 3) No syntax. Git has a lot of syntax. It has refspecs, revision ranges, symbolic names (although i do like these) that a user has to learn. I think this is one of the most error prone parts of the git for new users. Hopefully, I will be able to find simple and straightforward ways for the user to supply this info. Any comments/suggestions will be appreciated. Thanks, Govind. --
Git is missing the fact that, while refs/remotes/x86/latest doesn't exist, there is a fetch rule that would create it. It should suggest "git fetch x86" or "git fetch x86 latest". This is a bit tricky, because you've used a shorthand for something that doesn't exist, so there isn't a unique answer for which full name you're looking for, but there is a unique solution (in this case) for which one could be created by a pattern you The right error message here would probably be: /home/mingo/linux-2.6-sched-devel.git/x86/latest: No such file or directory That should at least tell you what git thinks, incorrectly, that you want I'm not sure we can figure out what the user actually meant in this case; there's just too much overlap in namespaces to determine reliably that you were giving it a remote repository on the local filesystem rather than anything else. -Daniel *This .sig left intentionally blank* --
well, current git got to /home/mingo/linux-2.6-x86.git/ which is a local path. (it is printing it in the error message above) So i think it was rather unambiguous what i meant and Git knew about it, right? but even if it _was_ ambiguous, i think tools should generally default to a minimal amount of hassle for new users and should try to pick reasonable "action" versus any "inaction". (as long as the behavior is still deterministic and reasonable even to the long-time user) but more importantly, i think this whole problem area has to be handled with a slightly different kind of mindset than other, more technical aspects of Git. Humans, and in particular males, when they see or learn new things, are very emotion-driven. The first 1-2 minutes (often just the first few seconds) have a very strong influence on whether that person 'likes' a new topic, tool or gizmo he is checking out - or not. Males often think of themselves as being objective when shopping new items - while in reality more than 90% of their purchasing decisions are emotion-driven and it's all set and done in the first 10 seconds of visual contact. (this ration is far higher than for females) Command-line tools like Git are at heavy natural disadvantage compared to say GUI tools because the "first impression" is so minimalistic and relatively unremarkable. A GUI can get people hooked by making the first 10% look easy just via old-fashioned, dishonest visual deception. so basically for 90% of the new users, we've got 2-3 shots or we lose their "sympathy". Starting with an error message is bad. Being uninformative about what happened is bad. Making the user wait without signalling why he is waiting is bad. Etc. etc. I think this experience of mine was a reasonable simulation of a first-time user reaction (by virtue of me having forgotten certain Git details). And the moment a negative first-time impression has settled in it's very hard to overcome that emotional mindset and barrier. ...
Actually, your shell did that. I don't think git can tell that the user typed something different and the shell converted it because it's a local It's hard to evaluate proposals for extending cases from inaction to some action because in trying to keep it deterministic, you have to decide whether future, possibly more compelling, extensions might want to overlap the space of commands. It's more conservative to have the command suggest some things the user might have meant, even if that's sometimes a list of one, so that the user doesn't come to rely on behavior that is only I think that it's far enough along before a user types "git merge ..." that we've got a chance to give a suggestive error message instead of just doing something, particularly if the thing we might do might be wrong and either annoying to clean up or slow. (OTOH, "git clone ..." had better work, and I think it does) And I agree strongly with the need for the error messages in the cases On the other hand, there's a conflict between having git do what the user seems to want it to do and having git's commands delineated by concepts that users need to know, such that users will be assisted in learning those concepts (and therefore have an easier time getting the results they expect from git consistantly). For example, "merge" works on information you have within the repository, and "fetch" brings information into the repository. In some cases, we could guess that the user has typed "merge" but wants to bring information into the repository, but we won't always be I think the market segment that most git developers would really like to get is the projects that they work on aside from git. There's a substantial itch to make git sufficiently compelling that nobody would make them use CVS/SVN/Perforce/ClearCase/etc. This has a significant usability-to-new-users component, and so there's more attention to that than in projects where use of the project doesn't require getting ...
