]>
Commit | Line | Data |
---|---|---|
9174026c | 1 | #include "cache.h" |
3ebfd4aa | 2 | #include "diff.h" |
e3bc7a3b | 3 | #include "commit.h" |
9174026c | 4 | |
dc26bd89 | 5 | static int show_root_diff = 0; |
601c978c | 6 | static int no_commit_id = 0; |
cee99d22 | 7 | static int verbose_header = 0; |
e0965d83 | 8 | static int ignore_merges = 1; |
6932c78c | 9 | static int combine_merges = 0; |
d8f4790e | 10 | static int dense_combined_merges = 0; |
e0965d83 | 11 | static int read_stdin = 0; |
ec0bdb6f | 12 | static int always_show_header = 0; |
6b5ee137 | 13 | |
f4f21ce3 | 14 | static const char *header = NULL; |
cee99d22 | 15 | static const char *header_prefix = ""; |
000182ea | 16 | static enum cmit_fmt commit_format = CMIT_FMT_RAW; |
9174026c | 17 | |
ac1b3d12 | 18 | static struct diff_options diff_options; |
73134b6d | 19 | |
09d74b3b | 20 | static int call_diff_flush(void) |
38c6f780 | 21 | { |
6b5ee137 | 22 | diffcore_std(&diff_options); |
9ab55bd2 | 23 | if (diff_queue_is_empty()) { |
6b5ee137 JH |
24 | int saved_fmt = diff_options.output_format; |
25 | diff_options.output_format = DIFF_FORMAT_NO_OUTPUT; | |
26 | diff_flush(&diff_options); | |
27 | diff_options.output_format = saved_fmt; | |
9ab55bd2 | 28 | return 0; |
6b14d7fa | 29 | } |
6b14d7fa | 30 | if (header) { |
601c978c PR |
31 | if (!no_commit_id) |
32 | printf("%s%c", header, diff_options.line_termination); | |
6b14d7fa JH |
33 | header = NULL; |
34 | } | |
6b5ee137 | 35 | diff_flush(&diff_options); |
6b14d7fa | 36 | return 1; |
38c6f780 JH |
37 | } |
38 | ||
5c97558c JH |
39 | static int diff_tree_sha1_top(const unsigned char *old, |
40 | const unsigned char *new, const char *base) | |
41 | { | |
42 | int ret; | |
57fe64a4 | 43 | |
ac1b3d12 | 44 | ret = diff_tree_sha1(old, new, base, &diff_options); |
38c6f780 | 45 | call_diff_flush(); |
5c97558c JH |
46 | return ret; |
47 | } | |
48 | ||
dc26bd89 LT |
49 | static int diff_root_tree(const unsigned char *new, const char *base) |
50 | { | |
51 | int retval; | |
52 | void *tree; | |
ac1b3d12 | 53 | struct tree_desc empty, real; |
dc26bd89 | 54 | |
ac1b3d12 | 55 | tree = read_object_with_reference(new, "tree", &real.size, NULL); |
dc26bd89 LT |
56 | if (!tree) |
57 | die("unable to read root tree (%s)", sha1_to_hex(new)); | |
ac1b3d12 LT |
58 | real.buf = tree; |
59 | ||
60 | empty.buf = ""; | |
61 | empty.size = 0; | |
62 | retval = diff_tree(&empty, &real, base, &diff_options); | |
dc26bd89 | 63 | free(tree); |
38c6f780 | 64 | call_diff_flush(); |
dc26bd89 LT |
65 | return retval; |
66 | } | |
67 | ||
47dd0d59 JH |
68 | static const char *generate_header(const unsigned char *commit_sha1, |
69 | const unsigned char *parent_sha1, | |
3815f423 | 70 | const struct commit *commit) |
cee99d22 | 71 | { |
3258c902 | 72 | static char this_header[16384]; |
cee99d22 | 73 | int offset; |
a50b870a | 74 | unsigned long len; |
47dd0d59 | 75 | int abbrev = diff_options.abbrev; |
3815f423 | 76 | const char *msg = commit->buffer; |
cee99d22 | 77 | |
18092663 | 78 | if (!verbose_header) |
47dd0d59 | 79 | return sha1_to_hex(commit_sha1); |
cee99d22 | 80 | |
a50b870a | 81 | len = strlen(msg); |
47dd0d59 JH |
82 | |
83 | offset = sprintf(this_header, "%s%s ", | |
84 | header_prefix, | |
85 | diff_unique_abbrev(commit_sha1, abbrev)); | |
af3feefa JH |
86 | if (commit_sha1 != parent_sha1) |
87 | offset += sprintf(this_header + offset, "(from %s)\n", | |
88 | parent_sha1 | |
89 | ? diff_unique_abbrev(parent_sha1, abbrev) | |
90 | : "root"); | |
91 | else | |
92 | offset += sprintf(this_header + offset, "(from parents)\n"); | |
3815f423 | 93 | offset += pretty_print_commit(commit_format, commit, len, |
47dd0d59 | 94 | this_header + offset, |
b2d4c56f | 95 | sizeof(this_header) - offset, abbrev); |
ec0bdb6f LT |
96 | if (always_show_header) { |
97 | puts(this_header); | |
98 | return NULL; | |
99 | } | |
cee99d22 LT |
100 | return this_header; |
101 | } | |
102 | ||
45392a64 | 103 | static int diff_tree_commit(struct commit *commit) |
e0965d83 | 104 | { |
a50b870a | 105 | struct commit_list *parents; |
45392a64 | 106 | unsigned const char *sha1 = commit->object.sha1; |
e0965d83 | 107 | |
dc26bd89 | 108 | /* Root commit? */ |
a50b870a | 109 | if (show_root_diff && !commit->parents) { |
3815f423 | 110 | header = generate_header(sha1, NULL, commit); |
45392a64 | 111 | diff_root_tree(sha1, ""); |
dc26bd89 LT |
112 | } |
113 | ||
114 | /* More than one parent? */ | |
af3feefa JH |
115 | if (commit->parents && commit->parents->next) { |
116 | if (ignore_merges) | |
117 | return 0; | |
118 | else if (combine_merges) { | |
addafaf9 | 119 | header = generate_header(sha1, sha1, commit); |
ee638024 LT |
120 | header = diff_tree_combined_merge(sha1, header, |
121 | dense_combined_merges, | |
122 | &diff_options); | |
123 | if (!header && verbose_header) | |
124 | header_prefix = "\ndiff-tree "; | |
125 | return 0; | |
af3feefa JH |
126 | } |
127 | } | |
dc26bd89 | 128 | |
a50b870a JH |
129 | for (parents = commit->parents; parents; parents = parents->next) { |
130 | struct commit *parent = parents->item; | |
3815f423 | 131 | header = generate_header(sha1, parent->object.sha1, commit); |
45392a64 | 132 | diff_tree_sha1_top(parent->object.sha1, sha1, ""); |
d6db0107 | 133 | if (!header && verbose_header) { |
cee99d22 | 134 | header_prefix = "\ndiff-tree "; |
d6db0107 LT |
135 | /* |
136 | * Don't print multiple merge entries if we | |
137 | * don't print the diffs. | |
138 | */ | |
d6db0107 | 139 | } |
e0965d83 | 140 | } |
b11645be LT |
141 | return 0; |
142 | } | |
143 | ||
45392a64 JH |
144 | static int diff_tree_commit_sha1(const unsigned char *sha1) |
145 | { | |
146 | struct commit *commit = lookup_commit_reference(sha1); | |
147 | if (!commit) | |
148 | return -1; | |
149 | return diff_tree_commit(commit); | |
150 | } | |
151 | ||
b11645be LT |
152 | static int diff_tree_stdin(char *line) |
153 | { | |
154 | int len = strlen(line); | |
45392a64 JH |
155 | unsigned char sha1[20]; |
156 | struct commit *commit; | |
b11645be LT |
157 | |
158 | if (!len || line[len-1] != '\n') | |
159 | return -1; | |
160 | line[len-1] = 0; | |
45392a64 JH |
161 | if (get_sha1_hex(line, sha1)) |
162 | return -1; | |
163 | commit = lookup_commit(sha1); | |
164 | if (!commit || parse_commit(commit)) | |
b11645be | 165 | return -1; |
45392a64 JH |
166 | if (isspace(line[40]) && !get_sha1_hex(line+41, sha1)) { |
167 | /* Graft the fake parents locally to the commit */ | |
168 | int pos = 41; | |
169 | struct commit_list **pptr, *parents; | |
170 | ||
171 | /* Free the real parent list */ | |
172 | for (parents = commit->parents; parents; ) { | |
173 | struct commit_list *tmp = parents->next; | |
174 | free(parents); | |
175 | parents = tmp; | |
176 | } | |
177 | commit->parents = NULL; | |
178 | pptr = &(commit->parents); | |
179 | while (line[pos] && !get_sha1_hex(line + pos, sha1)) { | |
180 | struct commit *parent = lookup_commit(sha1); | |
181 | if (parent) { | |
182 | pptr = &commit_list_insert(parent, pptr)->next; | |
183 | } | |
184 | pos += 41; | |
185 | } | |
b11645be | 186 | } |
a50b870a | 187 | return diff_tree_commit(commit); |
e0965d83 LT |
188 | } |
189 | ||
4d1f1190 | 190 | static const char diff_tree_usage[] = |
d8f4790e | 191 | "git-diff-tree [--stdin] [-m] [-c] [--cc] [-s] [-v] [--pretty] [-t] [-r] [--root] " |
50b8e355 CS |
192 | "[<common diff options>] <tree-ish> [<tree-ish>] [<path>...]\n" |
193 | " -r diff recursively\n" | |
194 | " --root include the initial commit as diff against /dev/null\n" | |
dda2d79a | 195 | COMMON_DIFF_OPTIONS_HELP; |
a8db165e | 196 | |
6b5ee137 | 197 | int main(int argc, const char **argv) |
73134b6d | 198 | { |
0a8365a1 | 199 | int nr_sha1; |
e0965d83 | 200 | char line[1000]; |
0a8365a1 | 201 | unsigned char sha1[2][20]; |
d288a700 | 202 | const char *prefix = setup_git_directory(); |
73134b6d | 203 | |
9ce392f4 | 204 | git_config(git_diff_config); |
0a8365a1 | 205 | nr_sha1 = 0; |
6b5ee137 JH |
206 | diff_setup(&diff_options); |
207 | ||
c5b42386 | 208 | for (;;) { |
6b5ee137 | 209 | int diff_opt_cnt; |
6b14d7fa | 210 | const char *arg; |
c5b42386 | 211 | |
e0965d83 LT |
212 | argv++; |
213 | argc--; | |
214 | arg = *argv; | |
0a8365a1 | 215 | if (!arg) |
c5b42386 LT |
216 | break; |
217 | ||
0a8365a1 LT |
218 | if (*arg != '-') { |
219 | if (nr_sha1 < 2 && !get_sha1(arg, sha1[nr_sha1])) { | |
220 | nr_sha1++; | |
221 | continue; | |
222 | } | |
223 | break; | |
224 | } | |
225 | ||
6b5ee137 JH |
226 | diff_opt_cnt = diff_opt_parse(&diff_options, argv, argc); |
227 | if (diff_opt_cnt < 0) | |
228 | usage(diff_tree_usage); | |
229 | else if (diff_opt_cnt) { | |
230 | argv += diff_opt_cnt - 1; | |
231 | argc -= diff_opt_cnt - 1; | |
232 | continue; | |
233 | } | |
234 | ||
235 | ||
0a8365a1 | 236 | if (!strcmp(arg, "--")) { |
e0965d83 LT |
237 | argv++; |
238 | argc--; | |
239 | break; | |
240 | } | |
bf16c71e | 241 | if (!strcmp(arg, "-r")) { |
ac1b3d12 | 242 | diff_options.recursive = 1; |
73134b6d LT |
243 | continue; |
244 | } | |
4cae1a96 | 245 | if (!strcmp(arg, "-t")) { |
ac1b3d12 LT |
246 | diff_options.recursive = 1; |
247 | diff_options.tree_in_recursive = 1; | |
4cae1a96 JH |
248 | continue; |
249 | } | |
e0965d83 | 250 | if (!strcmp(arg, "-m")) { |
6932c78c | 251 | ignore_merges = 0; |
e0965d83 LT |
252 | continue; |
253 | } | |
af3feefa JH |
254 | if (!strcmp(arg, "-c")) { |
255 | combine_merges = 1; | |
256 | continue; | |
257 | } | |
d8f4790e JH |
258 | if (!strcmp(arg, "--cc")) { |
259 | dense_combined_merges = combine_merges = 1; | |
260 | continue; | |
261 | } | |
cee99d22 LT |
262 | if (!strcmp(arg, "-v")) { |
263 | verbose_header = 1; | |
264 | header_prefix = "diff-tree "; | |
265 | continue; | |
266 | } | |
a8db165e JH |
267 | if (!strncmp(arg, "--pretty", 8)) { |
268 | verbose_header = 1; | |
ba88e54b | 269 | header_prefix = "diff-tree "; |
a8db165e JH |
270 | commit_format = get_commit_format(arg+8); |
271 | continue; | |
272 | } | |
e0965d83 LT |
273 | if (!strcmp(arg, "--stdin")) { |
274 | read_stdin = 1; | |
275 | continue; | |
276 | } | |
dc26bd89 LT |
277 | if (!strcmp(arg, "--root")) { |
278 | show_root_diff = 1; | |
279 | continue; | |
280 | } | |
601c978c PR |
281 | if (!strcmp(arg, "--no-commit-id")) { |
282 | no_commit_id = 1; | |
283 | continue; | |
284 | } | |
ec0bdb6f LT |
285 | if (!strcmp(arg, "--always")) { |
286 | always_show_header = 1; | |
287 | continue; | |
288 | } | |
c5bac17a | 289 | usage(diff_tree_usage); |
73134b6d LT |
290 | } |
291 | ||
ee638024 | 292 | if (combine_merges) |
af3feefa | 293 | ignore_merges = 0; |
ee638024 LT |
294 | |
295 | /* We can only do dense combined merges with diff output */ | |
296 | if (dense_combined_merges) | |
297 | diff_options.output_format = DIFF_FORMAT_PATCH; | |
af3feefa | 298 | |
deb989b5 LT |
299 | if (diff_options.output_format == DIFF_FORMAT_PATCH) |
300 | diff_options.recursive = 1; | |
301 | ||
ac1b3d12 | 302 | diff_tree_setup_paths(get_pathspec(prefix, argv)); |
47dd0d59 | 303 | diff_setup_done(&diff_options); |
c5b42386 | 304 | |
0a8365a1 LT |
305 | switch (nr_sha1) { |
306 | case 0: | |
307 | if (!read_stdin) | |
308 | usage(diff_tree_usage); | |
309 | break; | |
310 | case 1: | |
45392a64 | 311 | diff_tree_commit_sha1(sha1[0]); |
0a8365a1 LT |
312 | break; |
313 | case 2: | |
5c97558c | 314 | diff_tree_sha1_top(sha1[0], sha1[1], ""); |
0a8365a1 LT |
315 | break; |
316 | } | |
317 | ||
e0965d83 | 318 | if (!read_stdin) |
0a8365a1 | 319 | return 0; |
e0965d83 | 320 | |
6b5ee137 JH |
321 | if (diff_options.detect_rename) |
322 | diff_options.setup |= (DIFF_SETUP_USE_SIZE_CACHE | | |
323 | DIFF_SETUP_USE_CACHE); | |
e0965d83 LT |
324 | while (fgets(line, sizeof(line), stdin)) |
325 | diff_tree_stdin(line); | |
326 | ||
327 | return 0; | |
9174026c | 328 | } |