stagit

optimization: only diff the tree when it is needed for the diffstat...

... also clear all fields in the structure on failure.

This is not as big an optimization as stagit-gopher, because the diffstat is
displayed in the log, but the difference is still measurable.

Hiltjo Posthuma contact@arjunchoudhary.com

commit: 7013a46 parent: 29d0a52
1 files changed, 27 insertions(+), 17 deletions(-)
Mstagit.c+27-17
M · stagit.c +27, -17
 1@@ -87,7 +87,7 @@ deltainfo_free(struct deltainfo *di)
 2 	if (!di)
 3 		return;
 4 	git_patch_free(di->patch);
 5-	di->patch = NULL;
 6+	memset(di, 0, sizeof(*di));
 7 	free(di);
 8 }
 9 
10@@ -95,6 +95,7 @@ int
11 commitinfo_getstats(struct commitinfo *ci)
12 {
13 	struct deltainfo *di;
14+	git_diff_options opts;
15 	const git_diff_delta *delta;
16 	const git_diff_hunk *hunk;
17 	const git_diff_line *line;
18@@ -102,6 +103,20 @@ commitinfo_getstats(struct commitinfo *ci)
19 	size_t ndeltas, nhunks, nhunklines;
20 	size_t i, j, k;
21 
22+	if (git_tree_lookup(&(ci->commit_tree), repo, git_commit_tree_id(ci->commit)))
23+		goto err;
24+	if (!git_commit_parent(&(ci->parent), ci->commit, 0)) {
25+		if (git_tree_lookup(&(ci->parent_tree), repo, git_commit_tree_id(ci->parent))) {
26+			ci->parent = NULL;
27+			ci->parent_tree = NULL;
28+		}
29+	}
30+
31+	git_diff_init_options(&opts, GIT_DIFF_OPTIONS_VERSION);
32+	opts.flags |= GIT_DIFF_DISABLE_PATHSPEC_MATCH;
33+	if (git_diff_tree_to_tree(&(ci->diff), repo, ci->parent_tree, ci->commit_tree, &opts))
34+		goto err;
35+
36 	ndeltas = git_diff_num_deltas(ci->diff);
37 	if (ndeltas && !(ci->deltas = calloc(ndeltas, sizeof(struct deltainfo *))))
38 		err(1, "calloc");
39@@ -143,6 +158,15 @@ commitinfo_getstats(struct commitinfo *ci)
40 	return 0;
41 
42 err:
43+	git_diff_free(ci->diff);
44+	ci->diff = NULL;
45+	git_tree_free(ci->commit_tree);
46+	ci->commit_tree = NULL;
47+	git_tree_free(ci->parent_tree);
48+	ci->parent_tree = NULL;
49+	git_commit_free(ci->parent);
50+	ci->parent = NULL;
51+
52 	if (ci->deltas)
53 		for (i = 0; i < ci->ndeltas; i++)
54 			deltainfo_free(ci->deltas[i]);
55@@ -166,13 +190,14 @@ commitinfo_free(struct commitinfo *ci)
56 	if (ci->deltas)
57 		for (i = 0; i < ci->ndeltas; i++)
58 			deltainfo_free(ci->deltas[i]);
59+
60 	free(ci->deltas);
61-	ci->deltas = NULL;
62 	git_diff_free(ci->diff);
63 	git_tree_free(ci->commit_tree);
64 	git_tree_free(ci->parent_tree);
65 	git_commit_free(ci->commit);
66 	git_commit_free(ci->parent);
67+	memset(ci, 0, sizeof(*ci));
68 	free(ci);
69 }
70 
71@@ -180,7 +205,6 @@ struct commitinfo *
72 commitinfo_getbyoid(const git_oid *id)
73 {
74 	struct commitinfo *ci;
75-	git_diff_options opts;
76 
77 	if (!(ci = calloc(1, sizeof(struct commitinfo))))
78 		err(1, "calloc");
79@@ -197,20 +221,6 @@ commitinfo_getbyoid(const git_oid *id)
80 	ci->summary = git_commit_summary(ci->commit);
81 	ci->msg = git_commit_message(ci->commit);
82 
83-	if (git_tree_lookup(&(ci->commit_tree), repo, git_commit_tree_id(ci->commit)))
84-		goto err;
85-	if (!git_commit_parent(&(ci->parent), ci->commit, 0)) {
86-		if (git_tree_lookup(&(ci->parent_tree), repo, git_commit_tree_id(ci->parent))) {
87-			ci->parent = NULL;
88-			ci->parent_tree = NULL;
89-		}
90-	}
91-
92-	git_diff_init_options(&opts, GIT_DIFF_OPTIONS_VERSION);
93-	opts.flags |= GIT_DIFF_DISABLE_PATHSPEC_MATCH;
94-	if (git_diff_tree_to_tree(&(ci->diff), repo, ci->parent_tree, ci->commit_tree, &opts))
95-		goto err;
96-
97 	return ci;
98 
99 err: