Commit 31b4484f27afc8ceaf636ad8c97d8a9aa119693e

Stefan Sperling 2019-07-27T19:01:01

speed up rebase and histedit path prefix check: skip blob content diffs

diff --git a/got/got.c b/got/got.c
index 0d710de..753ca96 100644
--- a/got/got.c
+++ b/got/got.c
@@ -1273,7 +1273,7 @@ print_patch(struct got_commit_object *commit, struct got_object_id *id,
 	arg.diff_context = diff_context;
 	arg.outfile = stdout;
 	err = got_diff_tree(tree1, tree2, "", "", repo,
-	    got_diff_blob_output_unidiff, &arg);
+	    got_diff_blob_output_unidiff, &arg, 1);
 done:
 	if (tree1)
 		got_object_tree_close(tree1);
@@ -3738,7 +3738,7 @@ check_path_prefix(struct got_object_id *parent_id,
 	cpp_arg.len = strlen(cpp_arg.path_prefix);
 	cpp_arg.errcode = errcode;
 	err = got_diff_tree(tree1, tree2, "", "", repo,
-	    check_path_prefix_in_diff, &cpp_arg);
+	    check_path_prefix_in_diff, &cpp_arg, 0);
 done:
 	if (tree1)
 		got_object_tree_close(tree1);
diff --git a/include/got_diff.h b/include/got_diff.h
index 8ab2399..0d86e3c 100644
--- a/include/got_diff.h
+++ b/include/got_diff.h
@@ -64,10 +64,13 @@ const struct got_error *got_diff_blob_output_unidiff(void *,
 /*
  * Compute the differences between two trees and invoke the provided
  * got_diff_blob_cb() callback when content differs.
+ * Diffing of blob content can be suppressed by passing zero for the
+ * 'diff_content' parameter. The callback will then only receive blob
+ * object IDs and diff labels, but NULL pointers instead of blob objects.
  */
 const struct got_error *got_diff_tree(struct got_tree_object *,
     struct got_tree_object *, const char *, const char *,
-    struct got_repository *, got_diff_blob_cb cb, void *cb_arg);
+    struct got_repository *, got_diff_blob_cb cb, void *cb_arg, int);
 
 /*
  * Diff two objects, assuming both objects are blobs. Two const char * diff
diff --git a/lib/diff.c b/lib/diff.c
index 241a941..d572937 100644
--- a/lib/diff.c
+++ b/lib/diff.c
@@ -325,7 +325,8 @@ done:
 
 static const struct got_error *
 diff_added_tree(struct got_object_id *id, const char *label,
-    struct got_repository *repo, got_diff_blob_cb cb, void *cb_arg)
+    struct got_repository *repo, got_diff_blob_cb cb, void *cb_arg,
+    int diff_content)
 {
 	const struct got_error *err = NULL;
 	struct got_object *treeobj = NULL;
@@ -344,7 +345,8 @@ diff_added_tree(struct got_object_id *id, const char *label,
 	if (err)
 		goto done;
 
-	err = got_diff_tree(NULL, tree, NULL, label, repo, cb, cb_arg);
+	err = got_diff_tree(NULL, tree, NULL, label, repo, cb, cb_arg,
+	    diff_content);
 done:
 	if (tree)
 		got_object_tree_close(tree);
@@ -356,7 +358,7 @@ 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, struct got_repository *repo,
-    got_diff_blob_cb cb, void *cb_arg)
+    got_diff_blob_cb cb, void *cb_arg, int diff_content)
 {
 	const struct got_error *err;
 	struct got_object *treeobj1 = NULL;
@@ -390,7 +392,8 @@ diff_modified_tree(struct got_object_id *id1, struct got_object_id *id2,
 	if (err)
 		goto done;
 
-	err = got_diff_tree(tree1, tree2, label1, label2, repo, cb, cb_arg);
+	err = got_diff_tree(tree1, tree2, label1, label2, repo, cb, cb_arg,
+	    diff_content);
 
 done:
 	if (tree1)
@@ -406,7 +409,8 @@ done:
 
 static const struct got_error *
 diff_deleted_tree(struct got_object_id *id, const char *label,
-    struct got_repository *repo, got_diff_blob_cb cb, void *cb_arg)
+    struct got_repository *repo, got_diff_blob_cb cb, void *cb_arg,
+    int diff_content)
 {
 	const struct got_error *err;
 	struct got_object *treeobj = NULL;
@@ -425,7 +429,8 @@ diff_deleted_tree(struct got_object_id *id, const char *label,
 	if (err)
 		goto done;
 
-	err = got_diff_tree(tree, NULL, label, NULL, repo, cb, cb_arg);
+	err = got_diff_tree(tree, NULL, label, NULL, repo, cb, cb_arg,
+	    diff_content);
 done:
 	if (tree)
 		got_object_tree_close(tree);
@@ -446,7 +451,8 @@ diff_kind_mismatch(struct got_object_id *id1, struct got_object_id *id2,
 static const struct got_error *
 diff_entry_old_new(const struct got_tree_entry *te1,
     const struct got_tree_entry *te2, const char *label1, const char *label2,
-    struct got_repository *repo, got_diff_blob_cb cb, void *cb_arg)
+    struct got_repository *repo, got_diff_blob_cb cb, void *cb_arg,
+    int diff_content)
 {
 	const struct got_error *err = NULL;
 	int id_match;
@@ -454,10 +460,15 @@ diff_entry_old_new(const struct got_tree_entry *te1,
 	if (te2 == NULL) {
 		if (S_ISDIR(te1->mode))
 			err = diff_deleted_tree(te1->id, label1, repo,
-			    cb, cb_arg);
-		else
-			err = diff_deleted_blob(te1->id, label1, repo,
-			    cb, cb_arg);
+			    cb, cb_arg, diff_content);
+		else {
+			if (diff_content)
+				err = diff_deleted_blob(te1->id, label1, repo,
+				    cb, cb_arg);
+			else
+				err = cb(cb_arg, NULL, NULL, te1->id, NULL,
+				    label1, NULL, repo);
+		}
 		return err;
 	}
 
@@ -465,11 +476,16 @@ diff_entry_old_new(const struct got_tree_entry *te1,
 	if (S_ISDIR(te1->mode) && S_ISDIR(te2->mode)) {
 		if (!id_match)
 			return diff_modified_tree(te1->id, te2->id,
-			    label1, label2, repo, cb, cb_arg);
+			    label1, label2, repo, cb, cb_arg, diff_content);
 	} else if (S_ISREG(te1->mode) && S_ISREG(te2->mode)) {
-		if (!id_match)
-			return diff_modified_blob(te1->id, te2->id,
-			    label1, label2, repo, cb, cb_arg);
+		if (!id_match) {
+			if (diff_content)
+				return diff_modified_blob(te1->id, te2->id,
+				    label1, label2, repo, cb, cb_arg);
+			else
+				return cb(cb_arg, NULL, NULL, te1->id,
+				    te2->id, label1, label2, repo);
+		}
 	}
 
 	if (id_match)
@@ -482,21 +498,26 @@ diff_entry_old_new(const struct got_tree_entry *te1,
 static const struct got_error *
 diff_entry_new_old(const struct got_tree_entry *te2,
     const struct got_tree_entry *te1, const char *label2,
-    struct got_repository *repo, got_diff_blob_cb cb, void *cb_arg)
+    struct got_repository *repo, got_diff_blob_cb cb, void *cb_arg,
+    int diff_content)
 {
 	if (te1 != NULL) /* handled by diff_entry_old_new() */
 		return NULL;
 
 	if (S_ISDIR(te2->mode))
-		return diff_added_tree(te2->id, label2, repo, cb, cb_arg);
+		return diff_added_tree(te2->id, label2, repo, cb, cb_arg,
+		    diff_content);
 
-	return diff_added_blob(te2->id, label2, repo, cb, cb_arg);
+	if (diff_content)
+		return diff_added_blob(te2->id, label2, repo, cb, cb_arg);
+
+	return cb(cb_arg, NULL, NULL, NULL, te2->id, NULL, label2, repo);
 }
 
 const struct got_error *
 got_diff_tree(struct got_tree_object *tree1, struct got_tree_object *tree2,
     const char *label1, const char *label2, struct got_repository *repo,
-    got_diff_blob_cb cb, void *cb_arg)
+    got_diff_blob_cb cb, void *cb_arg, int diff_content)
 {
 	const struct got_error *err = NULL;
 	struct got_tree_entry *te1 = NULL;
@@ -535,7 +556,7 @@ got_diff_tree(struct got_tree_object *tree1, struct got_tree_object *tree2,
 					    got_error_from_errno("asprintf");
 			}
 			err = diff_entry_old_new(te1, te, l1, l2, repo, cb,
-			    cb_arg);
+			    cb_arg, diff_content);
 			if (err)
 				break;
 		}
@@ -557,7 +578,8 @@ got_diff_tree(struct got_tree_object *tree1, struct got_tree_object *tree2,
 					return
 					    got_error_from_errno("asprintf");
 			}
-			err = diff_entry_new_old(te2, te, l2, repo, cb, cb_arg);
+			err = diff_entry_new_old(te2, te, l2, repo,
+			    cb, cb_arg, diff_content);
 			if (err)
 				break;
 		}
@@ -641,7 +663,7 @@ got_diff_objects_as_trees(struct got_object_id *id1, struct got_object_id *id2,
 	arg.diff_context = diff_context;
 	arg.outfile = outfile;
 	err = got_diff_tree(tree1, tree2, label1, label2, repo,
-	    got_diff_blob_output_unidiff, &arg);
+	    got_diff_blob_output_unidiff, &arg, 1);
 done:
 	if (tree1)
 		got_object_tree_close(tree1);
diff --git a/lib/worktree.c b/lib/worktree.c
index 102a998..b40be45 100644
--- a/lib/worktree.c
+++ b/lib/worktree.c
@@ -2112,7 +2112,7 @@ merge_files(struct got_worktree *worktree, struct got_fileindex *fileindex,
 	arg.cancel_cb = cancel_cb;
 	arg.cancel_arg = cancel_arg;
 	arg.commit_id2 = commit_id2;
-	err = got_diff_tree(tree1, tree2, "", "", repo, merge_file_cb, &arg);
+	err = got_diff_tree(tree1, tree2, "", "", repo, merge_file_cb, &arg, 1);
 	sync_err = sync_fileindex(fileindex, fileindex_path);
 	if (sync_err && err == NULL)
 		err = sync_err;
diff --git a/regress/repository/repository_test.c b/regress/repository/repository_test.c
index b6001e3..c195445 100644
--- a/regress/repository/repository_test.c
+++ b/regress/repository/repository_test.c
@@ -397,7 +397,7 @@ repo_diff_tree(const char *repo_path)
 	arg.diff_context = 3;
 	arg.outfile = outfile;
 	got_diff_tree(tree1, tree2, "", "", repo,
-	    got_diff_blob_output_unidiff, &arg);
+	    got_diff_blob_output_unidiff, &arg, 1);
 	test_printf("\n");
 
 	got_object_tree_close(tree1);