Commit | Line | Data |
---|---|---|
5f1c3f07 JH |
1 | #include "cache.h" |
2 | #include "diff.h" | |
3 | #include "commit.h" | |
4 | #include "log-tree.h" | |
5 | ||
91539833 LT |
6 | void show_log(struct rev_info *opt, struct log_info *log, const char *sep) |
7 | { | |
8 | static char this_header[16384]; | |
9 | struct commit *commit = log->commit, *parent = log->parent; | |
10 | int abbrev = opt->diffopt.abbrev; | |
11 | int abbrev_commit = opt->abbrev_commit ? opt->abbrev : 40; | |
a4d34e2d | 12 | const char *extra; |
91539833 | 13 | int len; |
596524b3 | 14 | char* subject = NULL; |
91539833 LT |
15 | |
16 | opt->loginfo = NULL; | |
17 | if (!opt->verbose_header) { | |
18 | puts(sha1_to_hex(commit->object.sha1)); | |
19 | return; | |
20 | } | |
21 | ||
22 | /* | |
a4d34e2d LT |
23 | * The "oneline" format has several special cases: |
24 | * - The pretty-printed commit lacks a newline at the end | |
25 | * of the buffer, but we do want to make sure that we | |
26 | * have a newline there. If the separator isn't already | |
27 | * a newline, add an extra one. | |
28 | * - unlike other log messages, the one-line format does | |
29 | * not have an empty line between entries. | |
91539833 | 30 | */ |
a4d34e2d LT |
31 | extra = ""; |
32 | if (*sep != '\n' && opt->commit_format == CMIT_FMT_ONELINE) | |
33 | extra = "\n"; | |
91539833 LT |
34 | if (opt->shown_one && opt->commit_format != CMIT_FMT_ONELINE) |
35 | putchar('\n'); | |
36 | opt->shown_one = 1; | |
37 | ||
38 | /* | |
39 | * Print header line of header.. | |
40 | */ | |
3eefc189 | 41 | |
596524b3 JS |
42 | if (opt->commit_format == CMIT_FMT_EMAIL) { |
43 | if (opt->total > 0) { | |
44 | static char buffer[64]; | |
45 | snprintf(buffer, sizeof(buffer), | |
46 | "Subject: [PATCH %d/%d] ", | |
47 | opt->nr, opt->total); | |
48 | subject = buffer; | |
8ac80a57 | 49 | } else if (opt->total == 0) |
596524b3 | 50 | subject = "Subject: [PATCH] "; |
8ac80a57 JS |
51 | else |
52 | subject = "Subject: "; | |
53 | ||
3eefc189 JH |
54 | printf("From %s Thu Apr 7 15:13:13 2005\n", |
55 | sha1_to_hex(commit->object.sha1)); | |
596524b3 | 56 | } else { |
3eefc189 JH |
57 | printf("%s%s", |
58 | opt->commit_format == CMIT_FMT_ONELINE ? "" : "commit ", | |
59 | diff_unique_abbrev(commit->object.sha1, abbrev_commit)); | |
60 | if (parent) | |
61 | printf(" (from %s)", | |
62 | diff_unique_abbrev(parent->object.sha1, | |
63 | abbrev_commit)); | |
64 | putchar(opt->commit_format == CMIT_FMT_ONELINE ? ' ' : '\n'); | |
65 | } | |
91539833 LT |
66 | |
67 | /* | |
68 | * And then the pretty-printed message itself | |
69 | */ | |
596524b3 | 70 | len = pretty_print_commit(opt->commit_format, commit, ~0u, this_header, sizeof(this_header), abbrev, subject); |
a4d34e2d | 71 | printf("%s%s%s", this_header, extra, sep); |
91539833 LT |
72 | } |
73 | ||
cd2bdc53 | 74 | int log_tree_diff_flush(struct rev_info *opt) |
5f1c3f07 JH |
75 | { |
76 | diffcore_std(&opt->diffopt); | |
91539833 | 77 | |
5f1c3f07 JH |
78 | if (diff_queue_is_empty()) { |
79 | int saved_fmt = opt->diffopt.output_format; | |
80 | opt->diffopt.output_format = DIFF_FORMAT_NO_OUTPUT; | |
81 | diff_flush(&opt->diffopt); | |
82 | opt->diffopt.output_format = saved_fmt; | |
83 | return 0; | |
84 | } | |
91539833 LT |
85 | |
86 | if (opt->loginfo && !opt->no_commit_id) | |
eab144ac | 87 | show_log(opt, opt->loginfo, opt->diffopt.with_stat ? "---\n" : "\n"); |
5f1c3f07 JH |
88 | diff_flush(&opt->diffopt); |
89 | return 1; | |
90 | } | |
91 | ||
cd2bdc53 | 92 | static int diff_root_tree(struct rev_info *opt, |
5f1c3f07 JH |
93 | const unsigned char *new, const char *base) |
94 | { | |
95 | int retval; | |
96 | void *tree; | |
97 | struct tree_desc empty, real; | |
98 | ||
99 | tree = read_object_with_reference(new, tree_type, &real.size, NULL); | |
100 | if (!tree) | |
101 | die("unable to read root tree (%s)", sha1_to_hex(new)); | |
102 | real.buf = tree; | |
103 | ||
104 | empty.buf = ""; | |
105 | empty.size = 0; | |
106 | retval = diff_tree(&empty, &real, base, &opt->diffopt); | |
107 | free(tree); | |
108 | log_tree_diff_flush(opt); | |
109 | return retval; | |
110 | } | |
111 | ||
cd2bdc53 | 112 | static int do_diff_combined(struct rev_info *opt, struct commit *commit) |
5f1c3f07 JH |
113 | { |
114 | unsigned const char *sha1 = commit->object.sha1; | |
115 | ||
91539833 LT |
116 | diff_tree_combined_merge(sha1, opt->dense_combined_merges, opt); |
117 | return !opt->loginfo; | |
5f1c3f07 JH |
118 | } |
119 | ||
91539833 LT |
120 | /* |
121 | * Show the diff of a commit. | |
122 | * | |
123 | * Return true if we printed any log info messages | |
124 | */ | |
125 | static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log_info *log) | |
5f1c3f07 | 126 | { |
91539833 | 127 | int showed_log; |
5f1c3f07 JH |
128 | struct commit_list *parents; |
129 | unsigned const char *sha1 = commit->object.sha1; | |
130 | ||
91539833 LT |
131 | if (!opt->diff) |
132 | return 0; | |
133 | ||
5f1c3f07 | 134 | /* Root commit? */ |
91539833 LT |
135 | parents = commit->parents; |
136 | if (!parents) { | |
137 | if (opt->show_root_diff) | |
138 | diff_root_tree(opt, sha1, ""); | |
139 | return !opt->loginfo; | |
5f1c3f07 JH |
140 | } |
141 | ||
142 | /* More than one parent? */ | |
91539833 | 143 | if (parents && parents->next) { |
5f1c3f07 JH |
144 | if (opt->ignore_merges) |
145 | return 0; | |
146 | else if (opt->combine_merges) | |
147 | return do_diff_combined(opt, commit); | |
91539833 LT |
148 | |
149 | /* If we show individual diffs, show the parent info */ | |
150 | log->parent = parents->item; | |
5f1c3f07 JH |
151 | } |
152 | ||
91539833 LT |
153 | showed_log = 0; |
154 | for (;;) { | |
5f1c3f07 | 155 | struct commit *parent = parents->item; |
5f1c3f07 | 156 | |
91539833 LT |
157 | diff_tree_sha1(parent->object.sha1, sha1, "", &opt->diffopt); |
158 | log_tree_diff_flush(opt); | |
159 | ||
160 | showed_log |= !opt->loginfo; | |
161 | ||
162 | /* Set up the log info for the next parent, if any.. */ | |
163 | parents = parents->next; | |
164 | if (!parents) | |
165 | break; | |
166 | log->parent = parents->item; | |
167 | opt->loginfo = log; | |
168 | } | |
169 | return showed_log; | |
170 | } | |
171 | ||
172 | int log_tree_commit(struct rev_info *opt, struct commit *commit) | |
173 | { | |
174 | struct log_info log; | |
3eefc189 | 175 | int shown; |
91539833 LT |
176 | |
177 | log.commit = commit; | |
178 | log.parent = NULL; | |
179 | opt->loginfo = &log; | |
180 | ||
3eefc189 JH |
181 | shown = log_tree_diff(opt, commit, &log); |
182 | if (!shown && opt->loginfo && opt->always_show_header) { | |
91539833 LT |
183 | log.parent = NULL; |
184 | show_log(opt, opt->loginfo, ""); | |
3eefc189 | 185 | shown = 1; |
5f1c3f07 | 186 | } |
91539833 | 187 | opt->loginfo = NULL; |
3eefc189 | 188 | return shown; |
5f1c3f07 | 189 | } |