mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-29 20:42:23 +00:00
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.
This commit is contained in:
parent
a32d684f86
commit
12e422a056
151
examples/diff.c
151
examples/diff.c
@ -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 {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/** 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[])
|
|||||||
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[])
|
|||||||
* * <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[])
|
|||||||
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) {
|
||||||
check_lg2(
|
if (!t1)
|
||||||
git_diff_tree_to_index(&diff, repo, t1, NULL, &o.diffopts),
|
treeish_to_tree(&t1, repo, "HEAD");
|
||||||
"diff tree to index", NULL);
|
|
||||||
|
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)
|
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[])
|
|||||||
|
|
||||||
/** 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[])
|
|||||||
|
|
||||||
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[])
|
|||||||
!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;
|
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"))
|
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[])
|
|||||||
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[])
|
|||||||
&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[])
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 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)
|
|||||||
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");
|
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) {
|
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(
|
|||||||
* 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
|
||||||
|
* `git_diff_tree_to_workdir_with_index` to emulate those commands.
|
||||||
*
|
*
|
||||||
* This function returns strictly the differences between the tree and the
|
* To see difference between this and `git_diff_tree_to_workdir_with_index`,
|
||||||
* files contained in the working directory, regardless of the state of
|
* consider the example of a staged file deletion where the file has then
|
||||||
* files in the index. It may come as a surprise, but there is no direct
|
* been put back into the working dir and further modified. The
|
||||||
* equivalent in core git.
|
* tree-to-workdir diff for that file is 'modified', but `git diff` would
|
||||||
*
|
* show status 'deleted' since there is a staged delete.
|
||||||
* To emulate `git diff <tree>`, 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.
|
|
||||||
*
|
*
|
||||||
* @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(
|
|||||||
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)
|
||||||
|
Loading…
Reference in New Issue
Block a user