From 12e422a0562de2aebb05f5f414dbcde7caf85886 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Mon, 21 Apr 2014 16:08:05 -0700 Subject: [PATCH] Some doc and examples/diff.c changes I was playing with "git diff-index" and wanted to be able to emulate that behavior a little more closely with the diff example. Also, I wanted to play with running `git_diff_tree_to_workdir` directly even though core Git doesn't exactly have the equivalent, so I added a command line option for that and tweaked some other things in the example code. This changes a minor output thing in that the "raw" print helper function will no longer add ellipses (...) if the OID is not actually abbreviated. --- examples/diff.c | 151 +++++++++++++++++++++++++------------------- include/git2/diff.h | 27 +++----- src/diff_print.c | 3 +- 3 files changed, 98 insertions(+), 83 deletions(-) diff --git a/examples/diff.c b/examples/diff.c index 6f68e8305..1dbf85f61 100644 --- a/examples/diff.c +++ b/examples/diff.c @@ -33,14 +33,26 @@ static const char *colors[] = { "\033[36m" /* cyan */ }; +enum { + OUTPUT_DIFF = 0, + OUTPUT_STAT = 1, + OUTPUT_SHORTSTAT = 2, + OUTPUT_NUMSTAT = 3 +}; + +enum { + CACHE_NORMAL = 0, + CACHE_ONLY = 1, + CACHE_NONE = 2 +}; + /** The 'opts' struct captures all the various parsed command line options. */ struct opts { git_diff_options diffopts; git_diff_find_options findopts; int color; - int cached; - int numstat; - int shortstat; + int cache; + int output; git_diff_format_t format; const char *treeish1; const char *treeish2; @@ -48,11 +60,11 @@ struct opts { }; /** These functions are implemented at the end */ +static void usage(const char *message, const char *arg); static void parse_opts(struct opts *o, int argc, char *argv[]); static int color_printer( const git_diff_delta*, const git_diff_hunk*, const git_diff_line*, void*); -static void diff_print_numstat(git_diff *diff); -static void diff_print_shortstat(git_diff *diff); +static void diff_print_stats(git_diff *diff, struct opts *o); int main(int argc, char *argv[]) { @@ -61,7 +73,7 @@ int main(int argc, char *argv[]) git_diff *diff; struct opts o = { GIT_DIFF_OPTIONS_INIT, GIT_DIFF_FIND_OPTIONS_INIT, - -1, 0, 0, 0, GIT_DIFF_FORMAT_PATCH, NULL, NULL, "." + -1, 0, 0, GIT_DIFF_FORMAT_PATCH, NULL, NULL, "." }; git_threads_init(); @@ -78,6 +90,7 @@ int main(int argc, char *argv[]) * * <sha1> --cached * * <sha1> * * --cached + * * --nocache (don't use index data in diff at all) * * nothing * * Currently ranged arguments like <sha1>..<sha2> and <sha1>...<sha2> @@ -93,20 +106,23 @@ int main(int argc, char *argv[]) check_lg2( git_diff_tree_to_tree(&diff, repo, t1, t2, &o.diffopts), "diff trees", NULL); - else if (t1 && o.cached) - check_lg2( - git_diff_tree_to_index(&diff, repo, t1, NULL, &o.diffopts), - "diff tree to index", NULL); + else if (o.cache != CACHE_NORMAL) { + if (!t1) + treeish_to_tree(&t1, repo, "HEAD"); + + if (o.cache == CACHE_NONE) + check_lg2( + git_diff_tree_to_workdir(&diff, repo, t1, &o.diffopts), + "diff tree to working directory", NULL); + else + check_lg2( + git_diff_tree_to_index(&diff, repo, t1, NULL, &o.diffopts), + "diff tree to index", NULL); + } else if (t1) check_lg2( git_diff_tree_to_workdir_with_index(&diff, repo, t1, &o.diffopts), "diff tree to working directory", NULL); - else if (o.cached) { - treeish_to_tree(&t1, repo, "HEAD"); - check_lg2( - git_diff_tree_to_index(&diff, repo, t1, NULL, &o.diffopts), - "diff tree to index", NULL); - } else check_lg2( git_diff_index_to_workdir(&diff, repo, NULL, &o.diffopts), @@ -121,11 +137,14 @@ int main(int argc, char *argv[]) /** Generate simple output using libgit2 display helper. */ - if (o.numstat == 1) - diff_print_numstat(diff); - else if (o.shortstat == 1) - diff_print_shortstat(diff); - else { + switch (o.output) { + case OUTPUT_STAT: + case OUTPUT_NUMSTAT: + case OUTPUT_SHORTSTAT: + diff_print_stats(diff, &o); + break; + + case OUTPUT_DIFF: if (o.color >= 0) fputs(colors[0], stdout); @@ -135,6 +154,10 @@ int main(int argc, char *argv[]) if (o.color >= 0) fputs(colors[0], stdout); + break; + + default: + usage("Unknown output format", "programmer error"); } /** Cleanup before exiting. */ @@ -213,13 +236,20 @@ static void parse_opts(struct opts *o, int argc, char *argv[]) !strcmp(a, "--patch")) o->format = GIT_DIFF_FORMAT_PATCH; else if (!strcmp(a, "--cached")) - o->cached = 1; - else if (!strcmp(a, "--name-only")) + o->cache = CACHE_ONLY; + else if (!strcmp(a, "--nocache")) + o->cache = CACHE_NONE; + else if (!strcmp(a, "--name-only") || !strcmp(a, "--format=name")) o->format = GIT_DIFF_FORMAT_NAME_ONLY; - else if (!strcmp(a, "--name-status")) + else if (!strcmp(a, "--name-status") || + !strcmp(a, "--format=name-status")) o->format = GIT_DIFF_FORMAT_NAME_STATUS; - else if (!strcmp(a, "--raw")) + else if (!strcmp(a, "--raw") || !strcmp(a, "--format=raw")) o->format = GIT_DIFF_FORMAT_RAW; + else if (!strcmp(a, "--format=diff-index")) { + o->format = GIT_DIFF_FORMAT_RAW; + o->diffopts.id_abbrev = 40; + } else if (!strcmp(a, "--color")) o->color = 0; else if (!strcmp(a, "--no-color")) @@ -242,10 +272,12 @@ static void parse_opts(struct opts *o, int argc, char *argv[]) o->diffopts.flags |= GIT_DIFF_PATIENCE; else if (!strcmp(a, "--minimal")) o->diffopts.flags |= GIT_DIFF_MINIMAL; + else if (!strcmp(a, "--stat")) + o->output = OUTPUT_STAT; else if (!strcmp(a, "--numstat")) - o->numstat = 1; + o->output = OUTPUT_NUMSTAT; else if (!strcmp(a, "--shortstat")) - o->shortstat = 1; + o->output = OUTPUT_SHORTSTAT; else if (match_uint16_arg( &o->findopts.rename_threshold, &args, "-M") || match_uint16_arg( @@ -267,6 +299,8 @@ static void parse_opts(struct opts *o, int argc, char *argv[]) &o->diffopts.context_lines, &args, "--unified") && !match_uint16_arg( &o->diffopts.interhunk_lines, &args, "--inter-hunk-context") && + !match_uint16_arg( + &o->diffopts.id_abbrev, &args, "--abbrev") && !match_str_arg(&o->diffopts.old_prefix, &args, "--src-prefix") && !match_str_arg(&o->diffopts.new_prefix, &args, "--dst-prefix") && !match_str_arg(&o->dir, &args, "--git-dir")) @@ -274,34 +308,8 @@ static void parse_opts(struct opts *o, int argc, char *argv[]) } } -/** Display diff output with "--numstat".*/ -static void diff_print_numstat(git_diff *diff) -{ - git_patch *patch; - const git_diff_delta *delta; - size_t d, ndeltas = git_diff_num_deltas(diff); - size_t nadditions, ndeletions; - - for (d = 0; d < ndeltas; d++){ - check_lg2( - git_patch_from_diff(&patch, diff, d), - "generating patch from diff", NULL); - - check_lg2( - git_patch_line_stats(NULL, &nadditions, &ndeletions, patch), - "generating the number of additions and deletions", NULL); - - delta = git_patch_get_delta(patch); - - printf("%ld\t%ld\t%s\n", - (long)nadditions, (long)ndeletions, delta->new_file.path); - - git_patch_free(patch); - } -} - -/** Display diff output with "--shortstat".*/ -static void diff_print_shortstat(git_diff *diff) +/** Display diff output with "--numstat" or "--shortstat" */ +static void diff_print_stats(git_diff *diff, struct opts *o) { git_patch *patch; size_t d, ndeltas = git_diff_num_deltas(diff); @@ -320,26 +328,39 @@ static void diff_print_shortstat(git_diff *diff) git_patch_line_stats(NULL, &nadditions, &ndeletions, patch), "generating the number of additions and deletions", NULL); + if (o->output == OUTPUT_NUMSTAT) { + const git_diff_delta *delta = git_patch_get_delta(patch); + printf("%ld\t%ld\t%s\n", + (long)nadditions, (long)ndeletions, delta->new_file.path); + } + else if (o->output == OUTPUT_STAT) { + const git_diff_delta *delta = git_patch_get_delta(patch); + printf(" %s\t| %ld\t(%ld+ %ld-)\n", + delta->new_file.path, (long)nadditions + (long)ndeletions, + (long)nadditions, (long)ndeletions); + } + nadditions_sum += nadditions; ndeletions_sum += ndeletions; git_patch_free(patch); } - if (ndeltas) { + if (o->output != OUTPUT_NUMSTAT && ndeltas > 0) { + printf(" %ld %s", (long)ndeltas, + 1 == ndeltas ? "file changed" : "files changed"); - printf(" %ld ", (long)ndeltas); - printf("%s", 1==ndeltas ? "file changed" : "files changed"); - - if(nadditions_sum) { - printf(", %ld ",nadditions_sum); - printf("%s", 1==nadditions_sum ? "insertion(+)" : "insertions(+)"); + if (nadditions_sum) { + printf(", %ld ",nadditions_sum); + printf("%s", 1 == nadditions_sum ? "insertion(+)" : "insertions(+)"); } - if(ndeletions_sum) { - printf(", %ld ",ndeletions_sum); - printf("%s", 1==ndeletions_sum ? "deletion(-)" : "deletions(-)"); + if (ndeletions_sum) { + printf(", %ld ",ndeletions_sum); + printf("%s", 1 == ndeletions_sum ? "deletion(-)" : "deletions(-)"); } + printf("\n"); } } + diff --git a/include/git2/diff.h b/include/git2/diff.h index a0cfbc918..c8e1ad143 100644 --- a/include/git2/diff.h +++ b/include/git2/diff.h @@ -725,24 +725,17 @@ GIT_EXTERN(int) git_diff_index_to_workdir( * The tree you provide will be used for the "old_file" side of the delta, * and the working directory will be used for the "new_file" side. * - * Please note: this is *NOT* the same as `git diff `. Running - * `git diff HEAD` or the like actually uses information from the index, - * along with the tree and working directory info. + * This is not the same as `git diff ` or `git diff-index + * `. Those commands use information from the index, whereas this + * function strictly returns the differences between the tree and the files + * in the working directory, regardless of the state of the index. Use + * `git_diff_tree_to_workdir_with_index` to emulate those commands. * - * This function returns strictly the differences between the tree and the - * files contained in the working directory, regardless of the state of - * files in the index. It may come as a surprise, but there is no direct - * equivalent in core git. - * - * To emulate `git diff `, use `git_diff_tree_to_workdir_with_index` - * (or `git_diff_tree_to_index` and `git_diff_index_to_workdir`, then call - * `git_diff_merge` on the results). That will yield a `git_diff` that - * matches the git output. - * - * If this seems confusing, take the case of a file with a staged deletion - * where the file has then been put back into the working dir and modified. - * The tree-to-workdir diff for that file is 'modified', but core git would - * show status 'deleted' since there is a pending deletion in the index. + * To see difference between this and `git_diff_tree_to_workdir_with_index`, + * consider the example of a staged file deletion where the file has then + * been put back into the working dir and further modified. The + * tree-to-workdir diff for that file is 'modified', but `git diff` would + * show status 'deleted' since there is a staged delete. * * @param diff A pointer to a git_diff pointer that will be allocated. * @param repo The repository containing the tree. diff --git a/src/diff_print.c b/src/diff_print.c index a7f7b6fe8..ee5cd8dfb 100644 --- a/src/diff_print.c +++ b/src/diff_print.c @@ -175,7 +175,8 @@ static int diff_print_one_raw( git_oid_tostr(end_oid, pi->oid_strlen, &delta->new_file.id); git_buf_printf( - out, ":%06o %06o %s... %s... %c", + out, (pi->oid_strlen <= GIT_OID_HEXSZ) ? + ":%06o %06o %s... %s... %c" : ":%06o %06o %s %s %c", delta->old_file.mode, delta->new_file.mode, start_oid, end_oid, code); if (delta->similarity > 0)