]>
Commit | Line | Data |
---|---|---|
9174026c | 1 | #include "cache.h" |
3ebfd4aa | 2 | #include "diff.h" |
e3bc7a3b | 3 | #include "commit.h" |
5f1c3f07 | 4 | #include "log-tree.h" |
e8cc9cd9 | 5 | #include "builtin.h" |
302ad7a9 | 6 | #include "submodule.h" |
9174026c | 7 | |
cd2bdc53 | 8 | static struct rev_info log_tree_opt; |
b11645be | 9 | |
5f5e936d | 10 | static int diff_tree_commit_sha1(const struct object_id *oid) |
45392a64 | 11 | { |
bc83266a | 12 | struct commit *commit = lookup_commit_reference(oid); |
45392a64 JH |
13 | if (!commit) |
14 | return -1; | |
5f1c3f07 | 15 | return log_tree_commit(&log_tree_opt, commit); |
45392a64 JH |
16 | } |
17 | ||
a57114c8 | 18 | /* Diff one or more commits. */ |
5f5e936d | 19 | static int stdin_diff_commit(struct commit *commit, const char *p) |
b11645be | 20 | { |
5f5e936d | 21 | struct object_id oid; |
22 | struct commit_list **pptr = NULL; | |
23 | ||
24 | /* Graft the fake parents locally to the commit */ | |
25 | while (isspace(*p++) && !parse_oid_hex(p, &oid, &p)) { | |
bc83266a | 26 | struct commit *parent = lookup_commit(&oid); |
5f5e936d | 27 | if (!pptr) { |
28 | /* Free the real parent list */ | |
29 | free_commit_list(commit->parents); | |
30 | commit->parents = NULL; | |
31 | pptr = &(commit->parents); | |
32 | } | |
33 | if (parent) { | |
34 | pptr = &commit_list_insert(parent, pptr)->next; | |
45392a64 | 35 | } |
b11645be | 36 | } |
5f1c3f07 | 37 | return log_tree_commit(&log_tree_opt, commit); |
e0965d83 LT |
38 | } |
39 | ||
140b378d | 40 | /* Diff two trees. */ |
5f5e936d | 41 | static int stdin_diff_trees(struct tree *tree1, const char *p) |
140b378d | 42 | { |
5f5e936d | 43 | struct object_id oid; |
140b378d | 44 | struct tree *tree2; |
5f5e936d | 45 | if (!isspace(*p++) || parse_oid_hex(p, &oid, &p) || *p) |
140b378d | 46 | return error("Need exactly two trees, separated by a space"); |
740ee055 | 47 | tree2 = lookup_tree(&oid); |
140b378d KW |
48 | if (!tree2 || parse_tree(tree2)) |
49 | return -1; | |
f2fd0760 | 50 | printf("%s %s\n", oid_to_hex(&tree1->object.oid), |
51 | oid_to_hex(&tree2->object.oid)); | |
ed1c9977 | 52 | diff_tree_sha1(tree1->object.oid.hash, tree2->object.oid.hash, |
140b378d KW |
53 | "", &log_tree_opt.diffopt); |
54 | log_tree_diff_flush(&log_tree_opt); | |
55 | return 0; | |
56 | } | |
57 | ||
a57114c8 KW |
58 | static int diff_tree_stdin(char *line) |
59 | { | |
60 | int len = strlen(line); | |
5f5e936d | 61 | struct object_id oid; |
140b378d | 62 | struct object *obj; |
5f5e936d | 63 | const char *p; |
a57114c8 KW |
64 | |
65 | if (!len || line[len-1] != '\n') | |
66 | return -1; | |
67 | line[len-1] = 0; | |
5f5e936d | 68 | if (parse_oid_hex(line, &oid, &p)) |
a57114c8 | 69 | return -1; |
c251c83d | 70 | obj = parse_object(&oid); |
140b378d | 71 | if (!obj) |
a57114c8 | 72 | return -1; |
140b378d | 73 | if (obj->type == OBJ_COMMIT) |
5f5e936d | 74 | return stdin_diff_commit((struct commit *)obj, p); |
140b378d | 75 | if (obj->type == OBJ_TREE) |
5f5e936d | 76 | return stdin_diff_trees((struct tree *)obj, p); |
140b378d | 77 | error("Object %s is a %s, not a commit or tree", |
5f5e936d | 78 | oid_to_hex(&oid), typename(obj->type)); |
140b378d | 79 | return -1; |
a57114c8 KW |
80 | } |
81 | ||
4d1f1190 | 82 | static const char diff_tree_usage[] = |
1b1dd23f | 83 | "git diff-tree [--stdin] [-m] [-c] [--cc] [-s] [-v] [--pretty] [-t] [-r] [--root] " |
9c9b4f2f | 84 | "[<common-diff-options>] <tree-ish> [<tree-ish>] [<path>...]\n" |
50b8e355 CS |
85 | " -r diff recursively\n" |
86 | " --root include the initial commit as diff against /dev/null\n" | |
dda2d79a | 87 | COMMON_DIFF_OPTIONS_HELP; |
a8db165e | 88 | |
b4490059 JH |
89 | static void diff_tree_tweak_rev(struct rev_info *rev, struct setup_revision_opt *opt) |
90 | { | |
91 | if (!rev->diffopt.output_format) { | |
92 | if (rev->dense_combined_merges) | |
93 | rev->diffopt.output_format = DIFF_FORMAT_PATCH; | |
94 | else | |
95 | rev->diffopt.output_format = DIFF_FORMAT_RAW; | |
96 | } | |
97 | } | |
98 | ||
a633fca0 | 99 | int cmd_diff_tree(int argc, const char **argv, const char *prefix) |
73134b6d | 100 | { |
0a8365a1 | 101 | int nr_sha1; |
e0965d83 | 102 | char line[1000]; |
cd2bdc53 LT |
103 | struct object *tree1, *tree2; |
104 | static struct rev_info *opt = &log_tree_opt; | |
b4490059 | 105 | struct setup_revision_opt s_r_opt; |
5f1c3f07 | 106 | int read_stdin = 0; |
73134b6d | 107 | |
a633fca0 | 108 | init_revisions(opt, prefix); |
302ad7a9 | 109 | gitmodules_config(); |
ef90d6d4 | 110 | git_config(git_diff_basic_config, NULL); /* no "diff" UI options */ |
8e8f9987 | 111 | opt->abbrev = 0; |
91539833 | 112 | opt->diff = 1; |
8b3dce56 | 113 | opt->disable_stdin = 1; |
b4490059 JH |
114 | memset(&s_r_opt, 0, sizeof(s_r_opt)); |
115 | s_r_opt.tweak = diff_tree_tweak_rev; | |
90a78b83 AR |
116 | |
117 | precompose_argv(argc, argv); | |
b4490059 | 118 | argc = setup_revisions(argc, argv, opt, &s_r_opt); |
6b5ee137 | 119 | |
cd2bdc53 LT |
120 | while (--argc > 0) { |
121 | const char *arg = *++argv; | |
c5b42386 | 122 | |
e0965d83 LT |
123 | if (!strcmp(arg, "--stdin")) { |
124 | read_stdin = 1; | |
125 | continue; | |
126 | } | |
c5bac17a | 127 | usage(diff_tree_usage); |
73134b6d LT |
128 | } |
129 | ||
cd2bdc53 | 130 | /* |
1f1e895f LT |
131 | * NOTE! We expect "a ^b" to be equal to "a..b", so we |
132 | * reverse the order of the objects if the second one | |
133 | * is marked UNINTERESTING. | |
cd2bdc53 | 134 | */ |
1f1e895f | 135 | nr_sha1 = opt->pending.nr; |
0a8365a1 LT |
136 | switch (nr_sha1) { |
137 | case 0: | |
138 | if (!read_stdin) | |
139 | usage(diff_tree_usage); | |
140 | break; | |
141 | case 1: | |
1f1e895f | 142 | tree1 = opt->pending.objects[0].item; |
5f5e936d | 143 | diff_tree_commit_sha1(&tree1->oid); |
0a8365a1 LT |
144 | break; |
145 | case 2: | |
1f1e895f LT |
146 | tree1 = opt->pending.objects[0].item; |
147 | tree2 = opt->pending.objects[1].item; | |
148 | if (tree2->flags & UNINTERESTING) { | |
35d803bc | 149 | SWAP(tree2, tree1); |
1f1e895f | 150 | } |
ed1c9977 | 151 | diff_tree_sha1(tree1->oid.hash, |
152 | tree2->oid.hash, | |
cd2bdc53 | 153 | "", &opt->diffopt); |
5f1c3f07 | 154 | log_tree_diff_flush(opt); |
0a8365a1 LT |
155 | break; |
156 | } | |
157 | ||
62c64895 | 158 | if (read_stdin) { |
f31027c9 JH |
159 | int saved_nrl = 0; |
160 | int saved_dcctc = 0; | |
161 | ||
62c64895 WC |
162 | if (opt->diffopt.detect_rename) |
163 | opt->diffopt.setup |= (DIFF_SETUP_USE_SIZE_CACHE | | |
164 | DIFF_SETUP_USE_CACHE); | |
165 | while (fgets(line, sizeof(line), stdin)) { | |
5f5e936d | 166 | struct object_id oid; |
e0965d83 | 167 | |
5f5e936d | 168 | if (get_oid_hex(line, &oid)) { |
62c64895 WC |
169 | fputs(line, stdout); |
170 | fflush(stdout); | |
171 | } | |
f31027c9 | 172 | else { |
62c64895 | 173 | diff_tree_stdin(line); |
f31027c9 JH |
174 | if (saved_nrl < opt->diffopt.needed_rename_limit) |
175 | saved_nrl = opt->diffopt.needed_rename_limit; | |
176 | if (opt->diffopt.degraded_cc_to_c) | |
177 | saved_dcctc = 1; | |
178 | } | |
e0c97ca6 | 179 | } |
f31027c9 JH |
180 | opt->diffopt.degraded_cc_to_c = saved_dcctc; |
181 | opt->diffopt.needed_rename_limit = saved_nrl; | |
e0c97ca6 | 182 | } |
da31b358 JH |
183 | |
184 | return diff_result_code(&opt->diffopt, 0); | |
9174026c | 185 | } |