Commit 12e422a0 by Russell Belfer

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.
parent a32d684f
...@@ -33,14 +33,26 @@ static const char *colors[] = { ...@@ -33,14 +33,26 @@ static const char *colors[] = {
"\033[36m" /* cyan */ "\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. */ /** The 'opts' struct captures all the various parsed command line options. */
struct opts { struct opts {
git_diff_options diffopts; git_diff_options diffopts;
git_diff_find_options findopts; git_diff_find_options findopts;
int color; int color;
int cached; int cache;
int numstat; int output;
int shortstat;
git_diff_format_t format; git_diff_format_t format;
const char *treeish1; const char *treeish1;
const char *treeish2; const char *treeish2;
...@@ -48,11 +60,11 @@ struct opts { ...@@ -48,11 +60,11 @@ struct opts {
}; };
/** These functions are implemented at the end */ /** 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 void parse_opts(struct opts *o, int argc, char *argv[]);
static int color_printer( static int color_printer(
const git_diff_delta*, const git_diff_hunk*, const git_diff_line*, void*); 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_stats(git_diff *diff, struct opts *o);
static void diff_print_shortstat(git_diff *diff);
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
...@@ -61,7 +73,7 @@ int main(int argc, char *argv[]) ...@@ -61,7 +73,7 @@ int main(int argc, char *argv[])
git_diff *diff; git_diff *diff;
struct opts o = { struct opts o = {
GIT_DIFF_OPTIONS_INIT, GIT_DIFF_FIND_OPTIONS_INIT, 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(); git_threads_init();
...@@ -78,6 +90,7 @@ int main(int argc, char *argv[]) ...@@ -78,6 +90,7 @@ int main(int argc, char *argv[])
* * <sha1> --cached * * <sha1> --cached
* * <sha1> * * <sha1>
* * --cached * * --cached
* * --nocache (don't use index data in diff at all)
* * nothing * * nothing
* *
* Currently ranged arguments like <sha1>..<sha2> and <sha1>...<sha2> * Currently ranged arguments like <sha1>..<sha2> and <sha1>...<sha2>
...@@ -93,20 +106,23 @@ int main(int argc, char *argv[]) ...@@ -93,20 +106,23 @@ int main(int argc, char *argv[])
check_lg2( check_lg2(
git_diff_tree_to_tree(&diff, repo, t1, t2, &o.diffopts), git_diff_tree_to_tree(&diff, repo, t1, t2, &o.diffopts),
"diff trees", NULL); "diff trees", NULL);
else if (t1 && o.cached) 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( check_lg2(
git_diff_tree_to_index(&diff, repo, t1, NULL, &o.diffopts), git_diff_tree_to_index(&diff, repo, t1, NULL, &o.diffopts),
"diff tree to index", NULL); "diff tree to index", NULL);
}
else if (t1) else if (t1)
check_lg2( check_lg2(
git_diff_tree_to_workdir_with_index(&diff, repo, t1, &o.diffopts), git_diff_tree_to_workdir_with_index(&diff, repo, t1, &o.diffopts),
"diff tree to working directory", NULL); "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 else
check_lg2( check_lg2(
git_diff_index_to_workdir(&diff, repo, NULL, &o.diffopts), git_diff_index_to_workdir(&diff, repo, NULL, &o.diffopts),
...@@ -121,11 +137,14 @@ int main(int argc, char *argv[]) ...@@ -121,11 +137,14 @@ int main(int argc, char *argv[])
/** Generate simple output using libgit2 display helper. */ /** Generate simple output using libgit2 display helper. */
if (o.numstat == 1) switch (o.output) {
diff_print_numstat(diff); case OUTPUT_STAT:
else if (o.shortstat == 1) case OUTPUT_NUMSTAT:
diff_print_shortstat(diff); case OUTPUT_SHORTSTAT:
else { diff_print_stats(diff, &o);
break;
case OUTPUT_DIFF:
if (o.color >= 0) if (o.color >= 0)
fputs(colors[0], stdout); fputs(colors[0], stdout);
...@@ -135,6 +154,10 @@ int main(int argc, char *argv[]) ...@@ -135,6 +154,10 @@ int main(int argc, char *argv[])
if (o.color >= 0) if (o.color >= 0)
fputs(colors[0], stdout); fputs(colors[0], stdout);
break;
default:
usage("Unknown output format", "programmer error");
} }
/** Cleanup before exiting. */ /** Cleanup before exiting. */
...@@ -213,13 +236,20 @@ static void parse_opts(struct opts *o, int argc, char *argv[]) ...@@ -213,13 +236,20 @@ static void parse_opts(struct opts *o, int argc, char *argv[])
!strcmp(a, "--patch")) !strcmp(a, "--patch"))
o->format = GIT_DIFF_FORMAT_PATCH; o->format = GIT_DIFF_FORMAT_PATCH;
else if (!strcmp(a, "--cached")) else if (!strcmp(a, "--cached"))
o->cached = 1; o->cache = CACHE_ONLY;
else if (!strcmp(a, "--name-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; 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; 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->format = GIT_DIFF_FORMAT_RAW;
o->diffopts.id_abbrev = 40;
}
else if (!strcmp(a, "--color")) else if (!strcmp(a, "--color"))
o->color = 0; o->color = 0;
else if (!strcmp(a, "--no-color")) else if (!strcmp(a, "--no-color"))
...@@ -242,10 +272,12 @@ static void parse_opts(struct opts *o, int argc, char *argv[]) ...@@ -242,10 +272,12 @@ static void parse_opts(struct opts *o, int argc, char *argv[])
o->diffopts.flags |= GIT_DIFF_PATIENCE; o->diffopts.flags |= GIT_DIFF_PATIENCE;
else if (!strcmp(a, "--minimal")) else if (!strcmp(a, "--minimal"))
o->diffopts.flags |= GIT_DIFF_MINIMAL; o->diffopts.flags |= GIT_DIFF_MINIMAL;
else if (!strcmp(a, "--stat"))
o->output = OUTPUT_STAT;
else if (!strcmp(a, "--numstat")) else if (!strcmp(a, "--numstat"))
o->numstat = 1; o->output = OUTPUT_NUMSTAT;
else if (!strcmp(a, "--shortstat")) else if (!strcmp(a, "--shortstat"))
o->shortstat = 1; o->output = OUTPUT_SHORTSTAT;
else if (match_uint16_arg( else if (match_uint16_arg(
&o->findopts.rename_threshold, &args, "-M") || &o->findopts.rename_threshold, &args, "-M") ||
match_uint16_arg( match_uint16_arg(
...@@ -267,6 +299,8 @@ static void parse_opts(struct opts *o, int argc, char *argv[]) ...@@ -267,6 +299,8 @@ static void parse_opts(struct opts *o, int argc, char *argv[])
&o->diffopts.context_lines, &args, "--unified") && &o->diffopts.context_lines, &args, "--unified") &&
!match_uint16_arg( !match_uint16_arg(
&o->diffopts.interhunk_lines, &args, "--inter-hunk-context") && &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.old_prefix, &args, "--src-prefix") &&
!match_str_arg(&o->diffopts.new_prefix, &args, "--dst-prefix") && !match_str_arg(&o->diffopts.new_prefix, &args, "--dst-prefix") &&
!match_str_arg(&o->dir, &args, "--git-dir")) !match_str_arg(&o->dir, &args, "--git-dir"))
...@@ -274,34 +308,8 @@ static void parse_opts(struct opts *o, int argc, char *argv[]) ...@@ -274,34 +308,8 @@ static void parse_opts(struct opts *o, int argc, char *argv[])
} }
} }
/** Display diff output with "--numstat".*/ /** Display diff output with "--numstat" or "--shortstat" */
static void diff_print_numstat(git_diff *diff) static void diff_print_stats(git_diff *diff, struct opts *o)
{
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)
{ {
git_patch *patch; git_patch *patch;
size_t d, ndeltas = git_diff_num_deltas(diff); size_t d, ndeltas = git_diff_num_deltas(diff);
...@@ -320,26 +328,39 @@ static void diff_print_shortstat(git_diff *diff) ...@@ -320,26 +328,39 @@ static void diff_print_shortstat(git_diff *diff)
git_patch_line_stats(NULL, &nadditions, &ndeletions, patch), git_patch_line_stats(NULL, &nadditions, &ndeletions, patch),
"generating the number of additions and deletions", NULL); "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; nadditions_sum += nadditions;
ndeletions_sum += ndeletions; ndeletions_sum += ndeletions;
git_patch_free(patch); 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); if (nadditions_sum) {
printf("%s", 1==ndeltas ? "file changed" : "files changed");
if(nadditions_sum) {
printf(", %ld ",nadditions_sum); printf(", %ld ",nadditions_sum);
printf("%s", 1==nadditions_sum ? "insertion(+)" : "insertions(+)"); printf("%s", 1 == nadditions_sum ? "insertion(+)" : "insertions(+)");
} }
if(ndeletions_sum) { if (ndeletions_sum) {
printf(", %ld ",ndeletions_sum); printf(", %ld ",ndeletions_sum);
printf("%s", 1==ndeletions_sum ? "deletion(-)" : "deletions(-)"); printf("%s", 1 == ndeletions_sum ? "deletion(-)" : "deletions(-)");
} }
printf("\n"); printf("\n");
} }
} }
...@@ -725,24 +725,17 @@ GIT_EXTERN(int) git_diff_index_to_workdir( ...@@ -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, * 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. * and the working directory will be used for the "new_file" side.
* *
* Please note: this is *NOT* the same as `git diff <treeish>`. Running * This is not the same as `git diff <treeish>` or `git diff-index
* `git diff HEAD` or the like actually uses information from the index, * <treeish>`. Those commands use information from the index, whereas this
* along with the tree and working directory info. * function strictly returns the differences between the tree and the files
* * in the working directory, regardless of the state of the index. Use
* This function returns strictly the differences between the tree and the * `git_diff_tree_to_workdir_with_index` to emulate those commands.
* 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 * To see difference between this and `git_diff_tree_to_workdir_with_index`,
* equivalent in core git. * consider the example of a staged file deletion where the file has then
* * been put back into the working dir and further modified. The
* To emulate `git diff <tree>`, use `git_diff_tree_to_workdir_with_index` * tree-to-workdir diff for that file is 'modified', but `git diff` would
* (or `git_diff_tree_to_index` and `git_diff_index_to_workdir`, then call * show status 'deleted' since there is a staged delete.
* `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.
* *
* @param diff A pointer to a git_diff pointer that will be allocated. * @param diff A pointer to a git_diff pointer that will be allocated.
* @param repo The repository containing the tree. * @param repo The repository containing the tree.
......
...@@ -175,7 +175,8 @@ static int diff_print_one_raw( ...@@ -175,7 +175,8 @@ static int diff_print_one_raw(
git_oid_tostr(end_oid, pi->oid_strlen, &delta->new_file.id); git_oid_tostr(end_oid, pi->oid_strlen, &delta->new_file.id);
git_buf_printf( 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); delta->old_file.mode, delta->new_file.mode, start_oid, end_oid, code);
if (delta->similarity > 0) if (delta->similarity > 0)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment