* [PATCH 0/2] Better advice on merge
@ 2013-05-01 11:22 Vikrant Varma
2013-05-01 11:22 ` [PATCH 1/2] help: add help_unknown_ref Vikrant Varma
` (2 more replies)
0 siblings, 3 replies; 16+ messages in thread
From: Vikrant Varma @ 2013-05-01 11:22 UTC (permalink / raw)
To: git; +Cc: Vikrant Varma
If origin/foo exists, but foo doesn't:
$ git merge foo
fatal: foo - not something we can merge
This patch series improves the error message. If a remote branch exists
with the same name, it now says:
$ git merge foo
fatal: foo - not something we can merge
Did you mean this?
origin/foo
It does this by adding a new help function, help_unknown_ref, that takes
care of printing the more friendly error message, and modifies builtin/merge.c
to use it. In the future, this could also be extended to other operations
involving branches that don't exist locally, instead of providing blanket
failure error messages (eg. git checkout foo).
Vikrant Varma (2):
help: add help_unknown_ref
merge: use help_unknown_ref instead of die
builtin/merge.c | 4 ++--
help.c | 44 ++++++++++++++++++++++++++++++++++++++++++++
help.h | 6 ++++++
3 files changed, 52 insertions(+), 2 deletions(-)
--
1.8.3-rc0
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH 1/2] help: add help_unknown_ref
2013-05-01 11:22 [PATCH 0/2] Better advice on merge Vikrant Varma
@ 2013-05-01 11:22 ` Vikrant Varma
2013-05-01 12:23 ` Ramkumar Ramachandra
2013-05-01 18:35 ` Junio C Hamano
2013-05-01 11:22 ` [PATCH 2/2] merge: use help_unknown_ref instead of die Vikrant Varma
2013-05-01 18:27 ` [PATCH 0/2] Better advice on merge Jonathan Nieder
2 siblings, 2 replies; 16+ messages in thread
From: Vikrant Varma @ 2013-05-01 11:22 UTC (permalink / raw)
To: git; +Cc: Vikrant Varma
Give better advice when trying to merge a branch that doesn't exist. If
the branch exists in any remotes, display a list of suggestions.
Example:
$ git merge foo
fatal: foo - not something we can merge
Did you mean this?
bar/foo
Signed-off-by: Vikrant Varma <vikrant.varma94@gmail.com>
---
help.c | 44 ++++++++++++++++++++++++++++++++++++++++++++
help.h | 6 ++++++
2 files changed, 50 insertions(+)
diff --git a/help.c b/help.c
index 02ba043..faf18b9 100644
--- a/help.c
+++ b/help.c
@@ -7,6 +7,7 @@
#include "string-list.h"
#include "column.h"
#include "version.h"
+#include "refs.h"
void add_cmdname(struct cmdnames *cmds, const char *name, int len)
{
@@ -404,3 +405,46 @@ int cmd_version(int argc, const char **argv, const char *prefix)
printf("git version %s\n", git_version_string);
return 0;
}
+
+struct similar_ref_cb {
+ const char *base_ref;
+ struct string_list similar_refs;
+};
+
+static int append_similar_ref(const char* refname, const unsigned char *sha1, int flags, void *cb_data)
+{
+ int i;
+ struct similar_ref_cb *cb = (struct similar_ref_cb *)(cb_data);
+ for (i = strlen(refname); refname[i] != '/'; i--)
+ ;
+ /* A remote branch of the same name is deemed similar */
+ if (!prefixcmp(refname, "refs/remotes/") && !strcmp(refname + i + 1, cb->base_ref))
+ string_list_append(&(cb->similar_refs), refname + 13);
+ return 0;
+}
+
+void help_unknown_ref(const char* ref) {
+ int i;
+ struct similar_ref_cb ref_cb;
+ ref_cb.similar_refs = (struct string_list)STRING_LIST_INIT_NODUP;
+ ref_cb.base_ref = ref;
+
+ for_each_ref(append_similar_ref, &ref_cb);
+
+ fprintf_ln(stderr, _("fatal: %s - not something we can merge"), ref);
+
+ if (ref_cb.similar_refs.nr > 0) {
+ fprintf_ln(stderr,
+ Q_("\nDid you mean this?",
+ "\nDid you mean one of these?",
+ ref_cb.similar_refs.nr));
+
+ for (i = 0; i < ref_cb.similar_refs.nr; i++)
+ fprintf(stderr, "\t%s\n", ref_cb.similar_refs.items[i].string);
+ }
+ exit(1);
+}
+
+
+
+
diff --git a/help.h b/help.h
index 0ae5a12..613cb45 100644
--- a/help.h
+++ b/help.h
@@ -27,4 +27,10 @@ extern void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes);
extern int is_in_cmdlist(struct cmdnames *cmds, const char *name);
extern void list_commands(unsigned int colopts, struct cmdnames *main_cmds, struct cmdnames *other_cmds);
+/*
+ * ref is not something that can be merged. Print a list of remote branches of the
+ * same name that the user might have meant.
+ */
+extern void help_unknown_ref(const char* ref);
+
#endif /* HELP_H */
--
1.8.3-rc0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH 2/2] merge: use help_unknown_ref instead of die
2013-05-01 11:22 [PATCH 0/2] Better advice on merge Vikrant Varma
2013-05-01 11:22 ` [PATCH 1/2] help: add help_unknown_ref Vikrant Varma
@ 2013-05-01 11:22 ` Vikrant Varma
2013-05-01 18:36 ` Junio C Hamano
2013-05-01 18:27 ` [PATCH 0/2] Better advice on merge Jonathan Nieder
2 siblings, 1 reply; 16+ messages in thread
From: Vikrant Varma @ 2013-05-01 11:22 UTC (permalink / raw)
To: git; +Cc: Vikrant Varma
The previous patch added help_unknown_ref to print a more helpful error
message when trying to merge a branch that doesn't exist, by printing a
list of remote branches the user might have meant. Use it.
Signed-off-by: Vikrant Varma <vikrant.varma94@gmail.com>
---
builtin/merge.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/builtin/merge.c b/builtin/merge.c
index 3e2daa3..0f1f39b 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -1053,8 +1053,8 @@ static struct commit_list *collect_parents(struct commit *head_commit,
remotes = &commit_list_insert(head_commit, remotes)->next;
for (i = 0; i < argc; i++) {
struct commit *commit = get_merge_parent(argv[i]);
- if (!commit)
- die(_("%s - not something we can merge"), argv[i]);
+ if (!commit)
+ help_unknown_ref(argv[i]);
remotes = &commit_list_insert(commit, remotes)->next;
}
*remotes = NULL;
--
1.8.3-rc0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [PATCH 1/2] help: add help_unknown_ref
2013-05-01 11:22 ` [PATCH 1/2] help: add help_unknown_ref Vikrant Varma
@ 2013-05-01 12:23 ` Ramkumar Ramachandra
2013-05-01 14:06 ` Matthieu Moy
2013-05-01 19:55 ` Vikrant Varma
2013-05-01 18:35 ` Junio C Hamano
1 sibling, 2 replies; 16+ messages in thread
From: Ramkumar Ramachandra @ 2013-05-01 12:23 UTC (permalink / raw)
To: Vikrant Varma; +Cc: git
Vikrant Varma wrote:
> Give better advice when trying to merge a branch that doesn't exist. If
> the branch exists in any remotes, display a list of suggestions.
Interesting. Thanks for working on this.
You say advice, but you're not invoking advise() or guarding the
advice with an advice.* -- the advice is undoubtedly helpful, but not
everyone wants to see it.
> diff --git a/help.c b/help.c
> index 02ba043..faf18b9 100644
> --- a/help.c
> +++ b/help.c
> @@ -7,6 +7,7 @@
> #include "string-list.h"
> #include "column.h"
> #include "version.h"
> +#include "refs.h"
>
> void add_cmdname(struct cmdnames *cmds, const char *name, int len)
> {
> @@ -404,3 +405,46 @@ int cmd_version(int argc, const char **argv, const char *prefix)
> printf("git version %s\n", git_version_string);
> return 0;
> }
> +
> +struct similar_ref_cb {
I see that there are other structs in our codebase suffixing _cb, to
indicate "callback data". I normally reserve _cb for callback
functions.
> + const char *base_ref;
> + struct string_list similar_refs;
Okay, so you might have more than one matching candidate.
> +static int append_similar_ref(const char* refname, const unsigned char *sha1, int flags, void *cb_data)
> +{
> + int i;
> + struct similar_ref_cb *cb = (struct similar_ref_cb *)(cb_data);
> + for (i = strlen(refname); refname[i] != '/'; i--)
> + ;
Er, what is this? A re-implementation of strrchr()?
> + /* A remote branch of the same name is deemed similar */
> + if (!prefixcmp(refname, "refs/remotes/") && !strcmp(refname + i + 1, cb->base_ref))
> + string_list_append(&(cb->similar_refs), refname + 13);
What is 13? Please use strlen("refs/remotes/") for readability.
I don't like the + i + 1 thing, but you should be able to get rid of
it with strrchr().
> +void help_unknown_ref(const char* ref) {
> + int i;
> + struct similar_ref_cb ref_cb;
> + ref_cb.similar_refs = (struct string_list)STRING_LIST_INIT_NODUP;
Why are you casting STRING_LIST_INIT_NODUP?
> + ref_cb.base_ref = ref;
> +
> + for_each_ref(append_similar_ref, &ref_cb);
> +
> + fprintf_ln(stderr, _("fatal: %s - not something we can merge"), ref);
Hm, "fatal: " was emitted by die() earlier. I wonder if something
like error() will be nicer than hard-coding "fatal: ".
> + if (ref_cb.similar_refs.nr > 0) {
> + fprintf_ln(stderr,
> + Q_("\nDid you mean this?",
> + "\nDid you mean one of these?",
> + ref_cb.similar_refs.nr));
Hm, why did you use Q_?
> + for (i = 0; i < ref_cb.similar_refs.nr; i++)
> + fprintf(stderr, "\t%s\n", ref_cb.similar_refs.items[i].string);
> + }
> + exit(1);
die() exits with 128, no? Why are you exiting with 1 now?
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 1/2] help: add help_unknown_ref
2013-05-01 12:23 ` Ramkumar Ramachandra
@ 2013-05-01 14:06 ` Matthieu Moy
2013-05-01 19:55 ` Vikrant Varma
1 sibling, 0 replies; 16+ messages in thread
From: Matthieu Moy @ 2013-05-01 14:06 UTC (permalink / raw)
To: Ramkumar Ramachandra; +Cc: Vikrant Varma, git
Ramkumar Ramachandra <artagnon@gmail.com> writes:
> You say advice, but you're not invoking advise() or guarding the
> advice with an advice.* -- the advice is undoubtedly helpful, but not
> everyone wants to see it.
Quite franckly, I don't see why anybody would need to disable it.
advice.* is very nice to disable messages that are shown in normal Git
usage (e.g. running "git status" or attempting a non-fast forward push),
but this is clearly a user-error, that an advanced user is not supposed
to see anyway.
--
Matthieu Moy
http://www-verimag.imag.fr/~moy/
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 0/2] Better advice on merge
2013-05-01 11:22 [PATCH 0/2] Better advice on merge Vikrant Varma
2013-05-01 11:22 ` [PATCH 1/2] help: add help_unknown_ref Vikrant Varma
2013-05-01 11:22 ` [PATCH 2/2] merge: use help_unknown_ref instead of die Vikrant Varma
@ 2013-05-01 18:27 ` Jonathan Nieder
2013-05-01 23:06 ` Vikrant Varma
2 siblings, 1 reply; 16+ messages in thread
From: Jonathan Nieder @ 2013-05-01 18:27 UTC (permalink / raw)
To: Vikrant Varma; +Cc: git
Vikrant Varma wrote:
> If origin/foo exists, but foo doesn't:
>
> $ git merge foo
> fatal: foo - not something we can merge
>
> This patch series improves the error message. If a remote branch exists
> with the same name, it now says:
>
> $ git merge foo
> fatal: foo - not something we can merge
>
> Did you mean this?
> origin/foo
Fun. :)
I haven't looked at the patches closely. My only immediate thoughts
are:
- It would be nice to add a test under t/, so we can be sure without
manually testing it that this new feature doesn't break in the
future. See t/README if interested. I guess it would be t7613.
- Since the first patch isn't useful without or logically separate
from the second, this would probably be easier to read as a single
patch.
Thanks for your work, and hope that helps.
Sincerely,
Jonathan
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 1/2] help: add help_unknown_ref
2013-05-01 11:22 ` [PATCH 1/2] help: add help_unknown_ref Vikrant Varma
2013-05-01 12:23 ` Ramkumar Ramachandra
@ 2013-05-01 18:35 ` Junio C Hamano
2013-05-01 22:26 ` Vikrant Varma
1 sibling, 1 reply; 16+ messages in thread
From: Junio C Hamano @ 2013-05-01 18:35 UTC (permalink / raw)
To: Vikrant Varma; +Cc: git
Vikrant Varma <vikrant.varma94@gmail.com> writes:
> Give better advice when trying to merge a branch that doesn't exist. If
> the branch exists in any remotes, display a list of suggestions.
>
> Example:
> $ git merge foo
> fatal: foo - not something we can merge
>
> Did you mean this?
> bar/foo
>
> Signed-off-by: Vikrant Varma <vikrant.varma94@gmail.com>
> ---
Nicely explained.
If you step back a bit, you would notice two things.
(1) Saying 'foo' when the user means 'origin/foo' is hardly the
only (or even the most common) kind of mistake that the code
you need to add to 'git merge' would encounter and could help
the user with. "git merge origin/mastre" and "orign/master"
may benefit from a typofix as well, and the mechanism to come
up with the suggestion is likely to hook to the same codepath
you are modifying with this patch, even though the logic to
come up with the suggested alternatives may be different.
(2) "merge" is not the single command that user may make this kind
of mistake the command could help and use the same helper.
"git branch myfoo foo" may want to suggest "origin/foo", for
example. I just typed "git checkout mater", which could have
been easily corrected to "git checkout master" with a mechanism
like this.
> help.c | 44 ++++++++++++++++++++++++++++++++++++++++++++
> help.h | 6 ++++++
> 2 files changed, 50 insertions(+)
>
> diff --git a/help.c b/help.c
> index 02ba043..faf18b9 100644
> --- a/help.c
> +++ b/help.c
> @@ -7,6 +7,7 @@
> #include "string-list.h"
> #include "column.h"
> #include "version.h"
> +#include "refs.h"
>
> void add_cmdname(struct cmdnames *cmds, const char *name, int len)
> {
> @@ -404,3 +405,46 @@ int cmd_version(int argc, const char **argv, const char *prefix)
> printf("git version %s\n", git_version_string);
> return 0;
> }
> +
> +struct similar_ref_cb {
> + const char *base_ref;
> + struct string_list similar_refs;
> +};
> +
> +static int append_similar_ref(const char* refname, const unsigned char *sha1, int flags, void *cb_data)
An asterisk sticks to the parameter name, not type, like this:
..._ref(const char *refname, ...
There are other places with the same style problem in this patch.
> +{
> + int i;
> + struct similar_ref_cb *cb = (struct similar_ref_cb *)(cb_data);
> + for (i = strlen(refname); refname[i] != '/'; i--)
> + ;
Indent with two HT, not HT followed by a run of SPs.
> + /* A remote branch of the same name is deemed similar */
> + if (!prefixcmp(refname, "refs/remotes/") && !strcmp(refname + i + 1, cb->base_ref))
An overlong line can and should be split, perhaps like this:
if (!prefixcmp(... very long parameter list ...) &&
!strcmp(... another very long parameter list ...))
> + string_list_append(&(cb->similar_refs), refname + 13);
To suggest "orign/foo" => "origin/foo", "foz" => "origin/foo", and
"mastre" => "master", using levenshtein.c would help here.
You would special case the distance between "foo" and "origin/foo"
as "very low", e.g. 0, and compute levenshtein distance with refname
and cb->base_ref, store the result in the .util field of the string
list, and sort it at the end after you finish iterating using the
computed distance to come up with the list of suggestions.
> + return 0;
> +}
> +
> +void help_unknown_ref(const char* ref) {
> + int i;
> + struct similar_ref_cb ref_cb;
> + ref_cb.similar_refs = (struct string_list)STRING_LIST_INIT_NODUP;
> + ref_cb.base_ref = ref;
> +
> + for_each_ref(append_similar_ref, &ref_cb);
> +
> + fprintf_ln(stderr, _("fatal: %s - not something we can merge"), ref);
When you consider the point (2) above, it becomes clear why this
message does not belong to a helper function with a bland and
generic name "help unknown ref".
This API is misdesigned. A possible alternative that may be better
reusable would be to have a helper that is used to come up with a
list of suggestions and make the caller responsible for emitting the
error message.
> + if (ref_cb.similar_refs.nr > 0) {
> + fprintf_ln(stderr,
> + Q_("\nDid you mean this?",
> + "\nDid you mean one of these?",
> + ref_cb.similar_refs.nr));
> +
> + for (i = 0; i < ref_cb.similar_refs.nr; i++)
> + fprintf(stderr, "\t%s\n", ref_cb.similar_refs.items[i].string);
> + }
> + exit(1);
> +}
> +
> +
> +
> +
Do not add trailing blank lines.
> diff --git a/help.h b/help.h
> index 0ae5a12..613cb45 100644
> --- a/help.h
> +++ b/help.h
> @@ -27,4 +27,10 @@ extern void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes);
> extern int is_in_cmdlist(struct cmdnames *cmds, const char *name);
> extern void list_commands(unsigned int colopts, struct cmdnames *main_cmds, struct cmdnames *other_cmds);
>
> +/*
> + * ref is not something that can be merged. Print a list of remote branches of the
> + * same name that the user might have meant.
> + */
> +extern void help_unknown_ref(const char* ref);
> +
> #endif /* HELP_H */
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 2/2] merge: use help_unknown_ref instead of die
2013-05-01 11:22 ` [PATCH 2/2] merge: use help_unknown_ref instead of die Vikrant Varma
@ 2013-05-01 18:36 ` Junio C Hamano
0 siblings, 0 replies; 16+ messages in thread
From: Junio C Hamano @ 2013-05-01 18:36 UTC (permalink / raw)
To: Vikrant Varma; +Cc: git
Vikrant Varma <vikrant.varma94@gmail.com> writes:
> The previous patch added help_unknown_ref to print a more helpful error
> message when trying to merge a branch that doesn't exist, by printing a
> list of remote branches the user might have meant. Use it.
>
> Signed-off-by: Vikrant Varma <vikrant.varma94@gmail.com>
> ---
> builtin/merge.c | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/builtin/merge.c b/builtin/merge.c
> index 3e2daa3..0f1f39b 100644
> --- a/builtin/merge.c
> +++ b/builtin/merge.c
> @@ -1053,8 +1053,8 @@ static struct commit_list *collect_parents(struct commit *head_commit,
> remotes = &commit_list_insert(head_commit, remotes)->next;
> for (i = 0; i < argc; i++) {
> struct commit *commit = get_merge_parent(argv[i]);
> - if (!commit)
> - die(_("%s - not something we can merge"), argv[i]);
> + if (!commit)
> + help_unknown_ref(argv[i]);
This calling site may become something like:
if (!commit) {
char *suggestion;
suggestion = guess_misspelled_ref(argv[i]);
die(suggestion == NULL
? _("%s - not something we can merge")
: _("%s - not something we can merge\n"
"Perhaps you meant one of these?\n"
"%s"), argv[i], suggestion);
}
if you really want to keep "not something we can merge" at the top.
I however suspect that this might be easier for the reader.
if (!commit) {
struct string_list *suggestion;
suggestion = guess_misspelled_ref(argv[i]);
if (suggestion)
print_string_list(suggestion,
_("Perhaps you meant one of these?"));
die(_("%s - not something we can merge"), argv[i]);
}
Note that print_string_list() needs to be enhanced so that the
caller can tell it not to show the .util field if you go in this
direction.
> remotes = &commit_list_insert(commit, remotes)->next;
> }
> *remotes = NULL;
Thanks.
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 1/2] help: add help_unknown_ref
2013-05-01 12:23 ` Ramkumar Ramachandra
2013-05-01 14:06 ` Matthieu Moy
@ 2013-05-01 19:55 ` Vikrant Varma
2013-05-01 20:23 ` Johannes Sixt
2013-05-01 20:32 ` Ramkumar Ramachandra
1 sibling, 2 replies; 16+ messages in thread
From: Vikrant Varma @ 2013-05-01 19:55 UTC (permalink / raw)
To: Ramkumar Ramachandra; +Cc: git
On 01-05-2013 17:53, Ramkumar Ramachandra wrote:
> Vikrant Varma wrote:
>> Give better advice when trying to merge a branch that doesn't exist. If
>> the branch exists in any remotes, display a list of suggestions.
>
> Interesting. Thanks for working on this.
>
> You say advice, but you're not invoking advise() or guarding the
> advice with an advice.* -- the advice is undoubtedly helpful, but not
> everyone wants to see it.
>
I agree with Matthieu, the people who don't want to see this advice
never will, because they won't make that mistake. Maybe advice is the
wrong word, corrections might be more appropriate.
>> diff --git a/help.c b/help.c
>> index 02ba043..faf18b9 100644
>> --- a/help.c
>> +++ b/help.c
>> @@ -7,6 +7,7 @@
>> #include "string-list.h"
>> #include "column.h"
>> #include "version.h"
>> +#include "refs.h"
>>
>> void add_cmdname(struct cmdnames *cmds, const char *name, int len)
>> {
>> @@ -404,3 +405,46 @@ int cmd_version(int argc, const char **argv, const char *prefix)
>> printf("git version %s\n", git_version_string);
>> return 0;
>> }
>> +
>> +struct similar_ref_cb {
>
> I see that there are other structs in our codebase suffixing _cb, to
> indicate "callback data". I normally reserve _cb for callback
> functions.
I'm following the convention (builtin/merge.c: struct append_ref_cb). If
there's a better way to name it, I'll use that.
>> +static int append_similar_ref(const char* refname, const unsigned char *sha1, int flags, void *cb_data)
>> +{
>> + int i;
>> + struct similar_ref_cb *cb = (struct similar_ref_cb *)(cb_data);
>> + for (i = strlen(refname); refname[i] != '/'; i--)
>> + ;
>
> Er, what is this? A re-implementation of strrchr()?
>
Oh so that's what it's called. Apologies, will fix this.
>> + /* A remote branch of the same name is deemed similar */
>> + if (!prefixcmp(refname, "refs/remotes/") && !strcmp(refname + i + 1, cb->base_ref))
>> + string_list_append(&(cb->similar_refs), refname + 13);
>
> What is 13? Please use strlen("refs/remotes/") for readability.
>
Yes, will fix this too.
>> +void help_unknown_ref(const char* ref) {
>> + int i;
>> + struct similar_ref_cb ref_cb;
>> + ref_cb.similar_refs = (struct string_list)STRING_LIST_INIT_NODUP;
>
> Why are you casting STRING_LIST_INIT_NODUP?
>
>> + ref_cb.base_ref = ref;
ref_cb.similar_refs has already been defined. The compiler won't let me
assign to it unless I cast first. However, I think compound literals are
a C99/gcc feature. Is this better?
struct similar_ref_cb ref_cb = {ref, STRING_LIST_INIT_NODUP};
>> + if (ref_cb.similar_refs.nr > 0) {
>> + fprintf_ln(stderr,
>> + Q_("\nDid you mean this?",
>> + "\nDid you mean one of these?",
>> + ref_cb.similar_refs.nr));
>
> Hm, why did you use Q_?
>
Q_ is a pluralization helper that picks one of the two strings based on
ref_cb.similar_refs.nr. It's used in help.c:help_unknown_cmd for the
same reason.
>> + for (i = 0; i < ref_cb.similar_refs.nr; i++)
>> + fprintf(stderr, "\t%s\n", ref_cb.similar_refs.items[i].string);
>> + }
>> + exit(1);
>
> die() exits with 128, no? Why are you exiting with 1 now?
>
Again, because help_unknown_cmd exited with 1. I've tried to follow the
convention as laid down there. What's the significance of the error code
for die()? When is it correct to use die(), and when to use error()
followed by exit(128)?
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 1/2] help: add help_unknown_ref
2013-05-01 19:55 ` Vikrant Varma
@ 2013-05-01 20:23 ` Johannes Sixt
2013-05-01 20:32 ` Ramkumar Ramachandra
1 sibling, 0 replies; 16+ messages in thread
From: Johannes Sixt @ 2013-05-01 20:23 UTC (permalink / raw)
To: Vikrant Varma; +Cc: Ramkumar Ramachandra, git
Am 01.05.2013 21:55, schrieb Vikrant Varma:
> On 01-05-2013 17:53, Ramkumar Ramachandra wrote:
>> Vikrant Varma wrote:
>>> +void help_unknown_ref(const char* ref) {
>>> + int i;
>>> + struct similar_ref_cb ref_cb;
>>> + ref_cb.similar_refs = (struct string_list)STRING_LIST_INIT_NODUP;
>>
>> Why are you casting STRING_LIST_INIT_NODUP?
>>
>>> + ref_cb.base_ref = ref;
>
>
> ref_cb.similar_refs has already been defined. The compiler won't let me
> assign to it unless I cast first. However, I think compound literals are
> a C99/gcc feature. Is this better?
>
> struct similar_ref_cb ref_cb = {ref, STRING_LIST_INIT_NODUP};
No. There are compilers that can initialize a struct only with constant
data, but ref is not a constant.
-- Hannes
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 1/2] help: add help_unknown_ref
2013-05-01 19:55 ` Vikrant Varma
2013-05-01 20:23 ` Johannes Sixt
@ 2013-05-01 20:32 ` Ramkumar Ramachandra
2013-05-01 21:45 ` Vikrant Varma
1 sibling, 1 reply; 16+ messages in thread
From: Ramkumar Ramachandra @ 2013-05-01 20:32 UTC (permalink / raw)
To: Vikrant Varma; +Cc: git
Vikrant Varma wrote:
> I agree with Matthieu, the people who don't want to see this advice never
> will, because they won't make that mistake. Maybe advice is the wrong word,
> corrections might be more appropriate.
Makes sense.
Perhaps it would make sense to hook into help.autocorrect. I would
definitely like that.
>> I see that there are other structs in our codebase suffixing _cb, to
>> indicate "callback data". I normally reserve _cb for callback
>> functions.
>
>
> I'm following the convention (builtin/merge.c: struct append_ref_cb). If
> there's a better way to name it, I'll use that.
Fine leaving it as it is.
> ref_cb.similar_refs has already been defined. The compiler won't let me
> assign to it unless I cast first. However, I think compound literals are a
> C99/gcc feature. Is this better?
>
> struct similar_ref_cb ref_cb = {ref, STRING_LIST_INIT_NODUP};
As Johannes pointed out, ref is a variable and that is problematic.
Leave the cast on: I didn't notice the compiler warning in my head.
> Q_ is a pluralization helper that picks one of the two strings based on
> ref_cb.similar_refs.nr. It's used in help.c:help_unknown_cmd for the same
> reason.
Thanks.
> Again, because help_unknown_cmd exited with 1. I've tried to follow the
> convention as laid down there.
Ah, I didn't notice that.
> What's the significance of the error code for
> die()?
When something _really_ bad happens, exit() with 128, without
bothering to go up the callstack. Return error() is a common idiom to
print an error message immediately, and propagate the return status -1
up the callstack.
> When is it correct to use die(), and when to use error() followed by
> exit(128)?
exit(128) is a bit rare [grep for it yourself]. It's for when you
want to die(), but exit() only after doing an important task in the
caller.
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 1/2] help: add help_unknown_ref
2013-05-01 20:32 ` Ramkumar Ramachandra
@ 2013-05-01 21:45 ` Vikrant Varma
2013-05-01 22:12 ` Junio C Hamano
0 siblings, 1 reply; 16+ messages in thread
From: Vikrant Varma @ 2013-05-01 21:45 UTC (permalink / raw)
To: Ramkumar Ramachandra; +Cc: git
On 02-05-2013 02:02, Ramkumar Ramachandra wrote:
>> ref_cb.similar_refs has already been defined. The compiler won't let me
>> assign to it unless I cast first. However, I think compound literals are a
>> C99/gcc feature. Is this better?
>>
>> struct similar_ref_cb ref_cb = {ref, STRING_LIST_INIT_NODUP};
>
> As Johannes pointed out, ref is a variable and that is problematic.
> Leave the cast on: I didn't notice the compiler warning in my head.
>
Is it okay to use a compound literal? It's not supported in C89.
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 1/2] help: add help_unknown_ref
2013-05-01 21:45 ` Vikrant Varma
@ 2013-05-01 22:12 ` Junio C Hamano
0 siblings, 0 replies; 16+ messages in thread
From: Junio C Hamano @ 2013-05-01 22:12 UTC (permalink / raw)
To: Vikrant Varma; +Cc: Ramkumar Ramachandra, git
Vikrant Varma <vikrant.varma94@gmail.com> writes:
> On 02-05-2013 02:02, Ramkumar Ramachandra wrote:
>>> ref_cb.similar_refs has already been defined. The compiler won't let me
>>> assign to it unless I cast first. However, I think compound literals are a
>>> C99/gcc feature. Is this better?
>>>
>>> struct similar_ref_cb ref_cb = {ref, STRING_LIST_INIT_NODUP};
>>
>> As Johannes pointed out, ref is a variable and that is problematic.
>> Leave the cast on: I didn't notice the compiler warning in my head.
>>
> Is it okay to use a compound literal? It's not supported in C89.
Building on top of what was suggested in the other message, the
helper could be made more reusable by doing something like this:
int suggest_misspelt_ref(const char *ref, struct string_list *suggested);
and the caller can do
if (!commit) {
struct string_list suggested = STRING_LIST_INIT;
if (suggest_misspelt_ref(argv[1], &suggested)) {
... Did you mean one of these??? ...
string_list_clear(&suggested);
}
die(_("'%s' is not something we can merge'), argv[1]);
}
So I think this point is moot. Of course, similar_ref_cb needs to
be updated to keep a pointer to an existing string_list, not an
instance of its own string_list.
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 1/2] help: add help_unknown_ref
2013-05-01 18:35 ` Junio C Hamano
@ 2013-05-01 22:26 ` Vikrant Varma
2013-05-01 23:07 ` Junio C Hamano
0 siblings, 1 reply; 16+ messages in thread
From: Vikrant Varma @ 2013-05-01 22:26 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
On 02-05-2013 00:05, Junio C Hamano wrote:
> If you step back a bit, you would notice two things.
>
> (1) Saying 'foo' when the user means 'origin/foo' is hardly the
> only (or even the most common) kind of mistake that the code
> you need to add to 'git merge' would encounter and could help
> the user with.
Yes. I like your suggestion of using levenshtein.c, similar to what's
been done in help.c:help_unknown_cmd. However, where do you draw the
line? Do you also suggest 'remotes/origin/foo' for 'remotes/foo'? Also,
which would you then prioritize for 'foo': 'fob' (this is local) or
'origin/foo'? In other words, what kind of mistakes are you looking to
correct - typos, or forgetful omissions, or both and something more?
> (2) "merge" is not the single command that user may make this kind
> of mistake the command could help and use the same helper.
> "git branch myfoo foo" may want to suggest "origin/foo", for
> example. I just typed "git checkout mater", which could have
> been easily corrected to "git checkout master" with a mechanism
> like this.
>
Of course, once the suggestion mechanism is in place, it can be used to
replace unfriendly die()s in every command that takes a ref.
>
> An asterisk sticks to the parameter name, not type
>
> Indent with two HT, not HT followed by a run of SPs.
>
> An overlong line can and should be split
>
> Do not add trailing blank lines.
>
Thanks, will fix this.
> When you consider the point (2) above, it becomes clear why this
> message does not belong to a helper function with a bland and
> generic name "help unknown ref".
>
> This API is misdesigned. A possible alternative that may be better
> reusable would be to have a helper that is used to come up with a
> list of suggestions and make the caller responsible for emitting the
> error message.
>
Yes, I think a better name is needed, I was trying to follow along the
lines of help_unknown_cmd.
However, making the caller responsible for printing the suggestions may
not be the best alternative. Borrowing from the way help_unknown_cmd
works, in help_unknown_ref we could:
1) check if autocorrect is on, returning the corrected refname to the
calling function, otherwise
2) print an error message, a list of suggestions, and exit()
I think this makes for a clean and reusable API, and requires changing
one line of code in every function that currently calls die().
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 0/2] Better advice on merge
2013-05-01 18:27 ` [PATCH 0/2] Better advice on merge Jonathan Nieder
@ 2013-05-01 23:06 ` Vikrant Varma
0 siblings, 0 replies; 16+ messages in thread
From: Vikrant Varma @ 2013-05-01 23:06 UTC (permalink / raw)
To: Jonathan Nieder; +Cc: git
On 01-05-2013 23:57, Jonathan Nieder wrote:
> - It would be nice to add a test under t/
>
Thanks, I'll do that.
> - Since the first patch isn't useful without or logically separate
> from the second, this would probably be easier to read as a single
> patch.
>
They are logically separate, even if the first isn't useful without the
second. I wanted to segregate the task of defining a helper function
that corrects the ref name, and changing the parts of the code that
should use it. The reason the second is separate is that once the first
is in place, even commands like 'checkout' can use the helper function.
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 1/2] help: add help_unknown_ref
2013-05-01 22:26 ` Vikrant Varma
@ 2013-05-01 23:07 ` Junio C Hamano
0 siblings, 0 replies; 16+ messages in thread
From: Junio C Hamano @ 2013-05-01 23:07 UTC (permalink / raw)
To: Vikrant Varma; +Cc: git
Vikrant Varma <vikrant.varma94@gmail.com> writes:
> On 02-05-2013 00:05, Junio C Hamano wrote:
>> If you step back a bit, you would notice two things.
>>
>> (1) Saying 'foo' when the user means 'origin/foo' is hardly the
>> only (or even the most common) kind of mistake that the code
>> you need to add to 'git merge' would encounter and could help
>> the user with.
>
> Yes. I like your suggestion of using levenshtein.c, similar to what's
> been done in help.c:help_unknown_cmd. However, where do you draw the
> line? Do you also suggest 'remotes/origin/foo' for 'remotes/foo'?
> Also, which would you then prioritize for 'foo': 'fob' (this is local)
> or 'origin/foo'? In other words, what kind of mistakes are you looking
> to correct - typos, or forgetful omissions, or both and something
> more?
This is your itch, so you get to choose what you would propose to
the list and have people tweak it ;-)
I personally think the first version should not use levenshtein _at
all_ (hence not solving my 'git checkout mastr'). I however want to
make sure the code is structured in such a way that allows other
people to build on top later.
> However, making the caller responsible for printing the suggestions
> may not be the best alternative.
That "responsibility" could be encapsulated in a separate helper
function the callers call instead of die().
The lower level machinery to come up with a suggested list of refs,
when the caller suspects that there is a typo in refs, is the same
across different commands, and it is insufficient to have a single
helper function that hardcodes "not something we can _MERGE_", and
copy the function to create many other helpers that do the same
thing but with different error messages.
You would need two layers, one that collects suggested list of refs,
and another that is directly called by the top-level caller that
takes the refname and the die message, and the latter would use the
former. What I was showing was the lower level one, without the
higher level one that takes die message and a suspicious user input
(the higher level one would be trivial and do not need hand-holding
while designing).
^ permalink raw reply [flat|nested] 16+ messages in thread
end of thread, other threads:[~2013-05-01 23:07 UTC | newest]
Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-05-01 11:22 [PATCH 0/2] Better advice on merge Vikrant Varma
2013-05-01 11:22 ` [PATCH 1/2] help: add help_unknown_ref Vikrant Varma
2013-05-01 12:23 ` Ramkumar Ramachandra
2013-05-01 14:06 ` Matthieu Moy
2013-05-01 19:55 ` Vikrant Varma
2013-05-01 20:23 ` Johannes Sixt
2013-05-01 20:32 ` Ramkumar Ramachandra
2013-05-01 21:45 ` Vikrant Varma
2013-05-01 22:12 ` Junio C Hamano
2013-05-01 18:35 ` Junio C Hamano
2013-05-01 22:26 ` Vikrant Varma
2013-05-01 23:07 ` Junio C Hamano
2013-05-01 11:22 ` [PATCH 2/2] merge: use help_unknown_ref instead of die Vikrant Varma
2013-05-01 18:36 ` Junio C Hamano
2013-05-01 18:27 ` [PATCH 0/2] Better advice on merge Jonathan Nieder
2013-05-01 23:06 ` Vikrant Varma
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).