yunomuのブログ

趣味のこと

gitでタイプミスした時に出るアレ

かみまみた

% git statsu
git: 'statsu' is not a git command. See 'git --help'.

Did you mean this?
        status

これ。

この"Did you mean this?"ってのどうやって出してるのかなって思って、とりあえずgitのソースをgrepしてみたけど(ソースはFri Mar 23 14:50:23 2012 -0700のmaster)

% cd $GIT_SOURCE
% grep -rn statsu *

なにもなし。

% grep -rn "Did you mean" *
Makefile:2464:          echo 2>&1 "Did you mean 'make test'?"; \
help.c:380:             fprintf(stderr, "\nDid you mean %s?\n",
sha1_name.c:924:                            "Did you mean '%s:%s' aka '%s:./%s'?",
sha1_name.c:961:                            "Did you mean ':%d:%s'?",
sha1_name.c:979:                            "Did you mean ':%d:%s' aka ':%d:./%s'?",
t/t1506-rev-parse-diagnosis.sh:14:      Did you mean '$1:$2$3'${2:+ aka $sq$1:./$3$sq}?

help.cっぽい。
この380行目はhelp_unknown_cmd()の最後あたりで、例のメッセージを出している関数のようです。

290 const char *help_unknown_cmd(const char *cmd)
291 {
292     int i, n, best_similarity = 0;
293     struct cmdnames main_cmds, other_cmds;
(略)
340     qsort(main_cmds.names, main_cmds.cnt,
341           sizeof(*main_cmds.names), levenshtein_compare);
342
343     if (!main_cmds.cnt)
344         die ("Uh oh. Your system reports no Git commands at all.");
345
346     /* skip and count prefix matches */
347     for (n = 0; n < main_cmds.cnt && !main_cmds.names[n]->len; n++)
348         ; /* still counting */
349
350     if (main_cmds.cnt <= n) {
351         /* prefix matches with everything? that is too ambiguous */
352         best_similarity = SIMILARITY_FLOOR + 1;
353     } else {
354         /* count all the most similar ones */
355         for (best_similarity = main_cmds.names[n++]->len;
356              (n < main_cmds.cnt &&
357               best_similarity == main_cmds.names[n]->len);
358              n++)
359             ; /* still counting */
360     }
(略)
377     fprintf(stderr, "git: '%s' is not a git command. See 'git --help'.\n", cmd);
378
379     if (SIMILAR_ENOUGH(best_similarity)) {
380         fprintf(stderr, "\nDid you mean %s?\n",
381             n < 2 ? "this": "one of these");
382
383         for (i = 0; i < n; i++)
384             fprintf(stderr, "\t%s\n", main_cmds.names[i]->name);
385     }
386
387     exit(1);
388 }

似てるコマンドを探して、メッセージを出力して終わり。
別に「よくある間違い文字列リスト」みたいなのを全部持っているわけじゃないみたい。そんな辞書あったら面白いかなぁと思ったんだけど。Levenshtein距離を測る関数とかあったから、まあそういうことなんでしょう。