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