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