Commit Diff


commit - 13c729f71056495e3b532f94badea43f10d98f49
commit + adacb96fd801526f57caee393ea94c6962781ff0
blob - 4f7d23771ac7850de8807514c25be47cc3ceb7fc
blob + ac5d837761422d5a991095c0be7f0e6d384be0cd
--- got/got.c
+++ got/got.c
@@ -304,7 +304,10 @@ print_patch(struct got_commit_object *commit, struct g
 	struct got_tree_object *tree1 = NULL, *tree2;
 	struct got_object_qid *qid;
 	char *id_str1 = NULL, *id_str2;
+	time_t time1 = 0, time2;
 
+	time2 = got_object_commit_get_committer_time(commit);
+
 	err = got_object_open_as_tree(&tree2, repo,
 	    got_object_commit_get_tree_id(commit));
 	if (err)
@@ -318,6 +321,7 @@ print_patch(struct got_commit_object *commit, struct g
 		if (err)
 			return err;
 
+		time1 = got_object_commit_get_committer_time(pcommit);
 		err = got_object_open_as_tree(&tree1, repo,
 		    got_object_commit_get_tree_id(pcommit));
 		got_object_commit_close(pcommit);
@@ -334,7 +338,8 @@ print_patch(struct got_commit_object *commit, struct g
 		goto done;
 
 	printf("diff %s %s\n", id_str1 ? id_str1 : "/dev/null", id_str2);
-	err = got_diff_tree(tree1, tree2, "", "", diff_context, repo, stdout);
+	err = got_diff_tree(tree1, tree2, "", "", time1, time2, diff_context,
+	    repo, stdout);
 done:
 	if (tree1)
 		got_object_tree_close(tree1);
@@ -700,11 +705,11 @@ 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);
+		    0, 0, diff_context, repo, stdout);
 		break;
 	case GOT_OBJ_TYPE_TREE:
 		error = got_diff_objects_as_trees(id1, id2, "", "",
-		    diff_context, repo, stdout);
+		    0, 0, diff_context, repo, stdout);
 		break;
 	case GOT_OBJ_TYPE_COMMIT:
 		printf("diff %s %s\n", id_str1 ? id_str1 : "/dev/null",
blob - 01e0ac643704c52d2defe4e6e2bffdc0b8b5f8e4
blob + e2ad0b8574261d2a1994d2b5bb1bb382d6ecc407
--- include/got_diff.h
+++ include/got_diff.h
@@ -19,42 +19,48 @@
  * to the provided output FILE. Two const char * diff header labels may
  * 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.
+ * Specified timestamps and will be shown in the diff unless they are zero.
  * The number of context lines to show in the diff must be specified as well.
  */
 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 *, time_t, time_t,
+    int, FILE *);
 
 /*
  * Compute the differences between two trees and write unified diff text
  * to the provided output FILE. Two const char * diff header labels may
  * 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.
+ * Specified timestamps and will be shown in the diff unless they are zero.
  * The number of context lines to show in the diff must be specified as well.
  */
 const struct got_error *got_diff_tree(struct got_tree_object *,
     struct got_tree_object *, const char *label1, const char *label2,
-    int, struct got_repository *, FILE *);
+    time_t, time_t, int, struct got_repository *, FILE *);
 
 /*
  * Diff two objects, assuming both objects are blobs. Two const char * diff
  * header labels may 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.
+ * Specified timestamps and will be shown in the diff unless they are zero.
  * The number of context lines to show in the diff must be specified as well.
  * 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_repository *, FILE *);
+    struct got_object_id *, const char *, const char *, time_t, time_t,
+    int, struct got_repository *, FILE *);
 
 /*
  * Diff two objects, assuming both objects are trees. Two const char * diff
  * header labels may be provided which will be used to identify each blob in
  * the trees. If a label is NULL, use the blob's SHA1 checksum instead.
+ * Specified timestamps and will be shown in the diff unless they are zero.
  * The number of context lines to show in diffs must be specified.
  * 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 *, time_t, time_t, int,
+    struct got_repository *, FILE *);
 
 /*
  * Diff two objects, assuming both objects are commits.
blob - 29d72606d8f28dd96deb06d37531e5db5e1c99ab
blob + 2f649f7fec0e73d3185d33b10add85ff2e52f728
--- lib/diff.c
+++ lib/diff.c
@@ -36,10 +36,40 @@
 #include "got_lib_inflate.h"
 #include "got_lib_object.h"
 
+static char *
+get_datestr(time_t *time, char *datebuf)
+{
+	char *p, *s = ctime_r(time, datebuf);
+	p = strchr(s, '\n');
+	if (p)
+		*p = '\0';
+	return s;
+}
+
+static char *
+get_label(const char *path, time_t time, const char *fallback)
+{
+	char datebuf[26];
+	char *datestr = NULL;
+	char *label;
+
+	if (path == NULL)
+		return strdup(fallback);
+
+	if (time)
+		datestr = get_datestr(&time, datebuf);
+
+	if (asprintf(&label, "%s%s%s%s", path, datestr ? "\t" : "",
+	    datestr ? datestr : "", datestr ? " UTC" : "") == -1)
+		return NULL;
+
+	return label;
+}
+
 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, time_t time1, time_t time2,
+    int diff_context, FILE *outfile, struct got_diff_changes *changes)
 {
 	struct got_diff_state ds;
 	struct got_diff_args args;
@@ -48,9 +78,12 @@ diff_blobs(struct got_blob_object *blob1, struct got_b
 	char hex1[SHA1_DIGEST_STRING_LENGTH];
 	char hex2[SHA1_DIGEST_STRING_LENGTH];
 	char *idstr1 = NULL, *idstr2 = NULL;
+	char *l1 = NULL, *l2 = NULL;
 	size_t size1, size2;
 	int res, flags = 0;
 
+	memset(&args, 0, sizeof(args));
+
 	if (blob1) {
 		f1 = got_opentemp();
 		if (f1 == NULL)
@@ -97,20 +130,31 @@ diff_blobs(struct got_blob_object *blob1, struct got_b
 		ds.stb2.st_size = size2;
 	ds.stb2.st_mtime = 0; /* XXX */
 
-	memset(&args, 0, sizeof(args));
 	args.diff_format = D_UNIFIED;
-	args.label[0] = label1 ? label1 : idstr1;
-	args.label[1] = label2 ? label2 : idstr2;
+	l1 = get_label(label1, time1, idstr1);
+	if (l1 == NULL) {
+		err = got_error_from_errno();
+		goto done;
+	}
+	args.label[0] = l1;
+	l2 = get_label(label2, time2, idstr2);
+	if (l2 == NULL) {
+		err = got_error_from_errno();
+		goto done;
+	}
+	args.label[1] = l2;
 	args.diff_context = diff_context;
 	flags |= D_PROTOTYPE;
 
-	if (label1 && strcmp(label1, idstr1) != 0)
+	if (label1 && strncmp(label1, idstr1, strlen(idstr1)) != 0)
 		fprintf(outfile, "blob - %s\n", idstr1);
-	if (label2 && strcmp(label2, idstr2) != 0)
+	if (label2 && strncmp(label2, idstr2, strlen(idstr2)) != 0)
 		fprintf(outfile, "blob + %s\n", idstr2);
 
 	err = got_diffreg(&res, f1, f2, flags, &args, &ds, outfile, changes);
 done:
+	free(l1);
+	free(l2);
 	if (f1)
 		fclose(f1);
 	if (f2)
@@ -120,10 +164,11 @@ done:
 
 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, time_t time1, time_t time2,
+    int diff_context, FILE *outfile)
 {
-	return diff_blobs(blob1, blob2, label1, label2, diff_context, outfile,
-	    NULL);
+	return diff_blobs(blob1, blob2, label1, label2, time1, time2,
+	    diff_context, outfile, NULL);
 }
 
 const struct got_error *
@@ -137,7 +182,7 @@ got_diff_blob_lines_changed(struct got_diff_changes **
 		return got_error_from_errno();
 	SIMPLEQ_INIT(&(*changes)->entries);
 
-	err = diff_blobs(blob1, blob2, NULL, NULL, 3, NULL, *changes);
+	err = diff_blobs(blob1, blob2, NULL, NULL, 0, 0, 3, NULL, *changes);
 	if (err) {
 		got_diff_free_changes(*changes);
 		*changes = NULL;
@@ -172,7 +217,7 @@ match_entry_by_name(struct got_tree_entry *te1, struct
 }
 
 static const struct got_error *
-diff_added_blob(struct got_object_id *id, const char *label,
+diff_added_blob(struct got_object_id *id, const char *label, time_t time,
     int diff_context, struct got_repository *repo, FILE *outfile)
 {
 	const struct got_error *err;
@@ -186,7 +231,8 @@ diff_added_blob(struct got_object_id *id, const char *
 	err = got_object_blob_open(&blob, repo, obj, 8192);
 	if (err)
 		goto done;
-	err = got_diff_blob(NULL, blob, NULL, label, diff_context, outfile);
+	err = got_diff_blob(NULL, blob, NULL, label, 0, time, diff_context,
+	    outfile);
 done:
 	got_object_close(obj);
 	if (blob)
@@ -196,8 +242,8 @@ done:
 
 static const struct got_error *
 diff_modified_blob(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)
+    const char *label1, const char *label2, time_t time1, time_t time2,
+    int diff_context, struct got_repository *repo, FILE *outfile)
 {
 	const struct got_error *err;
 	struct got_object *obj1 = NULL;
@@ -229,8 +275,8 @@ diff_modified_blob(struct got_object_id *id1, struct g
 	if (err)
 		goto done;
 
-	err = got_diff_blob(blob1, blob2, label1, label2, diff_context,
-	    outfile);
+	err = got_diff_blob(blob1, blob2, label1, label2, time1, time2,
+	    diff_context, outfile);
 
 done:
 	if (obj1)
@@ -246,7 +292,7 @@ done:
 
 static const struct got_error *
 diff_deleted_blob(struct got_object_id *id, const char *label,
-    int diff_context, struct got_repository *repo, FILE *outfile)
+    time_t time, int diff_context, struct got_repository *repo, FILE *outfile)
 {
 	const struct got_error *err;
 	struct got_blob_object  *blob = NULL;
@@ -259,7 +305,8 @@ diff_deleted_blob(struct got_object_id *id, const char
 	err = got_object_blob_open(&blob, repo, obj, 8192);
 	if (err)
 		goto done;
-	err = got_diff_blob(blob, NULL, label, NULL, diff_context, outfile);
+	err = got_diff_blob(blob, NULL, label, NULL, time, 0, diff_context,
+	    outfile);
 done:
 	got_object_close(obj);
 	if (blob)
@@ -268,7 +315,7 @@ done:
 }
 
 static const struct got_error *
-diff_added_tree(struct got_object_id *id, const char *label,
+diff_added_tree(struct got_object_id *id, const char *label, time_t time,
     int diff_context, struct got_repository *repo, FILE *outfile)
 {
 	const struct got_error *err = NULL;
@@ -288,8 +335,8 @@ diff_added_tree(struct got_object_id *id, const char *
 	if (err)
 		goto done;
 
-	err = got_diff_tree(NULL, tree, NULL, label, diff_context, repo,
-	    outfile);
+	err = got_diff_tree(NULL, tree, NULL, label, 0, time,
+	    diff_context, repo, outfile);
 
 done:
 	if (tree)
@@ -301,8 +348,8 @@ done:
 
 static const struct got_error *
 diff_modified_tree(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)
+    const char *label1, const char *label2, time_t time1, time_t time2,
+    int diff_context, struct got_repository *repo, FILE *outfile)
 {
 	const struct got_error *err;
 	struct got_object *treeobj1 = NULL;
@@ -336,8 +383,8 @@ diff_modified_tree(struct got_object_id *id1, struct g
 	if (err)
 		goto done;
 
-	err = got_diff_tree(tree1, tree2, label1, label2, diff_context, repo,
-	    outfile);
+	err = got_diff_tree(tree1, tree2, label1, label2, time1, time2,
+	    diff_context, repo, outfile);
 
 done:
 	if (tree1)
@@ -352,7 +399,7 @@ done:
 }
 
 static const struct got_error *
-diff_deleted_tree(struct got_object_id *id, const char *label,
+diff_deleted_tree(struct got_object_id *id, const char *label, time_t time,
     int diff_context, struct got_repository *repo, FILE *outfile)
 {
 	const struct got_error *err;
@@ -372,8 +419,8 @@ diff_deleted_tree(struct got_object_id *id, const char
 	if (err)
 		goto done;
 
-	err = got_diff_tree(tree, NULL, label, NULL, diff_context, repo,
-	    outfile);
+	err = got_diff_tree(tree, NULL, label, NULL, time, 0, diff_context,
+	    repo, outfile);
 done:
 	if (tree)
 		got_object_tree_close(tree);
@@ -392,19 +439,19 @@ diff_kind_mismatch(struct got_object_id *id1, struct g
 
 static const struct got_error *
 diff_entry_old_new(struct got_tree_entry *te1, struct got_tree_entry *te2,
-    const char *label1, const char *label2, int diff_context,
-    struct got_repository *repo, FILE *outfile)
+    const char *label1, const char *label2, time_t time1, time_t time2,
+    int diff_context, struct got_repository *repo, FILE *outfile)
 {
 	const struct got_error *err = NULL;
 	int id_match;
 
 	if (te2 == NULL) {
 		if (S_ISDIR(te1->mode))
-			err = diff_deleted_tree(te1->id, label1, diff_context,
-			    repo, outfile);
+			err = diff_deleted_tree(te1->id, label1, time1,
+			    diff_context, repo, outfile);
 		else
-			err = diff_deleted_blob(te1->id, label1, diff_context,
-			    repo, outfile);
+			err = diff_deleted_blob(te1->id, label1, time1,
+			    diff_context, repo, outfile);
 		return err;
 	}
 
@@ -412,11 +459,13 @@ diff_entry_old_new(struct got_tree_entry *te1, struct 
 	if (S_ISDIR(te1->mode) && S_ISDIR(te2->mode)) {
 		if (!id_match)
 			return diff_modified_tree(te1->id, te2->id,
-			    label1, label2, diff_context, repo, outfile);
+			    label1, label2, time1, time2, diff_context,
+			    repo, outfile);
 	} else if (S_ISREG(te1->mode) && S_ISREG(te2->mode)) {
 		if (!id_match)
 			return diff_modified_blob(te1->id, te2->id,
-			    label1, label2, diff_context, repo, outfile);
+			    label1, label2, time1, time2, diff_context,
+			    repo, outfile);
 	}
 
 	if (id_match)
@@ -427,23 +476,24 @@ diff_entry_old_new(struct got_tree_entry *te1, struct 
 
 static const struct got_error *
 diff_entry_new_old(struct got_tree_entry *te2, struct got_tree_entry *te1,
-    const char *label2, int diff_context, struct got_repository *repo,
-    FILE *outfile)
+    const char *label2, time_t time2, int diff_context,
+    struct got_repository *repo, FILE *outfile)
 {
 	if (te1 != NULL) /* handled by diff_entry_old_new() */
 		return NULL;
 
 	if (S_ISDIR(te2->mode))
-		return diff_added_tree(te2->id, label2, diff_context, repo,
-		    outfile);
+		return diff_added_tree(te2->id, label2, time2, diff_context,
+		    repo, outfile);
 
-	return diff_added_blob(te2->id, label2, diff_context, repo, outfile);
+	return diff_added_blob(te2->id, label2, time2, diff_context, repo,
+	    outfile);
 }
 
 const struct got_error *
 got_diff_tree(struct got_tree_object *tree1, struct got_tree_object *tree2,
-    const char *label1, const char *label2, int diff_context,
-    struct got_repository *repo, FILE *outfile)
+    const char *label1, const char *label2, time_t time1, time_t time2,
+    int diff_context, struct got_repository *repo, FILE *outfile)
 {
 	const struct got_error *err = NULL;
 	struct got_tree_entry *te1 = NULL;
@@ -479,8 +529,8 @@ got_diff_tree(struct got_tree_object *tree1, struct go
 				    label2[0] ? "/" : "", te->name) == -1)
 					return got_error_from_errno();
 			}
-			err = diff_entry_old_new(te1, te, l1, l2, diff_context,
-			    repo, outfile);
+			err = diff_entry_old_new(te1, te, l1, l2, time1, time2,
+			    diff_context, repo, outfile);
 			if (err)
 				break;
 		}
@@ -499,8 +549,8 @@ got_diff_tree(struct got_tree_object *tree1, struct go
 				    label2[0] ? "/" : "", te2->name) == -1)
 					return got_error_from_errno();
 			}
-			err = diff_entry_new_old(te2, te, l2, diff_context,
-			    repo, outfile);
+			err = diff_entry_new_old(te2, te, l2, time2,
+			    diff_context, repo, outfile);
 			if (err)
 				break;
 		}
@@ -530,8 +580,8 @@ 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)
+    const char *label1, const char *label2, time_t time1, time_t time2,
+    int diff_context, struct got_repository *repo, FILE *outfile)
 {
 	const struct got_error *err;
 	struct got_blob_object *blob1 = NULL, *blob2 = NULL;
@@ -549,8 +599,8 @@ got_diff_objects_as_blobs(struct got_object_id *id1, s
 		if (err)
 			goto done;
 	}
-	err = got_diff_blob(blob1, blob2, label1, label2, diff_context,
-	    outfile);
+	err = got_diff_blob(blob1, blob2, label1, label2, time1, time2,
+	    diff_context, outfile);
 done:
 	if (blob1)
 		got_object_blob_close(blob1);
@@ -561,8 +611,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, time_t time1, time_t time2,
+    int diff_context, struct got_repository *repo, FILE *outfile)
 {
 	const struct got_error *err;
 	struct got_tree_object *tree1 = NULL, *tree2 = NULL;
@@ -580,8 +630,8 @@ got_diff_objects_as_trees(struct got_object_id *id1, s
 		if (err)
 			goto done;
 	}
-	err = got_diff_tree(tree1, tree2, label1, label2, diff_context,
-	   repo, outfile);
+	err = got_diff_tree(tree1, tree2, label1, label2, time1, time2,
+	    diff_context, repo, outfile);
 done:
 	if (tree1)
 		got_object_tree_close(tree1);
@@ -613,8 +663,11 @@ 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), "", "",
+	    commit1 ? got_object_commit_get_committer_time(commit1) : 0,
+	    got_object_commit_get_committer_time(commit2),
+	    diff_context,
+	    repo, outfile);
 done:
 	if (commit1)
 		got_object_commit_close(commit1);
blob - b06a8e52157c5f52dce914f374c258995ac0dcb8
blob + b04f1979bb2f42847f9308fdd2a6a92de6af4a1e
--- regress/repository/repository_test.c
+++ regress/repository/repository_test.c
@@ -321,7 +321,7 @@ repo_diff_blob(const char *repo_path)
 	outfile = got_opentemp();
 	if (outfile == NULL)
 		return 0;
-	got_diff_blob(blob1, blob2, NULL, NULL, 3, outfile);
+	got_diff_blob(blob1, blob2, NULL, NULL, 0, 0, 3, outfile);
 	rewind(outfile);
 	i = 0;
 	while ((line = fparseln(outfile, &len, NULL, delim, 0)) != NULL) {
@@ -388,7 +388,7 @@ repo_diff_tree(const char *repo_path)
 	} else
 		outfile = stdout;
 	test_printf("\n");
-	got_diff_tree(tree1, tree2, "", "", 3, repo, outfile);
+	got_diff_tree(tree1, tree2, "", "", 0, 0, 3, repo, outfile);
 	test_printf("\n");
 
 	got_object_tree_close(tree1);
blob - e6c12b6914a3e45988975730c905d96a0b10cd33
blob + beb39332ea4ed819e99f2d96fcffe37fce09c987
--- tog/tog.c
+++ tog/tog.c
@@ -1879,10 +1879,10 @@ 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);
+		    0, 0, s->diff_context, s->repo, f);
 		break;
 	case GOT_OBJ_TYPE_TREE:
-		err = got_diff_objects_as_trees(s->id1, s->id2, "", "",
+		err = got_diff_objects_as_trees(s->id1, s->id2, "", "", 0, 0,
 		    s->diff_context, s->repo, f);
 		break;
 	case GOT_OBJ_TYPE_COMMIT: {