Commit 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: