]>
Commit | Line | Data |
---|---|---|
5f1c3f07 JH |
1 | #include "cache.h" |
2 | #include "diff.h" | |
3 | #include "commit.h" | |
4 | #include "log-tree.h" | |
5 | ||
6 | void init_log_tree_opt(struct log_tree_opt *opt) | |
7 | { | |
8 | memset(opt, 0, sizeof *opt); | |
9 | opt->ignore_merges = 1; | |
10 | opt->header_prefix = ""; | |
11 | opt->commit_format = CMIT_FMT_RAW; | |
12 | diff_setup(&opt->diffopt); | |
13 | } | |
14 | ||
15 | int log_tree_opt_parse(struct log_tree_opt *opt, const char **av, int ac) | |
16 | { | |
17 | const char *arg; | |
18 | int cnt = diff_opt_parse(&opt->diffopt, av, ac); | |
19 | if (0 < cnt) | |
20 | return cnt; | |
21 | arg = *av; | |
22 | if (!strcmp(arg, "-r")) | |
23 | opt->diffopt.recursive = 1; | |
24 | else if (!strcmp(arg, "-t")) { | |
25 | opt->diffopt.recursive = 1; | |
26 | opt->diffopt.tree_in_recursive = 1; | |
27 | } | |
28 | else if (!strcmp(arg, "-m")) | |
29 | opt->ignore_merges = 0; | |
30 | else if (!strcmp(arg, "-c")) | |
31 | opt->combine_merges = 1; | |
32 | else if (!strcmp(arg, "--cc")) { | |
33 | opt->dense_combined_merges = 1; | |
34 | opt->combine_merges = 1; | |
35 | } | |
36 | else if (!strcmp(arg, "-v")) { | |
37 | opt->verbose_header = 1; | |
38 | opt->header_prefix = "diff-tree "; | |
39 | } | |
40 | else if (!strncmp(arg, "--pretty", 8)) { | |
41 | opt->verbose_header = 1; | |
42 | opt->header_prefix = "diff-tree "; | |
43 | opt->commit_format = get_commit_format(arg+8); | |
44 | } | |
45 | else if (!strcmp(arg, "--root")) | |
46 | opt->show_root_diff = 1; | |
47 | else if (!strcmp(arg, "--no-commit-id")) | |
48 | opt->no_commit_id = 1; | |
49 | else if (!strcmp(arg, "--always")) | |
50 | opt->always_show_header = 1; | |
51 | else | |
52 | return 0; | |
53 | return 1; | |
54 | } | |
55 | ||
56 | int log_tree_diff_flush(struct log_tree_opt *opt) | |
57 | { | |
58 | diffcore_std(&opt->diffopt); | |
59 | if (diff_queue_is_empty()) { | |
60 | int saved_fmt = opt->diffopt.output_format; | |
61 | opt->diffopt.output_format = DIFF_FORMAT_NO_OUTPUT; | |
62 | diff_flush(&opt->diffopt); | |
63 | opt->diffopt.output_format = saved_fmt; | |
64 | return 0; | |
65 | } | |
66 | if (opt->header) { | |
67 | if (!opt->no_commit_id) | |
68 | printf("%s%c", opt->header, | |
69 | opt->diffopt.line_termination); | |
70 | opt->header = NULL; | |
71 | } | |
72 | diff_flush(&opt->diffopt); | |
73 | return 1; | |
74 | } | |
75 | ||
76 | static int diff_root_tree(struct log_tree_opt *opt, | |
77 | const unsigned char *new, const char *base) | |
78 | { | |
79 | int retval; | |
80 | void *tree; | |
81 | struct tree_desc empty, real; | |
82 | ||
83 | tree = read_object_with_reference(new, tree_type, &real.size, NULL); | |
84 | if (!tree) | |
85 | die("unable to read root tree (%s)", sha1_to_hex(new)); | |
86 | real.buf = tree; | |
87 | ||
88 | empty.buf = ""; | |
89 | empty.size = 0; | |
90 | retval = diff_tree(&empty, &real, base, &opt->diffopt); | |
91 | free(tree); | |
92 | log_tree_diff_flush(opt); | |
93 | return retval; | |
94 | } | |
95 | ||
96 | static const char *generate_header(struct log_tree_opt *opt, | |
97 | const unsigned char *commit_sha1, | |
98 | const unsigned char *parent_sha1, | |
99 | const struct commit *commit) | |
100 | { | |
101 | static char this_header[16384]; | |
102 | int offset; | |
103 | unsigned long len; | |
104 | int abbrev = opt->diffopt.abbrev; | |
105 | const char *msg = commit->buffer; | |
106 | ||
107 | if (!opt->verbose_header) | |
108 | return sha1_to_hex(commit_sha1); | |
109 | ||
110 | len = strlen(msg); | |
111 | ||
112 | offset = sprintf(this_header, "%s%s ", | |
113 | opt->header_prefix, | |
114 | diff_unique_abbrev(commit_sha1, abbrev)); | |
115 | if (commit_sha1 != parent_sha1) | |
116 | offset += sprintf(this_header + offset, "(from %s)\n", | |
117 | parent_sha1 | |
118 | ? diff_unique_abbrev(parent_sha1, abbrev) | |
119 | : "root"); | |
120 | else | |
121 | offset += sprintf(this_header + offset, "(from parents)\n"); | |
122 | offset += pretty_print_commit(opt->commit_format, commit, len, | |
123 | this_header + offset, | |
124 | sizeof(this_header) - offset, abbrev); | |
125 | if (opt->always_show_header) { | |
126 | puts(this_header); | |
127 | return NULL; | |
128 | } | |
129 | return this_header; | |
130 | } | |
131 | ||
132 | static int do_diff_combined(struct log_tree_opt *opt, struct commit *commit) | |
133 | { | |
134 | unsigned const char *sha1 = commit->object.sha1; | |
135 | ||
136 | opt->header = generate_header(opt, sha1, sha1, commit); | |
137 | opt->header = diff_tree_combined_merge(sha1, opt->header, | |
138 | opt->dense_combined_merges, | |
139 | &opt->diffopt); | |
140 | if (!opt->header && opt->verbose_header) | |
141 | opt->header_prefix = "\ndiff-tree "; | |
142 | return 0; | |
143 | } | |
144 | ||
145 | int log_tree_commit(struct log_tree_opt *opt, struct commit *commit) | |
146 | { | |
147 | struct commit_list *parents; | |
148 | unsigned const char *sha1 = commit->object.sha1; | |
149 | ||
150 | /* Root commit? */ | |
151 | if (opt->show_root_diff && !commit->parents) { | |
152 | opt->header = generate_header(opt, sha1, NULL, commit); | |
153 | diff_root_tree(opt, sha1, ""); | |
154 | } | |
155 | ||
156 | /* More than one parent? */ | |
157 | if (commit->parents && commit->parents->next) { | |
158 | if (opt->ignore_merges) | |
159 | return 0; | |
160 | else if (opt->combine_merges) | |
161 | return do_diff_combined(opt, commit); | |
162 | } | |
163 | ||
164 | for (parents = commit->parents; parents; parents = parents->next) { | |
165 | struct commit *parent = parents->item; | |
166 | unsigned const char *psha1 = parent->object.sha1; | |
167 | opt->header = generate_header(opt, sha1, psha1, commit); | |
168 | diff_tree_sha1(psha1, sha1, "", &opt->diffopt); | |
169 | log_tree_diff_flush(opt); | |
170 | ||
171 | if (!opt->header && opt->verbose_header) | |
172 | opt->header_prefix = "\ndiff-tree "; | |
173 | } | |
174 | return 0; | |
175 | } |