Vikrant Varma <vikrant.varm...@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.varm...@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 */ -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html