commit 63035f9f4ff2f4ea5b7361830edad916a30e37cd from: Stefan Sperling date: Sun Oct 06 19:24:31 2019 UTC add -w (ignore whitespace) option to 'got diff' commit - e19660d59fd85e4dc844d77fee9eb5837f3e3be5 commit + 63035f9f4ff2f4ea5b7361830edad916a30e37cd blob - 20222ee6b0aa62833a8c69e650cb151f963aafc9 blob + 74fbaf41f1e493e85741b0ef0c24782c6c023472 --- got/got.1 +++ got/got.1 @@ -361,7 +361,7 @@ If this directory is a .Nm work tree, use the repository path associated with this work tree. .El -.It Cm diff Oo Fl C Ar number Oc Oo Fl r Ar repository-path Oc Oo Fl s Oc Op Ar object1 Ar object2 | Ar path +.It Cm diff Oo Fl C Ar number Oc Oo Fl r Ar repository-path Oc Oo Fl s Oc Oo Fl w Oc Op Ar object1 Ar object2 | Ar path When invoked within a work tree with less than two arguments, display uncommitted changes in the work tree. If a @@ -396,6 +396,8 @@ instead of showing local changes. This option is only valid when .Cm got diff is invoked in a work tree. +.It Fl w +Ignore whitespace-only changes. .El .It Cm di Short alias for blob - 13dea80561dab55f3899f8130a265eb49dc72ebd blob + 0c7661cb83bd74a19bc65dabb5d4ecf110143c1b --- got/got.c +++ got/got.c @@ -1366,7 +1366,8 @@ done: static const struct got_error * diff_blobs(struct got_object_id *blob_id1, struct got_object_id *blob_id2, - const char *path, int diff_context, struct got_repository *repo) + const char *path, int diff_context, int ignore_whitespace, + struct got_repository *repo) { const struct got_error *err = NULL; struct got_blob_object *blob1 = NULL, *blob2 = NULL; @@ -1384,7 +1385,7 @@ diff_blobs(struct got_object_id *blob_id1, struct got_ while (path[0] == '/') path++; err = got_diff_blob(blob1, blob2, path, path, diff_context, - stdout); + ignore_whitespace, stdout); done: if (blob1) got_object_blob_close(blob1); @@ -1394,7 +1395,8 @@ done: static const struct got_error * diff_trees(struct got_object_id *tree_id1, struct got_object_id *tree_id2, - const char *path, int diff_context, struct got_repository *repo) + const char *path, int diff_context, int ignore_whitespace, + struct got_repository *repo) { const struct got_error *err = NULL; struct got_tree_object *tree1 = NULL, *tree2 = NULL; @@ -1411,6 +1413,7 @@ diff_trees(struct got_object_id *tree_id1, struct got_ goto done; arg.diff_context = diff_context; + arg.ignore_whitespace = ignore_whitespace; arg.outfile = stdout; while (path[0] == '/') path++; @@ -1473,11 +1476,11 @@ print_patch(struct got_commit_object *commit, struct g switch (obj_type) { case GOT_OBJ_TYPE_BLOB: err = diff_blobs(obj_id1, obj_id2, path, diff_context, - repo); + 0, repo); break; case GOT_OBJ_TYPE_TREE: err = diff_trees(obj_id1, obj_id2, path, diff_context, - repo); + 0, repo); break; default: err = got_error(GOT_ERR_OBJ_TYPE); @@ -1495,7 +1498,7 @@ print_patch(struct got_commit_object *commit, struct g if (err) goto done; printf("diff %s %s\n", id_str1 ? id_str1 : "/dev/null", id_str2); - err = diff_trees(obj_id1, obj_id2, "", diff_context, repo); + err = diff_trees(obj_id1, obj_id2, "", diff_context, 0, repo); } done: @@ -1939,7 +1942,7 @@ __dead static void usage_diff(void) { fprintf(stderr, "usage: %s diff [-C number] [-r repository-path] [-s] " - "[object1 object2 | path]\n", getprogname()); + "[-w] [object1 object2 | path]\n", getprogname()); exit(1); } @@ -1950,6 +1953,7 @@ struct print_diff_arg { const char *id_str; int header_shown; int diff_staged; + int ignore_whitespace; }; static const struct got_error * @@ -2005,7 +2009,8 @@ print_diff(void *arg, unsigned char status, unsigned c return got_error(GOT_ERR_FILE_STATUS); } return got_diff_objects_as_blobs(blob_id, staged_blob_id, - label1, label2, a->diff_context, a->repo, stdout); + label1, label2, a->diff_context, a->ignore_whitespace, + a->repo, stdout); } if (staged_status == GOT_STATUS_ADD || @@ -2050,7 +2055,7 @@ print_diff(void *arg, unsigned char status, unsigned c sb.st_size = 0; err = got_diff_blob_file(blob1, label1, f2, sb.st_size, path, - a->diff_context, stdout); + a->diff_context, a->ignore_whitespace, stdout); done: if (blob1) got_object_blob_close(blob1); @@ -2130,7 +2135,7 @@ cmd_diff(int argc, char *argv[]) const char *id_str1 = NULL, *id_str2 = NULL; char *label1 = NULL, *label2 = NULL; int type1, type2; - int diff_context = 3, diff_staged = 0, ch; + int diff_context = 3, diff_staged = 0, ignore_whitespace = 0, ch; const char *errstr; char *path = NULL; @@ -2140,7 +2145,7 @@ cmd_diff(int argc, char *argv[]) err(1, "pledge"); #endif - while ((ch = getopt(argc, argv, "C:r:s")) != -1) { + while ((ch = getopt(argc, argv, "C:r:sw")) != -1) { switch (ch) { case 'C': diff_context = strtonum(optarg, 1, INT_MAX, &errstr); @@ -2155,6 +2160,9 @@ cmd_diff(int argc, char *argv[]) break; case 's': diff_staged = 1; + break; + case 'w': + ignore_whitespace = 1; break; default: usage_diff(); @@ -2248,6 +2256,7 @@ cmd_diff(int argc, char *argv[]) arg.id_str = id_str; arg.header_shown = 0; arg.diff_staged = diff_staged; + arg.ignore_whitespace = ignore_whitespace; error = got_pathlist_append(&paths, path, NULL); if (error) @@ -2286,16 +2295,16 @@ cmd_diff(int argc, char *argv[]) switch (type1) { case GOT_OBJ_TYPE_BLOB: error = got_diff_objects_as_blobs(id1, id2, NULL, NULL, - diff_context, repo, stdout); + diff_context, ignore_whitespace, repo, stdout); break; case GOT_OBJ_TYPE_TREE: error = got_diff_objects_as_trees(id1, id2, "", "", - diff_context, repo, stdout); + diff_context, ignore_whitespace, repo, stdout); break; case GOT_OBJ_TYPE_COMMIT: printf("diff %s %s\n", label1, label2); error = got_diff_objects_as_commits(id1, id2, diff_context, - repo, stdout); + ignore_whitespace, repo, stdout); break; default: error = got_error(GOT_ERR_OBJ_TYPE); blob - 927863bea9c15cfb8336083f49201f2c717f2c89 blob + 2cbdb362bbc46817c1d3e664247b978b73e7f02c --- include/got_diff.h +++ include/got_diff.h @@ -20,9 +20,10 @@ * be provided which will be used to identify each blob in the diff output. * If a label is NULL, use the blob's SHA1 checksum instead. * The number of context lines to show in the diff must be specified as well. + * Whitespace differences may optionally be ignored. */ const struct got_error *got_diff_blob(struct got_blob_object *, - struct got_blob_object *, const char *, const char *, int, FILE *); + struct got_blob_object *, const char *, const char *, int, int, FILE *); /* * Compute the differences between a blob and a file and write unified diff @@ -30,9 +31,10 @@ const struct got_error *got_diff_blob(struct got_blob_ * well as a const char * diff header label which identifies the file. * An optional const char * diff header label for the blob may be provided, too. * The number of context lines to show in the diff must be specified as well. + * Whitespace differences may optionally be ignored. */ const struct got_error *got_diff_blob_file(struct got_blob_object *, - const char *, FILE *, size_t, const char *, int, FILE *); + const char *, FILE *, size_t, const char *, int, int, FILE *); /* * A callback function invoked to handle the differences between two blobs @@ -56,6 +58,7 @@ typedef const struct got_error *(*got_diff_blob_cb)(vo struct got_diff_blob_output_unidiff_arg { FILE *outfile; /* Unidiff text will be written here. */ int diff_context; /* Sets the number of context lines. */ + int ignore_whitespace; /* Ignore whitespace differences. */ }; const struct got_error *got_diff_blob_output_unidiff(void *, struct got_blob_object *, struct got_blob_object *, @@ -81,7 +84,7 @@ const struct got_error *got_diff_tree(struct got_tree_ * Write unified diff text to the provided output FILE. */ const struct got_error *got_diff_objects_as_blobs(struct got_object_id *, - struct got_object_id *, const char *, const char *, int, + struct got_object_id *, const char *, const char *, int, int, struct got_repository *, FILE *); /* @@ -92,7 +95,8 @@ const struct got_error *got_diff_objects_as_blobs(stru * Write unified diff text to the provided output FILE. */ const struct got_error *got_diff_objects_as_trees(struct got_object_id *, - struct got_object_id *, char *, char *, int, struct got_repository *, FILE *); + struct got_object_id *, char *, char *, int, int, + struct got_repository *, FILE *); /* * Diff two objects, assuming both objects are commits. @@ -100,6 +104,6 @@ const struct got_error *got_diff_objects_as_trees(stru * Write unified diff text to the provided output FILE. */ const struct got_error *got_diff_objects_as_commits(struct got_object_id *, - struct got_object_id *, int, struct got_repository *, FILE *); + struct got_object_id *, int, int, struct got_repository *, FILE *); #define GOT_DIFF_MAX_CONTEXT 64 blob - e269983fad8691f00210e955a6383796011dcfc7 blob + c100c664ee6266b7d278ba0176da2648da0f1053 --- lib/diff.c +++ lib/diff.c @@ -38,8 +38,8 @@ static const struct got_error * diff_blobs(struct got_blob_object *blob1, struct got_blob_object *blob2, - const char *label1, const char *label2, int diff_context, FILE *outfile, - struct got_diff_changes *changes) + const char *label1, const char *label2, int diff_context, + int ignore_whitespace, FILE *outfile, struct got_diff_changes *changes) { struct got_diff_state ds; struct got_diff_args args; @@ -106,6 +106,8 @@ diff_blobs(struct got_blob_object *blob1, struct got_b args.label[1] = label2 ? label2 : idstr2; args.diff_context = diff_context; flags |= D_PROTOTYPE; + if (ignore_whitespace) + flags |= D_IGNOREBLANKS; if (outfile) { fprintf(outfile, "blob - %s\n", idstr1); @@ -130,15 +132,16 @@ got_diff_blob_output_unidiff(void *arg, struct got_blo struct got_diff_blob_output_unidiff_arg *a = arg; return diff_blobs(blob1, blob2, label1, label2, a->diff_context, - a->outfile, NULL); + a->ignore_whitespace, a->outfile, NULL); } const struct got_error * got_diff_blob(struct got_blob_object *blob1, struct got_blob_object *blob2, - const char *label1, const char *label2, int diff_context, FILE *outfile) + const char *label1, const char *label2, int diff_context, + int ignore_whitespace, FILE *outfile) { - return diff_blobs(blob1, blob2, label1, label2, diff_context, outfile, - NULL); + return diff_blobs(blob1, blob2, label1, label2, diff_context, + ignore_whitespace, outfile, NULL); } static const struct got_error * @@ -154,7 +157,7 @@ alloc_changes(struct got_diff_changes **changes) static const struct got_error * diff_blob_file(struct got_diff_changes **changes, struct got_blob_object *blob1, const char *label1, FILE *f2, size_t size2, - const char *label2, int diff_context, FILE *outfile) + const char *label2, int diff_context, int ignore_whitespace, FILE *outfile) { struct got_diff_state ds; struct got_diff_args args; @@ -203,6 +206,8 @@ diff_blob_file(struct got_diff_changes **changes, args.label[1] = label2; args.diff_context = diff_context; flags |= D_PROTOTYPE; + if (ignore_whitespace) + flags |= D_IGNOREBLANKS; if (outfile) { fprintf(outfile, "blob - %s\n", label1 ? label1 : idstr1); @@ -226,10 +231,10 @@ done: const struct got_error * got_diff_blob_file(struct got_blob_object *blob1, const char *label1, FILE *f2, size_t size2, const char *label2, int diff_context, - FILE *outfile) + int ignore_whitespace, FILE *outfile) { return diff_blob_file(NULL, blob1, label1, f2, size2, label2, - diff_context, outfile); + diff_context, ignore_whitespace, outfile); } const struct got_error * @@ -237,7 +242,7 @@ got_diff_blob_file_lines_changed(struct got_diff_chang struct got_blob_object *blob1, FILE *f2, size_t size2) { return diff_blob_file(changes, blob1, NULL, f2, size2, NULL, - 0, NULL); + 0, 0, NULL); } const struct got_error * @@ -250,7 +255,7 @@ got_diff_blob_lines_changed(struct got_diff_changes ** if (err) return err; - err = diff_blobs(blob1, blob2, NULL, NULL, 3, NULL, *changes); + err = diff_blobs(blob1, blob2, NULL, NULL, 3, 0, NULL, *changes); if (err) { got_diff_free_changes(*changes); *changes = NULL; @@ -658,7 +663,7 @@ got_diff_tree(struct got_tree_object *tree1, struct go const struct got_error * got_diff_objects_as_blobs(struct got_object_id *id1, struct got_object_id *id2, const char *label1, const char *label2, int diff_context, - struct got_repository *repo, FILE *outfile) + int ignore_whitespace, struct got_repository *repo, FILE *outfile) { const struct got_error *err; struct got_blob_object *blob1 = NULL, *blob2 = NULL; @@ -677,7 +682,7 @@ got_diff_objects_as_blobs(struct got_object_id *id1, s goto done; } err = got_diff_blob(blob1, blob2, label1, label2, diff_context, - outfile); + ignore_whitespace, outfile); done: if (blob1) got_object_blob_close(blob1); @@ -688,8 +693,8 @@ done: const struct got_error * got_diff_objects_as_trees(struct got_object_id *id1, struct got_object_id *id2, - char *label1, char *label2, int diff_context, struct got_repository *repo, - FILE *outfile) + char *label1, char *label2, int diff_context, int ignore_whitespace, + struct got_repository *repo, FILE *outfile) { const struct got_error *err; struct got_tree_object *tree1 = NULL, *tree2 = NULL; @@ -709,6 +714,7 @@ got_diff_objects_as_trees(struct got_object_id *id1, s goto done; } arg.diff_context = diff_context; + arg.ignore_whitespace = ignore_whitespace; arg.outfile = outfile; err = got_diff_tree(tree1, tree2, label1, label2, repo, got_diff_blob_output_unidiff, &arg, 1); @@ -722,7 +728,7 @@ done: const struct got_error * got_diff_objects_as_commits(struct got_object_id *id1, - struct got_object_id *id2, int diff_context, + struct got_object_id *id2, int diff_context, int ignore_whitespace, struct got_repository *repo, FILE *outfile) { const struct got_error *err; @@ -743,8 +749,8 @@ got_diff_objects_as_commits(struct got_object_id *id1, err = got_diff_objects_as_trees( commit1 ? got_object_commit_get_tree_id(commit1) : NULL, - got_object_commit_get_tree_id(commit2), "", "", diff_context, repo, - outfile); + got_object_commit_get_tree_id(commit2), "", "", diff_context, + ignore_whitespace, repo, outfile); done: if (commit1) got_object_commit_close(commit1); blob - 455469c47cd574f5fca1a82ebd6b9e3e680dc5e8 (mode 755) blob + d5083e047e683d5211b8352a65aeb41fea0facb2 (mode 744) --- regress/cmdline/diff.sh +++ regress/cmdline/diff.sh @@ -219,6 +219,36 @@ function test_diff_tag { test_done "$testroot" "$ret" } +function test_diff_ignore_whitespace { + local testroot=`test_init diff_ignore_whitespace` + local commit_id0=`git_show_head $testroot/repo` + + got checkout $testroot/repo $testroot/wt > /dev/null + ret="$?" + if [ "$ret" != "0" ]; then + test_done "$testroot" "$ret" + return 1 + fi + + echo "alpha " > $testroot/wt/alpha + + (cd $testroot/wt && got diff -w > $testroot/stdout) + + echo "diff $commit_id0 $testroot/wt" > $testroot/stdout.expected + echo -n 'blob - ' >> $testroot/stdout.expected + got tree -r $testroot/repo -c $commit_id0 -i | grep 'alpha$' | \ + cut -d' ' -f 1 >> $testroot/stdout.expected + echo 'file + alpha' >> $testroot/stdout.expected + + cmp -s $testroot/stdout.expected $testroot/stdout + ret="$?" + if [ "$ret" != "0" ]; then + diff -u $testroot/stdout.expected $testroot/stdout + fi + test_done "$testroot" "$ret" +} + run_test test_diff_basic run_test test_diff_shows_conflict run_test test_diff_tag +run_test test_diff_ignore_whitespace blob - 9c5b076048da355aa22fb10fbd74a357c2146375 blob + aad8017a1963e96977883c2dadfcef0fce8eac58 --- tog/tog.c +++ tog/tog.c @@ -2580,11 +2580,11 @@ create_diff(struct tog_diff_view_state *s) switch (obj_type) { case GOT_OBJ_TYPE_BLOB: err = got_diff_objects_as_blobs(s->id1, s->id2, NULL, NULL, - s->diff_context, s->repo, f); + s->diff_context, 0, s->repo, f); break; case GOT_OBJ_TYPE_TREE: err = got_diff_objects_as_trees(s->id1, s->id2, "", "", - s->diff_context, s->repo, f); + s->diff_context, 0, s->repo, f); break; case GOT_OBJ_TYPE_COMMIT: { const struct got_object_id_queue *parent_ids; @@ -2610,7 +2610,7 @@ create_diff(struct tog_diff_view_state *s) got_object_commit_close(commit2); err = got_diff_objects_as_commits(s->id1, s->id2, - s->diff_context, s->repo, f); + s->diff_context, 0, s->repo, f); break; } default: