{"thread":{"id":"2867","subject":"[PATCH] diff: --abbrev option","startedAt":"2005-12-17T09:41:49Z","lastAt":"2005-12-18T18:35:01Z","messageCount":5,"participants":["Junio C Hamano","Petr Baudis"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"13767","messageId":"7v3bks12n6.fsf@assigned-by-dhcp.cox.net","threadId":"2867","inReplyTo":null,"subject":"[PATCH] diff: --abbrev option","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-12-17T09:41:49Z","receivedAt":"2005-12-17T09:41:49Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"When I show transcripts to explain how something works, I often\nfind myself hand-editing the diff-raw output to shorten various\nobject names in the output.\n\nThis adds --abbrev option to the diff family, which shortens\ndiff-raw output and diff-tree commit id headers.\n\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n\n---\n\n * Earlier I announced that I have this toy in proposed updates\n   without actually showing the code, so here it is.  I have\n   added code to find unique abbreviation as well.  It is\n   primarily useful to quote things in e-mail, like this:\n\n      $ git-rev-parse master | git-diff-tree --pretty -r --abbrev --stdin\n      diff-tree 01385e2... (from 6922471...)\n      Author: Junio C Hamano <junkio@cox.net>\n      Date:   Fri Dec 16 23:12:33 2005 -0800\n\n          Comment fixes.\n\n          Signed-off-by: Junio C Hamano <junkio@cox.net>\n\n      :100755 100755 0266f46... b0e54ed... M\tgit-branch.sh\n      :100755 100755 f241d4b... 36308d2... M\tgit-checkout.sh\n\n Documentation/diff-options.txt |    7 +++++\n diff-tree.c                    |   40 +++++++++++++++++-----------\n diff.c                         |   57 ++++++++++++++++++++++++++++++++++++----\n diff.h                         |    9 ++++++\n sha1_name.c                    |    3 ++\n 5 files changed, 93 insertions(+), 23 deletions(-)\n\nea2d93b12d2deae007311d0898616b4bb2f299d2\ndiff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt\nindex 6b496ed..3d1175e 100644\n--- a/Documentation/diff-options.txt\n+++ b/Documentation/diff-options.txt\n@@ -18,6 +18,13 @@\n \tobject name of pre- and post-image blob on the \"index\"\n \tline when generating a patch format output.\t\n \n+--abbrev::\n+\tInstead of showing the full 40-byte hexadecimal object\n+\tname in diff-raw format output and diff-tree header\n+\tlines, show only handful prefix.  This is independent of\n+\t--full-index option above, which controls the diff-patch\n+\toutput format.\n+\n -B::\n \tBreak complete rewrite changes into pairs of delete and create.\n \ndiff --git a/diff-tree.c b/diff-tree.c\nindex d56d921..efa2b94 100644\n--- a/diff-tree.c\n+++ b/diff-tree.c\n@@ -14,11 +14,6 @@ static enum cmit_fmt commit_format = CMI\n \n static struct diff_options diff_options;\n \n-static void call_diff_setup_done(void)\n-{\n-\tdiff_setup_done(&diff_options);\n-}\n-\n static int call_diff_flush(void)\n {\n \tdiffcore_std(&diff_options);\n@@ -43,7 +38,6 @@ static int diff_tree_sha1_top(const unsi\n {\n \tint ret;\n \n-\tcall_diff_setup_done();\n \tret = diff_tree_sha1(old, new, base, &diff_options);\n \tcall_diff_flush();\n \treturn ret;\n@@ -55,7 +49,6 @@ static int diff_root_tree(const unsigned\n \tvoid *tree;\n \tstruct tree_desc empty, real;\n \n-\tcall_diff_setup_done();\n \ttree = read_object_with_reference(new, \"tree\", &real.size, NULL);\n \tif (!tree)\n \t\tdie(\"unable to read root tree (%s)\", sha1_to_hex(new));\n@@ -69,18 +62,29 @@ static int diff_root_tree(const unsigned\n \treturn retval;\n }\n \n-static const char *generate_header(const char *commit, const char *parent, const char *msg)\n+static const char *generate_header(const unsigned char *commit_sha1,\n+\t\t\t\t   const unsigned char *parent_sha1,\n+\t\t\t\t   const char *msg)\n {\n \tstatic char this_header[16384];\n \tint offset;\n \tunsigned long len;\n+\tint abbrev = diff_options.abbrev;\n \n \tif (!verbose_header)\n-\t\treturn commit;\n+\t\treturn sha1_to_hex(commit_sha1);\n \n \tlen = strlen(msg);\n-\toffset = sprintf(this_header, \"%s%s (from %s)\\n\", header_prefix, commit, parent);\n-\toffset += pretty_print_commit(commit_format, msg, len, this_header + offset, sizeof(this_header) - offset);\n+\n+\toffset = sprintf(this_header, \"%s%s \",\n+\t\t\t header_prefix,\n+\t\t\t diff_unique_abbrev(commit_sha1, abbrev));\n+\toffset += sprintf(this_header + offset, \"(from %s)\\n\",\n+\t\t\t parent_sha1 ?\n+\t\t\t diff_unique_abbrev(parent_sha1, abbrev) : \"root\");\n+\toffset += pretty_print_commit(commit_format, msg, len,\n+\t\t\t\t      this_header + offset,\n+\t\t\t\t      sizeof(this_header) - offset);\n \treturn this_header;\n }\n \n@@ -99,18 +103,18 @@ static int diff_tree_commit(const unsign\n \t\n \t/* Root commit? */\n \tif (show_root_diff && !commit->parents) {\n-\t\theader = generate_header(name, \"root\", commit->buffer);\n+\t\theader = generate_header(sha1, NULL, commit->buffer);\n \t\tdiff_root_tree(commit_sha1, \"\");\n \t}\n \n \t/* More than one parent? */\n \tif (ignore_merges && commit->parents && commit->parents->next)\n-\t\t\treturn 0;\n+\t\treturn 0;\n \n \tfor (parents = commit->parents; parents; parents = parents->next) {\n \t\tstruct commit *parent = parents->item;\n-\t\theader = generate_header(name,\n-\t\t\t\t\t sha1_to_hex(parent->object.sha1),\n+\t\theader = generate_header(sha1,\n+\t\t\t\t\t parent->object.sha1,\n \t\t\t\t\t commit->buffer);\n \t\tdiff_tree_sha1_top(parent->object.sha1, commit_sha1, \"\");\n \t\tif (!header && verbose_header) {\n@@ -129,6 +133,7 @@ static int diff_tree_stdin(char *line)\n \tint len = strlen(line);\n \tunsigned char commit[20], parent[20];\n \tstatic char this_header[1000];\n+\tint abbrev = diff_options.abbrev;\n \n \tif (!len || line[len-1] != '\\n')\n \t\treturn -1;\n@@ -138,7 +143,9 @@ static int diff_tree_stdin(char *line)\n \tif (isspace(line[40]) && !get_sha1_hex(line+41, parent)) {\n \t\tline[40] = 0;\n \t\tline[81] = 0;\n-\t\tsprintf(this_header, \"%s (from %s)\\n\", line, line+41);\n+\t\tsprintf(this_header, \"%s (from %s)\\n\",\n+\t\t\tdiff_unique_abbrev(commit, abbrev),\n+\t\t\tdiff_unique_abbrev(parent, abbrev));\n \t\theader = this_header;\n \t\treturn diff_tree_sha1_top(parent, commit, \"\");\n \t}\n@@ -239,6 +246,7 @@ int main(int argc, const char **argv)\n \t\tdiff_options.recursive = 1;\n \n \tdiff_tree_setup_paths(get_pathspec(prefix, argv));\n+\tdiff_setup_done(&diff_options);\n \n \tswitch (nr_sha1) {\n \tcase 0:\ndiff --git a/diff.c b/diff.c\nindex 2e0797b..c815918 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -723,11 +723,13 @@ static void run_diff(struct diff_filepai\n \n \tif (memcmp(one->sha1, two->sha1, 20)) {\n \t\tchar one_sha1[41];\n-\t\tconst char *index_fmt = o->full_index ? \"index %s..%s\" : \"index %.7s..%.7s\";\n+\t\tint abbrev = o->full_index ? 40 : DIFF_DEFAULT_INDEX_ABBREV;\n \t\tmemcpy(one_sha1, sha1_to_hex(one->sha1), 41);\n \n \t\tlen += snprintf(msg + len, sizeof(msg) - len,\n-\t\t\t\tindex_fmt, one_sha1, sha1_to_hex(two->sha1));\n+\t\t\t\t\"index %.*s..%.*s\",\n+\t\t\t\tabbrev, one_sha1, abbrev,\n+\t\t\t\tsha1_to_hex(two->sha1));\n \t\tif (one->mode == two->mode)\n \t\t\tlen += snprintf(msg + len, sizeof(msg) - len,\n \t\t\t\t\t\" %06o\", one->mode);\n@@ -791,6 +793,8 @@ int diff_setup_done(struct diff_options \n \t}\n \tif (options->setup & DIFF_SETUP_USE_SIZE_CACHE)\n \t\tuse_size_cache = 1;\n+\tif (options->abbrev <= 0 || 40 < options->abbrev)\n+\t\toptions->abbrev = 40; /* full */\n \n \treturn 0;\n }\n@@ -841,6 +845,10 @@ int diff_opt_parse(struct diff_options *\n \t}\n \telse if (!strcmp(arg, \"--find-copies-harder\"))\n \t\toptions->find_copies_harder = 1;\n+\telse if (!strcmp(arg, \"--abbrev\"))\n+\t\toptions->abbrev = DIFF_DEFAULT_ABBREV;\n+\telse if (!strncmp(arg, \"--abbrev=\", 9))\n+\t\toptions->abbrev = strtoul(arg + 9, NULL, 10);\n \telse\n \t\treturn 0;\n \treturn 1;\n@@ -947,14 +955,49 @@ void diff_free_filepair(struct diff_file\n \tfree(p);\n }\n \n+/* This is different from find_unique_abbrev() in that\n+ * it needs to deal with 0{40} SHA1.\n+ */\n+const char *diff_unique_abbrev(const unsigned char *sha1, int len)\n+{\n+\tint abblen;\n+\tconst char *abbrev;\n+\tif (len == 40)\n+\t\treturn sha1_to_hex(sha1);\n+\n+\tabbrev = find_unique_abbrev(sha1, len);\n+\tif (!abbrev) {\n+\t\tif (!memcmp(sha1, null_sha1, 20)) {\n+\t\t\tchar *buf = sha1_to_hex(null_sha1);\n+\t\t\tif (len < 37)\n+\t\t\t\tstrcpy(buf + len, \"...\");\n+\t\t\treturn buf;\n+\t\t}\n+\t\telse \n+\t\t\treturn sha1_to_hex(sha1);\n+\t}\n+\tabblen = strlen(abbrev);\n+\tif (abblen < 37) {\n+\t\tstatic char hex[41];\n+\t\tif (len < abblen && abblen <= len + 2)\n+\t\t\tsprintf(hex, \"%s%.*s\", abbrev, len+3-abblen, \"..\");\n+\t\telse\n+\t\t\tsprintf(hex, \"%s...\", abbrev);\n+\t\treturn hex;\n+\t}\n+\treturn sha1_to_hex(sha1);\n+}\n+\n static void diff_flush_raw(struct diff_filepair *p,\n \t\t\t   int line_termination,\n \t\t\t   int inter_name_termination,\n-\t\t\t   int output_format)\n+\t\t\t   struct diff_options *options)\n {\n \tint two_paths;\n \tchar status[10];\n+\tint abbrev = options->abbrev;\n \tconst char *path_one, *path_two;\n+\tint output_format = options->output_format;\n \n \tpath_one = p->one->path;\n \tpath_two = p->two->path;\n@@ -985,8 +1028,10 @@ static void diff_flush_raw(struct diff_f\n \t}\n \tif (output_format != DIFF_FORMAT_NAME_STATUS) {\n \t\tprintf(\":%06o %06o %s \",\n-\t\t       p->one->mode, p->two->mode, sha1_to_hex(p->one->sha1));\n-\t\tprintf(\"%s \", sha1_to_hex(p->two->sha1));\n+\t\t       p->one->mode, p->two->mode,\n+\t\t       diff_unique_abbrev(p->one->sha1, abbrev));\n+\t\tprintf(\"%s \",\n+\t\t       diff_unique_abbrev(p->two->sha1, abbrev));\n \t}\n \tprintf(\"%s%c%s\", status, inter_name_termination, path_one);\n \tif (two_paths)\n@@ -1194,7 +1239,7 @@ void diff_flush(struct diff_options *opt\n \t\tcase DIFF_FORMAT_NAME_STATUS:\n \t\t\tdiff_flush_raw(p, line_termination,\n \t\t\t\t       inter_name_termination,\n-\t\t\t\t       diff_output_format);\n+\t\t\t\t       options);\n \t\t\tbreak;\n \t\tcase DIFF_FORMAT_NAME:\n \t\t\tdiff_flush_name(p,\ndiff --git a/diff.h b/diff.h\nindex 32b4780..c3486ff 100644\n--- a/diff.h\n+++ b/diff.h\n@@ -44,6 +44,7 @@ struct diff_options {\n \tint reverse_diff;\n \tint rename_limit;\n \tint setup;\n+\tint abbrev;\n \n \tchange_fn_t change;\n \tadd_remove_fn_t add_remove;\n@@ -87,6 +88,9 @@ extern int diff_setup_done(struct diff_o\n \n #define DIFF_PICKAXE_ALL\t1\n \n+#define DIFF_DEFAULT_INDEX_ABBREV\t7 /* hex digits */\n+#define DIFF_DEFAULT_ABBREV\t7 /* hex digits */\n+\n extern void diffcore_std(struct diff_options *);\n \n extern void diffcore_std_no_resolve(struct diff_options *);\n@@ -98,7 +102,8 @@ extern void diffcore_std_no_resolve(stru\n \"  -u            synonym for -p.\\n\" \\\n \"  --name-only   show only names of changed files.\\n\" \\\n \"  --name-status show names and status of changed files.\\n\" \\\n-\"  --full-index  show full object name on index ines.\\n\" \\\n+\"  --full-index  show full object name on index lines.\\n\" \\\n+\"  --abbrev      abbreviate object names in diff-tree header and diff-raw.\\n\" \\\n \"  -R            swap input file pairs.\\n\" \\\n \"  -B            detect complete rewrites.\\n\" \\\n \"  -M            detect renames.\\n\" \\\n@@ -137,4 +142,6 @@ extern void diff_flush(struct diff_optio\n #define DIFF_STATUS_FILTER_AON\t\t'*'\n #define DIFF_STATUS_FILTER_BROKEN\t'B'\n \n+extern const char *diff_unique_abbrev(const unsigned char *, int);\n+\n #endif /* DIFF_H */\ndiff --git a/sha1_name.c b/sha1_name.c\nindex bf8f0f0..875e2f8 100644\n--- a/sha1_name.c\n+++ b/sha1_name.c\n@@ -188,7 +188,10 @@ const char *find_unique_abbrev(const uns\n {\n \tint status;\n \tstatic char hex[41];\n+\n \tmemcpy(hex, sha1_to_hex(sha1), 40);\n+\tif (len == 40)\n+\t\treturn hex;\n \twhile (len < 40) {\n \t\tunsigned char sha1_ret[20];\n \t\tstatus = get_short_sha1(hex, len, sha1_ret, 1);\n-- \n0.99.9.GIT\n"},{"id":"13770","messageId":"20051218001756.GS22159@pasky.or.cz","threadId":"2867","inReplyTo":"7v3bks12n6.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] diff: --abbrev option","fromName":"Petr Baudis","fromEmail":"pasky@suse.cz","sentAt":"2005-12-18T00:17:56Z","receivedAt":"2005-12-18T00:17:56Z","isPatch":true,"sender":{"key":"pasky@ucw.cz","avatar":"https://avatars.githubusercontent.com/u/18439?v=4"},"body":"Dear diary, on Sat, Dec 17, 2005 at 10:41:49AM CET, I got a letter\nwhere Junio C Hamano <junkio@cox.net> said that...\n> When I show transcripts to explain how something works, I often\n> find myself hand-editing the diff-raw output to shorten various\n> object names in the output.\n> \n> This adds --abbrev option to the diff family, which shortens\n> diff-raw output and diff-tree commit id headers.\n> \n> Signed-off-by: Junio C Hamano <junkio@cox.net>\n> \n> ---\n> \n>  * Earlier I announced that I have this toy in proposed updates\n>    without actually showing the code, so here it is.  I have\n>    added code to find unique abbreviation as well.  It is\n>    primarily useful to quote things in e-mail, like this:\n> \n>       $ git-rev-parse master | git-diff-tree --pretty -r --abbrev --stdin\n>       diff-tree 01385e2... (from 6922471...)\n>       Author: Junio C Hamano <junkio@cox.net>\n>       Date:   Fri Dec 16 23:12:33 2005 -0800\n> \n>           Comment fixes.\n> \n>           Signed-off-by: Junio C Hamano <junkio@cox.net>\n> \n>       :100755 100755 0266f46... b0e54ed... M\tgit-branch.sh\n>       :100755 100755 f241d4b... 36308d2... M\tgit-checkout.sh\n\n  I think the '...' is just distracting. It makes cut'n'paste more\ndifficult, and it's usually fairly obvious that this is start of a hash,\nand that the hash might not be complete.\n\n  I was actually thinking to by default trim all the hashes Cogito show\nto 12 or 16 characters. Seven still seems dangerously low to me, though;\nit would be nice if the number of characters to trim would be\nconfigurable (unless I've missed that).\n\n-- \n\t\t\t\tPetr \"Pasky\" Baudis\nStuff: http://pasky.or.cz/\nVI has two modes: the one in which it beeps and the one in which\nit doesn't.\n"},{"id":"13774","messageId":"7vek4byuwg.fsf@assigned-by-dhcp.cox.net","threadId":"2867","inReplyTo":"20051218001756.GS22159@pasky.or.cz","subject":"Re: [PATCH] diff: --abbrev option","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-12-18T02:57:19Z","receivedAt":"2005-12-18T02:57:19Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Petr Baudis <pasky@suse.cz> writes:\n\n>   I was actually thinking to by default trim all the hashes Cogito show\n> to 12 or 16 characters. Seven still seems dangerously low to me, though;\n> it would be nice if the number of characters to trim would be\n> configurable (unless I've missed that).\n\nWell, I did better than you imagined this time, for a change ;-)\nIt trims and adds extra as needed without breaking alignments,\nso you could get something like this:\n\n>       :100755 100755 0266f46... b0e54ed... M\tgit-branch.sh\n>       :100755 100755 f241d4b9.. 36308d2ab. M\tgit-checkout.sh\n\nThat is, ... is not just distraction but are part of the\ndesign.  Cut and paste is a byproduct.\n"},{"id":"13781","messageId":"20051218114522.GW22159@pasky.or.cz","threadId":"2867","inReplyTo":"7vek4byuwg.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] diff: --abbrev option","fromName":"Petr Baudis","fromEmail":"pasky@suse.cz","sentAt":"2005-12-18T11:45:22Z","receivedAt":"2005-12-18T11:45:22Z","isPatch":true,"sender":{"key":"pasky@ucw.cz","avatar":"https://avatars.githubusercontent.com/u/18439?v=4"},"body":"Dear diary, on Sun, Dec 18, 2005 at 03:57:19AM CET, I got a letter\nwhere Junio C Hamano <junkio@cox.net> said that...\n> Petr Baudis <pasky@suse.cz> writes:\n> \n> >   I was actually thinking to by default trim all the hashes Cogito show\n> > to 12 or 16 characters. Seven still seems dangerously low to me, though;\n> > it would be nice if the number of characters to trim would be\n> > configurable (unless I've missed that).\n> \n> Well, I did better than you imagined this time, for a change ;-)\n> It trims and adds extra as needed without breaking alignments,\n> so you could get something like this:\n> \n> >       :100755 100755 0266f46... b0e54ed... M\tgit-branch.sh\n> >       :100755 100755 f241d4b9.. 36308d2ab. M\tgit-checkout.sh\n> \n> That is, ... is not just distraction but are part of the\n> design.  Cut and paste is a byproduct.\n\nOk, that's nice! :-) And if I'm going to machine-process this later,\nI can just trim the trailing dots anyway. And it seems that I can give\n--abbrev a number argument to specify the minimal abbreviation, even\ncooler! :-)\n\n-- \n\t\t\t\tPetr \"Pasky\" Baudis\nStuff: http://pasky.or.cz/\nVI has two modes: the one in which it beeps and the one in which\nit doesn't.\n"},{"id":"13787","messageId":"7v4q56qmne.fsf@assigned-by-dhcp.cox.net","threadId":"2867","inReplyTo":"20051218114522.GW22159@pasky.or.cz","subject":"Re: [PATCH] diff: --abbrev option","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-12-18T18:35:01Z","receivedAt":"2005-12-18T18:35:01Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Petr Baudis <pasky@suse.cz> writes:\n\n> Ok, that's nice! :-) And if I'm going to machine-process this later,\n> I can just trim the trailing dots anyway. And it seems that I can give\n> --abbrev a number argument to specify the minimal abbreviation, even\n> cooler! :-)\n\nWell, it is not for machine consumption to begin with anyway.\nIt is an optional toy ;-).\n"}]}