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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320
diff --git a/examples/diff.c b/examples/diff.c
index 6f68e83..1dbf85f 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) {
-
- printf(" %ld ", (long)ndeltas);
- printf("%s", 1==ndeltas ? "file changed" : "files changed");
+ if (o->output != OUTPUT_NUMSTAT && ndeltas > 0) {
+ printf(" %ld %s", (long)ndeltas,
+ 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 a0cfbc9..c8e1ad1 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 <treeish>`. Running
- * `git diff HEAD` or the like actually uses information from the index,
- * along with the tree and working directory info.
- *
- * 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 <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.
+ * This is not the same as `git diff <treeish>` or `git diff-index
+ * <treeish>`. 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.
+ *
+ * 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 a7f7b6f..ee5cd8d 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)