🌐 AI搜索 & 代理 主页
blob: 00d5c29bfce18a1d4a5f5d701a593596ccd65783 [file] [log] [blame]
Elijah Newrenbc5c5ec2023-05-16 06:33:571#include "git-compat-util.h"
Patrick Steinhardt8c1bc2a2022-11-17 05:46:562#include "config.h"
Elijah Newren32a8f512023-03-21 06:26:033#include "environment.h"
Elijah Newrenf394e092023-03-21 06:25:544#include "gettext.h"
Elijah Newren41771fa2023-02-24 00:09:275#include "hex.h"
Elijah Newrendabab1d2023-04-11 07:41:496#include "object-name.h"
Elijah Newren87bed172023-04-11 07:41:537#include "object-file.h"
Elijah Newrena034e912023-05-16 06:34:068#include "object-store-ll.h"
Karthik Nayak98309262023-10-27 07:59:299#include "oidset.h"
Linus Torvaldsae563542006-02-26 00:19:4610#include "tag.h"
11#include "blob.h"
12#include "tree.h"
13#include "commit.h"
Linus Torvaldsa4a88b22006-02-28 19:24:0014#include "diff.h"
Sergey Organova37eec62020-12-21 15:19:3315#include "diff-merges.h"
Linus Torvaldsae563542006-02-26 00:19:4616#include "refs.h"
17#include "revision.h"
Stefan Beller23a3f0c2018-04-12 00:21:0918#include "repository.h"
Adam Simpkins7fefda52008-05-04 10:36:5419#include "graph.h"
Junio C Hamano8ecae9b2006-09-17 22:43:4020#include "grep.h"
Johannes Schindelin8860fd42007-01-11 10:47:4821#include "reflog-walk.h"
Junio C Hamanod7a17ca2007-04-09 10:40:3822#include "patch-ids.h"
Junio C Hamanof35f5602008-04-03 09:12:0623#include "decorate.h"
Linus Torvalds78892e32008-11-03 19:25:4624#include "log-tree.h"
Thomas Rast894a9d32010-03-12 17:04:2625#include "string-list.h"
Thomas Rast12da1d12013-03-28 16:47:3226#include "line-log.h"
Antoine Pelissed72fbe82013-01-05 21:26:4527#include "mailmap.h"
Thomas Rast53d00b32013-07-31 20:13:2028#include "commit-slab.h"
Nguyễn Thái Ngọc Duy429bb402014-01-24 13:40:2829#include "dir.h"
Jeff King4fe10212014-10-17 00:44:2330#include "cache-tree.h"
Antoine Delaitecb46d632015-06-29 15:40:3031#include "bisect.h"
Jonathan Tan150e3002017-08-18 22:20:3632#include "packfile.h"
Nguyễn Thái Ngọc Duybe489d02017-08-23 12:36:5233#include "worktree.h"
Elijah Newren08c46a42023-05-16 06:33:5634#include "read-cache.h"
Elijah Newrene38da482023-03-21 06:26:0535#include "setup.h"
Elijah Newrenbaf889c2023-05-16 06:33:5136#include "sparse-index.h"
Jeff Kingdbbcd442020-07-28 20:23:3937#include "strvec.h"
Elijah Newren74ea5c92023-04-11 03:00:3838#include "trace2.h"
Derrick Stolee64043552018-07-20 16:33:0439#include "commit-reach.h"
Derrick Stoleef0d9cc42018-11-01 13:46:2040#include "commit-graph.h"
Derrick Stoleeb4542412018-11-01 13:46:2241#include "prio-queue.h"
Derrick Stoleed5d2e932019-01-16 18:25:5942#include "hashmap.h"
Ævar Arnfjörð Bjarmason44570182019-06-27 23:39:0543#include "utf8.h"
Garima Singha56b9462020-04-06 16:59:5244#include "bloom.h"
Garima Singh42e50e72020-04-06 16:59:5345#include "json-writer.h"
Derrick Stoleec4ea5132022-03-09 16:01:4046#include "list-objects-filter-options.h"
Junio C Hamano5a5ea142022-06-09 23:44:2047#include "resolve-undo.h"
SZEDER Gábor49fd5512023-03-19 16:27:1148#include "parse-options.h"
Elijah Newrendd77d582023-05-16 06:34:0349#include "wildmatch.h"
Linus Torvaldsae563542006-02-26 00:19:4650
Linus Torvaldscdcefbc2007-11-03 18:11:1051volatile show_early_output_fn_t show_early_output;
52
Antoine Delaitecb46d632015-06-29 15:40:3053static const char *term_bad;
54static const char *term_good;
55
Nguyễn Thái Ngọc Duy87be2522018-05-19 05:28:2456implement_shared_commit_slab(revision_sources, char *);
57
SZEDER Gábor3cb9d2b2020-05-11 11:56:1758static inline int want_ancestry(const struct rev_info *revs);
59
Jeff Kingde1e67d2016-02-11 22:28:3660void show_object_with_name(FILE *out, struct object *obj, const char *name)
Linus Torvaldsae563542006-02-26 00:19:4661{
brian m. carlsonf2fd0762015-11-10 02:22:2862 fprintf(out, "%s ", oid_to_hex(&obj->oid));
Junio C Hamano44ba10d2021-11-15 06:27:4563 for (const char *p = name; *p && *p != '\n'; p++)
Jeff Kingf9fb9d02016-02-11 22:24:1864 fputc(*p, out);
Junio C Hamanobeba25a2011-08-17 21:30:3565 fputc('\n', out);
Junio C Hamano91f17512011-08-17 21:30:3466}
67
Linus Torvaldsae563542006-02-26 00:19:4668static void mark_blob_uninteresting(struct blob *blob)
69{
Martin Koeglerc1ee9012008-02-18 20:47:5470 if (!blob)
71 return;
Linus Torvaldsae563542006-02-26 00:19:4672 if (blob->object.flags & UNINTERESTING)
73 return;
74 blob->object.flags |= UNINTERESTING;
75}
76
Nguyễn Thái Ngọc Duyb3c7eef2018-09-21 15:57:3977static void mark_tree_contents_uninteresting(struct repository *r,
78 struct tree *tree)
Linus Torvaldsae563542006-02-26 00:19:4679{
Linus Torvaldsf75e53e2006-05-29 19:20:1480 struct tree_desc desc;
Linus Torvalds4c068a92006-05-30 16:45:4581 struct name_entry entry;
Linus Torvaldsae563542006-02-26 00:19:4682
Jeff Kinga5411df2018-05-11 18:00:5583 if (parse_tree_gently(tree, 1) < 0)
Linus Torvaldsae563542006-02-26 00:19:4684 return;
Linus Torvaldsf75e53e2006-05-29 19:20:1485
Linus Torvalds6fda5e52007-03-21 17:08:2586 init_tree_desc(&desc, tree->buffer, tree->size);
Linus Torvalds4c068a92006-05-30 16:45:4587 while (tree_entry(&desc, &entry)) {
Linus Torvalds4d1012c2007-11-11 23:35:2388 switch (object_type(entry.mode)) {
89 case OBJ_TREE:
brian m. carlsonea82b2a2019-01-15 00:39:4490 mark_tree_uninteresting(r, lookup_tree(r, &entry.oid));
Linus Torvalds4d1012c2007-11-11 23:35:2391 break;
92 case OBJ_BLOB:
brian m. carlsonea82b2a2019-01-15 00:39:4493 mark_blob_uninteresting(lookup_blob(r, &entry.oid));
Linus Torvalds4d1012c2007-11-11 23:35:2394 break;
95 default:
96 /* Subproject commit - not in this repository */
97 break;
98 }
Linus Torvaldsae563542006-02-26 00:19:4699 }
Linus Torvaldsf75e53e2006-05-29 19:20:14100
101 /*
102 * We don't care about the tree any more
103 * after it has been marked uninteresting.
104 */
Jeff King6e454b92013-06-05 22:37:39105 free_tree_buffer(tree);
Linus Torvaldsae563542006-02-26 00:19:46106}
107
Nguyễn Thái Ngọc Duyb3c7eef2018-09-21 15:57:39108void mark_tree_uninteresting(struct repository *r, struct tree *tree)
Junio C Hamano2ac5e442014-01-15 23:38:01109{
Stefan Naewea2678df2015-12-05 15:27:24110 struct object *obj;
Junio C Hamano2ac5e442014-01-15 23:38:01111
112 if (!tree)
113 return;
Stefan Naewea2678df2015-12-05 15:27:24114
115 obj = &tree->object;
Junio C Hamano2ac5e442014-01-15 23:38:01116 if (obj->flags & UNINTERESTING)
117 return;
118 obj->flags |= UNINTERESTING;
Nguyễn Thái Ngọc Duyb3c7eef2018-09-21 15:57:39119 mark_tree_contents_uninteresting(r, tree);
Linus Torvaldsae563542006-02-26 00:19:46120}
121
Derrick Stoleed5d2e932019-01-16 18:25:59122struct path_and_oids_entry {
123 struct hashmap_entry ent;
124 char *path;
125 struct oidset trees;
126};
127
Ævar Arnfjörð Bjarmason5cf88fd2022-08-25 17:09:48128static int path_and_oids_cmp(const void *hashmap_cmp_fn_data UNUSED,
Eric Wong939af162019-10-06 23:30:37129 const struct hashmap_entry *eptr,
130 const struct hashmap_entry *entry_or_key,
Ævar Arnfjörð Bjarmason5cf88fd2022-08-25 17:09:48131 const void *keydata UNUSED)
Derrick Stoleed5d2e932019-01-16 18:25:59132{
Eric Wong939af162019-10-06 23:30:37133 const struct path_and_oids_entry *e1, *e2;
134
135 e1 = container_of(eptr, const struct path_and_oids_entry, ent);
136 e2 = container_of(entry_or_key, const struct path_and_oids_entry, ent);
137
Derrick Stoleed5d2e932019-01-16 18:25:59138 return strcmp(e1->path, e2->path);
139}
140
Derrick Stoleed5d2e932019-01-16 18:25:59141static void paths_and_oids_clear(struct hashmap *map)
142{
143 struct hashmap_iter iter;
144 struct path_and_oids_entry *entry;
Derrick Stoleed5d2e932019-01-16 18:25:59145
Eric Wong23dee692019-10-06 23:30:41146 hashmap_for_each_entry(map, &iter, entry, ent /* member name */) {
Derrick Stoleed5d2e932019-01-16 18:25:59147 oidset_clear(&entry->trees);
148 free(entry->path);
149 }
150
Elijah Newren6da1a252020-11-02 18:55:05151 hashmap_clear_and_free(map, struct path_and_oids_entry, ent);
Derrick Stoleed5d2e932019-01-16 18:25:59152}
153
154static void paths_and_oids_insert(struct hashmap *map,
155 const char *path,
156 const struct object_id *oid)
157{
158 int hash = strhash(path);
159 struct path_and_oids_entry key;
160 struct path_and_oids_entry *entry;
161
Eric Wongd22245a2019-10-06 23:30:27162 hashmap_entry_init(&key.ent, hash);
Derrick Stoleed5d2e932019-01-16 18:25:59163
164 /* use a shallow copy for the lookup */
165 key.path = (char *)path;
166 oidset_init(&key.trees, 0);
167
Eric Wong404ab782019-10-06 23:30:42168 entry = hashmap_get_entry(map, &key, ent, NULL);
Eric Wongb6c52412019-10-06 23:30:30169 if (!entry) {
René Scharfeca56dad2021-03-13 16:17:22170 CALLOC_ARRAY(entry, 1);
Eric Wongd22245a2019-10-06 23:30:27171 hashmap_entry_init(&entry->ent, hash);
Derrick Stoleed5d2e932019-01-16 18:25:59172 entry->path = xstrdup(key.path);
173 oidset_init(&entry->trees, 16);
Eric Wong26b455f2019-10-06 23:30:32174 hashmap_put(map, &entry->ent);
Derrick Stoleed5d2e932019-01-16 18:25:59175 }
176
177 oidset_insert(&entry->trees, oid);
178}
179
180static void add_children_by_path(struct repository *r,
181 struct tree *tree,
182 struct hashmap *map)
183{
184 struct tree_desc desc;
185 struct name_entry entry;
186
187 if (!tree)
188 return;
189
190 if (parse_tree_gently(tree, 1) < 0)
191 return;
192
193 init_tree_desc(&desc, tree->buffer, tree->size);
194 while (tree_entry(&desc, &entry)) {
195 switch (object_type(entry.mode)) {
196 case OBJ_TREE:
Junio C Hamano5fda3432019-02-07 06:05:24197 paths_and_oids_insert(map, entry.path, &entry.oid);
Derrick Stoleed5d2e932019-01-16 18:25:59198
199 if (tree->object.flags & UNINTERESTING) {
Junio C Hamano5fda3432019-02-07 06:05:24200 struct tree *child = lookup_tree(r, &entry.oid);
Derrick Stoleed5d2e932019-01-16 18:25:59201 if (child)
202 child->object.flags |= UNINTERESTING;
203 }
204 break;
205 case OBJ_BLOB:
206 if (tree->object.flags & UNINTERESTING) {
Junio C Hamano5fda3432019-02-07 06:05:24207 struct blob *child = lookup_blob(r, &entry.oid);
Derrick Stoleed5d2e932019-01-16 18:25:59208 if (child)
209 child->object.flags |= UNINTERESTING;
210 }
211 break;
212 default:
213 /* Subproject commit - not in this repository */
214 break;
215 }
216 }
217
218 free_tree_buffer(tree);
219}
220
Derrick Stoleef1f5de42019-01-16 18:25:58221void mark_trees_uninteresting_sparse(struct repository *r,
222 struct oidset *trees)
223{
Derrick Stoleed5d2e932019-01-16 18:25:59224 unsigned has_interesting = 0, has_uninteresting = 0;
Elijah Newrenb19315d2020-11-11 20:02:20225 struct hashmap map = HASHMAP_INIT(path_and_oids_cmp, NULL);
Derrick Stoleed5d2e932019-01-16 18:25:59226 struct hashmap_iter map_iter;
227 struct path_and_oids_entry *entry;
Derrick Stoleef1f5de42019-01-16 18:25:58228 struct object_id *oid;
229 struct oidset_iter iter;
230
231 oidset_iter_init(trees, &iter);
Derrick Stoleed5d2e932019-01-16 18:25:59232 while ((!has_interesting || !has_uninteresting) &&
233 (oid = oidset_iter_next(&iter))) {
Derrick Stoleef1f5de42019-01-16 18:25:58234 struct tree *tree = lookup_tree(r, oid);
235
236 if (!tree)
237 continue;
238
Derrick Stoleed5d2e932019-01-16 18:25:59239 if (tree->object.flags & UNINTERESTING)
240 has_uninteresting = 1;
241 else
242 has_interesting = 1;
Derrick Stoleef1f5de42019-01-16 18:25:58243 }
Derrick Stoleed5d2e932019-01-16 18:25:59244
245 /* Do not walk unless we have both types of trees. */
246 if (!has_uninteresting || !has_interesting)
247 return;
248
Derrick Stoleed5d2e932019-01-16 18:25:59249 oidset_iter_init(trees, &iter);
250 while ((oid = oidset_iter_next(&iter))) {
251 struct tree *tree = lookup_tree(r, oid);
252 add_children_by_path(r, tree, &map);
253 }
254
Eric Wong23dee692019-10-06 23:30:41255 hashmap_for_each_entry(&map, &map_iter, entry, ent /* member name */)
Derrick Stoleed5d2e932019-01-16 18:25:59256 mark_trees_uninteresting_sparse(r, &entry->trees);
257
258 paths_and_oids_clear(&map);
Derrick Stoleef1f5de42019-01-16 18:25:58259}
260
Jeff King43fc6432018-05-11 18:02:27261struct commit_stack {
262 struct commit **items;
263 size_t nr, alloc;
264};
Ævar Arnfjörð Bjarmason9865b6e2021-09-27 12:54:25265#define COMMIT_STACK_INIT { 0 }
Jeff King43fc6432018-05-11 18:02:27266
267static void commit_stack_push(struct commit_stack *stack, struct commit *commit)
268{
269 ALLOC_GROW(stack->items, stack->nr + 1, stack->alloc);
270 stack->items[stack->nr++] = commit;
271}
272
273static struct commit *commit_stack_pop(struct commit_stack *stack)
274{
275 return stack->nr ? stack->items[--stack->nr] : NULL;
276}
277
278static void commit_stack_clear(struct commit_stack *stack)
279{
280 FREE_AND_NULL(stack->items);
281 stack->nr = stack->alloc = 0;
282}
283
Jerry Zhang9d505b72022-01-11 21:39:41284static void mark_one_parent_uninteresting(struct rev_info *revs, struct commit *commit,
Jeff King8702b302018-05-11 18:03:15285 struct commit_stack *pending)
286{
287 struct commit_list *l;
288
289 if (commit->object.flags & UNINTERESTING)
290 return;
291 commit->object.flags |= UNINTERESTING;
292
293 /*
294 * Normally we haven't parsed the parent
295 * yet, so we won't have a parent of a parent
296 * here. However, it may turn out that we've
297 * reached this commit some other way (where it
298 * wasn't uninteresting), in which case we need
299 * to mark its parents recursively too..
300 */
Jerry Zhang9d505b72022-01-11 21:39:41301 for (l = commit->parents; l; l = l->next) {
Jeff King8702b302018-05-11 18:03:15302 commit_stack_push(pending, l->item);
Jerry Zhang9d505b72022-01-11 21:39:41303 if (revs && revs->exclude_first_parent_only)
304 break;
305 }
Jeff King8702b302018-05-11 18:03:15306}
307
Jerry Zhang9d505b72022-01-11 21:39:41308void mark_parents_uninteresting(struct rev_info *revs, struct commit *commit)
Linus Torvaldsae563542006-02-26 00:19:46309{
Jeff King43fc6432018-05-11 18:02:27310 struct commit_stack pending = COMMIT_STACK_INIT;
311 struct commit_list *l;
Nguyễn Thái Ngọc Duy941ba8d2012-01-14 12:19:53312
Jerry Zhang9d505b72022-01-11 21:39:41313 for (l = commit->parents; l; l = l->next) {
314 mark_one_parent_uninteresting(revs, l->item, &pending);
315 if (revs && revs->exclude_first_parent_only)
316 break;
317 }
Linus Torvaldsae563542006-02-26 00:19:46318
Jeff King8702b302018-05-11 18:03:15319 while (pending.nr > 0)
Jerry Zhang9d505b72022-01-11 21:39:41320 mark_one_parent_uninteresting(revs, commit_stack_pop(&pending),
Jeff King8702b302018-05-11 18:03:15321 &pending);
Nguyễn Thái Ngọc Duy941ba8d2012-01-14 12:19:53322
Jeff King43fc6432018-05-11 18:02:27323 commit_stack_clear(&pending);
Linus Torvaldsae563542006-02-26 00:19:46324}
325
Jeff King20739492014-10-15 22:43:19326static void add_pending_object_with_path(struct rev_info *revs,
Michael Haggertyff5f5f22013-05-25 09:08:07327 struct object *obj,
Jeff King20739492014-10-15 22:43:19328 const char *name, unsigned mode,
329 const char *path)
Martin Koeglerbb6c2fb2007-04-22 16:43:59330{
Jonathan Tana4f66a72020-09-01 22:28:07331 struct interpret_branch_name_options options = { 0 };
Junio C Hamanocc243c32011-05-19 01:08:09332 if (!obj)
333 return;
Linus Torvaldsaa27e462007-02-28 00:22:52334 if (revs->no_walk && (obj->flags & UNINTERESTING))
Linus Torvaldsf222abd2009-07-13 21:41:12335 revs->no_walk = 0;
Junio C Hamano105e4732010-01-26 21:48:28336 if (revs->reflog_info && obj->type == OBJ_COMMIT) {
337 struct strbuf buf = STRBUF_INIT;
Jeff King1d72b602021-06-10 13:06:43338 size_t namelen = strlen(name);
��var Arnfjörð Bjarmasond850b7a2023-03-28 13:58:46339 int len = repo_interpret_branch_name(the_repository, name,
340 namelen, &buf, &options);
Junio C Hamano105e4732010-01-26 21:48:28341
Jeff King1d72b602021-06-10 13:06:43342 if (0 < len && len < namelen && buf.len)
Junio C Hamano105e4732010-01-26 21:48:28343 strbuf_addstr(&buf, name + len);
Jeff Kingd08565b2017-07-07 09:14:07344 add_reflog_for_walk(revs->reflog_info,
345 (struct commit *)obj,
346 buf.buf[0] ? buf.buf: name);
Junio C Hamano105e4732010-01-26 21:48:28347 strbuf_release(&buf);
Jeff Kingd08565b2017-07-07 09:14:07348 return; /* do not add the commit itself */
Junio C Hamano105e4732010-01-26 21:48:28349 }
Jeff King20739492014-10-15 22:43:19350 add_object_array_with_path(obj, name, &revs->pending, mode, path);
351}
352
353static void add_pending_object_with_mode(struct rev_info *revs,
354 struct object *obj,
355 const char *name, unsigned mode)
356{
357 add_pending_object_with_path(revs, obj, name, mode, NULL);
Linus Torvaldsae563542006-02-26 00:19:46358}
359
Michael Haggertyff5f5f22013-05-25 09:08:07360void add_pending_object(struct rev_info *revs,
361 struct object *obj, const char *name)
Junio C Hamano2d93b9f2007-06-08 09:24:58362{
363 add_pending_object_with_mode(revs, obj, name, S_IFINVALID);
364}
365
Junio C Hamano3384a2d2007-12-11 18:09:04366void add_head_to_pending(struct rev_info *revs)
367{
brian m. carlson654b9a92017-05-06 22:10:27368 struct object_id oid;
Junio C Hamano3384a2d2007-12-11 18:09:04369 struct object *obj;
Ævar Arnfjörð Bjarmasond850b7a2023-03-28 13:58:46370 if (repo_get_oid(the_repository, "HEAD", &oid))
Junio C Hamano3384a2d2007-12-11 18:09:04371 return;
Nguyễn Thái Ngọc Duyb3c7eef2018-09-21 15:57:39372 obj = parse_object(revs->repo, &oid);
Junio C Hamano3384a2d2007-12-11 18:09:04373 if (!obj)
374 return;
375 add_pending_object(revs, obj, "HEAD");
376}
377
Michael Haggertyff5f5f22013-05-25 09:08:07378static struct object *get_reference(struct rev_info *revs, const char *name,
brian m. carlson654b9a92017-05-06 22:10:27379 const struct object_id *oid,
Michael Haggertyff5f5f22013-05-25 09:08:07380 unsigned int flags)
Linus Torvaldsae563542006-02-26 00:19:46381{
382 struct object *object;
Linus Torvaldsae563542006-02-26 00:19:46383
Jeff King9a8c3c42022-09-06 23:06:25384 object = parse_object_with_flags(revs->repo, oid,
385 revs->verify_objects ? 0 :
386 PARSE_OBJECT_SKIP_HASH_CHECK);
Jonathan Tanec0c5792018-12-04 22:42:38387
Junio C Hamanocc243c32011-05-19 01:08:09388 if (!object) {
389 if (revs->ignore_missing)
390 return object;
Jonathan Tandf11e192017-12-08 15:27:15391 if (revs->exclude_promisor_objects && is_promisor_object(oid))
392 return NULL;
Linus Torvaldsae563542006-02-26 00:19:46393 die("bad object %s", name);
Junio C Hamanocc243c32011-05-19 01:08:09394 }
Linus Torvaldscd2bdc52006-04-14 23:52:13395 object->flags |= flags;
396 return object;
397}
398
brian m. carlsona58a1b02017-05-06 22:10:26399void add_pending_oid(struct rev_info *revs, const char *name,
400 const struct object_id *oid, unsigned int flags)
René Scharfe26c31772011-10-01 15:43:52401{
brian m. carlson654b9a92017-05-06 22:10:27402 struct object *object = get_reference(revs, name, oid, flags);
René Scharfe26c31772011-10-01 15:43:52403 add_pending_object(revs, object, name);
404}
405
Michael Haggertyff5f5f22013-05-25 09:08:07406static struct commit *handle_commit(struct rev_info *revs,
Jeff King20739492014-10-15 22:43:19407 struct object_array_entry *entry)
Linus Torvaldscd2bdc52006-04-14 23:52:13408{
Jeff King20739492014-10-15 22:43:19409 struct object *object = entry->item;
410 const char *name = entry->name;
411 const char *path = entry->path;
412 unsigned int mode = entry->mode;
Linus Torvaldscd2bdc52006-04-14 23:52:13413 unsigned long flags = object->flags;
Linus Torvaldsae563542006-02-26 00:19:46414
415 /*
416 * Tag object? Look what it points to..
417 */
Linus Torvalds19746322006-07-12 03:45:31418 while (object->type == OBJ_TAG) {
Linus Torvaldsae563542006-02-26 00:19:46419 struct tag *tag = (struct tag *) object;
Linus Torvaldscd2bdc52006-04-14 23:52:13420 if (revs->tag_objects && !(flags & UNINTERESTING))
Linus Torvaldsae563542006-02-26 00:19:46421 add_pending_object(revs, object, tag->tag);
René Scharfedad3f062019-09-05 19:55:55422 object = parse_object(revs->repo, get_tagged_oid(tag));
Junio C Hamanoaeeae1b2009-01-28 07:19:30423 if (!object) {
Jeff Kinga3ba6bf2017-05-20 08:30:25424 if (revs->ignore_missing_links || (flags & UNINTERESTING))
Junio C Hamanoaeeae1b2009-01-28 07:19:30425 return NULL;
Jonathan Tandc0a13f2018-07-13 00:03:06426 if (revs->exclude_promisor_objects &&
427 is_promisor_object(&tag->tagged->oid))
428 return NULL;
brian m. carlsonf2fd0762015-11-10 02:22:28429 die("bad object %s", oid_to_hex(&tag->tagged->oid));
Junio C Hamanoaeeae1b2009-01-28 07:19:30430 }
Junio C Hamanoa7435282014-01-15 20:26:13431 object->flags |= flags;
Jeff King20739492014-10-15 22:43:19432 /*
433 * We'll handle the tagged object by looping or dropping
434 * through to the non-tag handlers below. Do not
Jeff King728350b2015-12-17 06:47:07435 * propagate path data from the tag's pending entry.
Jeff King20739492014-10-15 22:43:19436 */
Jeff King20739492014-10-15 22:43:19437 path = NULL;
438 mode = 0;
Linus Torvaldsae563542006-02-26 00:19:46439 }
440
441 /*
442 * Commit object? Just return it, we'll do all the complex
443 * reachability crud.
444 */
Linus Torvalds19746322006-07-12 03:45:31445 if (object->type == OBJ_COMMIT) {
Linus Torvaldsae563542006-02-26 00:19:46446 struct commit *commit = (struct commit *)object;
Nguyễn Thái Ngọc Duy87be2522018-05-19 05:28:24447
Michael Forneyea3f7e52020-06-23 20:56:58448 if (repo_parse_commit(revs->repo, commit) < 0)
Linus Torvaldsae563542006-02-26 00:19:46449 die("unable to parse commit %s", name);
Linus Torvaldsd9a83682006-02-27 16:54:36450 if (flags & UNINTERESTING) {
Jerry Zhang9d505b72022-01-11 21:39:41451 mark_parents_uninteresting(revs, commit);
Derrick Stolee1b4d8822019-05-21 13:14:38452
453 if (!revs->topo_order || !generation_numbers_enabled(the_repository))
454 revs->limited = 1;
Linus Torvaldsd9a83682006-02-27 16:54:36455 }
Nguyễn Thái Ngọc Duy87be2522018-05-19 05:28:24456 if (revs->sources) {
457 char **slot = revision_sources_at(revs->sources, commit);
458
459 if (!*slot)
460 *slot = xstrdup(name);
461 }
Linus Torvaldsae563542006-02-26 00:19:46462 return commit;
463 }
464
465 /*
Mike Ralphson3ea3c212009-04-17 18:13:30466 * Tree object? Either mark it uninteresting, or add it
Linus Torvaldsae563542006-02-26 00:19:46467 * to the list of objects to look at later..
468 */
Linus Torvalds19746322006-07-12 03:45:31469 if (object->type == OBJ_TREE) {
Linus Torvaldsae563542006-02-26 00:19:46470 struct tree *tree = (struct tree *)object;
471 if (!revs->tree_objects)
472 return NULL;
473 if (flags & UNINTERESTING) {
Nguyễn Thái Ngọc Duyb3c7eef2018-09-21 15:57:39474 mark_tree_contents_uninteresting(revs->repo, tree);
Linus Torvaldsae563542006-02-26 00:19:46475 return NULL;
476 }
Jeff King20739492014-10-15 22:43:19477 add_pending_object_with_path(revs, object, name, mode, path);
Linus Torvaldsae563542006-02-26 00:19:46478 return NULL;
479 }
480
481 /*
482 * Blob object? You know the drill by now..
483 */
Linus Torvalds19746322006-07-12 03:45:31484 if (object->type == OBJ_BLOB) {
Linus Torvaldsae563542006-02-26 00:19:46485 if (!revs->blob_objects)
486 return NULL;
Junio C Hamanoa7435282014-01-15 20:26:13487 if (flags & UNINTERESTING)
Linus Torvaldsae563542006-02-26 00:19:46488 return NULL;
Jeff King20739492014-10-15 22:43:19489 add_pending_object_with_path(revs, object, name, mode, path);
Linus Torvaldsae563542006-02-26 00:19:46490 return NULL;
491 }
492 die("%s is unknown object", name);
493}
494
Jeff Kingb6e8a3b2015-04-17 22:11:04495static int everybody_uninteresting(struct commit_list *orig,
496 struct commit **interesting_cache)
Linus Torvaldsa4a88b22006-02-28 19:24:00497{
498 struct commit_list *list = orig;
Jeff Kingb6e8a3b2015-04-17 22:11:04499
500 if (*interesting_cache) {
501 struct commit *commit = *interesting_cache;
502 if (!(commit->object.flags & UNINTERESTING))
503 return 0;
504 }
505
Linus Torvaldsa4a88b22006-02-28 19:24:00506 while (list) {
507 struct commit *commit = list->item;
508 list = list->next;
509 if (commit->object.flags & UNINTERESTING)
510 continue;
Stefan Bellerae40ebd2015-06-26 19:40:19511
512 *interesting_cache = commit;
Linus Torvaldsa4a88b22006-02-28 19:24:00513 return 0;
514 }
515 return 1;
516}
517
Junio C Hamano0a4ba7f2007-03-14 20:12:18518/*
Kevin Bracey4d826602013-05-16 15:32:39519 * A definition of "relevant" commit that we can use to simplify limited graphs
520 * by eliminating side branches.
521 *
522 * A "relevant" commit is one that is !UNINTERESTING (ie we are including it
523 * in our list), or that is a specified BOTTOM commit. Then after computing
524 * a limited list, during processing we can generally ignore boundary merges
525 * coming from outside the graph, (ie from irrelevant parents), and treat
526 * those merges as if they were single-parent. TREESAME is defined to consider
527 * only relevant parents, if any. If we are TREESAME to our on-graph parents,
528 * we don't care if we were !TREESAME to non-graph parents.
529 *
530 * Treating bottom commits as relevant ensures that a limited graph's
531 * connection to the actual bottom commit is not viewed as a side branch, but
532 * treated as part of the graph. For example:
533 *
534 * ....Z...A---X---o---o---B
535 * . /
536 * W---Y
537 *
538 * When computing "A..B", the A-X connection is at least as important as
539 * Y-X, despite A being flagged UNINTERESTING.
540 *
541 * And when computing --ancestry-path "A..B", the A-X connection is more
542 * important than Y-X, despite both A and Y being flagged UNINTERESTING.
543 */
544static inline int relevant_commit(struct commit *commit)
545{
546 return (commit->object.flags & (UNINTERESTING | BOTTOM)) != UNINTERESTING;
547}
548
549/*
550 * Return a single relevant commit from a parent list. If we are a TREESAME
551 * commit, and this selects one of our parents, then we can safely simplify to
552 * that parent.
553 */
554static struct commit *one_relevant_parent(const struct rev_info *revs,
555 struct commit_list *orig)
556{
557 struct commit_list *list = orig;
558 struct commit *relevant = NULL;
559
560 if (!orig)
561 return NULL;
562
563 /*
564 * For 1-parent commits, or if first-parent-only, then return that
565 * first parent (even if not "relevant" by the above definition).
566 * TREESAME will have been set purely on that parent.
567 */
568 if (revs->first_parent_only || !orig->next)
569 return orig->item;
570
571 /*
572 * For multi-parent commits, identify a sole relevant parent, if any.
573 * If we have only one relevant parent, then TREESAME will be set purely
574 * with regard to that parent, and we can simplify accordingly.
575 *
576 * If we have more than one relevant parent, or no relevant parents
577 * (and multiple irrelevant ones), then we can't select a parent here
578 * and return NULL.
579 */
580 while (list) {
581 struct commit *commit = list->item;
582 list = list->next;
583 if (relevant_commit(commit)) {
584 if (relevant)
585 return NULL;
586 relevant = commit;
587 }
588 }
589 return relevant;
590}
591
592/*
Junio C Hamano0a4ba7f2007-03-14 20:12:18593 * The goal is to get REV_TREE_NEW as the result only if the
Linus Torvaldsceff8e72009-06-03 01:34:01594 * diff consists of all '+' (and no other changes), REV_TREE_OLD
595 * if the whole diff is removal of old data, and otherwise
596 * REV_TREE_DIFFERENT (of course if the trees are the same we
597 * want REV_TREE_SAME).
Jeff Kinga937b372017-10-13 15:27:45598 *
599 * The only time we care about the distinction is when
600 * remove_empty_trees is in effect, in which case we care only about
601 * whether the whole change is REV_TREE_NEW, or if there's another type
602 * of change. Which means we can stop the diff early in either of these
603 * cases:
604 *
605 * 1. We're not using remove_empty_trees at all.
606 *
607 * 2. We saw anything except REV_TREE_NEW.
Junio C Hamano0a4ba7f2007-03-14 20:12:18608 */
Ævar Arnfjörð Bjarmason296a1432022-04-13 20:01:37609#define REV_TREE_SAME 0
610#define REV_TREE_NEW 1 /* Only new files */
611#define REV_TREE_OLD 2 /* Only files removed */
612#define REV_TREE_DIFFERENT 3 /* Mixed changes */
Fredrik Kuivinen8efdc322006-03-10 09:21:39613static int tree_difference = REV_TREE_SAME;
Linus Torvaldsa4a88b22006-02-28 19:24:00614
615static void file_add_remove(struct diff_options *options,
Jeff King61bdc7c2022-12-13 11:13:48616 int addremove,
617 unsigned mode UNUSED,
618 const struct object_id *oid UNUSED,
619 int oid_valid UNUSED,
620 const char *fullpath UNUSED,
621 unsigned dirty_submodule UNUSED)
Linus Torvaldsa4a88b22006-02-28 19:24:00622{
Linus Torvaldsceff8e72009-06-03 01:34:01623 int diff = addremove == '+' ? REV_TREE_NEW : REV_TREE_OLD;
Jeff Kinga937b372017-10-13 15:27:45624 struct rev_info *revs = options->change_fn_data;
Linus Torvaldsa4a88b22006-02-28 19:24:00625
Linus Torvaldsceff8e72009-06-03 01:34:01626 tree_difference |= diff;
Jeff Kinga937b372017-10-13 15:27:45627 if (!revs->remove_empty_trees || tree_difference != REV_TREE_NEW)
Brandon Williams0d1e0e72017-10-31 18:19:11628 options->flags.has_changes = 1;
Linus Torvaldsa4a88b22006-02-28 19:24:00629}
630
631static void file_change(struct diff_options *options,
Jeff King61bdc7c2022-12-13 11:13:48632 unsigned old_mode UNUSED,
633 unsigned new_mode UNUSED,
634 const struct object_id *old_oid UNUSED,
635 const struct object_id *new_oid UNUSED,
636 int old_oid_valid UNUSED,
637 int new_oid_valid UNUSED,
638 const char *fullpath UNUSED,
639 unsigned old_dirty_submodule UNUSED,
640 unsigned new_dirty_submodule UNUSED)
Linus Torvaldsa4a88b22006-02-28 19:24:00641{
Fredrik Kuivinen8efdc322006-03-10 09:21:39642 tree_difference = REV_TREE_DIFFERENT;
Brandon Williams0d1e0e72017-10-31 18:19:11643 options->flags.has_changes = 1;
Linus Torvaldsa4a88b22006-02-28 19:24:00644}
645
Garima Singh42e50e72020-04-06 16:59:53646static int bloom_filter_atexit_registered;
647static unsigned int count_bloom_filter_maybe;
648static unsigned int count_bloom_filter_definitely_not;
649static unsigned int count_bloom_filter_false_positive;
650static unsigned int count_bloom_filter_not_present;
Garima Singh42e50e72020-04-06 16:59:53651
652static void trace2_bloom_filter_statistics_atexit(void)
653{
654 struct json_writer jw = JSON_WRITER_INIT;
655
656 jw_object_begin(&jw, 0);
657 jw_object_intmax(&jw, "filter_not_present", count_bloom_filter_not_present);
Garima Singh42e50e72020-04-06 16:59:53658 jw_object_intmax(&jw, "maybe", count_bloom_filter_maybe);
659 jw_object_intmax(&jw, "definitely_not", count_bloom_filter_definitely_not);
660 jw_object_intmax(&jw, "false_positive", count_bloom_filter_false_positive);
661 jw_end(&jw);
662
663 trace2_data_json("bloom", the_repository, "statistics", &jw);
664
665 jw_release(&jw);
666}
667
Derrick Stolee8918e372020-04-16 20:14:02668static int forbid_bloom_filters(struct pathspec *spec)
669{
670 if (spec->has_wildcard)
671 return 1;
672 if (spec->nr > 1)
673 return 1;
674 if (spec->magic & ~PATHSPEC_LITERAL)
675 return 1;
676 if (spec->nr && (spec->items[0].magic & ~PATHSPEC_LITERAL))
677 return 1;
678
679 return 0;
680}
681
Garima Singha56b9462020-04-06 16:59:52682static void prepare_to_use_bloom_filter(struct rev_info *revs)
683{
684 struct pathspec_item *pi;
685 char *path_alloc = NULL;
SZEDER Gáborc525ce92020-07-01 13:27:30686 const char *path, *p;
SZEDER Gáborc525ce92020-07-01 13:27:30687 size_t len;
688 int path_component_nr = 1;
Garima Singha56b9462020-04-06 16:59:52689
690 if (!revs->commits)
Derrick Stolee8918e372020-04-16 20:14:02691 return;
692
693 if (forbid_bloom_filters(&revs->prune_data))
694 return;
Garima Singha56b9462020-04-06 16:59:52695
696 repo_parse_commit(revs->repo, revs->commits->item);
697
Taylor Blau4f364402020-09-09 15:22:44698 revs->bloom_filter_settings = get_bloom_filter_settings(revs->repo);
Garima Singha56b9462020-04-06 16:59:52699 if (!revs->bloom_filter_settings)
700 return;
701
Derrick Stoleef32dde82020-05-11 11:56:19702 if (!revs->pruning.pathspec.nr)
703 return;
704
Garima Singha56b9462020-04-06 16:59:52705 pi = &revs->pruning.pathspec.items[0];
Garima Singha56b9462020-04-06 16:59:52706
707 /* remove single trailing slash from path, if needed */
Jeff Kingfd9a6312020-08-04 07:46:52708 if (pi->len > 0 && pi->match[pi->len - 1] == '/') {
709 path_alloc = xmemdupz(pi->match, pi->len - 1);
Derrick Stoleedc8e95b2020-07-01 13:27:28710 path = path_alloc;
Garima Singha56b9462020-04-06 16:59:52711 } else
Derrick Stoleedc8e95b2020-07-01 13:27:28712 path = pi->match;
Garima Singha56b9462020-04-06 16:59:52713
714 len = strlen(path);
Taylor Blauf3c2a362020-07-01 13:27:29715 if (!len) {
716 revs->bloom_filter_settings = NULL;
Jeff King398e6592020-08-04 07:50:17717 free(path_alloc);
Taylor Blauf3c2a362020-07-01 13:27:29718 return;
719 }
Garima Singha56b9462020-04-06 16:59:52720
SZEDER Gáborc525ce92020-07-01 13:27:30721 p = path;
722 while (*p) {
723 /*
724 * At this point, the path is normalized to use Unix-style
725 * path separators. This is required due to how the
726 * changed-path Bloom filters store the paths.
727 */
728 if (*p == '/')
729 path_component_nr++;
730 p++;
731 }
732
733 revs->bloom_keys_nr = path_component_nr;
734 ALLOC_ARRAY(revs->bloom_keys, revs->bloom_keys_nr);
735
736 fill_bloom_key(path, len, &revs->bloom_keys[0],
737 revs->bloom_filter_settings);
738 path_component_nr = 1;
739
740 p = path + len - 1;
741 while (p > path) {
742 if (*p == '/')
743 fill_bloom_key(path, p - path,
744 &revs->bloom_keys[path_component_nr++],
745 revs->bloom_filter_settings);
746 p--;
747 }
Garima Singha56b9462020-04-06 16:59:52748
Garima Singh42e50e72020-04-06 16:59:53749 if (trace2_is_enabled() && !bloom_filter_atexit_registered) {
750 atexit(trace2_bloom_filter_statistics_atexit);
751 bloom_filter_atexit_registered = 1;
752 }
753
Garima Singha56b9462020-04-06 16:59:52754 free(path_alloc);
755}
756
757static int check_maybe_different_in_bloom_filter(struct rev_info *revs,
758 struct commit *commit)
759{
760 struct bloom_filter *filter;
SZEDER Gáborc525ce92020-07-01 13:27:30761 int result = 1, j;
Garima Singha56b9462020-04-06 16:59:52762
763 if (!revs->repo->objects->commit_graph)
764 return -1;
765
Abhishek Kumarc49c82a2020-06-17 09:14:10766 if (commit_graph_generation(commit) == GENERATION_NUMBER_INFINITY)
Garima Singha56b9462020-04-06 16:59:52767 return -1;
768
Taylor Blau312cff52020-09-16 18:07:32769 filter = get_bloom_filter(revs->repo, commit);
Garima Singha56b9462020-04-06 16:59:52770
771 if (!filter) {
Garima Singh42e50e72020-04-06 16:59:53772 count_bloom_filter_not_present++;
Garima Singha56b9462020-04-06 16:59:52773 return -1;
774 }
775
SZEDER Gáborc525ce92020-07-01 13:27:30776 for (j = 0; result && j < revs->bloom_keys_nr; j++) {
777 result = bloom_filter_contains(filter,
778 &revs->bloom_keys[j],
779 revs->bloom_filter_settings);
Garima Singha56b9462020-04-06 16:59:52780 }
781
Garima Singh42e50e72020-04-06 16:59:53782 if (result)
783 count_bloom_filter_maybe++;
784 else
785 count_bloom_filter_definitely_not++;
786
Garima Singha56b9462020-04-06 16:59:52787 return result;
788}
789
Michael Haggertyff5f5f22013-05-25 09:08:07790static int rev_compare_tree(struct rev_info *revs,
Garima Singha56b9462020-04-06 16:59:52791 struct commit *parent, struct commit *commit, int nth_parent)
Linus Torvaldsa4a88b22006-02-28 19:24:00792{
Ævar Arnfjörð Bjarmasonecb50912023-03-28 13:58:48793 struct tree *t1 = repo_get_commit_tree(the_repository, parent);
794 struct tree *t2 = repo_get_commit_tree(the_repository, commit);
Garima Singha56b9462020-04-06 16:59:52795 int bloom_ret = 1;
Linus Torvalds3a5e8602008-11-03 18:45:41796
Linus Torvaldsa4a88b22006-02-28 19:24:00797 if (!t1)
Fredrik Kuivinen8efdc322006-03-10 09:21:39798 return REV_TREE_NEW;
Linus Torvaldsceff8e72009-06-03 01:34:01799 if (!t2)
800 return REV_TREE_OLD;
Linus Torvalds78892e32008-11-03 19:25:46801
802 if (revs->simplify_by_decoration) {
803 /*
804 * If we are simplifying by decoration, then the commit
805 * is worth showing if it has a tag pointing at it.
806 */
Jeff King2608c242014-08-26 10:23:54807 if (get_name_decoration(&commit->object))
Linus Torvalds78892e32008-11-03 19:25:46808 return REV_TREE_DIFFERENT;
809 /*
810 * A commit that is not pointed by a tag is uninteresting
811 * if we are not limited by path. This means that you will
812 * see the usual "commits that touch the paths" plus any
813 * tagged commit by specifying both --simplify-by-decoration
814 * and pathspec.
815 */
Nguyễn Thái Ngọc Duyafe069d2010-12-17 12:43:06816 if (!revs->prune_data.nr)
Linus Torvalds78892e32008-11-03 19:25:46817 return REV_TREE_SAME;
818 }
Linus Torvaldsceff8e72009-06-03 01:34:01819
SZEDER Gáborc525ce92020-07-01 13:27:30820 if (revs->bloom_keys_nr && !nth_parent) {
Garima Singha56b9462020-04-06 16:59:52821 bloom_ret = check_maybe_different_in_bloom_filter(revs, commit);
822
823 if (bloom_ret == 0)
824 return REV_TREE_SAME;
825 }
826
Fredrik Kuivinen8efdc322006-03-10 09:21:39827 tree_difference = REV_TREE_SAME;
Brandon Williams0d1e0e72017-10-31 18:19:11828 revs->pruning.flags.has_changes = 0;
SZEDER Gábor0ee3cb82020-06-05 13:00:27829 diff_tree_oid(&t1->object.oid, &t2->object.oid, "", &revs->pruning);
Garima Singha56b9462020-04-06 16:59:52830
Garima Singh42e50e72020-04-06 16:59:53831 if (!nth_parent)
832 if (bloom_ret == 1 && tree_difference == REV_TREE_SAME)
833 count_bloom_filter_false_positive++;
834
Linus Torvaldsa4a88b22006-02-28 19:24:00835 return tree_difference;
836}
837
Linus Torvalds3a5e8602008-11-03 18:45:41838static int rev_same_tree_as_empty(struct rev_info *revs, struct commit *commit)
Linus Torvaldsa4a88b22006-02-28 19:24:00839{
Ævar Arnfjörð Bjarmasonecb50912023-03-28 13:58:48840 struct tree *t1 = repo_get_commit_tree(the_repository, commit);
Linus Torvaldsa4a88b22006-02-28 19:24:00841
842 if (!t1)
843 return 0;
844
Junio C Hamano0a4ba7f2007-03-14 20:12:18845 tree_difference = REV_TREE_SAME;
Brandon Williams0d1e0e72017-10-31 18:19:11846 revs->pruning.flags.has_changes = 0;
SZEDER Gábor0ee3cb82020-06-05 13:00:27847 diff_tree_oid(NULL, &t1->object.oid, "", &revs->pruning);
Linus Torvaldsa4a88b22006-02-28 19:24:00848
SZEDER Gábor0ee3cb82020-06-05 13:00:27849 return tree_difference == REV_TREE_SAME;
Linus Torvaldsa4a88b22006-02-28 19:24:00850}
851
Kevin Braceyd0af6632013-05-16 15:32:34852struct treesame_state {
853 unsigned int nparents;
854 unsigned char treesame[FLEX_ARRAY];
855};
856
857static struct treesame_state *initialise_treesame(struct rev_info *revs, struct commit *commit)
858{
859 unsigned n = commit_list_count(commit->parents);
Jeff King50a6c8e2016-02-22 22:44:35860 struct treesame_state *st = xcalloc(1, st_add(sizeof(*st), n));
Kevin Braceyd0af6632013-05-16 15:32:34861 st->nparents = n;
862 add_decoration(&revs->treesame, &commit->object, st);
863 return st;
864}
865
866/*
867 * Must be called immediately after removing the nth_parent from a commit's
868 * parent list, if we are maintaining the per-parent treesame[] decoration.
869 * This does not recalculate the master TREESAME flag - update_treesame()
870 * should be called to update it after a sequence of treesame[] modifications
871 * that may have affected it.
872 */
873static int compact_treesame(struct rev_info *revs, struct commit *commit, unsigned nth_parent)
874{
875 struct treesame_state *st;
876 int old_same;
877
878 if (!commit->parents) {
879 /*
880 * Have just removed the only parent from a non-merge.
881 * Different handling, as we lack decoration.
882 */
883 if (nth_parent != 0)
884 die("compact_treesame %u", nth_parent);
885 old_same = !!(commit->object.flags & TREESAME);
886 if (rev_same_tree_as_empty(revs, commit))
887 commit->object.flags |= TREESAME;
888 else
889 commit->object.flags &= ~TREESAME;
890 return old_same;
891 }
892
893 st = lookup_decoration(&revs->treesame, &commit->object);
894 if (!st || nth_parent >= st->nparents)
895 die("compact_treesame %u", nth_parent);
896
897 old_same = st->treesame[nth_parent];
898 memmove(st->treesame + nth_parent,
899 st->treesame + nth_parent + 1,
900 st->nparents - nth_parent - 1);
901
902 /*
903 * If we've just become a non-merge commit, update TREESAME
904 * immediately, and remove the no-longer-needed decoration.
905 * If still a merge, defer update until update_treesame().
906 */
907 if (--st->nparents == 1) {
908 if (commit->parents->next)
909 die("compact_treesame parents mismatch");
910 if (st->treesame[0] && revs->dense)
911 commit->object.flags |= TREESAME;
912 else
913 commit->object.flags &= ~TREESAME;
914 free(add_decoration(&revs->treesame, &commit->object, NULL));
915 }
916
917 return old_same;
918}
919
920static unsigned update_treesame(struct rev_info *revs, struct commit *commit)
921{
922 if (commit->parents && commit->parents->next) {
923 unsigned n;
924 struct treesame_state *st;
Kevin Bracey4d826602013-05-16 15:32:39925 struct commit_list *p;
926 unsigned relevant_parents;
927 unsigned relevant_change, irrelevant_change;
Kevin Braceyd0af6632013-05-16 15:32:34928
929 st = lookup_decoration(&revs->treesame, &commit->object);
930 if (!st)
brian m. carlsonf2fd0762015-11-10 02:22:28931 die("update_treesame %s", oid_to_hex(&commit->object.oid));
Kevin Bracey4d826602013-05-16 15:32:39932 relevant_parents = 0;
933 relevant_change = irrelevant_change = 0;
934 for (p = commit->parents, n = 0; p; n++, p = p->next) {
935 if (relevant_commit(p->item)) {
936 relevant_change |= !st->treesame[n];
937 relevant_parents++;
938 } else
939 irrelevant_change |= !st->treesame[n];
Kevin Braceyd0af6632013-05-16 15:32:34940 }
Kevin Bracey4d826602013-05-16 15:32:39941 if (relevant_parents ? relevant_change : irrelevant_change)
942 commit->object.flags &= ~TREESAME;
943 else
944 commit->object.flags |= TREESAME;
Kevin Braceyd0af6632013-05-16 15:32:34945 }
946
947 return commit->object.flags & TREESAME;
948}
949
Kevin Bracey4d826602013-05-16 15:32:39950static inline int limiting_can_increase_treesame(const struct rev_info *revs)
951{
952 /*
953 * TREESAME is irrelevant unless prune && dense;
954 * if simplify_history is set, we can't have a mixture of TREESAME and
955 * !TREESAME INTERESTING parents (and we don't have treesame[]
956 * decoration anyway);
957 * if first_parent_only is set, then the TREESAME flag is locked
958 * against the first parent (and again we lack treesame[] decoration).
959 */
960 return revs->prune && revs->dense &&
961 !revs->simplify_history &&
962 !revs->first_parent_only;
963}
964
Linus Torvaldsa4a88b22006-02-28 19:24:00965static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit)
966{
967 struct commit_list **pp, *parent;
Kevin Braceyd0af6632013-05-16 15:32:34968 struct treesame_state *ts = NULL;
Kevin Bracey4d826602013-05-16 15:32:39969 int relevant_change = 0, irrelevant_change = 0;
970 int relevant_parents, nth_parent;
Linus Torvaldsa4a88b22006-02-28 19:24:00971
Linus Torvalds53b2c822007-11-05 21:22:34972 /*
973 * If we don't do pruning, everything is interesting
974 */
Linus Torvalds7dc0fe32007-11-13 07:16:08975 if (!revs->prune)
Linus Torvalds53b2c822007-11-05 21:22:34976 return;
Linus Torvalds53b2c822007-11-05 21:22:34977
Ævar Arnfjörð Bjarmasonecb50912023-03-28 13:58:48978 if (!repo_get_commit_tree(the_repository, commit))
Linus Torvaldsa4a88b22006-02-28 19:24:00979 return;
980
981 if (!commit->parents) {
Linus Torvalds3a5e8602008-11-03 18:45:41982 if (rev_same_tree_as_empty(revs, commit))
Linus Torvalds7dc0fe32007-11-13 07:16:08983 commit->object.flags |= TREESAME;
Linus Torvaldsa4a88b22006-02-28 19:24:00984 return;
985 }
986
Linus Torvalds53b2c822007-11-05 21:22:34987 /*
988 * Normal non-merge commit? If we don't want to make the
989 * history dense, we consider it always to be a change..
990 */
Linus Torvalds7dc0fe32007-11-13 07:16:08991 if (!revs->dense && !commit->parents->next)
Linus Torvalds53b2c822007-11-05 21:22:34992 return;
Linus Torvalds53b2c822007-11-05 21:22:34993
Kevin Bracey4d826602013-05-16 15:32:39994 for (pp = &commit->parents, nth_parent = 0, relevant_parents = 0;
Kevin Braceyd0af6632013-05-16 15:32:34995 (parent = *pp) != NULL;
996 pp = &parent->next, nth_parent++) {
Linus Torvaldsa4a88b22006-02-28 19:24:00997 struct commit *p = parent->item;
Kevin Bracey4d826602013-05-16 15:32:39998 if (relevant_commit(p))
999 relevant_parents++;
Linus Torvaldsa4a88b22006-02-28 19:24:001000
Kevin Braceyd0af6632013-05-16 15:32:341001 if (nth_parent == 1) {
1002 /*
1003 * This our second loop iteration - so we now know
1004 * we're dealing with a merge.
1005 *
1006 * Do not compare with later parents when we care only about
1007 * the first parent chain, in order to avoid derailing the
1008 * traversal to follow a side branch that brought everything
1009 * in the path we are limited to by the pathspec.
1010 */
1011 if (revs->first_parent_only)
1012 break;
1013 /*
1014 * If this will remain a potentially-simplifiable
1015 * merge, remember per-parent treesame if needed.
1016 * Initialise the array with the comparison from our
1017 * first iteration.
1018 */
1019 if (revs->treesame.name &&
1020 !revs->simplify_history &&
1021 !(commit->object.flags & UNINTERESTING)) {
1022 ts = initialise_treesame(revs, commit);
Kevin Bracey4d826602013-05-16 15:32:391023 if (!(irrelevant_change || relevant_change))
Kevin Braceyd0af6632013-05-16 15:32:341024 ts->treesame[0] = 1;
1025 }
1026 }
Michael Forneyea3f7e52020-06-23 20:56:581027 if (repo_parse_commit(revs->repo, p) < 0)
Alex Riesencc0e6c52007-05-04 21:54:571028 die("cannot simplify commit %s (because of %s)",
brian m. carlsonf2fd0762015-11-10 02:22:281029 oid_to_hex(&commit->object.oid),
1030 oid_to_hex(&p->object.oid));
Garima Singha56b9462020-04-06 16:59:521031 switch (rev_compare_tree(revs, p, commit, nth_parent)) {
Fredrik Kuivinen8efdc322006-03-10 09:21:391032 case REV_TREE_SAME:
Kevin Bracey141efdb2013-05-16 15:32:411033 if (!revs->simplify_history || !relevant_commit(p)) {
Junio C Hamanof3219fb2006-03-11 05:59:371034 /* Even if a merge with an uninteresting
1035 * side branch brought the entire change
1036 * we are interested in, we do not want
1037 * to lose the other branches of this
1038 * merge, so we just keep going.
1039 */
Kevin Braceyd0af6632013-05-16 15:32:341040 if (ts)
1041 ts->treesame[nth_parent] = 1;
Junio C Hamanof3219fb2006-03-11 05:59:371042 continue;
1043 }
Linus Torvaldsa4a88b22006-02-28 19:24:001044 parent->next = NULL;
1045 commit->parents = parent;
Derrick Stolee8d049e12020-04-10 12:19:431046
1047 /*
1048 * A merge commit is a "diversion" if it is not
1049 * TREESAME to its first parent but is TREESAME
1050 * to a later parent. In the simplified history,
1051 * we "divert" the history walk to the later
1052 * parent. These commits are shown when "show_pulls"
1053 * is enabled, so do not mark the object as
1054 * TREESAME here.
1055 */
1056 if (!revs->show_pulls || !nth_parent)
1057 commit->object.flags |= TREESAME;
1058
Linus Torvaldsa4a88b22006-02-28 19:24:001059 return;
1060
Fredrik Kuivinen8efdc322006-03-10 09:21:391061 case REV_TREE_NEW:
1062 if (revs->remove_empty_trees &&
Linus Torvalds3a5e8602008-11-03 18:45:411063 rev_same_tree_as_empty(revs, p)) {
Junio C Hamanoc348f312006-03-12 21:39:311064 /* We are adding all the specified
1065 * paths from this parent, so the
1066 * history beyond this parent is not
1067 * interesting. Remove its parents
1068 * (they are grandparents for us).
1069 * IOW, we pretend this parent is a
1070 * "root" commit.
Junio C Hamanoa41e1092006-03-12 21:39:311071 */
Michael Forneyea3f7e52020-06-23 20:56:581072 if (repo_parse_commit(revs->repo, p) < 0)
Alex Riesencc0e6c52007-05-04 21:54:571073 die("cannot simplify commit %s (invalid %s)",
brian m. carlsonf2fd0762015-11-10 02:22:281074 oid_to_hex(&commit->object.oid),
1075 oid_to_hex(&p->object.oid));
Junio C Hamanoc348f312006-03-12 21:39:311076 p->parents = NULL;
Linus Torvaldsa4a88b22006-02-28 19:24:001077 }
1078 /* fallthrough */
Linus Torvaldsceff8e72009-06-03 01:34:011079 case REV_TREE_OLD:
Fredrik Kuivinen8efdc322006-03-10 09:21:391080 case REV_TREE_DIFFERENT:
Kevin Bracey4d826602013-05-16 15:32:391081 if (relevant_commit(p))
1082 relevant_change = 1;
1083 else
1084 irrelevant_change = 1;
Derrick Stolee8d049e12020-04-10 12:19:431085
1086 if (!nth_parent)
1087 commit->object.flags |= PULL_MERGE;
1088
Linus Torvaldsa4a88b22006-02-28 19:24:001089 continue;
1090 }
brian m. carlsonf2fd0762015-11-10 02:22:281091 die("bad tree compare for commit %s", oid_to_hex(&commit->object.oid));
Linus Torvaldsa4a88b22006-02-28 19:24:001092 }
Kevin Bracey4d826602013-05-16 15:32:391093
1094 /*
1095 * TREESAME is straightforward for single-parent commits. For merge
1096 * commits, it is most useful to define it so that "irrelevant"
1097 * parents cannot make us !TREESAME - if we have any relevant
1098 * parents, then we only consider TREESAMEness with respect to them,
1099 * allowing irrelevant merges from uninteresting branches to be
1100 * simplified away. Only if we have only irrelevant parents do we
1101 * base TREESAME on them. Note that this logic is replicated in
1102 * update_treesame, which should be kept in sync.
1103 */
1104 if (relevant_parents ? !relevant_change : !irrelevant_change)
1105 commit->object.flags |= TREESAME;
Linus Torvaldsa4a88b22006-02-28 19:24:001106}
1107
Derrick Stolee5284fc52018-11-01 13:46:211108static int process_parents(struct rev_info *revs, struct commit *commit,
Jeff King8320b1d2019-04-04 01:41:091109 struct commit_list **list, struct prio_queue *queue)
Linus Torvaldsa4a88b22006-02-28 19:24:001110{
1111 struct commit_list *parent = commit->parents;
Elijah Newren257418c2022-08-19 04:28:101112 unsigned pass_flags;
Linus Torvaldsa4a88b22006-02-28 19:24:001113
Linus Torvalds3381c792006-04-09 00:05:581114 if (commit->object.flags & ADDED)
Alex Riesencc0e6c52007-05-04 21:54:571115 return 0;
Karthik Nayak98309262023-10-27 07:59:291116 if (revs->do_not_die_on_missing_objects &&
1117 oidset_contains(&revs->missing_commits, &commit->object.oid))
1118 return 0;
Linus Torvalds3381c792006-04-09 00:05:581119 commit->object.flags |= ADDED;
1120
Vicent Martia330de32013-10-24 18:01:411121 if (revs->include_check &&
1122 !revs->include_check(commit, revs->include_check_data))
1123 return 0;
1124
Linus Torvaldsa4a88b22006-02-28 19:24:001125 /*
1126 * If the commit is uninteresting, don't try to
1127 * prune parents - we want the maximal uninteresting
1128 * set.
1129 *
1130 * Normally we haven't parsed the parent
1131 * yet, so we won't have a parent of a parent
1132 * here. However, it may turn out that we've
1133 * reached this commit some other way (where it
1134 * wasn't uninteresting), in which case we need
1135 * to mark its parents recursively too..
1136 */
1137 if (commit->object.flags & UNINTERESTING) {
1138 while (parent) {
1139 struct commit *p = parent->item;
1140 parent = parent->next;
Junio C Hamanoaeeae1b2009-01-28 07:19:301141 if (p)
1142 p->object.flags |= UNINTERESTING;
Michael Forneyea3f7e52020-06-23 20:56:581143 if (repo_parse_commit_gently(revs->repo, p, 1) < 0)
Junio C Hamanoaeeae1b2009-01-28 07:19:301144 continue;
Linus Torvaldsa4a88b22006-02-28 19:24:001145 if (p->parents)
Jerry Zhang9d505b72022-01-11 21:39:411146 mark_parents_uninteresting(revs, p);
Linus Torvaldsa4a88b22006-02-28 19:24:001147 if (p->object.flags & SEEN)
1148 continue;
Patrick Steinhardtb2025da2021-04-09 11:27:571149 p->object.flags |= (SEEN | NOT_USER_GIVEN);
Derrick Stolee5284fc52018-11-01 13:46:211150 if (list)
Jeff King8320b1d2019-04-04 01:41:091151 commit_list_insert_by_date(p, list);
1152 if (queue)
1153 prio_queue_put(queue, p);
Jerry Zhang9d505b72022-01-11 21:39:411154 if (revs->exclude_first_parent_only)
1155 break;
Linus Torvaldsa4a88b22006-02-28 19:24:001156 }
Alex Riesencc0e6c52007-05-04 21:54:571157 return 0;
Linus Torvaldsa4a88b22006-02-28 19:24:001158 }
1159
1160 /*
1161 * Ok, the commit wasn't uninteresting. Try to
1162 * simplify the commit history and find the parent
1163 * that has no differences in the path set if one exists.
1164 */
Linus Torvalds53b2c822007-11-05 21:22:341165 try_to_simplify_commit(revs, commit);
Linus Torvaldsa4a88b22006-02-28 19:24:001166
Linus Torvaldsba1d4502006-04-15 19:09:561167 if (revs->no_walk)
Alex Riesencc0e6c52007-05-04 21:54:571168 return 0;
Linus Torvaldsba1d4502006-04-15 19:09:561169
Elijah Newren257418c2022-08-19 04:28:101170 pass_flags = (commit->object.flags & (SYMMETRIC_LEFT | ANCESTRY_PATH));
Junio C Hamano0053e902007-03-13 08:57:221171
Stephen R. van den Bergd9c292e2008-04-27 17:32:461172 for (parent = commit->parents; parent; parent = parent->next) {
Linus Torvaldsa4a88b22006-02-28 19:24:001173 struct commit *p = parent->item;
Jonathan Tandf11e192017-12-08 15:27:151174 int gently = revs->ignore_missing_links ||
Karthik Nayak98309262023-10-27 07:59:291175 revs->exclude_promisor_objects ||
1176 revs->do_not_die_on_missing_objects;
Michael Forneyea3f7e52020-06-23 20:56:581177 if (repo_parse_commit_gently(revs->repo, p, gently) < 0) {
Jonathan Tandf11e192017-12-08 15:27:151178 if (revs->exclude_promisor_objects &&
1179 is_promisor_object(&p->object.oid)) {
1180 if (revs->first_parent_only)
1181 break;
1182 continue;
1183 }
Karthik Nayak98309262023-10-27 07:59:291184
1185 if (revs->do_not_die_on_missing_objects)
1186 oidset_insert(&revs->missing_commits, &p->object.oid);
1187 else
1188 return -1; /* corrupt repository */
Jonathan Tandf11e192017-12-08 15:27:151189 }
Nguyễn Thái Ngọc Duy87be2522018-05-19 05:28:241190 if (revs->sources) {
1191 char **slot = revision_sources_at(revs->sources, p);
1192
1193 if (!*slot)
1194 *slot = *revision_sources_at(revs->sources, commit);
1195 }
Elijah Newren257418c2022-08-19 04:28:101196 p->object.flags |= pass_flags;
Lars Hjemliad1012e2008-05-12 15:12:361197 if (!(p->object.flags & SEEN)) {
Patrick Steinhardtb2025da2021-04-09 11:27:571198 p->object.flags |= (SEEN | NOT_USER_GIVEN);
Derrick Stolee5284fc52018-11-01 13:46:211199 if (list)
Jeff King8320b1d2019-04-04 01:41:091200 commit_list_insert_by_date(p, list);
1201 if (queue)
1202 prio_queue_put(queue, p);
Lars Hjemliad1012e2008-05-12 15:12:361203 }
Junio C Hamano60d30b02008-08-01 05:17:131204 if (revs->first_parent_only)
Stephen R. van den Bergd9c292e2008-04-27 17:32:461205 break;
Linus Torvaldsa4a88b22006-02-28 19:24:001206 }
Alex Riesencc0e6c52007-05-04 21:54:571207 return 0;
Linus Torvaldsa4a88b22006-02-28 19:24:001208}
1209
Johannes Schindelin36d56de2007-07-10 13:50:491210static void cherry_pick_list(struct commit_list *list, struct rev_info *revs)
Junio C Hamanod7a17ca2007-04-09 10:40:381211{
1212 struct commit_list *p;
1213 int left_count = 0, right_count = 0;
1214 int left_first;
1215 struct patch_ids ids;
Michael J Gruberadbbb312011-03-07 12:31:401216 unsigned cherry_flag;
Junio C Hamanod7a17ca2007-04-09 10:40:381217
1218 /* First count the commits on the left and on the right */
1219 for (p = list; p; p = p->next) {
1220 struct commit *commit = p->item;
1221 unsigned flags = commit->object.flags;
1222 if (flags & BOUNDARY)
1223 ;
1224 else if (flags & SYMMETRIC_LEFT)
1225 left_count++;
1226 else
1227 right_count++;
1228 }
1229
Thomas Rast36c07972010-02-20 11:42:041230 if (!left_count || !right_count)
1231 return;
1232
Junio C Hamanod7a17ca2007-04-09 10:40:381233 left_first = left_count < right_count;
Nguyễn Thái Ngọc Duy2abf3502018-09-21 15:57:381234 init_patch_ids(revs->repo, &ids);
Nguyễn Thái Ngọc Duy66f13622010-12-15 15:02:381235 ids.diffopts.pathspec = revs->diffopt.pathspec;
Junio C Hamanod7a17ca2007-04-09 10:40:381236
1237 /* Compute patch-ids for one side */
1238 for (p = list; p; p = p->next) {
1239 struct commit *commit = p->item;
1240 unsigned flags = commit->object.flags;
1241
1242 if (flags & BOUNDARY)
1243 continue;
1244 /*
1245 * If we have fewer left, left_first is set and we omit
1246 * commits on the right branch in this loop. If we have
1247 * fewer right, we skip the left ones.
1248 */
1249 if (left_first != !!(flags & SYMMETRIC_LEFT))
1250 continue;
Kevin Willford683f17e2016-07-29 16:19:181251 add_commit_patch_id(commit, &ids);
Junio C Hamanod7a17ca2007-04-09 10:40:381252 }
1253
Michael J Gruberadbbb312011-03-07 12:31:401254 /* either cherry_mark or cherry_pick are true */
1255 cherry_flag = revs->cherry_mark ? PATCHSAME : SHOWN;
1256
Junio C Hamanod7a17ca2007-04-09 10:40:381257 /* Check the other side */
1258 for (p = list; p; p = p->next) {
1259 struct commit *commit = p->item;
1260 struct patch_id *id;
1261 unsigned flags = commit->object.flags;
1262
1263 if (flags & BOUNDARY)
1264 continue;
1265 /*
1266 * If we have fewer left, left_first is set and we omit
1267 * commits on the left branch in this loop.
1268 */
1269 if (left_first == !!(flags & SYMMETRIC_LEFT))
1270 continue;
1271
1272 /*
1273 * Have we seen the same patch id?
1274 */
Jeff Kingc9e3a4e2021-01-12 15:52:321275 id = patch_id_iter_first(commit, &ids);
Junio C Hamanod7a17ca2007-04-09 10:40:381276 if (!id)
1277 continue;
Kevin Willford683f17e2016-07-29 16:19:181278
Michael J Gruberadbbb312011-03-07 12:31:401279 commit->object.flags |= cherry_flag;
Jeff Kingc9e3a4e2021-01-12 15:52:321280 do {
1281 id->commit->object.flags |= cherry_flag;
1282 } while ((id = patch_id_iter_next(id, &ids)));
Junio C Hamanod7a17ca2007-04-09 10:40:381283 }
1284
1285 free_patch_ids(&ids);
1286}
1287
Linus Torvalds7d004192008-03-18 01:56:331288/* How many extra uninteresting commits we want to see.. */
1289#define SLOP 5
1290
Johannes Schindelindddbad72017-04-26 19:29:311291static int still_interesting(struct commit_list *src, timestamp_t date, int slop,
Jeff Kingb6e8a3b2015-04-17 22:11:041292 struct commit **interesting_cache)
Linus Torvalds3131b712008-02-09 22:02:071293{
Linus Torvalds7d004192008-03-18 01:56:331294 /*
1295 * No source list at all? We're definitely done..
1296 */
1297 if (!src)
1298 return 0;
1299
1300 /*
1301 * Does the destination list contain entries with a date
1302 * before the source list? Definitely _not_ done.
1303 */
Kacper Kornetc19d1b42013-03-22 18:38:191304 if (date <= src->item->date)
Linus Torvalds7d004192008-03-18 01:56:331305 return SLOP;
1306
1307 /*
1308 * Does the source list still have interesting commits in
1309 * it? Definitely not done..
1310 */
Jeff Kingb6e8a3b2015-04-17 22:11:041311 if (!everybody_uninteresting(src, interesting_cache))
Linus Torvalds7d004192008-03-18 01:56:331312 return SLOP;
1313
1314 /* Ok, we're closing in.. */
1315 return slop-1;
Linus Torvalds3131b712008-02-09 22:02:071316}
1317
Junio C Hamanoebdc94f2010-04-20 20:48:391318/*
Elijah Newren257418c2022-08-19 04:28:101319 * "rev-list --ancestry-path=C_0 [--ancestry-path=C_1 ...] A..B"
1320 * computes commits that are ancestors of B but not ancestors of A but
1321 * further limits the result to those that have any of C in their
1322 * ancestry path (i.e. are either ancestors of any of C, descendants
1323 * of any of C, or are any of C). If --ancestry-path is specified with
1324 * no commit, we use all bottom commits for C.
1325 *
1326 * Before this function is called, ancestors of C will have already
1327 * been marked with ANCESTRY_PATH previously.
1328 *
1329 * This takes the list of bottom commits and the result of "A..B"
1330 * without --ancestry-path, and limits the latter further to the ones
1331 * that have any of C in their ancestry path. Since the ancestors of C
1332 * have already been marked (a prerequisite of this function), we just
1333 * need to mark the descendants, then exclude any commit that does not
1334 * have any of these marks.
Junio C Hamanoebdc94f2010-04-20 20:48:391335 */
Elijah Newren257418c2022-08-19 04:28:101336static void limit_to_ancestry(struct commit_list *bottoms, struct commit_list *list)
Junio C Hamanoebdc94f2010-04-20 20:48:391337{
1338 struct commit_list *p;
1339 struct commit_list *rlist = NULL;
1340 int made_progress;
1341
1342 /*
1343 * Reverse the list so that it will be likely that we would
1344 * process parents before children.
1345 */
1346 for (p = list; p; p = p->next)
1347 commit_list_insert(p->item, &rlist);
1348
Elijah Newren257418c2022-08-19 04:28:101349 for (p = bottoms; p; p = p->next)
Junio C Hamanoebdc94f2010-04-20 20:48:391350 p->item->object.flags |= TMP_MARK;
1351
1352 /*
1353 * Mark the ones that can reach bottom commits in "list",
1354 * in a bottom-up fashion.
1355 */
1356 do {
1357 made_progress = 0;
1358 for (p = rlist; p; p = p->next) {
1359 struct commit *c = p->item;
1360 struct commit_list *parents;
1361 if (c->object.flags & (TMP_MARK | UNINTERESTING))
1362 continue;
1363 for (parents = c->parents;
1364 parents;
1365 parents = parents->next) {
1366 if (!(parents->item->object.flags & TMP_MARK))
1367 continue;
1368 c->object.flags |= TMP_MARK;
1369 made_progress = 1;
1370 break;
1371 }
1372 }
1373 } while (made_progress);
1374
1375 /*
1376 * NEEDSWORK: decide if we want to remove parents that are
1377 * not marked with TMP_MARK from commit->parents for commits
1378 * in the resulting list. We may not want to do that, though.
1379 */
1380
1381 /*
Elijah Newren257418c2022-08-19 04:28:101382 * The ones that are not marked with either TMP_MARK or
1383 * ANCESTRY_PATH are uninteresting
Junio C Hamanoebdc94f2010-04-20 20:48:391384 */
1385 for (p = list; p; p = p->next) {
1386 struct commit *c = p->item;
Elijah Newren257418c2022-08-19 04:28:101387 if (c->object.flags & (TMP_MARK | ANCESTRY_PATH))
Junio C Hamanoebdc94f2010-04-20 20:48:391388 continue;
1389 c->object.flags |= UNINTERESTING;
1390 }
1391
Elijah Newren257418c2022-08-19 04:28:101392 /* We are done with TMP_MARK and ANCESTRY_PATH */
Junio C Hamanoebdc94f2010-04-20 20:48:391393 for (p = list; p; p = p->next)
Elijah Newren257418c2022-08-19 04:28:101394 p->item->object.flags &= ~(TMP_MARK | ANCESTRY_PATH);
1395 for (p = bottoms; p; p = p->next)
1396 p->item->object.flags &= ~(TMP_MARK | ANCESTRY_PATH);
Junio C Hamanoebdc94f2010-04-20 20:48:391397 free_commit_list(rlist);
1398}
1399
1400/*
Elijah Newren257418c2022-08-19 04:28:101401 * Before walking the history, add the set of "negative" refs the
1402 * caller has asked to exclude to the bottom list.
Junio C Hamanoebdc94f2010-04-20 20:48:391403 *
1404 * This is used to compute "rev-list --ancestry-path A..B", as we need
1405 * to filter the result of "A..B" further to the ones that can actually
1406 * reach A.
1407 */
Elijah Newren257418c2022-08-19 04:28:101408static void collect_bottom_commits(struct commit_list *list,
1409 struct commit_list **bottom)
Junio C Hamanoebdc94f2010-04-20 20:48:391410{
Elijah Newren257418c2022-08-19 04:28:101411 struct commit_list *elem;
Kevin Bracey7f34a462013-05-16 15:32:381412 for (elem = list; elem; elem = elem->next)
1413 if (elem->item->object.flags & BOTTOM)
Elijah Newren257418c2022-08-19 04:28:101414 commit_list_insert(elem->item, bottom);
Junio C Hamanoebdc94f2010-04-20 20:48:391415}
1416
Michael J Gruber60adf7d2011-02-21 16:09:111417/* Assumes either left_only or right_only is set */
1418static void limit_left_right(struct commit_list *list, struct rev_info *revs)
1419{
1420 struct commit_list *p;
1421
1422 for (p = list; p; p = p->next) {
1423 struct commit *commit = p->item;
1424
1425 if (revs->right_only) {
1426 if (commit->object.flags & SYMMETRIC_LEFT)
1427 commit->object.flags |= SHOWN;
1428 } else /* revs->left_only is set */
1429 if (!(commit->object.flags & SYMMETRIC_LEFT))
1430 commit->object.flags |= SHOWN;
1431 }
1432}
1433
Alex Riesencc0e6c52007-05-04 21:54:571434static int limit_list(struct rev_info *revs)
Linus Torvaldsa4a88b22006-02-28 19:24:001435{
Linus Torvalds7d004192008-03-18 01:56:331436 int slop = SLOP;
Johannes Schindelindddbad72017-04-26 19:29:311437 timestamp_t date = TIME_MAX;
Andrzej Huntdb69bf62021-04-25 14:16:081438 struct commit_list *original_list = revs->commits;
Linus Torvaldsa4a88b22006-02-28 19:24:001439 struct commit_list *newlist = NULL;
1440 struct commit_list **p = &newlist;
Jeff Kingb6e8a3b2015-04-17 22:11:041441 struct commit *interesting_cache = NULL;
Junio C Hamanoebdc94f2010-04-20 20:48:391442
Elijah Newren257418c2022-08-19 04:28:101443 if (revs->ancestry_path_implicit_bottoms) {
1444 collect_bottom_commits(original_list,
1445 &revs->ancestry_path_bottoms);
1446 if (!revs->ancestry_path_bottoms)
Johan Herland97b03c32010-06-03 23:17:361447 die("--ancestry-path given but there are no bottom commits");
Junio C Hamanoebdc94f2010-04-20 20:48:391448 }
Linus Torvaldsa4a88b22006-02-28 19:24:001449
Andrzej Huntdb69bf62021-04-25 14:16:081450 while (original_list) {
1451 struct commit *commit = pop_commit(&original_list);
Linus Torvaldsa4a88b22006-02-28 19:24:001452 struct object *obj = &commit->object;
Linus Torvaldscdcefbc2007-11-03 18:11:101453 show_early_output_fn_t show;
Linus Torvaldsa4a88b22006-02-28 19:24:001454
Jeff Kingb6e8a3b2015-04-17 22:11:041455 if (commit == interesting_cache)
1456 interesting_cache = NULL;
1457
Linus Torvaldsa4a88b22006-02-28 19:24:001458 if (revs->max_age != -1 && (commit->date < revs->max_age))
1459 obj->flags |= UNINTERESTING;
Andrzej Huntdb69bf62021-04-25 14:16:081460 if (process_parents(revs, commit, &original_list, NULL) < 0)
Alex Riesencc0e6c52007-05-04 21:54:571461 return -1;
Linus Torvaldsa4a88b22006-02-28 19:24:001462 if (obj->flags & UNINTERESTING) {
Jerry Zhang9d505b72022-01-11 21:39:411463 mark_parents_uninteresting(revs, commit);
Andrzej Huntdb69bf62021-04-25 14:16:081464 slop = still_interesting(original_list, date, slop, &interesting_cache);
Linus Torvalds7d004192008-03-18 01:56:331465 if (slop)
Linus Torvalds3131b712008-02-09 22:02:071466 continue;
Linus Torvalds7d004192008-03-18 01:56:331467 break;
Linus Torvaldsa4a88b22006-02-28 19:24:001468 }
René Scharfe01faa912020-07-04 12:56:321469 if (revs->min_age != -1 && (commit->date > revs->min_age) &&
1470 !revs->line_level_traverse)
Linus Torvaldsa4a88b22006-02-28 19:24:001471 continue;
Miklos Vajna96697782022-04-23 12:59:571472 if (revs->max_age_as_filter != -1 &&
1473 (commit->date < revs->max_age_as_filter) && !revs->line_level_traverse)
1474 continue;
Linus Torvalds7d004192008-03-18 01:56:331475 date = commit->date;
Linus Torvaldsa4a88b22006-02-28 19:24:001476 p = &commit_list_insert(commit, p)->next;
Linus Torvaldscdcefbc2007-11-03 18:11:101477
1478 show = show_early_output;
1479 if (!show)
1480 continue;
1481
1482 show(revs, newlist);
1483 show_early_output = NULL;
Linus Torvaldsa4a88b22006-02-28 19:24:001484 }
Michael J Gruberadbbb312011-03-07 12:31:401485 if (revs->cherry_pick || revs->cherry_mark)
Johannes Schindelin36d56de2007-07-10 13:50:491486 cherry_pick_list(newlist, revs);
Junio C Hamanod7a17ca2007-04-09 10:40:381487
Michael J Gruber60adf7d2011-02-21 16:09:111488 if (revs->left_only || revs->right_only)
1489 limit_left_right(newlist, revs);
1490
Elijah Newren257418c2022-08-19 04:28:101491 if (revs->ancestry_path)
1492 limit_to_ancestry(revs->ancestry_path_bottoms, newlist);
Junio C Hamanoebdc94f2010-04-20 20:48:391493
Kevin Bracey4d826602013-05-16 15:32:391494 /*
1495 * Check if any commits have become TREESAME by some of their parents
1496 * becoming UNINTERESTING.
1497 */
Andrzej Huntdb69bf62021-04-25 14:16:081498 if (limiting_can_increase_treesame(revs)) {
1499 struct commit_list *list = NULL;
Kevin Bracey4d826602013-05-16 15:32:391500 for (list = newlist; list; list = list->next) {
1501 struct commit *c = list->item;
1502 if (c->object.flags & (UNINTERESTING | TREESAME))
1503 continue;
1504 update_treesame(revs, c);
1505 }
Andrzej Huntdb69bf62021-04-25 14:16:081506 }
Kevin Bracey4d826602013-05-16 15:32:391507
Andrzej Huntdb69bf62021-04-25 14:16:081508 free_commit_list(original_list);
Linus Torvaldsa4a88b22006-02-28 19:24:001509 revs->commits = newlist;
Alex Riesencc0e6c52007-05-04 21:54:571510 return 0;
Linus Torvaldsa4a88b22006-02-28 19:24:001511}
1512
Michael Haggertydf835d32013-05-25 09:08:021513/*
1514 * Add an entry to refs->cmdline with the specified information.
1515 * *name is copied.
1516 */
Junio C Hamano281eee42011-08-26 00:35:391517static void add_rev_cmdline(struct rev_info *revs,
1518 struct object *item,
1519 const char *name,
1520 int whence,
1521 unsigned flags)
1522{
1523 struct rev_cmdline_info *info = &revs->cmdline;
Ramsay Jones071bcaa2017-09-21 16:49:381524 unsigned int nr = info->nr;
Junio C Hamano281eee42011-08-26 00:35:391525
1526 ALLOC_GROW(info->rev, nr + 1, info->alloc);
1527 info->rev[nr].item = item;
Michael Haggertydf835d32013-05-25 09:08:021528 info->rev[nr].name = xstrdup(name);
Junio C Hamano281eee42011-08-26 00:35:391529 info->rev[nr].whence = whence;
1530 info->rev[nr].flags = flags;
1531 info->nr++;
1532}
1533
Kevin Braceya7654992013-05-13 15:00:471534static void add_rev_cmdline_list(struct rev_info *revs,
1535 struct commit_list *commit_list,
1536 int whence,
1537 unsigned flags)
1538{
1539 while (commit_list) {
1540 struct object *object = &commit_list->item->object;
brian m. carlsonf2fd0762015-11-10 02:22:281541 add_rev_cmdline(revs, object, oid_to_hex(&object->oid),
Kevin Braceya7654992013-05-13 15:00:471542 whence, flags);
1543 commit_list = commit_list->next;
1544 }
1545}
1546
Patrick Steinhardt1e9f2732022-11-17 05:46:511547int ref_excluded(const struct ref_exclusions *exclusions, const char *path)
Junio C Hamanoe7b432c2013-08-30 23:37:551548{
Patrick Steinhardt8c1bc2a2022-11-17 05:46:561549 const char *stripped_path = strip_namespace(path);
Junio C Hamanoe7b432c2013-08-30 23:37:551550 struct string_list_item *item;
Patrick Steinhardt8c1bc2a2022-11-17 05:46:561551
Patrick Steinhardt1e9f2732022-11-17 05:46:511552 for_each_string_list_item(item, &exclusions->excluded_refs) {
Ævar Arnfjörð Bjarmason55d34262017-06-22 21:38:081553 if (!wildmatch(item->string, path, 0))
Junio C Hamanoe7b432c2013-08-30 23:37:551554 return 1;
1555 }
Patrick Steinhardt8c1bc2a2022-11-17 05:46:561556
1557 if (ref_is_hidden(stripped_path, path, &exclusions->hidden_refs))
1558 return 1;
1559
Junio C Hamanoe7b432c2013-08-30 23:37:551560 return 0;
1561}
1562
Patrick Steinhardt1e9f2732022-11-17 05:46:511563void init_ref_exclusions(struct ref_exclusions *exclusions)
Patrick Steinhardt05b94252022-11-17 05:46:471564{
Patrick Steinhardt1e9f2732022-11-17 05:46:511565 struct ref_exclusions blank = REF_EXCLUSIONS_INIT;
1566 memcpy(exclusions, &blank, sizeof(*exclusions));
Patrick Steinhardt05b94252022-11-17 05:46:471567}
1568
Patrick Steinhardt1e9f2732022-11-17 05:46:511569void clear_ref_exclusions(struct ref_exclusions *exclusions)
Patrick Steinhardt05b94252022-11-17 05:46:471570{
Patrick Steinhardt1e9f2732022-11-17 05:46:511571 string_list_clear(&exclusions->excluded_refs, 0);
Taylor Blauc45841f2023-07-10 21:12:331572 strvec_clear(&exclusions->hidden_refs);
Patrick Steinhardt8c1bc2a2022-11-17 05:46:561573 exclusions->hidden_refs_configured = 0;
Patrick Steinhardt1e9f2732022-11-17 05:46:511574}
1575
1576void add_ref_exclusion(struct ref_exclusions *exclusions, const char *exclude)
1577{
1578 string_list_append(&exclusions->excluded_refs, exclude);
Patrick Steinhardt05b94252022-11-17 05:46:471579}
1580
Patrick Steinhardt8c1bc2a2022-11-17 05:46:561581struct exclude_hidden_refs_cb {
1582 struct ref_exclusions *exclusions;
1583 const char *section;
1584};
1585
Glen Chooa4e7e312023-06-28 19:26:221586static int hide_refs_config(const char *var, const char *value,
1587 const struct config_context *ctx UNUSED,
1588 void *cb_data)
Patrick Steinhardt8c1bc2a2022-11-17 05:46:561589{
1590 struct exclude_hidden_refs_cb *cb = cb_data;
1591 cb->exclusions->hidden_refs_configured = 1;
1592 return parse_hide_refs_config(var, value, cb->section,
1593 &cb->exclusions->hidden_refs);
1594}
1595
1596void exclude_hidden_refs(struct ref_exclusions *exclusions, const char *section)
1597{
1598 struct exclude_hidden_refs_cb cb;
1599
Eric Wongc6ce27a2023-02-12 09:04:261600 if (strcmp(section, "fetch") && strcmp(section, "receive") &&
1601 strcmp(section, "uploadpack"))
Patrick Steinhardt8c1bc2a2022-11-17 05:46:561602 die(_("unsupported section for hidden refs: %s"), section);
1603
1604 if (exclusions->hidden_refs_configured)
1605 die(_("--exclude-hidden= passed more than once"));
1606
1607 cb.exclusions = exclusions;
1608 cb.section = section;
1609
1610 git_config(hide_refs_config, &cb);
1611}
1612
Junio C Hamano63049292006-12-19 01:25:281613struct all_refs_cb {
1614 int all_flags;
Shawn O. Pearce71b03b42006-12-22 00:49:061615 int warned_bad_reflog;
Junio C Hamano63049292006-12-19 01:25:281616 struct rev_info *all_revs;
1617 const char *name_for_errormsg;
Nguyễn Thái Ngọc Duyab3e1f72018-10-21 08:08:561618 struct worktree *wt;
Junio C Hamano63049292006-12-19 01:25:281619};
Linus Torvaldsae563542006-02-26 00:19:461620
Michael Haggertya217dcb2015-05-25 18:38:301621static int handle_one_ref(const char *path, const struct object_id *oid,
Ævar Arnfjörð Bjarmason5cf88fd2022-08-25 17:09:481622 int flag UNUSED,
Jeff King63e14ee2022-08-19 10:08:321623 void *cb_data)
Linus Torvaldsae563542006-02-26 00:19:461624{
Junio C Hamano63049292006-12-19 01:25:281625 struct all_refs_cb *cb = cb_data;
Junio C Hamanoe7b432c2013-08-30 23:37:551626 struct object *object;
1627
Patrick Steinhardt1e9f2732022-11-17 05:46:511628 if (ref_excluded(&cb->all_revs->ref_excludes, path))
Junio C Hamanoe7b432c2013-08-30 23:37:551629 return 0;
1630
brian m. carlson654b9a92017-05-06 22:10:271631 object = get_reference(cb->all_revs, path, oid, cb->all_flags);
Junio C Hamano281eee42011-08-26 00:35:391632 add_rev_cmdline(cb->all_revs, object, path, REV_CMD_REF, cb->all_flags);
Patrick Steinhardtbf9c0cb2021-08-09 08:11:541633 add_pending_object(cb->all_revs, object, path);
Linus Torvaldsae563542006-02-26 00:19:461634 return 0;
1635}
1636
Ilari Liusvaarad08bae72010-01-20 09:48:251637static void init_all_refs_cb(struct all_refs_cb *cb, struct rev_info *revs,
1638 unsigned flags)
1639{
1640 cb->all_revs = revs;
1641 cb->all_flags = flags;
Jeff King7ba82622017-08-02 22:25:271642 revs->rev_input_given = 1;
Nguyễn Thái Ngọc Duyab3e1f72018-10-21 08:08:561643 cb->wt = NULL;
Ilari Liusvaarad08bae72010-01-20 09:48:251644}
1645
Nguyễn Thái Ngọc Duy073cf632017-08-23 12:36:561646static void handle_refs(struct ref_store *refs,
1647 struct rev_info *revs, unsigned flags,
1648 int (*for_each)(struct ref_store *, each_ref_fn, void *))
Linus Torvaldsae563542006-02-26 00:19:461649{
Junio C Hamano63049292006-12-19 01:25:281650 struct all_refs_cb cb;
Nguyễn Thái Ngọc Duy073cf632017-08-23 12:36:561651
1652 if (!refs) {
1653 /* this could happen with uninitialized submodules */
1654 return;
1655 }
1656
Ilari Liusvaarad08bae72010-01-20 09:48:251657 init_all_refs_cb(&cb, revs, flags);
Nguyễn Thái Ngọc Duy073cf632017-08-23 12:36:561658 for_each(refs, handle_one_ref, &cb);
Junio C Hamano63049292006-12-19 01:25:281659}
1660
brian m. carlson9461d272017-02-21 23:47:321661static void handle_one_reflog_commit(struct object_id *oid, void *cb_data)
Junio C Hamano63049292006-12-19 01:25:281662{
1663 struct all_refs_cb *cb = cb_data;
brian m. carlson9461d272017-02-21 23:47:321664 if (!is_null_oid(oid)) {
Nguyễn Thái Ngọc Duyb3c7eef2018-09-21 15:57:391665 struct object *o = parse_object(cb->all_revs->repo, oid);
Shawn O. Pearce71b03b42006-12-22 00:49:061666 if (o) {
1667 o->flags |= cb->all_flags;
Junio C Hamano281eee42011-08-26 00:35:391668 /* ??? CMDLINEFLAGS ??? */
Shawn O. Pearce71b03b42006-12-22 00:49:061669 add_pending_object(cb->all_revs, o, "");
1670 }
1671 else if (!cb->warned_bad_reflog) {
Theodore Ts'o46efd2d2007-03-30 23:07:051672 warning("reflog of '%s' references pruned commits",
Shawn O. Pearce71b03b42006-12-22 00:49:061673 cb->name_for_errormsg);
1674 cb->warned_bad_reflog = 1;
1675 }
Junio C Hamano63049292006-12-19 01:25:281676 }
Shawn O. Pearce71b03b42006-12-22 00:49:061677}
1678
brian m. carlson9461d272017-02-21 23:47:321679static int handle_one_reflog_ent(struct object_id *ooid, struct object_id *noid,
Ævar Arnfjörð Bjarmason5cf88fd2022-08-25 17:09:481680 const char *email UNUSED,
1681 timestamp_t timestamp UNUSED,
1682 int tz UNUSED,
1683 const char *message UNUSED,
Jeff Kingc006e9f2022-08-19 10:08:351684 void *cb_data)
Shawn O. Pearce71b03b42006-12-22 00:49:061685{
brian m. carlson9461d272017-02-21 23:47:321686 handle_one_reflog_commit(ooid, cb_data);
1687 handle_one_reflog_commit(noid, cb_data);
Junio C Hamano63049292006-12-19 01:25:281688 return 0;
1689}
1690
Nguyễn Thái Ngọc Duyab3e1f72018-10-21 08:08:561691static int handle_one_reflog(const char *refname_in_wt,
Ævar Arnfjörð Bjarmason5cf88fd2022-08-25 17:09:481692 const struct object_id *oid UNUSED,
1693 int flag UNUSED, void *cb_data)
Junio C Hamano63049292006-12-19 01:25:281694{
1695 struct all_refs_cb *cb = cb_data;
Nguyễn Thái Ngọc Duyab3e1f72018-10-21 08:08:561696 struct strbuf refname = STRBUF_INIT;
1697
Shawn O. Pearce71b03b42006-12-22 00:49:061698 cb->warned_bad_reflog = 0;
Nguyễn Thái Ngọc Duyab3e1f72018-10-21 08:08:561699 strbuf_worktree_ref(cb->wt, &refname, refname_in_wt);
1700 cb->name_for_errormsg = refname.buf;
1701 refs_for_each_reflog_ent(get_main_ref_store(the_repository),
1702 refname.buf,
Nguyễn Thái Ngọc Duyacd95442017-08-23 12:37:011703 handle_one_reflog_ent, cb_data);
Nguyễn Thái Ngọc Duyab3e1f72018-10-21 08:08:561704 strbuf_release(&refname);
Junio C Hamano63049292006-12-19 01:25:281705 return 0;
1706}
1707
Nguyễn Thái Ngọc Duyacd95442017-08-23 12:37:011708static void add_other_reflogs_to_pending(struct all_refs_cb *cb)
1709{
1710 struct worktree **worktrees, **p;
1711
Eric Sunshine03f24652020-06-19 23:35:441712 worktrees = get_worktrees();
Nguyễn Thái Ngọc Duyacd95442017-08-23 12:37:011713 for (p = worktrees; *p; p++) {
1714 struct worktree *wt = *p;
1715
1716 if (wt->is_current)
1717 continue;
1718
Nguyễn Thái Ngọc Duyab3e1f72018-10-21 08:08:561719 cb->wt = wt;
1720 refs_for_each_reflog(get_worktree_ref_store(wt),
Nguyễn Thái Ngọc Duyacd95442017-08-23 12:37:011721 handle_one_reflog,
1722 cb);
1723 }
1724 free_worktrees(worktrees);
1725}
1726
Jeff King718ccc92014-10-15 22:38:311727void add_reflogs_to_pending(struct rev_info *revs, unsigned flags)
Junio C Hamano63049292006-12-19 01:25:281728{
1729 struct all_refs_cb cb;
Michael Haggerty2b2a5be2015-05-25 18:38:281730
Junio C Hamano63049292006-12-19 01:25:281731 cb.all_revs = revs;
1732 cb.all_flags = flags;
Nguyễn Thái Ngọc Duyab3e1f72018-10-21 08:08:561733 cb.wt = NULL;
Michael Haggertya89caf42015-05-25 18:39:031734 for_each_reflog(handle_one_reflog, &cb);
Nguyễn Thái Ngọc Duyacd95442017-08-23 12:37:011735
1736 if (!revs->single_worktree)
1737 add_other_reflogs_to_pending(&cb);
Linus Torvaldsae563542006-02-26 00:19:461738}
1739
Jeff King4fe10212014-10-17 00:44:231740static void add_cache_tree(struct cache_tree *it, struct rev_info *revs,
Jeff Kingb4cfcde2018-11-02 05:22:591741 struct strbuf *path, unsigned int flags)
Jeff King4fe10212014-10-17 00:44:231742{
1743 size_t baselen = path->len;
1744 int i;
1745
1746 if (it->entry_count >= 0) {
Nguyễn Thái Ngọc Duyb3c7eef2018-09-21 15:57:391747 struct tree *tree = lookup_tree(revs->repo, &it->oid);
Jeff Kingb4cfcde2018-11-02 05:22:591748 tree->object.flags |= flags;
Jeff King4fe10212014-10-17 00:44:231749 add_pending_object_with_path(revs, &tree->object, "",
1750 040000, path->buf);
1751 }
1752
1753 for (i = 0; i < it->subtree_nr; i++) {
1754 struct cache_tree_sub *sub = it->down[i];
1755 strbuf_addf(path, "%s%s", baselen ? "/" : "", sub->name);
Jeff Kingb4cfcde2018-11-02 05:22:591756 add_cache_tree(sub->cache_tree, revs, path, flags);
Jeff King4fe10212014-10-17 00:44:231757 strbuf_setlen(path, baselen);
1758 }
1759
1760}
1761
Junio C Hamano5a5ea142022-06-09 23:44:201762static void add_resolve_undo_to_pending(struct index_state *istate, struct rev_info *revs)
1763{
1764 struct string_list_item *item;
1765 struct string_list *resolve_undo = istate->resolve_undo;
1766
1767 if (!resolve_undo)
1768 return;
1769
1770 for_each_string_list_item(item, resolve_undo) {
1771 const char *path = item->string;
1772 struct resolve_undo_info *ru = item->util;
1773 int i;
1774
1775 if (!ru)
1776 continue;
1777 for (i = 0; i < 3; i++) {
1778 struct blob *blob;
1779
1780 if (!ru->mode[i] || !S_ISREG(ru->mode[i]))
1781 continue;
1782
1783 blob = lookup_blob(revs->repo, &ru->oid[i]);
1784 if (!blob) {
1785 warning(_("resolve-undo records `%s` which is missing"),
1786 oid_to_hex(&ru->oid[i]));
1787 continue;
1788 }
1789 add_pending_object_with_path(revs, &blob->object, "",
1790 ru->mode[i], path);
1791 }
1792 }
1793}
1794
Nguyễn Thái Ngọc Duy6c3d8182017-08-23 12:36:511795static void do_add_index_objects_to_pending(struct rev_info *revs,
Jeff Kingb4cfcde2018-11-02 05:22:591796 struct index_state *istate,
1797 unsigned int flags)
Jeff King4fe10212014-10-17 00:44:231798{
1799 int i;
1800
Derrick Stoleef5fed742021-04-01 01:50:001801 /* TODO: audit for interaction with sparse-index. */
1802 ensure_full_index(istate);
Nguyễn Thái Ngọc Duy6c3d8182017-08-23 12:36:511803 for (i = 0; i < istate->cache_nr; i++) {
1804 struct cache_entry *ce = istate->cache[i];
Jeff King4fe10212014-10-17 00:44:231805 struct blob *blob;
1806
1807 if (S_ISGITLINK(ce->ce_mode))
1808 continue;
1809
Nguyễn Thái Ngọc Duyb3c7eef2018-09-21 15:57:391810 blob = lookup_blob(revs->repo, &ce->oid);
Jeff King4fe10212014-10-17 00:44:231811 if (!blob)
1812 die("unable to add index blob to traversal");
Jeff Kingb4cfcde2018-11-02 05:22:591813 blob->object.flags |= flags;
Jeff King4fe10212014-10-17 00:44:231814 add_pending_object_with_path(revs, &blob->object, "",
1815 ce->ce_mode, ce->name);
1816 }
1817
Nguyễn Thái Ngọc Duy6c3d8182017-08-23 12:36:511818 if (istate->cache_tree) {
Jeff King4fe10212014-10-17 00:44:231819 struct strbuf path = STRBUF_INIT;
Jeff Kingb4cfcde2018-11-02 05:22:591820 add_cache_tree(istate->cache_tree, revs, &path, flags);
Jeff King4fe10212014-10-17 00:44:231821 strbuf_release(&path);
1822 }
Junio C Hamano5a5ea142022-06-09 23:44:201823
1824 add_resolve_undo_to_pending(istate, revs);
Jeff King4fe10212014-10-17 00:44:231825}
1826
Nguyễn Thái Ngọc Duy6c3d8182017-08-23 12:36:511827void add_index_objects_to_pending(struct rev_info *revs, unsigned int flags)
1828{
Nguyễn Thái Ngọc Duybe489d02017-08-23 12:36:521829 struct worktree **worktrees, **p;
1830
Nguyễn Thái Ngọc Duye1ff0a32019-01-12 02:13:261831 repo_read_index(revs->repo);
Jeff Kingb4cfcde2018-11-02 05:22:591832 do_add_index_objects_to_pending(revs, revs->repo->index, flags);
Nguyễn Thái Ngọc Duybe489d02017-08-23 12:36:521833
1834 if (revs->single_worktree)
1835 return;
1836
Eric Sunshine03f24652020-06-19 23:35:441837 worktrees = get_worktrees();
Nguyễn Thái Ngọc Duybe489d02017-08-23 12:36:521838 for (p = worktrees; *p; p++) {
1839 struct worktree *wt = *p;
Ævar Arnfjörð Bjarmason6269f8e2023-01-17 13:57:001840 struct index_state istate = INDEX_STATE_INIT(revs->repo);
Nguyễn Thái Ngọc Duybe489d02017-08-23 12:36:521841
1842 if (wt->is_current)
1843 continue; /* current index already taken care of */
1844
1845 if (read_index_from(&istate,
Thomas Gummerera125a222018-01-07 22:30:131846 worktree_git_path(wt, "index"),
1847 get_worktree_git_dir(wt)) > 0)
Jeff Kingb4cfcde2018-11-02 05:22:591848 do_add_index_objects_to_pending(revs, &istate, flags);
Nguyễn Thái Ngọc Duybe489d02017-08-23 12:36:521849 discard_index(&istate);
1850 }
1851 free_worktrees(worktrees);
Nguyễn Thái Ngọc Duy6c3d8182017-08-23 12:36:511852}
1853
Jeff King39b44ba2019-07-01 13:18:151854struct add_alternate_refs_data {
1855 struct rev_info *revs;
1856 unsigned int flags;
1857};
1858
1859static void add_one_alternate_ref(const struct object_id *oid,
1860 void *vdata)
1861{
1862 const char *name = ".alternate";
1863 struct add_alternate_refs_data *data = vdata;
1864 struct object *obj;
1865
1866 obj = get_reference(data->revs, name, oid, data->flags);
1867 add_rev_cmdline(data->revs, obj, name, REV_CMD_REV, data->flags);
1868 add_pending_object(data->revs, obj, name);
1869}
1870
1871static void add_alternate_refs_to_pending(struct rev_info *revs,
1872 unsigned int flags)
1873{
1874 struct add_alternate_refs_data data;
1875 data.revs = revs;
1876 data.flags = flags;
1877 for_each_alternate_ref(add_one_alternate_ref, &data);
1878}
1879
Vegard Nossum87793512016-09-27 08:32:491880static int add_parents_only(struct rev_info *revs, const char *arg_, int flags,
1881 int exclude_parent)
Junio C Hamanoea4a19e2006-04-30 07:54:291882{
brian m. carlson654b9a92017-05-06 22:10:271883 struct object_id oid;
Junio C Hamanoea4a19e2006-04-30 07:54:291884 struct object *it;
1885 struct commit *commit;
1886 struct commit_list *parents;
Vegard Nossum87793512016-09-27 08:32:491887 int parent_number;
Junio C Hamano281eee42011-08-26 00:35:391888 const char *arg = arg_;
Junio C Hamanoea4a19e2006-04-30 07:54:291889
1890 if (*arg == '^') {
Kevin Bracey7f34a462013-05-16 15:32:381891 flags ^= UNINTERESTING | BOTTOM;
Junio C Hamanoea4a19e2006-04-30 07:54:291892 arg++;
1893 }
Ævar Arnfjörð Bjarmasond850b7a2023-03-28 13:58:461894 if (repo_get_oid_committish(the_repository, arg, &oid))
Junio C Hamanoea4a19e2006-04-30 07:54:291895 return 0;
1896 while (1) {
brian m. carlson654b9a92017-05-06 22:10:271897 it = get_reference(revs, arg, &oid, 0);
Junio C Hamanocc243c32011-05-19 01:08:091898 if (!it && revs->ignore_missing)
1899 return 0;
Linus Torvalds19746322006-07-12 03:45:311900 if (it->type != OBJ_TAG)
Junio C Hamanoea4a19e2006-04-30 07:54:291901 break;
Martin Koegler9684afd2008-02-18 20:48:011902 if (!((struct tag*)it)->tagged)
1903 return 0;
brian m. carlson654b9a92017-05-06 22:10:271904 oidcpy(&oid, &((struct tag*)it)->tagged->oid);
Junio C Hamanoea4a19e2006-04-30 07:54:291905 }
Linus Torvalds19746322006-07-12 03:45:311906 if (it->type != OBJ_COMMIT)
Junio C Hamanoea4a19e2006-04-30 07:54:291907 return 0;
1908 commit = (struct commit *)it;
Vegard Nossum87793512016-09-27 08:32:491909 if (exclude_parent &&
1910 exclude_parent > commit_list_count(commit->parents))
1911 return 0;
1912 for (parents = commit->parents, parent_number = 1;
1913 parents;
1914 parents = parents->next, parent_number++) {
1915 if (exclude_parent && parent_number != exclude_parent)
1916 continue;
1917
Junio C Hamanoea4a19e2006-04-30 07:54:291918 it = &parents->item->object;
1919 it->flags |= flags;
Junio C Hamano281eee42011-08-26 00:35:391920 add_rev_cmdline(revs, it, arg_, REV_CMD_PARENTS_ONLY, flags);
Junio C Hamanoea4a19e2006-04-30 07:54:291921 add_pending_object(revs, it, arg);
1922 }
1923 return 1;
1924}
1925
Nguyễn Thái Ngọc Duy2abf3502018-09-21 15:57:381926void repo_init_revisions(struct repository *r,
1927 struct rev_info *revs,
1928 const char *prefix)
Fredrik Kuivinen8efdc322006-03-10 09:21:391929{
Ævar Arnfjörð Bjarmason916ebb32022-11-08 14:02:571930 struct rev_info blank = REV_INFO_INIT;
1931 memcpy(revs, &blank, sizeof(*revs));
Junio C Hamano8e8f9982006-04-15 05:19:381932
Nguyễn Thái Ngọc Duy2abf3502018-09-21 15:57:381933 revs->repo = r;
Nguyễn Thái Ngọc Duy67022e02018-11-18 16:47:571934 revs->pruning.repo = r;
Linus Torvaldscd2bdc52006-04-14 23:52:131935 revs->pruning.add_remove = file_add_remove;
1936 revs->pruning.change = file_change;
Jeff Kinga937b372017-10-13 15:27:451937 revs->pruning.change_fn_data = revs;
Linus Torvaldsdb6296a2006-07-29 04:21:481938 revs->prefix = prefix;
Linus Torvaldscd2bdc52006-04-14 23:52:131939
Ævar Arnfjörð Bjarmason9725c8d2022-02-16 00:00:341940 grep_init(&revs->grep_filter, revs->repo);
Jeff King0843acf2008-08-25 06:15:051941 revs->grep_filter.status_only = 1;
Jeff King0843acf2008-08-25 06:15:051942
Nguyễn Thái Ngọc Duy2abf3502018-09-21 15:57:381943 repo_diff_setup(revs->repo, &revs->diffopt);
Junio C Hamanoc0cb4a02008-02-13 08:34:391944 if (prefix && !revs->diffopt.prefix) {
Junio C Hamanocd676a52008-02-12 22:26:021945 revs->diffopt.prefix = prefix;
1946 revs->diffopt.prefix_length = strlen(prefix);
1947 }
Jeff King3a03cf62011-03-29 20:57:271948
Denton Liue6e230e2019-12-09 13:10:411949 init_display_notes(&revs->notes_opt);
Jeff King2a01bde2022-09-11 05:03:071950 list_objects_filter_init(&revs->filter);
Patrick Steinhardt1e9f2732022-11-17 05:46:511951 init_ref_exclusions(&revs->ref_excludes);
Fredrik Kuivinen8efdc322006-03-10 09:21:391952}
1953
Rene Scharfe0d2c9d62006-07-01 23:29:371954static void add_pending_commit_list(struct rev_info *revs,
Nguyễn Thái Ngọc Duyec36c422018-12-06 15:42:061955 struct commit_list *commit_list,
1956 unsigned int flags)
Rene Scharfe0d2c9d62006-07-01 23:29:371957{
1958 while (commit_list) {
1959 struct object *object = &commit_list->item->object;
1960 object->flags |= flags;
brian m. carlsonf2fd0762015-11-10 02:22:281961 add_pending_object(revs, object, oid_to_hex(&object->oid));
Rene Scharfe0d2c9d62006-07-01 23:29:371962 commit_list = commit_list->next;
1963 }
1964}
1965
Junio C Hamanoae3e5e12006-07-03 09:59:321966static void prepare_show_merge(struct rev_info *revs)
1967{
1968 struct commit_list *bases;
1969 struct commit *head, *other;
brian m. carlson68ab61d2017-05-06 22:10:051970 struct object_id oid;
Junio C Hamanoae3e5e12006-07-03 09:59:321971 const char **prune = NULL;
1972 int i, prune_num = 1; /* counting terminating NULL */
Nguyễn Thái Ngọc Duy2abf3502018-09-21 15:57:381973 struct index_state *istate = revs->repo->index;
Junio C Hamanoae3e5e12006-07-03 09:59:321974
Ævar Arnfjörð Bjarmasond850b7a2023-03-28 13:58:461975 if (repo_get_oid(the_repository, "HEAD", &oid))
Junio C Hamanoae3e5e12006-07-03 09:59:321976 die("--merge without HEAD?");
brian m. carlsonbc832662017-05-06 22:10:101977 head = lookup_commit_or_die(&oid, "HEAD");
Ævar Arnfjörð Bjarmasond850b7a2023-03-28 13:58:461978 if (repo_get_oid(the_repository, "MERGE_HEAD", &oid))
Junio C Hamanoae3e5e12006-07-03 09:59:321979 die("--merge without MERGE_HEAD?");
brian m. carlsonbc832662017-05-06 22:10:101980 other = lookup_commit_or_die(&oid, "MERGE_HEAD");
Junio C Hamanoae3e5e12006-07-03 09:59:321981 add_pending_object(revs, &head->object, "HEAD");
1982 add_pending_object(revs, &other->object, "MERGE_HEAD");
Ævar Arnfjörð Bjarmasoncb338c22023-03-28 13:58:471983 bases = repo_get_merge_bases(the_repository, head, other);
Kevin Bracey7f34a462013-05-16 15:32:381984 add_rev_cmdline_list(revs, bases, REV_CMD_MERGE_BASE, UNINTERESTING | BOTTOM);
1985 add_pending_commit_list(revs, bases, UNINTERESTING | BOTTOM);
Junio C Hamanoe82447b2008-02-27 07:18:381986 free_commit_list(bases);
1987 head->object.flags |= SYMMETRIC_LEFT;
Junio C Hamanoae3e5e12006-07-03 09:59:321988
Nguyễn Thái Ngọc Duy2abf3502018-09-21 15:57:381989 if (!istate->cache_nr)
Nguyễn Thái Ngọc Duye1ff0a32019-01-12 02:13:261990 repo_read_index(revs->repo);
Nguyễn Thái Ngọc Duy2abf3502018-09-21 15:57:381991 for (i = 0; i < istate->cache_nr; i++) {
1992 const struct cache_entry *ce = istate->cache[i];
Junio C Hamanoae3e5e12006-07-03 09:59:321993 if (!ce_stage(ce))
1994 continue;
Nguyễn Thái Ngọc Duy2abf3502018-09-21 15:57:381995 if (ce_path_match(istate, ce, &revs->prune_data, NULL)) {
Junio C Hamanoae3e5e12006-07-03 09:59:321996 prune_num++;
René Scharfe2756ca42014-09-16 18:56:571997 REALLOC_ARRAY(prune, prune_num);
Junio C Hamanoae3e5e12006-07-03 09:59:321998 prune[prune_num-2] = ce->name;
1999 prune[prune_num-1] = NULL;
2000 }
Nguyễn Thái Ngọc Duy2abf3502018-09-21 15:57:382001 while ((i+1 < istate->cache_nr) &&
2002 ce_same_name(ce, istate->cache[i+1]))
Junio C Hamanoae3e5e12006-07-03 09:59:322003 i++;
2004 }
Junio C Hamanoed6e8032016-06-02 21:09:222005 clear_pathspec(&revs->prune_data);
Nguyễn Thái Ngọc Duy4a2d5ae2013-10-26 02:09:202006 parse_pathspec(&revs->prune_data, PATHSPEC_ALL_MAGIC & ~PATHSPEC_LITERAL,
Junio C Hamanoc6f1b922013-11-18 22:31:292007 PATHSPEC_PREFER_FULL | PATHSPEC_LITERAL_PATH, "", prune);
Junio C Hamanoe82447b2008-02-27 07:18:382008 revs->limited = 1;
Junio C Hamanoae3e5e12006-07-03 09:59:322009}
2010
Jeff King62faad52017-05-19 12:52:002011static int dotdot_missing(const char *arg, char *dotdot,
2012 struct rev_info *revs, int symmetric)
2013{
2014 if (revs->ignore_missing)
2015 return 0;
2016 /* de-munge so we report the full argument */
2017 *dotdot = '.';
2018 die(symmetric
2019 ? "Invalid symmetric difference expression %s"
2020 : "Invalid revision range %s", arg);
2021}
2022
2023static int handle_dotdot_1(const char *arg, char *dotdot,
2024 struct rev_info *revs, int flags,
Jeff King18f1ad72017-05-19 12:55:262025 int cant_be_filename,
2026 struct object_context *a_oc,
2027 struct object_context *b_oc)
Jeff King62faad52017-05-19 12:52:002028{
2029 const char *a_name, *b_name;
2030 struct object_id a_oid, b_oid;
2031 struct object *a_obj, *b_obj;
2032 unsigned int a_flags, b_flags;
2033 int symmetric = 0;
2034 unsigned int flags_exclude = flags ^ (UNINTERESTING | BOTTOM);
brian m. carlson321c89b2017-07-13 23:49:292035 unsigned int oc_flags = GET_OID_COMMITTISH | GET_OID_RECORD_PATH;
Jeff King62faad52017-05-19 12:52:002036
2037 a_name = arg;
2038 if (!*a_name)
2039 a_name = "HEAD";
2040
2041 b_name = dotdot + 2;
2042 if (*b_name == '.') {
2043 symmetric = 1;
2044 b_name++;
2045 }
2046 if (!*b_name)
2047 b_name = "HEAD";
2048
Nguyễn Thái Ngọc Duy3a7a6982019-01-12 02:13:282049 if (get_oid_with_context(revs->repo, a_name, oc_flags, &a_oid, a_oc) ||
2050 get_oid_with_context(revs->repo, b_name, oc_flags, &b_oid, b_oc))
Jeff King62faad52017-05-19 12:52:002051 return -1;
2052
2053 if (!cant_be_filename) {
2054 *dotdot = '.';
2055 verify_non_filename(revs->prefix, arg);
2056 *dotdot = '\0';
2057 }
2058
Nguyễn Thái Ngọc Duyb3c7eef2018-09-21 15:57:392059 a_obj = parse_object(revs->repo, &a_oid);
2060 b_obj = parse_object(revs->repo, &b_oid);
Jeff King62faad52017-05-19 12:52:002061 if (!a_obj || !b_obj)
2062 return dotdot_missing(arg, dotdot, revs, symmetric);
2063
2064 if (!symmetric) {
2065 /* just A..B */
2066 b_flags = flags;
2067 a_flags = flags_exclude;
2068 } else {
2069 /* A...B -- find merge bases between the two */
2070 struct commit *a, *b;
2071 struct commit_list *exclude;
2072
Nguyễn Thái Ngọc Duyb3c7eef2018-09-21 15:57:392073 a = lookup_commit_reference(revs->repo, &a_obj->oid);
2074 b = lookup_commit_reference(revs->repo, &b_obj->oid);
Jeff King62faad52017-05-19 12:52:002075 if (!a || !b)
2076 return dotdot_missing(arg, dotdot, revs, symmetric);
2077
Ævar Arnfjörð Bjarmasoncb338c22023-03-28 13:58:472078 exclude = repo_get_merge_bases(the_repository, a, b);
Jeff King62faad52017-05-19 12:52:002079 add_rev_cmdline_list(revs, exclude, REV_CMD_MERGE_BASE,
2080 flags_exclude);
2081 add_pending_commit_list(revs, exclude, flags_exclude);
2082 free_commit_list(exclude);
2083
2084 b_flags = flags;
2085 a_flags = flags | SYMMETRIC_LEFT;
2086 }
2087
2088 a_obj->flags |= a_flags;
2089 b_obj->flags |= b_flags;
2090 add_rev_cmdline(revs, a_obj, a_name, REV_CMD_LEFT, a_flags);
2091 add_rev_cmdline(revs, b_obj, b_name, REV_CMD_RIGHT, b_flags);
Jeff King18f1ad72017-05-19 12:55:262092 add_pending_object_with_path(revs, a_obj, a_name, a_oc->mode, a_oc->path);
2093 add_pending_object_with_path(revs, b_obj, b_name, b_oc->mode, b_oc->path);
Jeff King62faad52017-05-19 12:52:002094 return 0;
2095}
2096
2097static int handle_dotdot(const char *arg,
2098 struct rev_info *revs, int flags,
2099 int cant_be_filename)
2100{
Jeff King18f1ad72017-05-19 12:55:262101 struct object_context a_oc, b_oc;
Jeff King62faad52017-05-19 12:52:002102 char *dotdot = strstr(arg, "..");
2103 int ret;
2104
2105 if (!dotdot)
2106 return -1;
2107
Jeff King18f1ad72017-05-19 12:55:262108 memset(&a_oc, 0, sizeof(a_oc));
2109 memset(&b_oc, 0, sizeof(b_oc));
2110
Jeff King62faad52017-05-19 12:52:002111 *dotdot = '\0';
Jeff King18f1ad72017-05-19 12:55:262112 ret = handle_dotdot_1(arg, dotdot, revs, flags, cant_be_filename,
2113 &a_oc, &b_oc);
Jeff King62faad52017-05-19 12:52:002114 *dotdot = '.';
2115
Jeff King18f1ad72017-05-19 12:55:262116 free(a_oc.path);
2117 free(b_oc.path);
2118
Jeff King62faad52017-05-19 12:52:002119 return ret;
2120}
2121
Jeff King04a0e982020-08-26 20:13:052122static int handle_revision_arg_1(const char *arg_, struct rev_info *revs, int flags, unsigned revarg_opt)
Junio C Hamano5d6f0932006-09-06 04:28:362123{
Junio C Hamano249c8f42012-07-02 19:56:442124 struct object_context oc;
Jeff Kingf632ded2017-05-19 12:50:072125 char *mark;
Junio C Hamano5d6f0932006-09-06 04:28:362126 struct object *object;
brian m. carlson654b9a92017-05-06 22:10:272127 struct object_id oid;
Junio C Hamano5d6f0932006-09-06 04:28:362128 int local_flags;
Junio C Hamano281eee42011-08-26 00:35:392129 const char *arg = arg_;
Junio C Hamano8e676e82012-07-02 19:33:522130 int cant_be_filename = revarg_opt & REVARG_CANNOT_BE_FILENAME;
brian m. carlson321c89b2017-07-13 23:49:292131 unsigned get_sha1_flags = GET_OID_RECORD_PATH;
Junio C Hamano5d6f0932006-09-06 04:28:362132
Kevin Bracey7f34a462013-05-16 15:32:382133 flags = flags & UNINTERESTING ? flags | BOTTOM : flags & ~BOTTOM;
2134
Jeff Kingd89797f2017-05-19 12:51:402135 if (!cant_be_filename && !strcmp(arg, "..")) {
2136 /*
2137 * Just ".."? That is not a range but the
2138 * pathspec for the parent directory.
2139 */
2140 return -1;
Junio C Hamano5d6f0932006-09-06 04:28:362141 }
Vegard Nossum87793512016-09-27 08:32:492142
Jeff King62faad52017-05-19 12:52:002143 if (!handle_dotdot(arg, revs, flags, revarg_opt))
2144 return 0;
Junio C Hamano5d6f0932006-09-06 04:28:362145
Jeff Kingf632ded2017-05-19 12:50:072146 mark = strstr(arg, "^@");
2147 if (mark && !mark[2]) {
2148 *mark = 0;
Vegard Nossum87793512016-09-27 08:32:492149 if (add_parents_only(revs, arg, flags, 0))
Junio C Hamano5d6f0932006-09-06 04:28:362150 return 0;
Jeff Kingf632ded2017-05-19 12:50:072151 *mark = '^';
Junio C Hamano5d6f0932006-09-06 04:28:362152 }
Jeff Kingf632ded2017-05-19 12:50:072153 mark = strstr(arg, "^!");
2154 if (mark && !mark[2]) {
2155 *mark = 0;
Vegard Nossum87793512016-09-27 08:32:492156 if (!add_parents_only(revs, arg, flags ^ (UNINTERESTING | BOTTOM), 0))
Jeff Kingf632ded2017-05-19 12:50:072157 *mark = '^';
Vegard Nossum87793512016-09-27 08:32:492158 }
Jeff Kingf632ded2017-05-19 12:50:072159 mark = strstr(arg, "^-");
2160 if (mark) {
Vegard Nossum87793512016-09-27 08:32:492161 int exclude_parent = 1;
2162
Jeff Kingf632ded2017-05-19 12:50:072163 if (mark[2]) {
René Scharfe793c2112022-10-01 10:25:362164 if (strtol_i(mark + 2, 10, &exclude_parent) ||
2165 exclude_parent < 1)
Vegard Nossum87793512016-09-27 08:32:492166 return -1;
2167 }
2168
Jeff Kingf632ded2017-05-19 12:50:072169 *mark = 0;
Vegard Nossum87793512016-09-27 08:32:492170 if (!add_parents_only(revs, arg, flags ^ (UNINTERESTING | BOTTOM), exclude_parent))
Jeff Kingf632ded2017-05-19 12:50:072171 *mark = '^';
Junio C Hamano62476c82006-10-31 22:22:342172 }
2173
Junio C Hamano5d6f0932006-09-06 04:28:362174 local_flags = 0;
2175 if (*arg == '^') {
Kevin Bracey7f34a462013-05-16 15:32:382176 local_flags = UNINTERESTING | BOTTOM;
Junio C Hamano5d6f0932006-09-06 04:28:362177 arg++;
2178 }
Junio C Hamanod5f6b1d2012-07-02 19:43:052179
2180 if (revarg_opt & REVARG_COMMITTISH)
brian m. carlson321c89b2017-07-13 23:49:292181 get_sha1_flags |= GET_OID_COMMITTISH;
Junio C Hamanod5f6b1d2012-07-02 19:43:052182
Nguyễn Thái Ngọc Duy3a7a6982019-01-12 02:13:282183 if (get_oid_with_context(revs->repo, arg, get_sha1_flags, &oid, &oc))
Junio C Hamanocc243c32011-05-19 01:08:092184 return revs->ignore_missing ? 0 : -1;
Junio C Hamano5d6f0932006-09-06 04:28:362185 if (!cant_be_filename)
2186 verify_non_filename(revs->prefix, arg);
brian m. carlson654b9a92017-05-06 22:10:272187 object = get_reference(revs, arg, &oid, flags ^ local_flags);
Matthew DeVore4cf67862018-12-05 21:43:462188 if (!object)
2189 return revs->ignore_missing ? 0 : -1;
Junio C Hamano281eee42011-08-26 00:35:392190 add_rev_cmdline(revs, object, arg_, REV_CMD_REV, flags ^ local_flags);
Jeff King18f1ad72017-05-19 12:55:262191 add_pending_object_with_path(revs, object, arg, oc.mode, oc.path);
2192 free(oc.path);
Junio C Hamano5d6f0932006-09-06 04:28:362193 return 0;
2194}
2195
Jeff King04a0e982020-08-26 20:13:052196int handle_revision_arg(const char *arg, struct rev_info *revs, int flags, unsigned revarg_opt)
2197{
2198 int ret = handle_revision_arg_1(arg, revs, flags, revarg_opt);
2199 if (!ret)
2200 revs->rev_input_given = 1;
2201 return ret;
2202}
2203
Jeff King91633992019-03-20 08:13:362204static void read_pathspec_from_stdin(struct strbuf *sb,
Jeff Kingc972bf42020-07-28 20:25:122205 struct strvec *prune)
Junio C Hamano4da5af32011-05-11 21:01:192206{
Jeff King7fa3c2a2017-09-20 20:36:592207 while (strbuf_getline(sb, stdin) != EOF)
Jeff Kingc972bf42020-07-28 20:25:122208 strvec_push(prune, sb->buf);
Junio C Hamano60da8b12009-11-20 10:50:212209}
2210
Junio C Hamano2d10c552006-09-20 20:21:562211static void add_grep(struct rev_info *revs, const char *ptn, enum grep_pat_token what)
2212{
Jeff King0843acf2008-08-25 06:15:052213 append_grep_pattern(&revs->grep_filter, ptn, "command line", 0, what);
Junio C Hamano2d10c552006-09-20 20:21:562214}
2215
Junio C Hamanoa4d7d2c2008-09-05 05:15:022216static void add_header_grep(struct rev_info *revs, enum grep_header_field field, const char *pattern)
Junio C Hamanobd95fcd2006-09-18 00:23:202217{
Junio C Hamanoa4d7d2c2008-09-05 05:15:022218 append_header_grep_pattern(&revs->grep_filter, field, pattern);
Junio C Hamanobd95fcd2006-09-18 00:23:202219}
2220
2221static void add_message_grep(struct rev_info *revs, const char *pattern)
2222{
Junio C Hamano2d10c552006-09-20 20:21:562223 add_grep(revs, pattern, GREP_PATTERN_BODY);
Junio C Hamanobd95fcd2006-09-18 00:23:202224}
2225
Pierre Habouzit6b61ec02008-07-09 21:38:342226static int handle_revision_opt(struct rev_info *revs, int argc, const char **argv,
Matthew DeVorebbcde412018-12-03 22:10:192227 int *unkc, const char **unkv,
2228 const struct setup_revision_opt* opt)
Pierre Habouzit02e54222008-07-08 13:19:332229{
2230 const char *arg = argv[0];
Elijah Newren257418c2022-08-19 04:28:102231 const char *optarg = NULL;
Matthieu Moy7d7b86f2010-08-05 08:22:552232 int argcount;
brian m. carlsonfd521242018-05-02 00:25:502233 const unsigned hexsz = the_hash_algo->hexsz;
Pierre Habouzit02e54222008-07-08 13:19:332234
2235 /* pseudo revision arguments */
2236 if (!strcmp(arg, "--all") || !strcmp(arg, "--branches") ||
2237 !strcmp(arg, "--tags") || !strcmp(arg, "--remotes") ||
2238 !strcmp(arg, "--reflog") || !strcmp(arg, "--not") ||
Linus Torvaldsad3f9a72009-10-27 18:28:072239 !strcmp(arg, "--no-walk") || !strcmp(arg, "--do-walk") ||
Christian Couder59556542013-11-30 20:55:402240 !strcmp(arg, "--bisect") || starts_with(arg, "--glob=") ||
Jeff King4fe10212014-10-17 00:44:232241 !strcmp(arg, "--indexed-objects") ||
Jeff King39b44ba2019-07-01 13:18:152242 !strcmp(arg, "--alternate-refs") ||
Patrick Steinhardt8c1bc2a2022-11-17 05:46:562243 starts_with(arg, "--exclude=") || starts_with(arg, "--exclude-hidden=") ||
Christian Couder59556542013-11-30 20:55:402244 starts_with(arg, "--branches=") || starts_with(arg, "--tags=") ||
2245 starts_with(arg, "--remotes=") || starts_with(arg, "--no-walk="))
Pierre Habouzit02e54222008-07-08 13:19:332246 {
2247 unkv[(*unkc)++] = arg;
Pierre Habouzit0fe8c132008-07-31 10:22:232248 return 1;
Pierre Habouzit02e54222008-07-08 13:19:332249 }
2250
Matthieu Moy7d7b86f2010-08-05 08:22:552251 if ((argcount = parse_long_opt("max-count", argv, &optarg))) {
2252 revs->max_count = atoi(optarg);
Jonathan Nieder5853cae2010-06-01 08:35:492253 revs->no_walk = 0;
Matthieu Moy7d7b86f2010-08-05 08:22:552254 return argcount;
2255 } else if ((argcount = parse_long_opt("skip", argv, &optarg))) {
2256 revs->skip_count = atoi(optarg);
2257 return argcount;
Pierre Habouzit02e54222008-07-08 13:19:332258 } else if ((*arg == '-') && isdigit(arg[1])) {
Junio C Hamanoe3fa5682014-06-06 22:33:252259 /* accept -<digit>, like traditional "head" */
2260 if (strtol_i(arg + 1, 10, &revs->max_count) < 0 ||
2261 revs->max_count < 0)
2262 die("'%s': not a non-negative integer", arg + 1);
Jonathan Nieder5853cae2010-06-01 08:35:492263 revs->no_walk = 0;
Pierre Habouzit02e54222008-07-08 13:19:332264 } else if (!strcmp(arg, "-n")) {
2265 if (argc <= 1)
2266 return error("-n requires an argument");
2267 revs->max_count = atoi(argv[1]);
Jonathan Nieder5853cae2010-06-01 08:35:492268 revs->no_walk = 0;
Pierre Habouzit02e54222008-07-08 13:19:332269 return 2;
SZEDER Gábor479b3d92017-06-09 18:17:322270 } else if (skip_prefix(arg, "-n", &optarg)) {
2271 revs->max_count = atoi(optarg);
Jonathan Nieder5853cae2010-06-01 08:35:492272 revs->no_walk = 0;
Matthieu Moy7d7b86f2010-08-05 08:22:552273 } else if ((argcount = parse_long_opt("max-age", argv, &optarg))) {
2274 revs->max_age = atoi(optarg);
2275 return argcount;
2276 } else if ((argcount = parse_long_opt("since", argv, &optarg))) {
2277 revs->max_age = approxidate(optarg);
2278 return argcount;
Miklos Vajna96697782022-04-23 12:59:572279 } else if ((argcount = parse_long_opt("since-as-filter", argv, &optarg))) {
2280 revs->max_age_as_filter = approxidate(optarg);
2281 return argcount;
Matthieu Moy7d7b86f2010-08-05 08:22:552282 } else if ((argcount = parse_long_opt("after", argv, &optarg))) {
2283 revs->max_age = approxidate(optarg);
2284 return argcount;
2285 } else if ((argcount = parse_long_opt("min-age", argv, &optarg))) {
2286 revs->min_age = atoi(optarg);
2287 return argcount;
2288 } else if ((argcount = parse_long_opt("before", argv, &optarg))) {
2289 revs->min_age = approxidate(optarg);
2290 return argcount;
2291 } else if ((argcount = parse_long_opt("until", argv, &optarg))) {
2292 revs->min_age = approxidate(optarg);
2293 return argcount;
Pierre Habouzit02e54222008-07-08 13:19:332294 } else if (!strcmp(arg, "--first-parent")) {
2295 revs->first_parent_only = 1;
Jerry Zhang9d505b72022-01-11 21:39:412296 } else if (!strcmp(arg, "--exclude-first-parent-only")) {
2297 revs->exclude_first_parent_only = 1;
Junio C Hamanoebdc94f2010-04-20 20:48:392298 } else if (!strcmp(arg, "--ancestry-path")) {
2299 revs->ancestry_path = 1;
Johan Herlandcb7529e2010-06-03 23:17:372300 revs->simplify_history = 0;
Junio C Hamanoebdc94f2010-04-20 20:48:392301 revs->limited = 1;
Elijah Newren257418c2022-08-19 04:28:102302 revs->ancestry_path_implicit_bottoms = 1;
2303 } else if (skip_prefix(arg, "--ancestry-path=", &optarg)) {
2304 struct commit *c;
2305 struct object_id oid;
2306 const char *msg = _("could not get commit for ancestry-path argument %s");
2307
2308 revs->ancestry_path = 1;
2309 revs->simplify_history = 0;
2310 revs->limited = 1;
2311
2312 if (repo_get_oid_committish(revs->repo, optarg, &oid))
2313 return error(msg, optarg);
2314 get_reference(revs, optarg, &oid, ANCESTRY_PATH);
2315 c = lookup_commit_reference(revs->repo, &oid);
2316 if (!c)
2317 return error(msg, optarg);
2318 commit_list_insert(c, &revs->ancestry_path_bottoms);
Pierre Habouzit02e54222008-07-08 13:19:332319 } else if (!strcmp(arg, "-g") || !strcmp(arg, "--walk-reflogs")) {
2320 init_reflog_walk(&revs->reflog_info);
2321 } else if (!strcmp(arg, "--default")) {
2322 if (argc <= 1)
2323 return error("bad --default argument");
2324 revs->def = argv[1];
2325 return 2;
2326 } else if (!strcmp(arg, "--merge")) {
2327 revs->show_merge = 1;
2328 } else if (!strcmp(arg, "--topo-order")) {
Junio C Hamano08f704f2013-06-06 23:07:142329 revs->sort_order = REV_SORT_IN_GRAPH_ORDER;
Pierre Habouzit02e54222008-07-08 13:19:332330 revs->topo_order = 1;
Junio C Hamano6546b592008-07-31 08:17:412331 } else if (!strcmp(arg, "--simplify-merges")) {
2332 revs->simplify_merges = 1;
Junio C Hamanoa52f0072012-06-08 21:47:082333 revs->topo_order = 1;
Junio C Hamano6546b592008-07-31 08:17:412334 revs->rewrite_parents = 1;
2335 revs->simplify_history = 0;
2336 revs->limited = 1;
Linus Torvalds78892e32008-11-03 19:25:462337 } else if (!strcmp(arg, "--simplify-by-decoration")) {
2338 revs->simplify_merges = 1;
Junio C Hamanoa52f0072012-06-08 21:47:082339 revs->topo_order = 1;
Linus Torvalds78892e32008-11-03 19:25:462340 revs->rewrite_parents = 1;
2341 revs->simplify_history = 0;
2342 revs->simplify_by_decoration = 1;
2343 revs->limited = 1;
2344 revs->prune = 1;
Pierre Habouzit02e54222008-07-08 13:19:332345 } else if (!strcmp(arg, "--date-order")) {
Junio C Hamano08f704f2013-06-06 23:07:142346 revs->sort_order = REV_SORT_BY_COMMIT_DATE;
Pierre Habouzit02e54222008-07-08 13:19:332347 revs->topo_order = 1;
Junio C Hamano81c6b382013-06-07 17:35:542348 } else if (!strcmp(arg, "--author-date-order")) {
2349 revs->sort_order = REV_SORT_BY_AUTHOR_DATE;
Pierre Habouzit02e54222008-07-08 13:19:332350 revs->topo_order = 1;
SZEDER Gábordffc6512017-06-09 18:17:312351 } else if (!strcmp(arg, "--early-output")) {
2352 revs->early_output = 100;
2353 revs->topo_order = 1;
2354 } else if (skip_prefix(arg, "--early-output=", &optarg)) {
2355 if (strtoul_ui(optarg, 10, &revs->early_output) < 0)
2356 die("'%s': not a non-negative integer", optarg);
2357 revs->topo_order = 1;
Pierre Habouzit02e54222008-07-08 13:19:332358 } else if (!strcmp(arg, "--parents")) {
2359 revs->rewrite_parents = 1;
2360 revs->print_parents = 1;
2361 } else if (!strcmp(arg, "--dense")) {
2362 revs->dense = 1;
2363 } else if (!strcmp(arg, "--sparse")) {
2364 revs->dense = 0;
Stefan Bellerce5b6f92017-11-16 02:00:352365 } else if (!strcmp(arg, "--in-commit-order")) {
2366 revs->tree_blobs_in_commit_order = 1;
Pierre Habouzit02e54222008-07-08 13:19:332367 } else if (!strcmp(arg, "--remove-empty")) {
2368 revs->remove_empty_trees = 1;
Linus Torvaldsb8e8db22009-06-29 17:28:252369 } else if (!strcmp(arg, "--merges")) {
Michael J Gruberad5aeed2011-03-21 10:14:062370 revs->min_parents = 2;
Pierre Habouzit02e54222008-07-08 13:19:332371 } else if (!strcmp(arg, "--no-merges")) {
Michael J Gruberad5aeed2011-03-21 10:14:062372 revs->max_parents = 1;
SZEDER Gábor479b3d92017-06-09 18:17:322373 } else if (skip_prefix(arg, "--min-parents=", &optarg)) {
2374 revs->min_parents = atoi(optarg);
SZEDER Gábor9ada7ae2017-06-09 18:17:302375 } else if (!strcmp(arg, "--no-min-parents")) {
Michael J Gruberad5aeed2011-03-21 10:14:062376 revs->min_parents = 0;
SZEDER Gábor479b3d92017-06-09 18:17:322377 } else if (skip_prefix(arg, "--max-parents=", &optarg)) {
2378 revs->max_parents = atoi(optarg);
SZEDER Gábor9ada7ae2017-06-09 18:17:302379 } else if (!strcmp(arg, "--no-max-parents")) {
Michael J Gruberad5aeed2011-03-21 10:14:062380 revs->max_parents = -1;
Pierre Habouzit02e54222008-07-08 13:19:332381 } else if (!strcmp(arg, "--boundary")) {
2382 revs->boundary = 1;
2383 } else if (!strcmp(arg, "--left-right")) {
2384 revs->left_right = 1;
Michael J Gruber60adf7d2011-02-21 16:09:112385 } else if (!strcmp(arg, "--left-only")) {
Junio C Hamano24852d92011-02-22 00:58:372386 if (revs->right_only)
Michael J Gruber94f605e2011-03-07 12:31:422387 die("--left-only is incompatible with --right-only"
2388 " or --cherry");
Michael J Gruber60adf7d2011-02-21 16:09:112389 revs->left_only = 1;
2390 } else if (!strcmp(arg, "--right-only")) {
Junio C Hamano24852d92011-02-22 00:58:372391 if (revs->left_only)
Jean-Noël Avila12909b62022-01-05 20:02:162392 die(_("options '%s' and '%s' cannot be used together"), "--right-only", "--left-only");
Michael J Gruber60adf7d2011-02-21 16:09:112393 revs->right_only = 1;
Michael J Gruber94f605e2011-03-07 12:31:422394 } else if (!strcmp(arg, "--cherry")) {
2395 if (revs->left_only)
Jean-Noël Avila12909b62022-01-05 20:02:162396 die(_("options '%s' and '%s' cannot be used together"), "--cherry", "--left-only");
Michael J Gruber94f605e2011-03-07 12:31:422397 revs->cherry_mark = 1;
2398 revs->right_only = 1;
Michael J Gruberad5aeed2011-03-21 10:14:062399 revs->max_parents = 1;
Michael J Gruber94f605e2011-03-07 12:31:422400 revs->limited = 1;
Thomas Rastf69c5012010-06-10 11:47:232401 } else if (!strcmp(arg, "--count")) {
2402 revs->count = 1;
Michael J Gruberadbbb312011-03-07 12:31:402403 } else if (!strcmp(arg, "--cherry-mark")) {
2404 if (revs->cherry_pick)
Jean-Noël Avila12909b62022-01-05 20:02:162405 die(_("options '%s' and '%s' cannot be used together"), "--cherry-mark", "--cherry-pick");
Michael J Gruberadbbb312011-03-07 12:31:402406 revs->cherry_mark = 1;
2407 revs->limited = 1; /* needs limit_list() */
Pierre Habouzit02e54222008-07-08 13:19:332408 } else if (!strcmp(arg, "--cherry-pick")) {
Michael J Gruberadbbb312011-03-07 12:31:402409 if (revs->cherry_mark)
Jean-Noël Avila12909b62022-01-05 20:02:162410 die(_("options '%s' and '%s' cannot be used together"), "--cherry-pick", "--cherry-mark");
Pierre Habouzit02e54222008-07-08 13:19:332411 revs->cherry_pick = 1;
2412 revs->limited = 1;
2413 } else if (!strcmp(arg, "--objects")) {
2414 revs->tag_objects = 1;
2415 revs->tree_objects = 1;
2416 revs->blob_objects = 1;
2417 } else if (!strcmp(arg, "--objects-edge")) {
2418 revs->tag_objects = 1;
2419 revs->tree_objects = 1;
2420 revs->blob_objects = 1;
2421 revs->edge_hint = 1;
brian m. carlson1684c1b2014-12-24 23:05:392422 } else if (!strcmp(arg, "--objects-edge-aggressive")) {
2423 revs->tag_objects = 1;
2424 revs->tree_objects = 1;
2425 revs->blob_objects = 1;
2426 revs->edge_hint = 1;
2427 revs->edge_hint_aggressive = 1;
Junio C Hamano5a48d242011-09-01 22:43:342428 } else if (!strcmp(arg, "--verify-objects")) {
2429 revs->tag_objects = 1;
2430 revs->tree_objects = 1;
2431 revs->blob_objects = 1;
2432 revs->verify_objects = 1;
Jeff Kingb27ccae2022-09-06 21:04:352433 disable_commit_graph(revs->repo);
Pierre Habouzit02e54222008-07-08 13:19:332434 } else if (!strcmp(arg, "--unpacked")) {
2435 revs->unpacked = 1;
Christian Couder59556542013-11-30 20:55:402436 } else if (starts_with(arg, "--unpacked=")) {
Sergey Organovf649aaa2020-08-04 22:26:302437 die(_("--unpacked=<packfile> no longer supported"));
Taylor Blauc9fff002021-02-23 02:25:072438 } else if (!strcmp(arg, "--no-kept-objects")) {
2439 revs->no_kept_objects = 1;
2440 revs->keep_pack_cache_flags |= IN_CORE_KEEP_PACKS;
2441 revs->keep_pack_cache_flags |= ON_DISK_KEEP_PACKS;
2442 } else if (skip_prefix(arg, "--no-kept-objects=", &optarg)) {
2443 revs->no_kept_objects = 1;
2444 if (!strcmp(optarg, "in-core"))
2445 revs->keep_pack_cache_flags |= IN_CORE_KEEP_PACKS;
2446 if (!strcmp(optarg, "on-disk"))
2447 revs->keep_pack_cache_flags |= ON_DISK_KEEP_PACKS;
Pierre Habouzit02e54222008-07-08 13:19:332448 } else if (!strcmp(arg, "-r")) {
2449 revs->diff = 1;
Brandon Williams0d1e0e72017-10-31 18:19:112450 revs->diffopt.flags.recursive = 1;
Pierre Habouzit02e54222008-07-08 13:19:332451 } else if (!strcmp(arg, "-t")) {
2452 revs->diff = 1;
Brandon Williams0d1e0e72017-10-31 18:19:112453 revs->diffopt.flags.recursive = 1;
2454 revs->diffopt.flags.tree_in_recursive = 1;
Sergey Organov18f09472020-12-21 15:19:342455 } else if ((argcount = diff_merges_parse_opts(revs, argv))) {
Sergey Organov65015802020-08-05 22:08:302456 return argcount;
Pierre Habouzit02e54222008-07-08 13:19:332457 } else if (!strcmp(arg, "-v")) {
2458 revs->verbose_header = 1;
2459 } else if (!strcmp(arg, "--pretty")) {
2460 revs->verbose_header = 1;
Junio C Hamano66b2ed02010-01-20 21:59:362461 revs->pretty_given = 1;
Jeff Kingae181652014-07-29 17:53:402462 get_commit_format(NULL, revs);
SZEDER Gábor479b3d92017-06-09 18:17:322463 } else if (skip_prefix(arg, "--pretty=", &optarg) ||
2464 skip_prefix(arg, "--format=", &optarg)) {
Matthieu Moy7d7b86f2010-08-05 08:22:552465 /*
2466 * Detached form ("--pretty X" as opposed to "--pretty=X")
2467 * not allowed, since the argument is optional.
2468 */
Pierre Habouzit02e54222008-07-08 13:19:332469 revs->verbose_header = 1;
Junio C Hamano66b2ed02010-01-20 21:59:362470 revs->pretty_given = 1;
SZEDER Gábor479b3d92017-06-09 18:17:322471 get_commit_format(optarg, revs);
Linus Torvalds7cc13c72016-03-16 16:15:532472 } else if (!strcmp(arg, "--expand-tabs")) {
Junio C Hamanofe37a9c2016-03-29 23:05:392473 revs->expand_tabs_in_log = 8;
Junio C Hamano0893eec2016-03-29 22:49:242474 } else if (!strcmp(arg, "--no-expand-tabs")) {
2475 revs->expand_tabs_in_log = 0;
Junio C Hamanofe37a9c2016-03-29 23:05:392476 } else if (skip_prefix(arg, "--expand-tabs=", &arg)) {
2477 int val;
2478 if (strtol_i(arg, 10, &val) < 0 || val < 0)
2479 die("'%s': not a non-negative integer", arg);
2480 revs->expand_tabs_in_log = val;
Jeff King7249e912011-03-29 20:57:472481 } else if (!strcmp(arg, "--show-notes") || !strcmp(arg, "--notes")) {
Denton Liu1d729752019-12-12 00:49:502482 enable_default_display_notes(&revs->notes_opt, &revs->show_notes);
Junio C Hamano66b2ed02010-01-20 21:59:362483 revs->show_notes_given = 1;
Junio C Hamano0c37f1f2011-10-18 22:53:232484 } else if (!strcmp(arg, "--show-signature")) {
2485 revs->show_signature = 1;
Mehul Jainaa379992016-06-22 16:51:252486 } else if (!strcmp(arg, "--no-show-signature")) {
2487 revs->show_signature = 0;
SZEDER Gábor479b3d92017-06-09 18:17:322488 } else if (!strcmp(arg, "--show-linear-break")) {
2489 revs->break_bar = " ..........";
Nguyễn Thái Ngọc Duy1b32dec2014-03-25 13:23:272490 revs->track_linear = 1;
2491 revs->track_first_time = 1;
SZEDER Gábor479b3d92017-06-09 18:17:322492 } else if (skip_prefix(arg, "--show-linear-break=", &optarg)) {
2493 revs->break_bar = xstrdup(optarg);
2494 revs->track_linear = 1;
2495 revs->track_first_time = 1;
Kristoffer Haugsbakk2e0d30d2023-09-19 20:26:502496 } else if (!strcmp(arg, "--show-notes-by-default")) {
2497 revs->show_notes_by_default = 1;
SZEDER Gábor479b3d92017-06-09 18:17:322498 } else if (skip_prefix(arg, "--show-notes=", &optarg) ||
2499 skip_prefix(arg, "--notes=", &optarg)) {
SZEDER Gábor479b3d92017-06-09 18:17:322500 if (starts_with(arg, "--show-notes=") &&
2501 revs->notes_opt.use_default_notes < 0)
2502 revs->notes_opt.use_default_notes = 1;
Denton Liu1d729752019-12-12 00:49:502503 enable_ref_display_notes(&revs->notes_opt, &revs->show_notes, optarg);
Junio C Hamano66b2ed02010-01-20 21:59:362504 revs->show_notes_given = 1;
Denton Liu452538c2019-12-09 13:10:442505 } else if (!strcmp(arg, "--no-notes")) {
Denton Liu1d729752019-12-12 00:49:502506 disable_display_notes(&revs->notes_opt, &revs->show_notes);
Denton Liu452538c2019-12-09 13:10:442507 revs->show_notes_given = 1;
Thomas Rast894a9d32010-03-12 17:04:262508 } else if (!strcmp(arg, "--standard-notes")) {
2509 revs->show_notes_given = 1;
Jeff King3a03cf62011-03-29 20:57:272510 revs->notes_opt.use_default_notes = 1;
Thomas Rast894a9d32010-03-12 17:04:262511 } else if (!strcmp(arg, "--no-standard-notes")) {
Jeff King3a03cf62011-03-29 20:57:272512 revs->notes_opt.use_default_notes = 0;
Nanako Shiraishide84acc2009-02-24 09:59:162513 } else if (!strcmp(arg, "--oneline")) {
2514 revs->verbose_header = 1;
2515 get_commit_format("oneline", revs);
Junio C Hamano7dccadf2010-01-21 22:57:412516 revs->pretty_given = 1;
Nanako Shiraishide84acc2009-02-24 09:59:162517 revs->abbrev_commit = 1;
Pierre Habouzit02e54222008-07-08 13:19:332518 } else if (!strcmp(arg, "--graph")) {
Alex Henriedccf6c12022-02-11 16:36:242519 graph_clear(revs->graph);
Pierre Habouzit02e54222008-07-08 13:19:332520 revs->graph = graph_init(revs);
Alex Henrie087c7452022-02-11 16:36:252521 } else if (!strcmp(arg, "--no-graph")) {
2522 graph_clear(revs->graph);
2523 revs->graph = NULL;
Emma Brooks19d097e2020-04-08 04:31:382524 } else if (!strcmp(arg, "--encode-email-headers")) {
2525 revs->encode_email_headers = 1;
2526 } else if (!strcmp(arg, "--no-encode-email-headers")) {
2527 revs->encode_email_headers = 0;
Pierre Habouzit02e54222008-07-08 13:19:332528 } else if (!strcmp(arg, "--root")) {
2529 revs->show_root_diff = 1;
2530 } else if (!strcmp(arg, "--no-commit-id")) {
2531 revs->no_commit_id = 1;
2532 } else if (!strcmp(arg, "--always")) {
2533 revs->always_show_header = 1;
2534 } else if (!strcmp(arg, "--no-abbrev")) {
2535 revs->abbrev = 0;
2536 } else if (!strcmp(arg, "--abbrev")) {
2537 revs->abbrev = DEFAULT_ABBREV;
SZEDER Gábor479b3d92017-06-09 18:17:322538 } else if (skip_prefix(arg, "--abbrev=", &optarg)) {
2539 revs->abbrev = strtoul(optarg, NULL, 10);
Pierre Habouzit02e54222008-07-08 13:19:332540 if (revs->abbrev < MINIMUM_ABBREV)
2541 revs->abbrev = MINIMUM_ABBREV;
brian m. carlsonfd521242018-05-02 00:25:502542 else if (revs->abbrev > hexsz)
2543 revs->abbrev = hexsz;
Pierre Habouzit02e54222008-07-08 13:19:332544 } else if (!strcmp(arg, "--abbrev-commit")) {
2545 revs->abbrev_commit = 1;
Jay Soffian0c476952011-05-18 17:56:042546 revs->abbrev_commit_given = 1;
2547 } else if (!strcmp(arg, "--no-abbrev-commit")) {
2548 revs->abbrev_commit = 0;
Pierre Habouzit02e54222008-07-08 13:19:332549 } else if (!strcmp(arg, "--full-diff")) {
2550 revs->diff = 1;
2551 revs->full_diff = 1;
Derrick Stolee8d049e12020-04-10 12:19:432552 } else if (!strcmp(arg, "--show-pulls")) {
2553 revs->show_pulls = 1;
Pierre Habouzit02e54222008-07-08 13:19:332554 } else if (!strcmp(arg, "--full-history")) {
2555 revs->simplify_history = 0;
2556 } else if (!strcmp(arg, "--relative-date")) {
Jeff Kinga5481a62015-06-25 16:55:022557 revs->date_mode.type = DATE_RELATIVE;
Jeff Kingf4ea32f2009-09-24 08:28:152558 revs->date_mode_explicit = 1;
Matthieu Moy7d7b86f2010-08-05 08:22:552559 } else if ((argcount = parse_long_opt("date", argv, &optarg))) {
Jeff Kinga5481a62015-06-25 16:55:022560 parse_date_format(optarg, &revs->date_mode);
Jeff Kingf4ea32f2009-09-24 08:28:152561 revs->date_mode_explicit = 1;
Matthieu Moy7d7b86f2010-08-05 08:22:552562 return argcount;
Pierre Habouzit02e54222008-07-08 13:19:332563 } else if (!strcmp(arg, "--log-size")) {
2564 revs->show_log_size = 1;
2565 }
2566 /*
2567 * Grepping the commit log
2568 */
Matthieu Moy7d7b86f2010-08-05 08:22:552569 else if ((argcount = parse_long_opt("author", argv, &optarg))) {
2570 add_header_grep(revs, GREP_HEADER_AUTHOR, optarg);
2571 return argcount;
2572 } else if ((argcount = parse_long_opt("committer", argv, &optarg))) {
2573 add_header_grep(revs, GREP_HEADER_COMMITTER, optarg);
2574 return argcount;
Nguyễn Thái Ngọc Duy72fd13f2012-09-29 04:41:282575 } else if ((argcount = parse_long_opt("grep-reflog", argv, &optarg))) {
2576 add_header_grep(revs, GREP_HEADER_REFLOG, optarg);
2577 return argcount;
Matthieu Moy7d7b86f2010-08-05 08:22:552578 } else if ((argcount = parse_long_opt("grep", argv, &optarg))) {
2579 add_message_grep(revs, optarg);
2580 return argcount;
Junio C Hamano727b6fc2012-10-03 22:01:342581 } else if (!strcmp(arg, "--basic-regexp")) {
Junio C Hamano84655412016-07-22 18:43:142582 revs->grep_filter.pattern_type_option = GREP_PATTERN_TYPE_BRE;
Pierre Habouzit02e54222008-07-08 13:19:332583 } else if (!strcmp(arg, "--extended-regexp") || !strcmp(arg, "-E")) {
Junio C Hamano84655412016-07-22 18:43:142584 revs->grep_filter.pattern_type_option = GREP_PATTERN_TYPE_ERE;
Pierre Habouzit02e54222008-07-08 13:19:332585 } else if (!strcmp(arg, "--regexp-ignore-case") || !strcmp(arg, "-i")) {
Ævar Arnfjörð Bjarmason9e3cbc52017-05-20 21:42:082586 revs->grep_filter.ignore_case = 1;
Stefan Bellerc1ddc462018-01-04 22:50:402587 revs->diffopt.pickaxe_opts |= DIFF_PICKAXE_IGNORE_CASE;
Pierre Habouzit02e54222008-07-08 13:19:332588 } else if (!strcmp(arg, "--fixed-strings") || !strcmp(arg, "-F")) {
Junio C Hamano84655412016-07-22 18:43:142589 revs->grep_filter.pattern_type_option = GREP_PATTERN_TYPE_FIXED;
Ævar Arnfjörð Bjarmason7531a2d2017-05-25 20:05:242590 } else if (!strcmp(arg, "--perl-regexp") || !strcmp(arg, "-P")) {
Junio C Hamano84655412016-07-22 18:43:142591 revs->grep_filter.pattern_type_option = GREP_PATTERN_TYPE_PCRE;
Pierre Habouzit02e54222008-07-08 13:19:332592 } else if (!strcmp(arg, "--all-match")) {
Jeff King0843acf2008-08-25 06:15:052593 revs->grep_filter.all_match = 1;
Christoph Junghans22dfa8a2015-01-13 01:33:322594 } else if (!strcmp(arg, "--invert-grep")) {
René Scharfe794c0002021-12-17 16:48:492595 revs->grep_filter.no_body_match = 1;
Matthieu Moy7d7b86f2010-08-05 08:22:552596 } else if ((argcount = parse_long_opt("encoding", argv, &optarg))) {
2597 if (strcmp(optarg, "none"))
2598 git_log_output_encoding = xstrdup(optarg);
Pierre Habouzit02e54222008-07-08 13:19:332599 else
2600 git_log_output_encoding = "";
Matthieu Moy7d7b86f2010-08-05 08:22:552601 return argcount;
Pierre Habouzit02e54222008-07-08 13:19:332602 } else if (!strcmp(arg, "--reverse")) {
2603 revs->reverse ^= 1;
2604 } else if (!strcmp(arg, "--children")) {
2605 revs->children.name = "children";
2606 revs->limited = 1;
Junio C Hamanocc243c32011-05-19 01:08:092607 } else if (!strcmp(arg, "--ignore-missing")) {
2608 revs->ignore_missing = 1;
Matthew DeVorebbcde412018-12-03 22:10:192609 } else if (opt && opt->allow_exclude_promisor_objects &&
Matthew DeVore669b1d22018-10-23 01:13:422610 !strcmp(arg, "--exclude-promisor-objects")) {
Jonathan Tandf11e192017-12-08 15:27:152611 if (fetch_if_missing)
Johannes Schindelin033abf92018-05-02 09:38:392612 BUG("exclude_promisor_objects can only be used when fetch_if_missing is 0");
Jonathan Tandf11e192017-12-08 15:27:152613 revs->exclude_promisor_objects = 1;
Pierre Habouzit02e54222008-07-08 13:19:332614 } else {
Duy Nguyena97262c2016-01-21 11:48:442615 int opts = diff_opt_parse(&revs->diffopt, argv, argc, revs->prefix);
Pierre Habouzit02e54222008-07-08 13:19:332616 if (!opts)
2617 unkv[(*unkc)++] = arg;
2618 return opts;
2619 }
Pierre Habouzit02e54222008-07-08 13:19:332620
2621 return 1;
2622}
2623
Pierre Habouzit6b61ec02008-07-09 21:38:342624void parse_revision_opt(struct rev_info *revs, struct parse_opt_ctx_t *ctx,
2625 const struct option *options,
2626 const char * const usagestr[])
2627{
2628 int n = handle_revision_opt(revs, ctx->argc, ctx->argv,
Matthew DeVorebbcde412018-12-03 22:10:192629 &ctx->cpidx, ctx->out, NULL);
Pierre Habouzit6b61ec02008-07-09 21:38:342630 if (n <= 0) {
2631 error("unknown option `%s'", ctx->argv[0]);
2632 usage_with_options(usagestr, options);
2633 }
2634 ctx->argv += n;
2635 ctx->argc -= n;
2636}
2637
Alex Henrie087c7452022-02-11 16:36:252638void revision_opts_finish(struct rev_info *revs)
2639{
2640 if (revs->graph && revs->track_linear)
2641 die(_("options '%s' and '%s' cannot be used together"), "--show-linear-break", "--graph");
2642
2643 if (revs->graph) {
2644 revs->topo_order = 1;
2645 revs->rewrite_parents = 1;
2646 }
2647}
2648
Nguyễn Thái Ngọc Duy073cf632017-08-23 12:36:562649static int for_each_bisect_ref(struct ref_store *refs, each_ref_fn fn,
2650 void *cb_data, const char *term)
2651{
Antoine Delaitecb46d632015-06-29 15:40:302652 struct strbuf bisect_refs = STRBUF_INIT;
2653 int status;
2654 strbuf_addf(&bisect_refs, "refs/bisect/%s", term);
Taylor Blaub269ac52023-07-10 21:12:222655 status = refs_for_each_fullref_in(refs, bisect_refs.buf, NULL, fn, cb_data);
Antoine Delaitecb46d632015-06-29 15:40:302656 strbuf_release(&bisect_refs);
2657 return status;
2658}
2659
Nguyễn Thái Ngọc Duy073cf632017-08-23 12:36:562660static int for_each_bad_bisect_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data)
Linus Torvaldsad3f9a72009-10-27 18:28:072661{
Nguyễn Thái Ngọc Duy073cf632017-08-23 12:36:562662 return for_each_bisect_ref(refs, fn, cb_data, term_bad);
Linus Torvaldsad3f9a72009-10-27 18:28:072663}
2664
Nguyễn Thái Ngọc Duy073cf632017-08-23 12:36:562665static int for_each_good_bisect_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data)
Linus Torvaldsad3f9a72009-10-27 18:28:072666{
Nguyễn Thái Ngọc Duy073cf632017-08-23 12:36:562667 return for_each_bisect_ref(refs, fn, cb_data, term_good);
Linus Torvaldsad3f9a72009-10-27 18:28:072668}
2669
Jonathan Tan10a0d6a2021-09-09 18:47:292670static int handle_revision_pseudo_opt(struct rev_info *revs,
Jeff Kinge885a842020-09-30 12:28:182671 const char **argv, int *flags)
Jonathan Niederf6aca0d2011-04-21 10:45:072672{
2673 const char *arg = argv[0];
2674 const char *optarg;
Nguyễn Thái Ngọc Duy073cf632017-08-23 12:36:562675 struct ref_store *refs;
Jonathan Niederf6aca0d2011-04-21 10:45:072676 int argcount;
2677
Jonathan Tan10a0d6a2021-09-09 18:47:292678 if (revs->repo != the_repository) {
Nguyễn Thái Ngọc Duyd0c39a42017-08-23 12:36:592679 /*
2680 * We need some something like get_submodule_worktrees()
2681 * before we can go through all worktrees of a submodule,
2682 * .e.g with adding all HEADs from --all, which is not
2683 * supported right now, so stick to single worktree.
2684 */
2685 if (!revs->single_worktree)
Johannes Schindelin033abf92018-05-02 09:38:392686 BUG("--single-worktree cannot be used together with submodule");
Jonathan Tan10a0d6a2021-09-09 18:47:292687 }
2688 refs = get_main_ref_store(revs->repo);
Nguyễn Thái Ngọc Duy073cf632017-08-23 12:36:562689
Jonathan Nieder0fc63ec2011-04-21 10:48:242690 /*
2691 * NOTE!
2692 *
2693 * Commands like "git shortlog" will not accept the options below
2694 * unless parse_revision_opt queues them (as opposed to erroring
2695 * out).
2696 *
2697 * When implementing your new pseudo-option, remember to
2698 * register it in the list at the top of handle_revision_opt.
2699 */
Jonathan Niederf6aca0d2011-04-21 10:45:072700 if (!strcmp(arg, "--all")) {
Nguyễn Thái Ngọc Duy073cf632017-08-23 12:36:562701 handle_refs(refs, revs, *flags, refs_for_each_ref);
2702 handle_refs(refs, revs, *flags, refs_head_ref);
Nguyễn Thái Ngọc Duyd0c39a42017-08-23 12:36:592703 if (!revs->single_worktree) {
2704 struct all_refs_cb cb;
2705
2706 init_all_refs_cb(&cb, revs, *flags);
2707 other_head_refs(handle_one_ref, &cb);
2708 }
Patrick Steinhardt1e9f2732022-11-17 05:46:512709 clear_ref_exclusions(&revs->ref_excludes);
Jonathan Niederf6aca0d2011-04-21 10:45:072710 } else if (!strcmp(arg, "--branches")) {
Patrick Steinhardt8c1bc2a2022-11-17 05:46:562711 if (revs->ref_excludes.hidden_refs_configured)
2712 return error(_("--exclude-hidden cannot be used together with --branches"));
Nguyễn Thái Ngọc Duy073cf632017-08-23 12:36:562713 handle_refs(refs, revs, *flags, refs_for_each_branch_ref);
Patrick Steinhardt1e9f2732022-11-17 05:46:512714 clear_ref_exclusions(&revs->ref_excludes);
Jonathan Niederf6aca0d2011-04-21 10:45:072715 } else if (!strcmp(arg, "--bisect")) {
Antoine Delaitecb46d632015-06-29 15:40:302716 read_bisect_terms(&term_bad, &term_good);
Nguyễn Thái Ngọc Duy073cf632017-08-23 12:36:562717 handle_refs(refs, revs, *flags, for_each_bad_bisect_ref);
2718 handle_refs(refs, revs, *flags ^ (UNINTERESTING | BOTTOM),
2719 for_each_good_bisect_ref);
Jonathan Niederf6aca0d2011-04-21 10:45:072720 revs->bisect = 1;
2721 } else if (!strcmp(arg, "--tags")) {
Patrick Steinhardt8c1bc2a2022-11-17 05:46:562722 if (revs->ref_excludes.hidden_refs_configured)
2723 return error(_("--exclude-hidden cannot be used together with --tags"));
Nguyễn Thái Ngọc Duy073cf632017-08-23 12:36:562724 handle_refs(refs, revs, *flags, refs_for_each_tag_ref);
Patrick Steinhardt1e9f2732022-11-17 05:46:512725 clear_ref_exclusions(&revs->ref_excludes);
Jonathan Niederf6aca0d2011-04-21 10:45:072726 } else if (!strcmp(arg, "--remotes")) {
Patrick Steinhardt8c1bc2a2022-11-17 05:46:562727 if (revs->ref_excludes.hidden_refs_configured)
2728 return error(_("--exclude-hidden cannot be used together with --remotes"));
Nguyễn Thái Ngọc Duy073cf632017-08-23 12:36:562729 handle_refs(refs, revs, *flags, refs_for_each_remote_ref);
Patrick Steinhardt1e9f2732022-11-17 05:46:512730 clear_ref_exclusions(&revs->ref_excludes);
Jonathan Niederf6aca0d2011-04-21 10:45:072731 } else if ((argcount = parse_long_opt("glob", argv, &optarg))) {
2732 struct all_refs_cb cb;
2733 init_all_refs_cb(&cb, revs, *flags);
Michael Haggertya217dcb2015-05-25 18:38:302734 for_each_glob_ref(handle_one_ref, optarg, &cb);
Patrick Steinhardt1e9f2732022-11-17 05:46:512735 clear_ref_exclusions(&revs->ref_excludes);
Junio C Hamanoe7b432c2013-08-30 23:37:552736 return argcount;
2737 } else if ((argcount = parse_long_opt("exclude", argv, &optarg))) {
Junio C Hamanoff32d342013-11-01 19:02:452738 add_ref_exclusion(&revs->ref_excludes, optarg);
Jonathan Niederf6aca0d2011-04-21 10:45:072739 return argcount;
Patrick Steinhardt8c1bc2a2022-11-17 05:46:562740 } else if ((argcount = parse_long_opt("exclude-hidden", argv, &optarg))) {
2741 exclude_hidden_refs(&revs->ref_excludes, optarg);
2742 return argcount;
SZEDER Gábor8b1d9132017-06-09 18:17:332743 } else if (skip_prefix(arg, "--branches=", &optarg)) {
Jonathan Niederf6aca0d2011-04-21 10:45:072744 struct all_refs_cb cb;
Patrick Steinhardt8c1bc2a2022-11-17 05:46:562745 if (revs->ref_excludes.hidden_refs_configured)
2746 return error(_("--exclude-hidden cannot be used together with --branches"));
Jonathan Niederf6aca0d2011-04-21 10:45:072747 init_all_refs_cb(&cb, revs, *flags);
SZEDER Gábor8b1d9132017-06-09 18:17:332748 for_each_glob_ref_in(handle_one_ref, optarg, "refs/heads/", &cb);
Patrick Steinhardt1e9f2732022-11-17 05:46:512749 clear_ref_exclusions(&revs->ref_excludes);
SZEDER Gábor8b1d9132017-06-09 18:17:332750 } else if (skip_prefix(arg, "--tags=", &optarg)) {
Jonathan Niederf6aca0d2011-04-21 10:45:072751 struct all_refs_cb cb;
Patrick Steinhardt8c1bc2a2022-11-17 05:46:562752 if (revs->ref_excludes.hidden_refs_configured)
2753 return error(_("--exclude-hidden cannot be used together with --tags"));
Jonathan Niederf6aca0d2011-04-21 10:45:072754 init_all_refs_cb(&cb, revs, *flags);
SZEDER Gábor8b1d9132017-06-09 18:17:332755 for_each_glob_ref_in(handle_one_ref, optarg, "refs/tags/", &cb);
Patrick Steinhardt1e9f2732022-11-17 05:46:512756 clear_ref_exclusions(&revs->ref_excludes);
SZEDER Gábor8b1d9132017-06-09 18:17:332757 } else if (skip_prefix(arg, "--remotes=", &optarg)) {
Jonathan Niederf6aca0d2011-04-21 10:45:072758 struct all_refs_cb cb;
Patrick Steinhardt8c1bc2a2022-11-17 05:46:562759 if (revs->ref_excludes.hidden_refs_configured)
2760 return error(_("--exclude-hidden cannot be used together with --remotes"));
Jonathan Niederf6aca0d2011-04-21 10:45:072761 init_all_refs_cb(&cb, revs, *flags);
SZEDER Gábor8b1d9132017-06-09 18:17:332762 for_each_glob_ref_in(handle_one_ref, optarg, "refs/remotes/", &cb);
Patrick Steinhardt1e9f2732022-11-17 05:46:512763 clear_ref_exclusions(&revs->ref_excludes);
Jonathan Niederf6aca0d2011-04-21 10:45:072764 } else if (!strcmp(arg, "--reflog")) {
Jeff King718ccc92014-10-15 22:38:312765 add_reflogs_to_pending(revs, *flags);
Jeff King4fe10212014-10-17 00:44:232766 } else if (!strcmp(arg, "--indexed-objects")) {
2767 add_index_objects_to_pending(revs, *flags);
Jeff King39b44ba2019-07-01 13:18:152768 } else if (!strcmp(arg, "--alternate-refs")) {
2769 add_alternate_refs_to_pending(revs, *flags);
Jonathan Niederf6aca0d2011-04-21 10:45:072770 } else if (!strcmp(arg, "--not")) {
Kevin Bracey7f34a462013-05-16 15:32:382771 *flags ^= UNINTERESTING | BOTTOM;
Jonathan Niederf6aca0d2011-04-21 10:45:072772 } else if (!strcmp(arg, "--no-walk")) {
Patrick Steinhardt29ef1f22021-08-05 11:25:242773 revs->no_walk = 1;
SZEDER Gábor8b1d9132017-06-09 18:17:332774 } else if (skip_prefix(arg, "--no-walk=", &optarg)) {
Martin von Zweigbergkca92e592012-08-29 06:15:542775 /*
2776 * Detached form ("--no-walk X" as opposed to "--no-walk=X")
2777 * not allowed, since the argument is optional.
2778 */
Patrick Steinhardt29ef1f22021-08-05 11:25:242779 revs->no_walk = 1;
SZEDER Gábor8b1d9132017-06-09 18:17:332780 if (!strcmp(optarg, "sorted"))
Patrick Steinhardt29ef1f22021-08-05 11:25:242781 revs->unsorted_input = 0;
SZEDER Gábor8b1d9132017-06-09 18:17:332782 else if (!strcmp(optarg, "unsorted"))
Patrick Steinhardt29ef1f22021-08-05 11:25:242783 revs->unsorted_input = 1;
Martin von Zweigbergkca92e592012-08-29 06:15:542784 else
2785 return error("invalid argument to --no-walk");
Jonathan Niederf6aca0d2011-04-21 10:45:072786 } else if (!strcmp(arg, "--do-walk")) {
2787 revs->no_walk = 0;
Nguyễn Thái Ngọc Duy32619f92017-08-23 12:37:022788 } else if (!strcmp(arg, "--single-worktree")) {
2789 revs->single_worktree = 1;
Derrick Stoleecc910442022-03-22 17:28:352790 } else if (skip_prefix(arg, ("--filter="), &arg)) {
Derrick Stoleec4ea5132022-03-09 16:01:402791 parse_list_objects_filter(&revs->filter, arg);
Derrick Stoleecc910442022-03-22 17:28:352792 } else if (!strcmp(arg, ("--no-filter"))) {
Derrick Stoleec4ea5132022-03-09 16:01:402793 list_objects_filter_set_no_filter(&revs->filter);
Jonathan Niederf6aca0d2011-04-21 10:45:072794 } else {
2795 return 0;
2796 }
2797
2798 return 1;
2799}
2800
Patrick Steinhardtcc804502023-06-15 14:39:512801static void read_revisions_from_stdin(struct rev_info *revs,
Patrick Steinhardtf97c8b12023-09-25 13:02:002802 struct strvec *prune)
Patrick Steinhardtcc804502023-06-15 14:39:512803{
2804 struct strbuf sb;
2805 int seen_dashdash = 0;
Patrick Steinhardtc40f0b72023-06-15 14:39:592806 int seen_end_of_options = 0;
Patrick Steinhardtcc804502023-06-15 14:39:512807 int save_warning;
Patrick Steinhardtf97c8b12023-09-25 13:02:002808 int flags = 0;
Patrick Steinhardtcc804502023-06-15 14:39:512809
2810 save_warning = warn_on_object_refname_ambiguity;
2811 warn_on_object_refname_ambiguity = 0;
2812
2813 strbuf_init(&sb, 1000);
2814 while (strbuf_getline(&sb, stdin) != EOF) {
Patrick Steinhardtaf37a202023-06-15 14:39:552815 if (!sb.len)
Patrick Steinhardtcc804502023-06-15 14:39:512816 break;
Patrick Steinhardtaf37a202023-06-15 14:39:552817
2818 if (!strcmp(sb.buf, "--")) {
2819 seen_dashdash = 1;
2820 break;
Patrick Steinhardtcc804502023-06-15 14:39:512821 }
Patrick Steinhardtaf37a202023-06-15 14:39:552822
Patrick Steinhardtc40f0b72023-06-15 14:39:592823 if (!seen_end_of_options && sb.buf[0] == '-') {
2824 const char *argv[] = { sb.buf, NULL };
2825
2826 if (!strcmp(sb.buf, "--end-of-options")) {
2827 seen_end_of_options = 1;
2828 continue;
2829 }
2830
Patrick Steinhardtf97c8b12023-09-25 13:02:002831 if (handle_revision_pseudo_opt(revs, argv, &flags) > 0)
Patrick Steinhardtc40f0b72023-06-15 14:39:592832 continue;
2833
2834 die(_("invalid option '%s' in --stdin mode"), sb.buf);
2835 }
Patrick Steinhardtaf37a202023-06-15 14:39:552836
Patrick Steinhardtf97c8b12023-09-25 13:02:002837 if (handle_revision_arg(sb.buf, revs, flags,
Patrick Steinhardtcc804502023-06-15 14:39:512838 REVARG_CANNOT_BE_FILENAME))
2839 die("bad revision '%s'", sb.buf);
2840 }
2841 if (seen_dashdash)
2842 read_pathspec_from_stdin(&sb, prune);
2843
2844 strbuf_release(&sb);
2845 warn_on_object_refname_ambiguity = save_warning;
2846}
2847
Jeff Kingce113602015-08-29 05:04:182848static void NORETURN diagnose_missing_default(const char *def)
2849{
Jeff Kingce113602015-08-29 05:04:182850 int flags;
2851 const char *refname;
2852
René Scharfe744c0402017-09-23 09:45:042853 refname = resolve_ref_unsafe(def, 0, NULL, &flags);
Jeff Kingce113602015-08-29 05:04:182854 if (!refname || !(flags & REF_ISSYMREF) || (flags & REF_ISBROKEN))
2855 die(_("your current branch appears to be broken"));
2856
2857 skip_prefix(refname, "refs/heads/", &refname);
2858 die(_("your current branch '%s' does not have any commits yet"),
2859 refname);
2860}
2861
Linus Torvaldsae563542006-02-26 00:19:462862/*
2863 * Parse revision information, filling in the "rev_info" structure,
2864 * and removing the used arguments from the argument list.
2865 *
Linus Torvalds765ac8e2006-02-28 23:07:202866 * Returns the number of arguments left that weren't recognized
2867 * (which are also moved to the head of the argument list)
Linus Torvaldsae563542006-02-26 00:19:462868 */
Junio C Hamano32962c92010-03-09 06:58:092869int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct setup_revision_opt *opt)
Linus Torvaldsae563542006-02-26 00:19:462870{
Jeff King04a0e982020-08-26 20:13:052871 int i, flags, left, seen_dashdash, revarg_opt;
Jeff Kingc972bf42020-07-28 20:25:122872 struct strvec prune_data = STRVEC_INIT;
Jeff King19e87892019-08-06 14:39:582873 int seen_end_of_options = 0;
Heiko Voigt9ef6aeb2010-07-07 13:39:122874
Linus Torvaldsae563542006-02-26 00:19:462875 /* First, search for "--" */
Clemens Buchacher6d5b93f2012-04-14 19:04:482876 if (opt && opt->assume_dashdash) {
Linus Torvaldsae563542006-02-26 00:19:462877 seen_dashdash = 1;
Clemens Buchacher6d5b93f2012-04-14 19:04:482878 } else {
2879 seen_dashdash = 0;
2880 for (i = 1; i < argc; i++) {
2881 const char *arg = argv[i];
2882 if (strcmp(arg, "--"))
2883 continue;
Ævar Arnfjörð Bjarmasonf92dbdb2022-08-02 15:33:162884 if (opt && opt->free_removed_argv_elements)
2885 free((char *)argv[i]);
Clemens Buchacher6d5b93f2012-04-14 19:04:482886 argv[i] = NULL;
2887 argc = i;
2888 if (argv[i + 1])
Jeff Kingc972bf42020-07-28 20:25:122889 strvec_pushv(&prune_data, argv + i + 1);
Clemens Buchacher6d5b93f2012-04-14 19:04:482890 seen_dashdash = 1;
2891 break;
2892 }
Linus Torvaldsae563542006-02-26 00:19:462893 }
2894
Pierre Habouzit02e54222008-07-08 13:19:332895 /* Second, deal with arguments and options */
2896 flags = 0;
Junio C Hamanod5f6b1d2012-07-02 19:43:052897 revarg_opt = opt ? opt->revarg_opt : 0;
2898 if (seen_dashdash)
2899 revarg_opt |= REVARG_CANNOT_BE_FILENAME;
Pierre Habouzit02e54222008-07-08 13:19:332900 for (left = i = 1; i < argc; i++) {
Linus Torvaldsae563542006-02-26 00:19:462901 const char *arg = argv[i];
Jeff King19e87892019-08-06 14:39:582902 if (!seen_end_of_options && *arg == '-') {
Linus Torvaldscd2bdc52006-04-14 23:52:132903 int opts;
Pierre Habouzit02e54222008-07-08 13:19:332904
Jonathan Tan10a0d6a2021-09-09 18:47:292905 opts = handle_revision_pseudo_opt(
Jeff Kinge885a842020-09-30 12:28:182906 revs, argv + i,
Jonathan Niederf6aca0d2011-04-21 10:45:072907 &flags);
2908 if (opts > 0) {
2909 i += opts - 1;
Uwe Kleine-Königa5aa9302008-02-28 07:24:252910 continue;
2911 }
Jonathan Niederf6aca0d2011-04-21 10:45:072912
Junio C Hamano8b3dce52009-11-03 14:59:182913 if (!strcmp(arg, "--stdin")) {
2914 if (revs->disable_stdin) {
2915 argv[left++] = arg;
2916 continue;
2917 }
Jeff Kinga12cbe22018-08-22 21:37:232918 if (revs->read_from_stdin++)
Junio C Hamano8b3dce52009-11-03 14:59:182919 die("--stdin given twice?");
Patrick Steinhardtf97c8b12023-09-25 13:02:002920 read_revisions_from_stdin(revs, &prune_data);
Junio C Hamano8b3dce52009-11-03 14:59:182921 continue;
2922 }
Junio C Hamano2d10c552006-09-20 20:21:562923
Jeff King19e87892019-08-06 14:39:582924 if (!strcmp(arg, "--end-of-options")) {
2925 seen_end_of_options = 1;
2926 continue;
2927 }
2928
Matthew DeVorebbcde412018-12-03 22:10:192929 opts = handle_revision_opt(revs, argc - i, argv + i,
2930 &left, argv, opt);
Linus Torvaldscd2bdc52006-04-14 23:52:132931 if (opts > 0) {
Linus Torvaldscd2bdc52006-04-14 23:52:132932 i += opts - 1;
2933 continue;
2934 }
Pierre Habouzit02e54222008-07-08 13:19:332935 if (opts < 0)
2936 exit(128);
Linus Torvaldsae563542006-02-26 00:19:462937 continue;
2938 }
Rene Scharfe0d2c9d62006-07-01 23:29:372939
Junio C Hamano8e676e82012-07-02 19:33:522940
2941 if (handle_revision_arg(arg, revs, flags, revarg_opt)) {
Linus Torvaldsae563542006-02-26 00:19:462942 int j;
Junio C Hamano5d6f0932006-09-06 04:28:362943 if (seen_dashdash || *arg == '^')
Linus Torvaldsae563542006-02-26 00:19:462944 die("bad revision '%s'", arg);
2945
Junio C Hamanoea92f412006-04-26 22:09:272946 /* If we didn't have a "--":
2947 * (1) all filenames must exist;
2948 * (2) all rev-args must not be interpretable
2949 * as a valid filename.
2950 * but the latter we have checked in the main loop.
2951 */
Linus Torvaldse23d0b42006-04-26 17:15:542952 for (j = i; j < argc; j++)
Matthieu Moy023e37c2012-06-18 18:18:212953 verify_filename(revs->prefix, argv[j], j == i);
Linus Torvaldse23d0b42006-04-26 17:15:542954
Jeff Kingc972bf42020-07-28 20:25:122955 strvec_pushv(&prune_data, argv + i);
Linus Torvaldsae563542006-02-26 00:19:462956 break;
2957 }
Linus Torvaldsae563542006-02-26 00:19:462958 }
Alex Henrie087c7452022-02-11 16:36:252959 revision_opts_finish(revs);
Junio C Hamano5d6f0932006-09-06 04:28:362960
Jeff Kingd70a9eb2020-07-29 00:37:202961 if (prune_data.nr) {
Junio C Hamano93e7d672011-05-11 22:23:252962 /*
2963 * If we need to introduce the magic "a lone ':' means no
2964 * pathspec whatsoever", here is the place to do so.
2965 *
2966 * if (prune_data.nr == 1 && !strcmp(prune_data[0], ":")) {
2967 * prune_data.nr = 0;
2968 * prune_data.alloc = 0;
2969 * free(prune_data.path);
2970 * prune_data.path = NULL;
2971 * } else {
2972 * terminate prune_data.alloc with NULL and
2973 * call init_pathspec() to set revs->prune_data here.
2974 * }
2975 */
Nguyễn Thái Ngọc Duy0fdc2ae2013-07-14 08:35:312976 parse_pathspec(&revs->prune_data, 0, 0,
Jeff Kingd70a9eb2020-07-29 00:37:202977 revs->prefix, prune_data.v);
Junio C Hamano4da5af32011-05-11 21:01:192978 }
Jeff Kingc972bf42020-07-28 20:25:122979 strvec_clear(&prune_data);
Junio C Hamano5486ef02009-11-20 10:33:282980
Junio C Hamanoafe8a902022-05-02 16:50:372981 if (!revs->def)
Junio C Hamano32962c92010-03-09 06:58:092982 revs->def = opt ? opt->def : NULL;
Junio C Hamanob4490052010-03-09 07:27:252983 if (opt && opt->tweak)
Jeff Kingcc88afa2023-07-03 06:44:162984 opt->tweak(revs);
Pierre Habouzit02e54222008-07-08 13:19:332985 if (revs->show_merge)
Junio C Hamanoae3e5e12006-07-03 09:59:322986 prepare_show_merge(revs);
Jeff King04a0e982020-08-26 20:13:052987 if (revs->def && !revs->pending.nr && !revs->rev_input_given) {
brian m. carlson654b9a92017-05-06 22:10:272988 struct object_id oid;
Linus Torvaldscd2bdc52006-04-14 23:52:132989 struct object *object;
Junio C Hamano249c8f42012-07-02 19:56:442990 struct object_context oc;
Nguyễn Thái Ngọc Duy3a7a6982019-01-12 02:13:282991 if (get_oid_with_context(revs->repo, revs->def, 0, &oid, &oc))
Jeff Kingce113602015-08-29 05:04:182992 diagnose_missing_default(revs->def);
brian m. carlson654b9a92017-05-06 22:10:272993 object = get_reference(revs, revs->def, &oid, 0);
Junio C Hamano249c8f42012-07-02 19:56:442994 add_pending_object_with_mode(revs, object, revs->def, oc.mode);
Linus Torvaldsae563542006-02-26 00:19:462995 }
Fredrik Kuivinen8efdc322006-03-10 09:21:392996
Linus Torvaldsb7bb7602007-09-29 16:50:392997 /* Did the user ask for any diff output? Run the diff! */
2998 if (revs->diffopt.output_format & ~DIFF_FORMAT_NO_OUTPUT)
2999 revs->diff = 1;
3000
Arjen Laarhoven0faf2da2007-12-25 11:06:473001 /* Pickaxe, diff-filter and rename following need diffs */
Stefan Bellercf630512018-01-04 22:50:413002 if ((revs->diffopt.pickaxe_opts & DIFF_PICKAXE_KINDS_MASK) ||
Arjen Laarhoven0faf2da2007-12-25 11:06:473003 revs->diffopt.filter ||
Brandon Williams0d1e0e72017-10-31 18:19:113004 revs->diffopt.flags.follow_renames)
Linus Torvaldsb7bb7602007-09-29 16:50:393005 revs->diff = 1;
3006
Stefan Beller15af58c2018-01-04 22:50:423007 if (revs->diffopt.objfind)
3008 revs->simplify_history = 0;
3009
SZEDER Gábor002933f2020-05-11 11:56:183010 if (revs->line_level_traverse) {
3011 if (want_ancestry(revs))
3012 revs->limited = 1;
3013 revs->topo_order = 1;
3014 }
3015
Derrick Stoleef0d9cc42018-11-01 13:46:203016 if (revs->topo_order && !generation_numbers_enabled(the_repository))
Junio C Hamano53069682006-04-02 02:38:253017 revs->limited = 1;
3018
Nguyễn Thái Ngọc Duyafe069d2010-12-17 12:43:063019 if (revs->prune_data.nr) {
Nguyễn Thái Ngọc Duybd1928d2013-07-14 08:35:583020 copy_pathspec(&revs->pruning.pathspec, &revs->prune_data);
Linus Torvalds750f7b62007-06-19 21:22:463021 /* Can't prune commits with rename following: the paths change.. */
Brandon Williams0d1e0e72017-10-31 18:19:113022 if (!revs->diffopt.flags.follow_renames)
Linus Torvalds53b2c822007-11-05 21:22:343023 revs->prune = 1;
Linus Torvaldscd2bdc52006-04-14 23:52:133024 if (!revs->full_diff)
Nguyễn Thái Ngọc Duybd1928d2013-07-14 08:35:583025 copy_pathspec(&revs->diffopt.pathspec,
3026 &revs->prune_data);
Fredrik Kuivinen8efdc322006-03-10 09:21:393027 }
Sergey Organov299a6632020-12-21 15:19:303028
Sergey Organov18f09472020-12-21 15:19:343029 diff_merges_setup_revs(revs);
Elijah Newrend76ce4f2019-02-08 01:12:463030
Linus Torvaldscd2bdc52006-04-14 23:52:133031 revs->diffopt.abbrev = revs->abbrev;
Thomas Rast12da1d12013-03-28 16:47:323032
Thomas Rast28452652012-08-03 12:16:243033 diff_setup_done(&revs->diffopt);
Fredrik Kuivinen8efdc322006-03-10 09:21:393034
Ævar Arnfjörð Bjarmason44570182019-06-27 23:39:053035 if (!is_encoding_utf8(get_log_output_encoding()))
3036 revs->grep_filter.ignore_locale = 1;
Jeff King0843acf2008-08-25 06:15:053037 compile_grep_patterns(&revs->grep_filter);
Junio C Hamanobd95fcd2006-09-18 00:23:203038
Shawn O. Pearced56651c2007-08-20 02:33:433039 if (revs->reverse && revs->reflog_info)
Jean-Noël Avila12909b62022-01-05 20:02:163040 die(_("options '%s' and '%s' cannot be used together"), "--reverse", "--walk-reflogs");
Jeff King82fd0f42017-07-07 09:07:163041 if (revs->reflog_info && revs->limited)
3042 die("cannot combine --walk-reflogs with history-limiting options");
Junio C Hamano8bb65882008-07-08 22:25:443043 if (revs->rewrite_parents && revs->children.name)
Jean-Noël Avila12909b62022-01-05 20:02:163044 die(_("options '%s' and '%s' cannot be used together"), "--parents", "--children");
Derrick Stoleec4ea5132022-03-09 16:01:403045 if (revs->filter.choice && !revs->blob_objects)
3046 die(_("object filtering requires --objects"));
Shawn O. Pearced56651c2007-08-20 02:33:433047
Adam Simpkins7fefda52008-05-04 10:36:543048 /*
3049 * Limitations on the graph functionality
3050 */
3051 if (revs->reverse && revs->graph)
Jean-Noël Avila12909b62022-01-05 20:02:163052 die(_("options '%s' and '%s' cannot be used together"), "--reverse", "--graph");
Adam Simpkins7fefda52008-05-04 10:36:543053
3054 if (revs->reflog_info && revs->graph)
Jean-Noël Avila12909b62022-01-05 20:02:163055 die(_("options '%s' and '%s' cannot be used together"), "--walk-reflogs", "--graph");
Dongcan Jiang695985f2015-03-11 02:13:023056 if (revs->no_walk && revs->graph)
Jean-Noël Avila12909b62022-01-05 20:02:163057 die(_("options '%s' and '%s' cannot be used together"), "--no-walk", "--graph");
Junio C Hamanobaa63782012-09-29 18:59:523058 if (!revs->reflog_info && revs->grep_filter.use_reflog_filter)
Jean-Noël Avila6fa00ee2022-01-05 20:02:193059 die(_("the option '%s' requires '%s'"), "--grep-reflog", "--walk-reflogs");
Adam Simpkins7fefda52008-05-04 10:36:543060
Jeff King05314ef2019-03-11 03:54:333061 if (revs->line_level_traverse &&
3062 (revs->diffopt.output_format & ~(DIFF_FORMAT_PATCH | DIFF_FORMAT_NO_OUTPUT)))
3063 die(_("-L does not yet support diff formats besides -p and -s"));
3064
Junio C Hamano0893eec2016-03-29 22:49:243065 if (revs->expand_tabs_in_log < 0)
3066 revs->expand_tabs_in_log = revs->expand_tabs_in_log_default;
3067
Kristoffer Haugsbakk2e0d30d2023-09-19 20:26:503068 if (!revs->show_notes_given && revs->show_notes_by_default) {
3069 enable_default_display_notes(&revs->notes_opt, &revs->show_notes);
3070 revs->show_notes_given = 1;
3071 }
3072
Linus Torvaldsae563542006-02-26 00:19:463073 return left;
3074}
Linus Torvaldsa4a88b22006-02-28 19:24:003075
Ævar Arnfjörð Bjarmason7a98d9a2022-04-13 20:01:473076static void release_revisions_cmdline(struct rev_cmdline_info *cmdline)
3077{
3078 unsigned int i;
3079
3080 for (i = 0; i < cmdline->nr; i++)
3081 free((char *)cmdline->rev[i].name);
3082 free(cmdline->rev);
3083}
3084
Ævar Arnfjörð Bjarmasona52f07a2022-04-13 20:01:463085static void release_revisions_mailmap(struct string_list *mailmap)
3086{
3087 if (!mailmap)
3088 return;
3089 clear_mailmap(mailmap);
3090 free(mailmap);
3091}
3092
Ævar Arnfjörð Bjarmasonae1b3832022-04-14 05:56:393093static void release_revisions_topo_walk_info(struct topo_walk_info *info);
3094
Jeff King8ef8da42023-10-05 21:30:143095static void free_void_commit_list(void *list)
3096{
3097 free_commit_list(list);
3098}
3099
Ævar Arnfjörð Bjarmason1878b5e2022-04-13 20:01:353100void release_revisions(struct rev_info *revs)
3101{
Ævar Arnfjörð Bjarmasone966fc52022-04-13 20:01:453102 free_commit_list(revs->commits);
Elijah Newren257418c2022-08-19 04:28:103103 free_commit_list(revs->ancestry_path_bottoms);
Ævar Arnfjörð Bjarmason1878b5e2022-04-13 20:01:353104 object_array_clear(&revs->pending);
Ævar Arnfjörð Bjarmasonab1f6922022-04-13 20:01:513105 object_array_clear(&revs->boundary_commits);
Ævar Arnfjörð Bjarmason7a98d9a2022-04-13 20:01:473106 release_revisions_cmdline(&revs->cmdline);
Ævar Arnfjörð Bjarmasone75d2f72022-04-13 20:01:483107 list_objects_filter_release(&revs->filter);
Ævar Arnfjörð Bjarmason689a8e82022-04-13 20:01:503108 clear_pathspec(&revs->prune_data);
Ævar Arnfjörð Bjarmason9d5a7df2022-04-14 05:56:383109 date_mode_release(&revs->date_mode);
Ævar Arnfjörð Bjarmasona52f07a2022-04-13 20:01:463110 release_revisions_mailmap(revs->mailmap);
Ævar Arnfjörð Bjarmasonf41fb662022-04-13 20:01:493111 free_grep_patterns(&revs->grep_filter);
Ævar Arnfjörð Bjarmasonfc472522022-11-08 18:17:443112 graph_clear(revs->graph);
Ævar Arnfjörð Bjarmason54c8a7c2022-04-14 05:56:403113 /* TODO (need to handle "no_free"): diff_free(&revs->diffopt) */
Ævar Arnfjörð Bjarmason6ab75ac2022-04-13 20:01:533114 diff_free(&revs->pruning);
Ævar Arnfjörð Bjarmason81ffbf82022-04-13 20:01:523115 reflog_walk_info_release(revs->reflog_info);
Ævar Arnfjörð Bjarmasonae1b3832022-04-14 05:56:393116 release_revisions_topo_walk_info(revs->topo_walk_info);
Jeff King8ef8da42023-10-05 21:30:143117 clear_decoration(&revs->children, free_void_commit_list);
3118 clear_decoration(&revs->merge_simplification, free);
3119 clear_decoration(&revs->treesame, free);
3120 line_log_free(revs);
Karthik Nayak98309262023-10-27 07:59:293121 oidset_clear(&revs->missing_commits);
Ævar Arnfjörð Bjarmason1878b5e2022-04-13 20:01:353122}
3123
Junio C Hamanof35f5602008-04-03 09:12:063124static void add_child(struct rev_info *revs, struct commit *parent, struct commit *child)
3125{
3126 struct commit_list *l = xcalloc(1, sizeof(*l));
3127
3128 l->item = child;
3129 l->next = add_decoration(&revs->children, &parent->object, l);
3130}
3131
Kevin Braceyd0af6632013-05-16 15:32:343132static int remove_duplicate_parents(struct rev_info *revs, struct commit *commit)
Junio C Hamano6546b592008-07-31 08:17:413133{
Kevin Braceyd0af6632013-05-16 15:32:343134 struct treesame_state *ts = lookup_decoration(&revs->treesame, &commit->object);
Junio C Hamano6546b592008-07-31 08:17:413135 struct commit_list **pp, *p;
3136 int surviving_parents;
3137
3138 /* Examine existing parents while marking ones we have seen... */
3139 pp = &commit->parents;
Kevin Braceyd0af6632013-05-16 15:32:343140 surviving_parents = 0;
Junio C Hamano6546b592008-07-31 08:17:413141 while ((p = *pp) != NULL) {
3142 struct commit *parent = p->item;
3143 if (parent->object.flags & TMP_MARK) {
3144 *pp = p->next;
Kevin Braceyd0af6632013-05-16 15:32:343145 if (ts)
3146 compact_treesame(revs, commit, surviving_parents);
Junio C Hamano6546b592008-07-31 08:17:413147 continue;
3148 }
3149 parent->object.flags |= TMP_MARK;
Kevin Braceyd0af6632013-05-16 15:32:343150 surviving_parents++;
Junio C Hamano6546b592008-07-31 08:17:413151 pp = &p->next;
3152 }
Kevin Braceyd0af6632013-05-16 15:32:343153 /* clear the temporary mark */
Junio C Hamano6546b592008-07-31 08:17:413154 for (p = commit->parents; p; p = p->next) {
3155 p->item->object.flags &= ~TMP_MARK;
Junio C Hamano6546b592008-07-31 08:17:413156 }
Kevin Braceyd0af6632013-05-16 15:32:343157 /* no update_treesame() - removing duplicates can't affect TREESAME */
Junio C Hamano6546b592008-07-31 08:17:413158 return surviving_parents;
3159}
3160
Junio C Hamanofaf01562008-08-14 17:59:443161struct merge_simplify_state {
3162 struct commit *simplified;
3163};
3164
3165static struct merge_simplify_state *locate_simplify_state(struct rev_info *revs, struct commit *commit)
3166{
3167 struct merge_simplify_state *st;
3168
3169 st = lookup_decoration(&revs->merge_simplification, &commit->object);
3170 if (!st) {
René Scharfeca56dad2021-03-13 16:17:223171 CALLOC_ARRAY(st, 1);
Junio C Hamanofaf01562008-08-14 17:59:443172 add_decoration(&revs->merge_simplification, &commit->object, st);
3173 }
3174 return st;
3175}
3176
Jeff King91633992019-03-20 08:13:363177static int mark_redundant_parents(struct commit *commit)
Kevin Braceyd0af6632013-05-16 15:32:343178{
3179 struct commit_list *h = reduce_heads(commit->parents);
3180 int i = 0, marked = 0;
3181 struct commit_list *po, *pn;
3182
3183 /* Want these for sanity-checking only */
3184 int orig_cnt = commit_list_count(commit->parents);
3185 int cnt = commit_list_count(h);
3186
3187 /*
3188 * Not ready to remove items yet, just mark them for now, based
3189 * on the output of reduce_heads(). reduce_heads outputs the reduced
3190 * set in its original order, so this isn't too hard.
3191 */
3192 po = commit->parents;
3193 pn = h;
3194 while (po) {
3195 if (pn && po->item == pn->item) {
3196 pn = pn->next;
3197 i++;
3198 } else {
3199 po->item->object.flags |= TMP_MARK;
3200 marked++;
3201 }
3202 po=po->next;
3203 }
3204
3205 if (i != cnt || cnt+marked != orig_cnt)
3206 die("mark_redundant_parents %d %d %d %d", orig_cnt, cnt, i, marked);
3207
3208 free_commit_list(h);
3209
3210 return marked;
3211}
3212
Jeff King91633992019-03-20 08:13:363213static int mark_treesame_root_parents(struct commit *commit)
Kevin Bracey143f1ea2013-05-16 15:32:373214{
3215 struct commit_list *p;
3216 int marked = 0;
3217
3218 for (p = commit->parents; p; p = p->next) {
3219 struct commit *parent = p->item;
3220 if (!parent->parents && (parent->object.flags & TREESAME)) {
3221 parent->object.flags |= TMP_MARK;
3222 marked++;
3223 }
3224 }
3225
3226 return marked;
3227}
3228
Kevin Bracey9c129ea2013-05-16 15:32:363229/*
3230 * Awkward naming - this means one parent we are TREESAME to.
3231 * cf mark_treesame_root_parents: root parents that are TREESAME (to an
3232 * empty tree). Better name suggestions?
3233 */
3234static int leave_one_treesame_to_parent(struct rev_info *revs, struct commit *commit)
3235{
3236 struct treesame_state *ts = lookup_decoration(&revs->treesame, &commit->object);
3237 struct commit *unmarked = NULL, *marked = NULL;
3238 struct commit_list *p;
3239 unsigned n;
3240
3241 for (p = commit->parents, n = 0; p; p = p->next, n++) {
3242 if (ts->treesame[n]) {
3243 if (p->item->object.flags & TMP_MARK) {
3244 if (!marked)
3245 marked = p->item;
3246 } else {
3247 if (!unmarked) {
3248 unmarked = p->item;
3249 break;
3250 }
3251 }
3252 }
3253 }
3254
3255 /*
3256 * If we are TREESAME to a marked-for-deletion parent, but not to any
3257 * unmarked parents, unmark the first TREESAME parent. This is the
3258 * parent that the default simplify_history==1 scan would have followed,
3259 * and it doesn't make sense to omit that path when asking for a
3260 * simplified full history. Retaining it improves the chances of
3261 * understanding odd missed merges that took an old version of a file.
3262 *
3263 * Example:
3264 *
3265 * I--------*X A modified the file, but mainline merge X used
3266 * \ / "-s ours", so took the version from I. X is
3267 * `-*A--' TREESAME to I and !TREESAME to A.
3268 *
3269 * Default log from X would produce "I". Without this check,
3270 * --full-history --simplify-merges would produce "I-A-X", showing
3271 * the merge commit X and that it changed A, but not making clear that
3272 * it had just taken the I version. With this check, the topology above
3273 * is retained.
3274 *
3275 * Note that it is possible that the simplification chooses a different
3276 * TREESAME parent from the default, in which case this test doesn't
3277 * activate, and we _do_ drop the default parent. Example:
3278 *
3279 * I------X A modified the file, but it was reverted in B,
3280 * \ / meaning mainline merge X is TREESAME to both
3281 * *A-*B parents.
3282 *
3283 * Default log would produce "I" by following the first parent;
3284 * --full-history --simplify-merges will produce "I-A-B". But this is a
3285 * reasonable result - it presents a logical full history leading from
3286 * I to X, and X is not an important merge.
3287 */
3288 if (!unmarked && marked) {
3289 marked->object.flags &= ~TMP_MARK;
3290 return 1;
3291 }
3292
3293 return 0;
3294}
3295
Kevin Braceyd0af6632013-05-16 15:32:343296static int remove_marked_parents(struct rev_info *revs, struct commit *commit)
3297{
3298 struct commit_list **pp, *p;
3299 int nth_parent, removed = 0;
3300
3301 pp = &commit->parents;
3302 nth_parent = 0;
3303 while ((p = *pp) != NULL) {
3304 struct commit *parent = p->item;
3305 if (parent->object.flags & TMP_MARK) {
3306 parent->object.flags &= ~TMP_MARK;
3307 *pp = p->next;
3308 free(p);
3309 removed++;
3310 compact_treesame(revs, commit, nth_parent);
3311 continue;
3312 }
3313 pp = &p->next;
3314 nth_parent++;
3315 }
3316
3317 /* Removing parents can only increase TREESAMEness */
3318 if (removed && !(commit->object.flags & TREESAME))
3319 update_treesame(revs, commit);
3320
3321 return nth_parent;
3322}
3323
Junio C Hamanofaf01562008-08-14 17:59:443324static struct commit_list **simplify_one(struct rev_info *revs, struct commit *commit, struct commit_list **tail)
Junio C Hamano6546b592008-07-31 08:17:413325{
3326 struct commit_list *p;
Kevin Bracey4d826602013-05-16 15:32:393327 struct commit *parent;
Junio C Hamanofaf01562008-08-14 17:59:443328 struct merge_simplify_state *st, *pst;
Junio C Hamano6546b592008-07-31 08:17:413329 int cnt;
3330
Junio C Hamanofaf01562008-08-14 17:59:443331 st = locate_simplify_state(revs, commit);
3332
Junio C Hamano6546b592008-07-31 08:17:413333 /*
Junio C Hamano6546b592008-07-31 08:17:413334 * Have we handled this one?
3335 */
Junio C Hamanofaf01562008-08-14 17:59:443336 if (st->simplified)
Junio C Hamano6546b592008-07-31 08:17:413337 return tail;
3338
3339 /*
3340 * An UNINTERESTING commit simplifies to itself, so does a
3341 * root commit. We do not rewrite parents of such commit
3342 * anyway.
3343 */
3344 if ((commit->object.flags & UNINTERESTING) || !commit->parents) {
Junio C Hamanofaf01562008-08-14 17:59:443345 st->simplified = commit;
Junio C Hamano6546b592008-07-31 08:17:413346 return tail;
3347 }
3348
3349 /*
Junio C Hamano6e513ba2012-06-08 21:56:033350 * Do we know what commit all of our parents that matter
3351 * should be rewritten to? Otherwise we are not ready to
3352 * rewrite this one yet.
Junio C Hamano6546b592008-07-31 08:17:413353 */
3354 for (cnt = 0, p = commit->parents; p; p = p->next) {
Junio C Hamanofaf01562008-08-14 17:59:443355 pst = locate_simplify_state(revs, p->item);
3356 if (!pst->simplified) {
Junio C Hamano6546b592008-07-31 08:17:413357 tail = &commit_list_insert(p->item, tail)->next;
3358 cnt++;
3359 }
Junio C Hamano6e513ba2012-06-08 21:56:033360 if (revs->first_parent_only)
3361 break;
Junio C Hamano6546b592008-07-31 08:17:413362 }
Junio C Hamano53030f82008-08-18 07:37:343363 if (cnt) {
3364 tail = &commit_list_insert(commit, tail)->next;
Junio C Hamano6546b592008-07-31 08:17:413365 return tail;
Junio C Hamano53030f82008-08-18 07:37:343366 }
Junio C Hamano6546b592008-07-31 08:17:413367
3368 /*
Kevin Braceyd0af6632013-05-16 15:32:343369 * Rewrite our list of parents. Note that this cannot
3370 * affect our TREESAME flags in any way - a commit is
3371 * always TREESAME to its simplification.
Junio C Hamano6546b592008-07-31 08:17:413372 */
Junio C Hamanofaf01562008-08-14 17:59:443373 for (p = commit->parents; p; p = p->next) {
3374 pst = locate_simplify_state(revs, p->item);
3375 p->item = pst->simplified;
Junio C Hamano6e513ba2012-06-08 21:56:033376 if (revs->first_parent_only)
3377 break;
Junio C Hamanofaf01562008-08-14 17:59:443378 }
Junio C Hamano4b7f53d2013-01-17 22:23:033379
Junio C Hamano0290bf12013-04-08 20:10:273380 if (revs->first_parent_only)
Junio C Hamano6e513ba2012-06-08 21:56:033381 cnt = 1;
Junio C Hamano0290bf12013-04-08 20:10:273382 else
Kevin Braceyd0af6632013-05-16 15:32:343383 cnt = remove_duplicate_parents(revs, commit);
Junio C Hamano6546b592008-07-31 08:17:413384
3385 /*
3386 * It is possible that we are a merge and one side branch
3387 * does not have any commit that touches the given paths;
Kevin Braceyd0af6632013-05-16 15:32:343388 * in such a case, the immediate parent from that branch
3389 * will be rewritten to be the merge base.
Junio C Hamano6546b592008-07-31 08:17:413390 *
3391 * o----X X: the commit we are looking at;
3392 * / / o: a commit that touches the paths;
3393 * ---o----'
3394 *
Kevin Bracey143f1ea2013-05-16 15:32:373395 * Further, a merge of an independent branch that doesn't
3396 * touch the path will reduce to a treesame root parent:
3397 *
3398 * ----o----X X: the commit we are looking at;
3399 * / o: a commit that touches the paths;
3400 * r r: a root commit not touching the paths
3401 *
3402 * Detect and simplify both cases.
Junio C Hamano6546b592008-07-31 08:17:413403 */
3404 if (1 < cnt) {
Jeff King91633992019-03-20 08:13:363405 int marked = mark_redundant_parents(commit);
3406 marked += mark_treesame_root_parents(commit);
Kevin Braceyd0af6632013-05-16 15:32:343407 if (marked)
Kevin Bracey9c129ea2013-05-16 15:32:363408 marked -= leave_one_treesame_to_parent(revs, commit);
3409 if (marked)
Kevin Braceyd0af6632013-05-16 15:32:343410 cnt = remove_marked_parents(revs, commit);
Junio C Hamano6546b592008-07-31 08:17:413411 }
3412
3413 /*
3414 * A commit simplifies to itself if it is a root, if it is
3415 * UNINTERESTING, if it touches the given paths, or if it is a
Kevin Bracey4d826602013-05-16 15:32:393416 * merge and its parents don't simplify to one relevant commit
Junio C Hamano6546b592008-07-31 08:17:413417 * (the first two cases are already handled at the beginning of
3418 * this function).
3419 *
Kevin Bracey4d826602013-05-16 15:32:393420 * Otherwise, it simplifies to what its sole relevant parent
3421 * simplifies to.
Junio C Hamano6546b592008-07-31 08:17:413422 */
3423 if (!cnt ||
3424 (commit->object.flags & UNINTERESTING) ||
3425 !(commit->object.flags & TREESAME) ||
Derrick Stolee8d049e12020-04-10 12:19:433426 (parent = one_relevant_parent(revs, commit->parents)) == NULL ||
3427 (revs->show_pulls && (commit->object.flags & PULL_MERGE)))
Junio C Hamanofaf01562008-08-14 17:59:443428 st->simplified = commit;
3429 else {
Kevin Bracey4d826602013-05-16 15:32:393430 pst = locate_simplify_state(revs, parent);
Junio C Hamanofaf01562008-08-14 17:59:443431 st->simplified = pst->simplified;
3432 }
Junio C Hamano6546b592008-07-31 08:17:413433 return tail;
3434}
3435
3436static void simplify_merges(struct rev_info *revs)
3437{
Junio C Hamanoab9d75a2012-06-08 21:50:223438 struct commit_list *list, *next;
Junio C Hamano6546b592008-07-31 08:17:413439 struct commit_list *yet_to_do, **tail;
Junio C Hamanoab9d75a2012-06-08 21:50:223440 struct commit *commit;
Junio C Hamano6546b592008-07-31 08:17:413441
Junio C Hamano5eac7392008-08-14 20:52:363442 if (!revs->prune)
3443 return;
Junio C Hamano65347032008-08-04 00:47:163444
Junio C Hamano6546b592008-07-31 08:17:413445 /* feed the list reversed */
3446 yet_to_do = NULL;
Junio C Hamanoab9d75a2012-06-08 21:50:223447 for (list = revs->commits; list; list = next) {
3448 commit = list->item;
3449 next = list->next;
3450 /*
3451 * Do not free(list) here yet; the original list
3452 * is used later in this function.
3453 */
3454 commit_list_insert(commit, &yet_to_do);
3455 }
Junio C Hamano6546b592008-07-31 08:17:413456 while (yet_to_do) {
3457 list = yet_to_do;
3458 yet_to_do = NULL;
3459 tail = &yet_to_do;
3460 while (list) {
René Scharfee510ab82015-10-24 16:21:313461 commit = pop_commit(&list);
Junio C Hamanofaf01562008-08-14 17:59:443462 tail = simplify_one(revs, commit, tail);
Junio C Hamano6546b592008-07-31 08:17:413463 }
3464 }
3465
3466 /* clean up the result, removing the simplified ones */
3467 list = revs->commits;
3468 revs->commits = NULL;
3469 tail = &revs->commits;
3470 while (list) {
Junio C Hamanofaf01562008-08-14 17:59:443471 struct merge_simplify_state *st;
Junio C Hamanoab9d75a2012-06-08 21:50:223472
René Scharfee510ab82015-10-24 16:21:313473 commit = pop_commit(&list);
Junio C Hamanofaf01562008-08-14 17:59:443474 st = locate_simplify_state(revs, commit);
3475 if (st->simplified == commit)
Junio C Hamano6546b592008-07-31 08:17:413476 tail = &commit_list_insert(commit, tail)->next;
3477 }
Junio C Hamano6546b592008-07-31 08:17:413478}
3479
Junio C Hamanof35f5602008-04-03 09:12:063480static void set_children(struct rev_info *revs)
3481{
3482 struct commit_list *l;
3483 for (l = revs->commits; l; l = l->next) {
3484 struct commit *commit = l->item;
3485 struct commit_list *p;
3486
3487 for (p = commit->parents; p; p = p->next)
3488 add_child(revs, p->item, commit);
3489 }
3490}
3491
Heiko Voigtbcc0a3e2012-03-29 07:21:213492void reset_revision_walk(void)
3493{
Mike Hommeyffa1f282019-11-22 08:37:033494 clear_object_flags(SEEN | ADDED | SHOWN | TOPO_WALK_EXPLORED | TOPO_WALK_INDEGREE);
Heiko Voigtbcc0a3e2012-03-29 07:21:213495}
3496
Jonathan Tandf11e192017-12-08 15:27:153497static int mark_uninteresting(const struct object_id *oid,
Jeff Kingbe252d32023-02-24 06:39:243498 struct packed_git *pack UNUSED,
3499 uint32_t pos UNUSED,
Nguyễn Thái Ngọc Duyb3c7eef2018-09-21 15:57:393500 void *cb)
Jonathan Tandf11e192017-12-08 15:27:153501{
Nguyễn Thái Ngọc Duyb3c7eef2018-09-21 15:57:393502 struct rev_info *revs = cb;
Jeff Kingc1fa9512021-04-13 07:17:483503 struct object *o = lookup_unknown_object(revs->repo, oid);
Jonathan Tandf11e192017-12-08 15:27:153504 o->flags |= UNINTERESTING | SEEN;
3505 return 0;
3506}
3507
Derrick Stoleeb4542412018-11-01 13:46:223508define_commit_slab(indegree_slab, int);
3509define_commit_slab(author_date_slab, timestamp_t);
3510
3511struct topo_walk_info {
Abhishek Kumard7f92782021-01-16 18:11:133512 timestamp_t min_generation;
Derrick Stoleeb4542412018-11-01 13:46:223513 struct prio_queue explore_queue;
3514 struct prio_queue indegree_queue;
3515 struct prio_queue topo_queue;
3516 struct indegree_slab indegree;
3517 struct author_date_slab author_date;
3518};
3519
Derrick Stolee90b666d2020-12-30 04:31:533520static int topo_walk_atexit_registered;
3521static unsigned int count_explore_walked;
3522static unsigned int count_indegree_walked;
3523static unsigned int count_topo_walked;
3524
3525static void trace2_topo_walk_statistics_atexit(void)
3526{
3527 struct json_writer jw = JSON_WRITER_INIT;
3528
3529 jw_object_begin(&jw, 0);
3530 jw_object_intmax(&jw, "count_explore_walked", count_explore_walked);
3531 jw_object_intmax(&jw, "count_indegree_walked", count_indegree_walked);
3532 jw_object_intmax(&jw, "count_topo_walked", count_topo_walked);
3533 jw_end(&jw);
3534
3535 trace2_data_json("topo_walk", the_repository, "statistics", &jw);
3536
3537 jw_release(&jw);
3538}
3539
Derrick Stoleeb4542412018-11-01 13:46:223540static inline void test_flag_and_insert(struct prio_queue *q, struct commit *c, int flag)
3541{
3542 if (c->object.flags & flag)
3543 return;
3544
3545 c->object.flags |= flag;
3546 prio_queue_put(q, c);
3547}
3548
3549static void explore_walk_step(struct rev_info *revs)
3550{
3551 struct topo_walk_info *info = revs->topo_walk_info;
3552 struct commit_list *p;
3553 struct commit *c = prio_queue_get(&info->explore_queue);
3554
3555 if (!c)
3556 return;
3557
Michael Forneyea3f7e52020-06-23 20:56:583558 if (repo_parse_commit_gently(revs->repo, c, 1) < 0)
Derrick Stoleeb4542412018-11-01 13:46:223559 return;
3560
Derrick Stolee90b666d2020-12-30 04:31:533561 count_explore_walked++;
3562
Derrick Stoleeb4542412018-11-01 13:46:223563 if (revs->sort_order == REV_SORT_BY_AUTHOR_DATE)
3564 record_author_date(&info->author_date, c);
3565
3566 if (revs->max_age != -1 && (c->date < revs->max_age))
3567 c->object.flags |= UNINTERESTING;
3568
3569 if (process_parents(revs, c, NULL, NULL) < 0)
3570 return;
3571
3572 if (c->object.flags & UNINTERESTING)
Jerry Zhang9d505b72022-01-11 21:39:413573 mark_parents_uninteresting(revs, c);
Derrick Stoleeb4542412018-11-01 13:46:223574
3575 for (p = c->parents; p; p = p->next)
3576 test_flag_and_insert(&info->explore_queue, p->item, TOPO_WALK_EXPLORED);
3577}
3578
3579static void explore_to_depth(struct rev_info *revs,
Abhishek Kumard7f92782021-01-16 18:11:133580 timestamp_t gen_cutoff)
Derrick Stoleeb4542412018-11-01 13:46:223581{
3582 struct topo_walk_info *info = revs->topo_walk_info;
3583 struct commit *c;
3584 while ((c = prio_queue_peek(&info->explore_queue)) &&
Abhishek Kumarc49c82a2020-06-17 09:14:103585 commit_graph_generation(c) >= gen_cutoff)
Derrick Stoleeb4542412018-11-01 13:46:223586 explore_walk_step(revs);
3587}
3588
3589static void indegree_walk_step(struct rev_info *revs)
3590{
3591 struct commit_list *p;
3592 struct topo_walk_info *info = revs->topo_walk_info;
3593 struct commit *c = prio_queue_get(&info->indegree_queue);
3594
3595 if (!c)
3596 return;
3597
Michael Forneyea3f7e52020-06-23 20:56:583598 if (repo_parse_commit_gently(revs->repo, c, 1) < 0)
Derrick Stoleeb4542412018-11-01 13:46:223599 return;
3600
Derrick Stolee90b666d2020-12-30 04:31:533601 count_indegree_walked++;
3602
Abhishek Kumarc49c82a2020-06-17 09:14:103603 explore_to_depth(revs, commit_graph_generation(c));
Derrick Stoleeb4542412018-11-01 13:46:223604
3605 for (p = c->parents; p; p = p->next) {
3606 struct commit *parent = p->item;
3607 int *pi = indegree_slab_at(&info->indegree, parent);
3608
Abhishek Kumar2f9bbb62021-01-16 18:11:093609 if (repo_parse_commit_gently(revs->repo, parent, 1) < 0)
3610 return;
3611
Derrick Stoleeb4542412018-11-01 13:46:223612 if (*pi)
3613 (*pi)++;
3614 else
3615 *pi = 2;
3616
3617 test_flag_and_insert(&info->indegree_queue, parent, TOPO_WALK_INDEGREE);
3618
3619 if (revs->first_parent_only)
3620 return;
3621 }
3622}
3623
3624static void compute_indegrees_to_depth(struct rev_info *revs,
Abhishek Kumard7f92782021-01-16 18:11:133625 timestamp_t gen_cutoff)
Derrick Stoleeb4542412018-11-01 13:46:223626{
3627 struct topo_walk_info *info = revs->topo_walk_info;
3628 struct commit *c;
3629 while ((c = prio_queue_peek(&info->indegree_queue)) &&
Abhishek Kumarc49c82a2020-06-17 09:14:103630 commit_graph_generation(c) >= gen_cutoff)
Derrick Stoleeb4542412018-11-01 13:46:223631 indegree_walk_step(revs);
3632}
Derrick Stoleef0d9cc42018-11-01 13:46:203633
Ævar Arnfjörð Bjarmasonae1b3832022-04-14 05:56:393634static void release_revisions_topo_walk_info(struct topo_walk_info *info)
Mike Hommey0aa0c2b2019-11-22 08:37:043635{
Ævar Arnfjörð Bjarmasonae1b3832022-04-14 05:56:393636 if (!info)
3637 return;
Mike Hommey0aa0c2b2019-11-22 08:37:043638 clear_prio_queue(&info->explore_queue);
3639 clear_prio_queue(&info->indegree_queue);
3640 clear_prio_queue(&info->topo_queue);
3641 clear_indegree_slab(&info->indegree);
3642 clear_author_date_slab(&info->author_date);
Ævar Arnfjörð Bjarmasonae1b3832022-04-14 05:56:393643 free(info);
3644}
Mike Hommey0aa0c2b2019-11-22 08:37:043645
Ævar Arnfjörð Bjarmasonae1b3832022-04-14 05:56:393646static void reset_topo_walk(struct rev_info *revs)
3647{
3648 release_revisions_topo_walk_info(revs->topo_walk_info);
3649 revs->topo_walk_info = NULL;
Mike Hommey0aa0c2b2019-11-22 08:37:043650}
3651
Derrick Stoleef0d9cc42018-11-01 13:46:203652static void init_topo_walk(struct rev_info *revs)
3653{
3654 struct topo_walk_info *info;
Derrick Stoleeb4542412018-11-01 13:46:223655 struct commit_list *list;
Mike Hommey0aa0c2b2019-11-22 08:37:043656 if (revs->topo_walk_info)
3657 reset_topo_walk(revs);
3658
Derrick Stoleef0d9cc42018-11-01 13:46:203659 revs->topo_walk_info = xmalloc(sizeof(struct topo_walk_info));
3660 info = revs->topo_walk_info;
3661 memset(info, 0, sizeof(struct topo_walk_info));
3662
Derrick Stoleeb4542412018-11-01 13:46:223663 init_indegree_slab(&info->indegree);
3664 memset(&info->explore_queue, 0, sizeof(info->explore_queue));
3665 memset(&info->indegree_queue, 0, sizeof(info->indegree_queue));
3666 memset(&info->topo_queue, 0, sizeof(info->topo_queue));
3667
3668 switch (revs->sort_order) {
3669 default: /* REV_SORT_IN_GRAPH_ORDER */
3670 info->topo_queue.compare = NULL;
3671 break;
3672 case REV_SORT_BY_COMMIT_DATE:
3673 info->topo_queue.compare = compare_commits_by_commit_date;
3674 break;
3675 case REV_SORT_BY_AUTHOR_DATE:
3676 init_author_date_slab(&info->author_date);
3677 info->topo_queue.compare = compare_commits_by_author_date;
3678 info->topo_queue.cb_data = &info->author_date;
3679 break;
3680 }
3681
3682 info->explore_queue.compare = compare_commits_by_gen_then_commit_date;
3683 info->indegree_queue.compare = compare_commits_by_gen_then_commit_date;
3684
3685 info->min_generation = GENERATION_NUMBER_INFINITY;
3686 for (list = revs->commits; list; list = list->next) {
3687 struct commit *c = list->item;
Abhishek Kumard7f92782021-01-16 18:11:133688 timestamp_t generation;
Derrick Stoleeb4542412018-11-01 13:46:223689
Michael Forneyea3f7e52020-06-23 20:56:583690 if (repo_parse_commit_gently(revs->repo, c, 1))
Derrick Stoleeb4542412018-11-01 13:46:223691 continue;
3692
3693 test_flag_and_insert(&info->explore_queue, c, TOPO_WALK_EXPLORED);
3694 test_flag_and_insert(&info->indegree_queue, c, TOPO_WALK_INDEGREE);
3695
Abhishek Kumarc752ad02020-06-17 09:14:113696 generation = commit_graph_generation(c);
3697 if (generation < info->min_generation)
3698 info->min_generation = generation;
Derrick Stoleeb4542412018-11-01 13:46:223699
3700 *(indegree_slab_at(&info->indegree, c)) = 1;
3701
3702 if (revs->sort_order == REV_SORT_BY_AUTHOR_DATE)
3703 record_author_date(&info->author_date, c);
3704 }
3705 compute_indegrees_to_depth(revs, info->min_generation);
3706
3707 for (list = revs->commits; list; list = list->next) {
3708 struct commit *c = list->item;
3709
3710 if (*(indegree_slab_at(&info->indegree, c)) == 1)
3711 prio_queue_put(&info->topo_queue, c);
3712 }
3713
3714 /*
3715 * This is unfortunate; the initial tips need to be shown
3716 * in the order given from the revision traversal machinery.
3717 */
3718 if (revs->sort_order == REV_SORT_IN_GRAPH_ORDER)
3719 prio_queue_reverse(&info->topo_queue);
Derrick Stolee90b666d2020-12-30 04:31:533720
3721 if (trace2_is_enabled() && !topo_walk_atexit_registered) {
3722 atexit(trace2_topo_walk_statistics_atexit);
3723 topo_walk_atexit_registered = 1;
3724 }
Derrick Stoleef0d9cc42018-11-01 13:46:203725}
3726
3727static struct commit *next_topo_commit(struct rev_info *revs)
3728{
Derrick Stoleeb4542412018-11-01 13:46:223729 struct commit *c;
3730 struct topo_walk_info *info = revs->topo_walk_info;
3731
3732 /* pop next off of topo_queue */
3733 c = prio_queue_get(&info->topo_queue);
3734
3735 if (c)
3736 *(indegree_slab_at(&info->indegree, c)) = 0;
3737
3738 return c;
Derrick Stoleef0d9cc42018-11-01 13:46:203739}
3740
3741static void expand_topo_walk(struct rev_info *revs, struct commit *commit)
3742{
Derrick Stoleeb4542412018-11-01 13:46:223743 struct commit_list *p;
3744 struct topo_walk_info *info = revs->topo_walk_info;
3745 if (process_parents(revs, commit, NULL, NULL) < 0) {
Derrick Stoleef0d9cc42018-11-01 13:46:203746 if (!revs->ignore_missing_links)
3747 die("Failed to traverse parents of commit %s",
3748 oid_to_hex(&commit->object.oid));
3749 }
Derrick Stoleeb4542412018-11-01 13:46:223750
Derrick Stolee90b666d2020-12-30 04:31:533751 count_topo_walked++;
3752
Derrick Stoleeb4542412018-11-01 13:46:223753 for (p = commit->parents; p; p = p->next) {
3754 struct commit *parent = p->item;
3755 int *pi;
Abhishek Kumard7f92782021-01-16 18:11:133756 timestamp_t generation;
Derrick Stoleeb4542412018-11-01 13:46:223757
Derrick Stolee1d8e31a2019-05-21 13:59:533758 if (parent->object.flags & UNINTERESTING)
3759 continue;
3760
Michael Forneyea3f7e52020-06-23 20:56:583761 if (repo_parse_commit_gently(revs->repo, parent, 1) < 0)
Derrick Stoleeb4542412018-11-01 13:46:223762 continue;
3763
Abhishek Kumarc752ad02020-06-17 09:14:113764 generation = commit_graph_generation(parent);
3765 if (generation < info->min_generation) {
3766 info->min_generation = generation;
Derrick Stoleeb4542412018-11-01 13:46:223767 compute_indegrees_to_depth(revs, info->min_generation);
3768 }
3769
3770 pi = indegree_slab_at(&info->indegree, parent);
3771
3772 (*pi)--;
3773 if (*pi == 1)
3774 prio_queue_put(&info->topo_queue, parent);
3775
3776 if (revs->first_parent_only)
3777 return;
3778 }
Derrick Stoleef0d9cc42018-11-01 13:46:203779}
3780
Alex Riesencc0e6c52007-05-04 21:54:573781int prepare_revision_walk(struct rev_info *revs)
Linus Torvaldsa4a88b22006-02-28 19:24:003782{
Jeff King1da1e072014-10-15 22:35:123783 int i;
3784 struct object_array old_pending;
René Scharfe2e7da8e2012-04-25 20:35:413785 struct commit_list **next = &revs->commits;
Linus Torvaldscd2bdc52006-04-14 23:52:133786
Jeff King1da1e072014-10-15 22:35:123787 memcpy(&old_pending, &revs->pending, sizeof(old_pending));
Linus Torvalds1f1e8952006-06-20 00:42:353788 revs->pending.nr = 0;
3789 revs->pending.alloc = 0;
3790 revs->pending.objects = NULL;
Jeff King1da1e072014-10-15 22:35:123791 for (i = 0; i < old_pending.nr; i++) {
3792 struct object_array_entry *e = old_pending.objects + i;
Jeff King20739492014-10-15 22:43:193793 struct commit *commit = handle_commit(revs, e);
Linus Torvaldscd2bdc52006-04-14 23:52:133794 if (commit) {
3795 if (!(commit->object.flags & SEEN)) {
3796 commit->object.flags |= SEEN;
René Scharfe2e7da8e2012-04-25 20:35:413797 next = commit_list_append(commit, next);
Linus Torvaldscd2bdc52006-04-14 23:52:133798 }
3799 }
Linus Torvaldscd2bdc52006-04-14 23:52:133800 }
René Scharfef1230fb2017-12-25 17:47:513801 object_array_clear(&old_pending);
Linus Torvaldscd2bdc52006-04-14 23:52:133802
Kevin Braceyd0af6632013-05-16 15:32:343803 /* Signal whether we need per-parent treesame decoration */
Kevin Bracey4d826602013-05-16 15:32:393804 if (revs->simplify_merges ||
3805 (revs->limited && limiting_can_increase_treesame(revs)))
Kevin Braceyd0af6632013-05-16 15:32:343806 revs->treesame.name = "treesame";
3807
Jonathan Tandf11e192017-12-08 15:27:153808 if (revs->exclude_promisor_objects) {
Nguyễn Thái Ngọc Duyb3c7eef2018-09-21 15:57:393809 for_each_packed_object(mark_uninteresting, revs,
Jonathan Tandf11e192017-12-08 15:27:153810 FOR_EACH_OBJECT_PROMISOR_ONLY);
3811 }
3812
Karthik Nayak98309262023-10-27 07:59:293813 oidset_init(&revs->missing_commits, 0);
3814
Derrick Stoleef32dde82020-05-11 11:56:193815 if (!revs->reflog_info)
Garima Singha56b9462020-04-06 16:59:523816 prepare_to_use_bloom_filter(revs);
Patrick Steinhardt29ef1f22021-08-05 11:25:243817 if (!revs->unsorted_input)
Martin von Zweigbergkca92e592012-08-29 06:15:543818 commit_list_sort_by_date(&revs->commits);
Linus Torvaldsba1d4502006-04-15 19:09:563819 if (revs->no_walk)
Alex Riesencc0e6c52007-05-04 21:54:573820 return 0;
Derrick Stoleef0d9cc42018-11-01 13:46:203821 if (revs->limited) {
Alex Riesencc0e6c52007-05-04 21:54:573822 if (limit_list(revs) < 0)
3823 return -1;
Derrick Stoleef0d9cc42018-11-01 13:46:203824 if (revs->topo_order)
3825 sort_in_topological_order(&revs->commits, revs->sort_order);
3826 } else if (revs->topo_order)
3827 init_topo_walk(revs);
SZEDER Gábor3cb9d2b2020-05-11 11:56:173828 if (revs->line_level_traverse && want_ancestry(revs))
3829 /*
3830 * At the moment we can only do line-level log with parent
3831 * rewriting by performing this expensive pre-filtering step.
3832 * If parent rewriting is not requested, then we rather
3833 * perform the line-level log filtering during the regular
3834 * history traversal.
3835 */
Thomas Rast12da1d12013-03-28 16:47:323836 line_log_filter(revs);
Junio C Hamano6546b592008-07-31 08:17:413837 if (revs->simplify_merges)
3838 simplify_merges(revs);
Junio C Hamanof35f5602008-04-03 09:12:063839 if (revs->children.name)
3840 set_children(revs);
Garima Singha56b9462020-04-06 16:59:523841
Alex Riesencc0e6c52007-05-04 21:54:573842 return 0;
Linus Torvaldsa4a88b22006-02-28 19:24:003843}
3844
Jeff King8320b1d2019-04-04 01:41:093845static enum rewrite_result rewrite_one_1(struct rev_info *revs,
3846 struct commit **pp,
3847 struct prio_queue *queue)
Linus Torvaldsa4a88b22006-02-28 19:24:003848{
Linus Torvalds765ac8e2006-02-28 23:07:203849 for (;;) {
3850 struct commit *p = *pp;
Linus Torvalds3381c792006-04-09 00:05:583851 if (!revs->limited)
Jeff King8320b1d2019-04-04 01:41:093852 if (process_parents(revs, p, NULL, queue) < 0)
Alex Riesencc0e6c52007-05-04 21:54:573853 return rewrite_one_error;
Linus Torvalds7dc0fe32007-11-13 07:16:083854 if (p->object.flags & UNINTERESTING)
3855 return rewrite_one_ok;
3856 if (!(p->object.flags & TREESAME))
Alex Riesencc0e6c52007-05-04 21:54:573857 return rewrite_one_ok;
Linus Torvalds765ac8e2006-02-28 23:07:203858 if (!p->parents)
Alex Riesencc0e6c52007-05-04 21:54:573859 return rewrite_one_noparents;
Junio C Hamanoafe8a902022-05-02 16:50:373860 if (!(p = one_relevant_parent(revs, p->parents)))
Kevin Bracey4d826602013-05-16 15:32:393861 return rewrite_one_ok;
3862 *pp = p;
Linus Torvalds765ac8e2006-02-28 23:07:203863 }
Linus Torvaldsa4a88b22006-02-28 19:24:003864}
3865
Jeff King8320b1d2019-04-04 01:41:093866static void merge_queue_into_list(struct prio_queue *q, struct commit_list **list)
3867{
3868 while (q->nr) {
3869 struct commit *item = prio_queue_peek(q);
3870 struct commit_list *p = *list;
3871
3872 if (p && p->item->date >= item->date)
3873 list = &p->next;
3874 else {
3875 p = commit_list_insert(item, list);
3876 list = &p->next; /* skip newly added item */
3877 prio_queue_get(q); /* pop item */
3878 }
3879 }
3880}
3881
3882static enum rewrite_result rewrite_one(struct rev_info *revs, struct commit **pp)
3883{
3884 struct prio_queue queue = { compare_commits_by_commit_date };
3885 enum rewrite_result ret = rewrite_one_1(revs, pp, &queue);
3886 merge_queue_into_list(&queue, &revs->commits);
3887 clear_prio_queue(&queue);
3888 return ret;
3889}
3890
Bo Yangc7edcae2013-03-28 16:47:313891int rewrite_parents(struct rev_info *revs, struct commit *commit,
3892 rewrite_parent_fn_t rewrite_parent)
Linus Torvalds765ac8e2006-02-28 23:07:203893{
3894 struct commit_list **pp = &commit->parents;
3895 while (*pp) {
3896 struct commit_list *parent = *pp;
Bo Yangc7edcae2013-03-28 16:47:313897 switch (rewrite_parent(revs, &parent->item)) {
Alex Riesencc0e6c52007-05-04 21:54:573898 case rewrite_one_ok:
3899 break;
3900 case rewrite_one_noparents:
Linus Torvalds765ac8e2006-02-28 23:07:203901 *pp = parent->next;
3902 continue;
Alex Riesencc0e6c52007-05-04 21:54:573903 case rewrite_one_error:
3904 return -1;
Linus Torvalds765ac8e2006-02-28 23:07:203905 }
3906 pp = &parent->next;
3907 }
Kevin Braceyd0af6632013-05-16 15:32:343908 remove_duplicate_parents(revs, commit);
Alex Riesencc0e6c52007-05-04 21:54:573909 return 0;
Linus Torvalds765ac8e2006-02-28 23:07:203910}
Linus Torvaldsa4a88b22006-02-28 19:24:003911
Junio C Hamano8ecae9b2006-09-17 22:43:403912static int commit_match(struct commit *commit, struct rev_info *opt)
3913{
Nguyễn Thái Ngọc Duy72fd13f2012-09-29 04:41:283914 int retval;
Jeff King04deccd2013-02-11 20:59:583915 const char *encoding;
Jeff Kingb000c592014-06-10 21:39:303916 const char *message;
Nguyễn Thái Ngọc Duy72fd13f2012-09-29 04:41:283917 struct strbuf buf = STRBUF_INIT;
Jeff King04deccd2013-02-11 20:59:583918
Junio C Hamano80235ba2010-01-18 04:09:063919 if (!opt->grep_filter.pattern_list && !opt->grep_filter.header_list)
Junio C Hamano8ecae9b2006-09-17 22:43:403920 return 1;
Junio C Hamanobaa63782012-09-29 18:59:523921
3922 /* Prepend "fake" headers as needed */
3923 if (opt->grep_filter.use_reflog_filter) {
Nguyễn Thái Ngọc Duy72fd13f2012-09-29 04:41:283924 strbuf_addstr(&buf, "reflog ");
3925 get_reflog_message(&buf, opt->reflog_info);
3926 strbuf_addch(&buf, '\n');
Nguyễn Thái Ngọc Duy72fd13f2012-09-29 04:41:283927 }
Junio C Hamanobaa63782012-09-29 18:59:523928
Jeff King04deccd2013-02-11 20:59:583929 /*
3930 * We grep in the user's output encoding, under the assumption that it
3931 * is the encoding they are most likely to write their grep pattern
3932 * for. In addition, it means we will match the "notes" encoding below,
3933 * so we will not end up with a buffer that has two different encodings
3934 * in it.
3935 */
3936 encoding = get_log_output_encoding();
Ævar Arnfjörð Bjarmasonecb50912023-03-28 13:58:483937 message = repo_logmsg_reencode(the_repository, commit, NULL, encoding);
Jeff King04deccd2013-02-11 20:59:583938
Junio C Hamanobaa63782012-09-29 18:59:523939 /* Copy the commit to temporary if we are using "fake" headers */
3940 if (buf.len)
Jeff King04deccd2013-02-11 20:59:583941 strbuf_addstr(&buf, message);
Junio C Hamanobaa63782012-09-29 18:59:523942
Junio C Hamanodf874fa2013-01-08 08:02:493943 if (opt->grep_filter.header_list && opt->mailmap) {
Siddharth Asthanae9c1b0e2022-07-18 19:50:593944 const char *commit_headers[] = { "author ", "committer ", NULL };
3945
Antoine Pelissed72fbe82013-01-05 21:26:453946 if (!buf.len)
Jeff King04deccd2013-02-11 20:59:583947 strbuf_addstr(&buf, message);
Antoine Pelissed72fbe82013-01-05 21:26:453948
Siddharth Asthana66a8a952022-07-18 19:51:013949 apply_mailmap_to_header(&buf, commit_headers, opt->mailmap);
Antoine Pelissed72fbe82013-01-05 21:26:453950 }
3951
Nguyễn Thái Ngọc Duy38cfe912012-09-29 04:41:293952 /* Append "fake" message parts as needed */
3953 if (opt->show_notes) {
3954 if (!buf.len)
Jeff King04deccd2013-02-11 20:59:583955 strbuf_addstr(&buf, message);
brian m. carlsonfb61e4d2017-05-30 17:30:413956 format_display_notes(&commit->object.oid, &buf, encoding, 1);
Nguyễn Thái Ngọc Duy38cfe912012-09-29 04:41:293957 }
3958
Jeff Kingb000c592014-06-10 21:39:303959 /*
3960 * Find either in the original commit message, or in the temporary.
3961 * Note that we cast away the constness of "message" here. It is
3962 * const because it may come from the cached commit buffer. That's OK,
3963 * because we know that it is modifiable heap memory, and that while
3964 * grep_buffer may modify it for speed, it will restore any
3965 * changes before returning.
3966 */
Nguyễn Thái Ngọc Duy72fd13f2012-09-29 04:41:283967 if (buf.len)
3968 retval = grep_buffer(&opt->grep_filter, buf.buf, buf.len);
3969 else
3970 retval = grep_buffer(&opt->grep_filter,
Jeff Kingb000c592014-06-10 21:39:303971 (char *)message, strlen(message));
Nguyễn Thái Ngọc Duy72fd13f2012-09-29 04:41:283972 strbuf_release(&buf);
Ævar Arnfjörð Bjarmasonecb50912023-03-28 13:58:483973 repo_unuse_commit_buffer(the_repository, commit, message);
René Scharfe794c0002021-12-17 16:48:493974 return retval;
Junio C Hamano8ecae9b2006-09-17 22:43:403975}
3976
Thomas Rast53d00b32013-07-31 20:13:203977static inline int want_ancestry(const struct rev_info *revs)
Junio C Hamanof35f5602008-04-03 09:12:063978{
Junio C Hamano8bb65882008-07-08 22:25:443979 return (revs->rewrite_parents || revs->children.name);
Junio C Hamanof35f5602008-04-03 09:12:063980}
3981
Jeff Kingde239442017-07-07 09:16:213982/*
3983 * Return a timestamp to be used for --since/--until comparisons for this
3984 * commit, based on the revision options.
3985 */
3986static timestamp_t comparison_date(const struct rev_info *revs,
3987 struct commit *commit)
3988{
3989 return revs->reflog_info ?
3990 get_reflog_timestamp(revs->reflog_info) :
3991 commit->date;
3992}
3993
Adam Simpkinsbeb5af42009-08-19 02:34:333994enum commit_action get_commit_action(struct rev_info *revs, struct commit *commit)
Linus Torvalds252a7c02007-11-04 20:12:053995{
3996 if (commit->object.flags & SHOWN)
3997 return commit_ignore;
brian m. carlson14c3c802018-05-02 00:25:333998 if (revs->unpacked && has_object_pack(&commit->object.oid))
Linus Torvalds252a7c02007-11-04 20:12:053999 return commit_ignore;
Taylor Blauc9fff002021-02-23 02:25:074000 if (revs->no_kept_objects) {
4001 if (has_object_kept_pack(&commit->object.oid,
4002 revs->keep_pack_cache_flags))
4003 return commit_ignore;
4004 }
Linus Torvalds252a7c02007-11-04 20:12:054005 if (commit->object.flags & UNINTERESTING)
4006 return commit_ignore;
SZEDER Gábor3cb9d2b2020-05-11 11:56:174007 if (revs->line_level_traverse && !want_ancestry(revs)) {
4008 /*
4009 * In case of line-level log with parent rewriting
4010 * prepare_revision_walk() already took care of all line-level
4011 * log filtering, and there is nothing left to do here.
4012 *
4013 * If parent rewriting was not requested, then this is the
4014 * place to perform the line-level log filtering. Notably,
4015 * this check, though expensive, must come before the other,
4016 * cheaper filtering conditions, because the tracked line
4017 * ranges must be adjusted even when the commit will end up
4018 * being ignored based on other conditions.
4019 */
4020 if (!line_log_process_ranges_arbitrary_commit(revs, commit))
4021 return commit_ignore;
4022 }
Jeff Kingde239442017-07-07 09:16:214023 if (revs->min_age != -1 &&
4024 comparison_date(revs, commit) > revs->min_age)
4025 return commit_ignore;
Miklos Vajna96697782022-04-23 12:59:574026 if (revs->max_age_as_filter != -1 &&
4027 comparison_date(revs, commit) < revs->max_age_as_filter)
4028 return commit_ignore;
Michael J Gruberad5aeed2011-03-21 10:14:064029 if (revs->min_parents || (revs->max_parents >= 0)) {
Kevin Braceybf3418b2013-05-16 15:32:404030 int n = commit_list_count(commit->parents);
Michael J Gruberad5aeed2011-03-21 10:14:064031 if ((n < revs->min_parents) ||
4032 ((revs->max_parents >= 0) && (n > revs->max_parents)))
4033 return commit_ignore;
4034 }
Linus Torvalds252a7c02007-11-04 20:12:054035 if (!commit_match(commit, revs))
4036 return commit_ignore;
Linus Torvalds53b2c822007-11-05 21:22:344037 if (revs->prune && revs->dense) {
Linus Torvalds252a7c02007-11-04 20:12:054038 /* Commit without changes? */
Linus Torvalds7dc0fe32007-11-13 07:16:084039 if (commit->object.flags & TREESAME) {
Kevin Braceybf3418b2013-05-16 15:32:404040 int n;
4041 struct commit_list *p;
Linus Torvalds252a7c02007-11-04 20:12:054042 /* drop merges unless we want parenthood */
Junio C Hamanof35f5602008-04-03 09:12:064043 if (!want_ancestry(revs))
Linus Torvalds252a7c02007-11-04 20:12:054044 return commit_ignore;
Derrick Stolee8d049e12020-04-10 12:19:434045
4046 if (revs->show_pulls && (commit->object.flags & PULL_MERGE))
4047 return commit_show;
4048
Kevin Braceybf3418b2013-05-16 15:32:404049 /*
4050 * If we want ancestry, then need to keep any merges
4051 * between relevant commits to tie together topology.
4052 * For consistency with TREESAME and simplification
4053 * use "relevant" here rather than just INTERESTING,
4054 * to treat bottom commit(s) as part of the topology.
4055 */
4056 for (n = 0, p = commit->parents; p; p = p->next)
4057 if (relevant_commit(p->item))
4058 if (++n >= 2)
4059 return commit_show;
4060 return commit_ignore;
Linus Torvalds252a7c02007-11-04 20:12:054061 }
Linus Torvalds252a7c02007-11-04 20:12:054062 }
4063 return commit_show;
4064}
4065
Junio C Hamano0131c492015-01-14 22:49:244066define_commit_slab(saved_parents, struct commit_list *);
4067
4068#define EMPTY_PARENT_LIST ((struct commit_list *)-1)
4069
4070/*
4071 * You may only call save_parents() once per commit (this is checked
4072 * for non-root commits).
4073 */
4074static void save_parents(struct rev_info *revs, struct commit *commit)
4075{
4076 struct commit_list **pp;
4077
4078 if (!revs->saved_parents_slab) {
4079 revs->saved_parents_slab = xmalloc(sizeof(struct saved_parents));
4080 init_saved_parents(revs->saved_parents_slab);
4081 }
4082
4083 pp = saved_parents_at(revs->saved_parents_slab, commit);
4084
4085 /*
4086 * When walking with reflogs, we may visit the same commit
4087 * several times: once for each appearance in the reflog.
4088 *
4089 * In this case, save_parents() will be called multiple times.
4090 * We want to keep only the first set of parents. We need to
4091 * store a sentinel value for an empty (i.e., NULL) parent
4092 * list to distinguish it from a not-yet-saved list, however.
4093 */
4094 if (*pp)
4095 return;
4096 if (commit->parents)
4097 *pp = copy_commit_list(commit->parents);
4098 else
4099 *pp = EMPTY_PARENT_LIST;
4100}
4101
4102static void free_saved_parents(struct rev_info *revs)
4103{
4104 if (revs->saved_parents_slab)
4105 clear_saved_parents(revs->saved_parents_slab);
4106}
4107
4108struct commit_list *get_saved_parents(struct rev_info *revs, const struct commit *commit)
4109{
4110 struct commit_list *parents;
4111
4112 if (!revs->saved_parents_slab)
4113 return commit->parents;
4114
4115 parents = *saved_parents_at(revs->saved_parents_slab, commit);
4116 if (parents == EMPTY_PARENT_LIST)
4117 return NULL;
4118 return parents;
4119}
4120
Adam Simpkinsbeb5af42009-08-19 02:34:334121enum commit_action simplify_commit(struct rev_info *revs, struct commit *commit)
4122{
4123 enum commit_action action = get_commit_action(revs, commit);
4124
4125 if (action == commit_show &&
Adam Simpkinsbeb5af42009-08-19 02:34:334126 revs->prune && revs->dense && want_ancestry(revs)) {
Thomas Rast53d00b32013-07-31 20:13:204127 /*
4128 * --full-diff on simplified parents is no good: it
4129 * will show spurious changes from the commits that
4130 * were elided. So we save the parents on the side
4131 * when --full-diff is in effect.
4132 */
4133 if (revs->full_diff)
4134 save_parents(revs, commit);
Bo Yangc7edcae2013-03-28 16:47:314135 if (rewrite_parents(revs, commit, rewrite_one) < 0)
Adam Simpkinsbeb5af42009-08-19 02:34:334136 return commit_error;
4137 }
4138 return action;
4139}
4140
Nguyễn Thái Ngọc Duy1b32dec2014-03-25 13:23:274141static void track_linear(struct rev_info *revs, struct commit *commit)
4142{
4143 if (revs->track_first_time) {
4144 revs->linear = 1;
4145 revs->track_first_time = 0;
4146 } else {
4147 struct commit_list *p;
4148 for (p = revs->previous_parents; p; p = p->next)
4149 if (p->item == NULL || /* first commit */
Jeff King4a7e27e2018-08-28 21:22:404150 oideq(&p->item->object.oid, &commit->object.oid))
Nguyễn Thái Ngọc Duy1b32dec2014-03-25 13:23:274151 break;
4152 revs->linear = p != NULL;
4153 }
4154 if (revs->reverse) {
4155 if (revs->linear)
4156 commit->object.flags |= TRACK_LINEAR;
4157 }
4158 free_commit_list(revs->previous_parents);
4159 revs->previous_parents = copy_commit_list(commit->parents);
4160}
4161
Junio C Hamanod5db6c92006-12-20 02:25:324162static struct commit *get_revision_1(struct rev_info *revs)
Linus Torvalds765ac8e2006-02-28 23:07:204163{
Jeff King7c2f08a2017-07-07 09:07:584164 while (1) {
Jeff Kingd08565b2017-07-07 09:14:074165 struct commit *commit;
Linus Torvalds765ac8e2006-02-28 23:07:204166
Jeff Kingd08565b2017-07-07 09:14:074167 if (revs->reflog_info)
4168 commit = next_reflog_entry(revs->reflog_info);
Derrick Stoleef0d9cc42018-11-01 13:46:204169 else if (revs->topo_walk_info)
4170 commit = next_topo_commit(revs);
Jeff Kingd08565b2017-07-07 09:14:074171 else
4172 commit = pop_commit(&revs->commits);
Linus Torvalds2a0925b2006-03-31 01:05:254173
Jeff King7c2f08a2017-07-07 09:07:584174 if (!commit)
4175 return NULL;
4176
Jeff Kingd08565b2017-07-07 09:14:074177 if (revs->reflog_info)
Jeff Kingffa1eea2010-11-22 04:42:534178 commit->object.flags &= ~(ADDED | SEEN | SHOWN);
Johannes Schindelin8860fd42007-01-11 10:47:484179
Linus Torvalds2a0925b2006-03-31 01:05:254180 /*
4181 * If we haven't done the list limiting, we need to look at
Linus Torvaldsbe7db6e2006-04-02 00:35:064182 * the parents here. We also need to do the date-based limiting
4183 * that we'd otherwise have done in limit_list().
Linus Torvalds2a0925b2006-03-31 01:05:254184 */
Linus Torvaldsbe7db6e2006-04-02 00:35:064185 if (!revs->limited) {
Jan Harkes744f4982006-10-31 01:37:494186 if (revs->max_age != -1 &&
Jeff Kingde239442017-07-07 09:16:214187 comparison_date(revs, commit) < revs->max_age)
Junio C Hamano86ab4902007-03-05 21:10:064188 continue;
Jeff Kingd08565b2017-07-07 09:14:074189
4190 if (revs->reflog_info)
4191 try_to_simplify_commit(revs, commit);
Derrick Stoleef0d9cc42018-11-01 13:46:204192 else if (revs->topo_walk_info)
4193 expand_topo_walk(revs, commit);
Derrick Stolee5284fc52018-11-01 13:46:214194 else if (process_parents(revs, commit, &revs->commits, NULL) < 0) {
Vicent Marti2db1a432014-03-28 10:00:434195 if (!revs->ignore_missing_links)
4196 die("Failed to traverse parents of commit %s",
brian m. carlsonf2fd0762015-11-10 02:22:284197 oid_to_hex(&commit->object.oid));
Vicent Marti2db1a432014-03-28 10:00:434198 }
Linus Torvaldsbe7db6e2006-04-02 00:35:064199 }
Junio C Hamano1b65a5a2006-04-17 01:12:494200
Linus Torvalds252a7c02007-11-04 20:12:054201 switch (simplify_commit(revs, commit)) {
4202 case commit_ignore:
Linus Torvalds2a0925b2006-03-31 01:05:254203 continue;
Linus Torvalds252a7c02007-11-04 20:12:054204 case commit_error:
Junio C Hamanoed620892009-02-11 09:27:434205 die("Failed to simplify parents of commit %s",
brian m. carlsonf2fd0762015-11-10 02:22:284206 oid_to_hex(&commit->object.oid));
Linus Torvalds252a7c02007-11-04 20:12:054207 default:
Nguyễn Thái Ngọc Duy1b32dec2014-03-25 13:23:274208 if (revs->track_linear)
4209 track_linear(revs, commit);
Linus Torvalds252a7c02007-11-04 20:12:054210 return commit;
Junio C Hamano384e99a2006-03-28 07:58:344211 }
Jeff King7c2f08a2017-07-07 09:07:584212 }
Linus Torvalds765ac8e2006-02-28 23:07:204213}
Junio C Hamanod5db6c92006-12-20 02:25:324214
Michael Haggertybe6754c2013-05-25 09:08:094215/*
4216 * Return true for entries that have not yet been shown. (This is an
4217 * object_array_each_func_t.)
4218 */
Jeff Kingd3dcfa02023-02-24 06:39:154219static int entry_unshown(struct object_array_entry *entry, void *cb_data UNUSED)
Michael Haggertybe6754c2013-05-25 09:08:094220{
4221 return !(entry->item->flags & SHOWN);
4222}
4223
4224/*
4225 * If array is on the verge of a realloc, garbage-collect any entries
4226 * that have already been shown to try to free up some space.
4227 */
Junio C Hamano86ab4902007-03-05 21:10:064228static void gc_boundary(struct object_array *array)
4229{
Michael Haggertybe6754c2013-05-25 09:08:094230 if (array->nr == array->alloc)
4231 object_array_filter(array, entry_unshown, NULL);
Junio C Hamano86ab4902007-03-05 21:10:064232}
4233
Adam Simpkins4603ec02008-05-24 23:02:054234static void create_boundary_commit_list(struct rev_info *revs)
4235{
4236 unsigned i;
4237 struct commit *c;
4238 struct object_array *array = &revs->boundary_commits;
4239 struct object_array_entry *objects = array->objects;
4240
4241 /*
4242 * If revs->commits is non-NULL at this point, an error occurred in
4243 * get_revision_1(). Ignore the error and continue printing the
4244 * boundary commits anyway. (This is what the code has always
4245 * done.)
4246 */
Ævar Arnfjörð Bjarmasonbf20fe42022-04-13 20:01:344247 free_commit_list(revs->commits);
4248 revs->commits = NULL;
Adam Simpkins4603ec02008-05-24 23:02:054249
4250 /*
4251 * Put all of the actual boundary commits from revs->boundary_commits
4252 * into revs->commits
4253 */
4254 for (i = 0; i < array->nr; i++) {
4255 c = (struct commit *)(objects[i].item);
4256 if (!c)
4257 continue;
4258 if (!(c->object.flags & CHILD_SHOWN))
4259 continue;
4260 if (c->object.flags & (SHOWN | BOUNDARY))
4261 continue;
4262 c->object.flags |= BOUNDARY;
4263 commit_list_insert(c, &revs->commits);
4264 }
4265
4266 /*
4267 * If revs->topo_order is set, sort the boundary commits
4268 * in topological order
4269 */
Junio C Hamano08f704f2013-06-06 23:07:144270 sort_in_topological_order(&revs->commits, revs->sort_order);
Adam Simpkins4603ec02008-05-24 23:02:054271}
4272
Adam Simpkins7fefda52008-05-04 10:36:544273static struct commit *get_revision_internal(struct rev_info *revs)
Junio C Hamanod5db6c92006-12-20 02:25:324274{
4275 struct commit *c = NULL;
Junio C Hamano86ab4902007-03-05 21:10:064276 struct commit_list *l;
Junio C Hamanod5db6c92006-12-20 02:25:324277
Junio C Hamano86ab4902007-03-05 21:10:064278 if (revs->boundary == 2) {
Adam Simpkins4603ec02008-05-24 23:02:054279 /*
4280 * All of the normal commits have already been returned,
4281 * and we are now returning boundary commits.
4282 * create_boundary_commit_list() has populated
4283 * revs->commits with the remaining commits to return.
4284 */
4285 c = pop_commit(&revs->commits);
4286 if (c)
4287 c->object.flags |= SHOWN;
Johannes Schindelin9c5e66e2007-01-20 22:04:024288 return c;
4289 }
4290
Junio C Hamano86ab4902007-03-05 21:10:064291 /*
Jeff Kingb72a1902012-07-13 07:50:234292 * If our max_count counter has reached zero, then we are done. We
4293 * don't simply return NULL because we still might need to show
4294 * boundary commits. But we want to avoid calling get_revision_1, which
4295 * might do a considerable amount of work finding the next commit only
4296 * for us to throw it away.
4297 *
4298 * If it is non-zero, then either we don't have a max_count at all
4299 * (-1), or it is still counting, in which case we decrement.
Junio C Hamano86ab4902007-03-05 21:10:064300 */
Jeff Kingb72a1902012-07-13 07:50:234301 if (revs->max_count) {
4302 c = get_revision_1(revs);
4303 if (c) {
Felipe Contreras9e57ac52013-10-31 09:25:434304 while (revs->skip_count > 0) {
Jeff Kingb72a1902012-07-13 07:50:234305 revs->skip_count--;
4306 c = get_revision_1(revs);
4307 if (!c)
4308 break;
4309 }
Junio C Hamano8839ac92007-03-06 11:20:554310 }
Junio C Hamano86ab4902007-03-05 21:10:064311
Jeff Kingb72a1902012-07-13 07:50:234312 if (revs->max_count > 0)
4313 revs->max_count--;
Junio C Hamanod5db6c92006-12-20 02:25:324314 }
Junio C Hamano86ab4902007-03-05 21:10:064315
Junio C Hamanoc33d8592007-03-06 02:23:574316 if (c)
4317 c->object.flags |= SHOWN;
4318
Felipe Contreras9e57ac52013-10-31 09:25:434319 if (!revs->boundary)
Junio C Hamanod5db6c92006-12-20 02:25:324320 return c;
Junio C Hamano86ab4902007-03-05 21:10:064321
4322 if (!c) {
4323 /*
4324 * get_revision_1() runs out the commits, and
4325 * we are done computing the boundaries.
4326 * switch to boundary commits output mode.
4327 */
4328 revs->boundary = 2;
Adam Simpkins4603ec02008-05-24 23:02:054329
4330 /*
4331 * Update revs->commits to contain the list of
4332 * boundary commits.
4333 */
4334 create_boundary_commit_list(revs);
4335
Adam Simpkins3c68d672008-05-24 23:02:044336 return get_revision_internal(revs);
Junio C Hamano86ab4902007-03-05 21:10:064337 }
4338
4339 /*
4340 * boundary commits are the commits that are parents of the
4341 * ones we got from get_revision_1() but they themselves are
4342 * not returned from get_revision_1(). Before returning
4343 * 'c', we need to mark its parents that they could be boundaries.
4344 */
4345
4346 for (l = c->parents; l; l = l->next) {
4347 struct object *p;
4348 p = &(l->item->object);
Junio C Hamanoc33d8592007-03-06 02:23:574349 if (p->flags & (CHILD_SHOWN | SHOWN))
Junio C Hamano86ab4902007-03-05 21:10:064350 continue;
4351 p->flags |= CHILD_SHOWN;
4352 gc_boundary(&revs->boundary_commits);
4353 add_object_array(p, NULL, &revs->boundary_commits);
4354 }
4355
4356 return c;
Junio C Hamanod5db6c92006-12-20 02:25:324357}
Adam Simpkins7fefda52008-05-04 10:36:544358
4359struct commit *get_revision(struct rev_info *revs)
4360{
Thomas Rast498bcd32008-08-29 19:18:384361 struct commit *c;
4362 struct commit_list *reversed;
4363
4364 if (revs->reverse) {
4365 reversed = NULL;
Felipe Contreras9e57ac52013-10-31 09:25:434366 while ((c = get_revision_internal(revs)))
Thomas Rast498bcd32008-08-29 19:18:384367 commit_list_insert(c, &reversed);
Thomas Rast498bcd32008-08-29 19:18:384368 revs->commits = reversed;
4369 revs->reverse = 0;
4370 revs->reverse_output_stage = 1;
4371 }
4372
Nguyễn Thái Ngọc Duy1b32dec2014-03-25 13:23:274373 if (revs->reverse_output_stage) {
4374 c = pop_commit(&revs->commits);
4375 if (revs->track_linear)
4376 revs->linear = !!(c && c->object.flags & TRACK_LINEAR);
4377 return c;
4378 }
Thomas Rast498bcd32008-08-29 19:18:384379
4380 c = get_revision_internal(revs);
Adam Simpkins7fefda52008-05-04 10:36:544381 if (c && revs->graph)
4382 graph_update(revs->graph, c);
Nguyễn Thái Ngọc Duy1b32dec2014-03-25 13:23:274383 if (!c) {
Thomas Rast53d00b32013-07-31 20:13:204384 free_saved_parents(revs);
Ævar Arnfjörð Bjarmasonbf20fe42022-04-13 20:01:344385 free_commit_list(revs->previous_parents);
4386 revs->previous_parents = NULL;
Nguyễn Thái Ngọc Duy1b32dec2014-03-25 13:23:274387 }
Adam Simpkins7fefda52008-05-04 10:36:544388 return c;
4389}
Michael J Gruber1df2d652011-03-07 12:31:394390
Denton Liu49825162019-11-20 00:51:134391const char *get_revision_mark(const struct rev_info *revs, const struct commit *commit)
Michael J Gruber1df2d652011-03-07 12:31:394392{
4393 if (commit->object.flags & BOUNDARY)
4394 return "-";
4395 else if (commit->object.flags & UNINTERESTING)
4396 return "^";
Michael J Gruberadbbb312011-03-07 12:31:404397 else if (commit->object.flags & PATCHSAME)
4398 return "=";
Michael J Gruber1df2d652011-03-07 12:31:394399 else if (!revs || revs->left_right) {
4400 if (commit->object.flags & SYMMETRIC_LEFT)
4401 return "<";
4402 else
4403 return ">";
4404 } else if (revs->graph)
4405 return "*";
Michael J Gruberadbbb312011-03-07 12:31:404406 else if (revs->cherry_mark)
4407 return "+";
Michael J Gruber1df2d652011-03-07 12:31:394408 return "";
4409}
Michael J Gruberb1b47552011-03-10 14:45:034410
4411void put_revision_mark(const struct rev_info *revs, const struct commit *commit)
4412{
Denton Liu49825162019-11-20 00:51:134413 const char *mark = get_revision_mark(revs, commit);
Michael J Gruberb1b47552011-03-10 14:45:034414 if (!strlen(mark))
4415 return;
4416 fputs(mark, stdout);
4417 putchar(' ');
4418}