blob: f29b06a5d059e23030333f26d5ba0667872251ab [file] [log] [blame]
Elijah Newren98750582023-03-21 06:26:04 +00001#include "git-compat-util.h"
Elijah Newrenf394e092023-03-21 06:25:54 +00002#include "gettext.h"
Elijah Newren41771fa2023-02-24 00:09:27 +00003#include "hex.h"
Junio C Hamano94421472007-01-06 02:16:17 -08004#include "refs.h"
Junio C Hamano94421472007-01-06 02:16:17 -08005#include "commit.h"
6#include "blob.h"
7#include "diff.h"
8#include "revision.h"
9#include "reachable.h"
10#include "cache-tree.h"
Nguyễn Thái Ngọc Duydc347192011-11-05 19:00:08 +070011#include "progress.h"
Jeff King5f78a432014-10-15 18:37:28 -040012#include "list-objects.h"
Jonathan Tan7709f462017-08-18 15:20:38 -070013#include "packfile.h"
Nguyễn Thái Ngọc Duyd0c39a42017-08-23 19:36:59 +070014#include "worktree.h"
Elijah Newrena034e912023-05-16 06:34:06 +000015#include "object-store-ll.h"
Jeff Kingfde67d62019-02-13 23:37:43 -050016#include "pack-bitmap.h"
Taylor Blaufb546d62022-05-20 19:17:57 -040017#include "pack-mtimes.h"
Taylor Blau4dc16e22023-06-07 18:58:17 -040018#include "config.h"
19#include "run-command.h"
Junio C Hamano94421472007-01-06 02:16:17 -080020
Jeff King0b26abc2011-11-08 00:37:00 -050021struct connectivity_progress {
22 struct progress *progress;
23 unsigned long count;
24};
25
26static void update_progress(struct connectivity_progress *cp)
27{
28 cp->count++;
29 if ((cp->count & 1023) == 0)
30 display_progress(cp->progress, cp->count);
31}
32
Michael Haggerty635170f2015-05-25 18:39:00 +000033static int add_one_ref(const char *path, const struct object_id *oid,
34 int flag, void *cb_data)
Junio C Hamano94421472007-01-06 02:16:17 -080035{
Junio C Hamano94421472007-01-06 02:16:17 -080036 struct rev_info *revs = (struct rev_info *)cb_data;
Johannes Schindelin14886b42015-09-28 16:01:25 +020037 struct object *object;
Junio C Hamano94421472007-01-06 02:16:17 -080038
Johannes Schindelin14886b42015-09-28 16:01:25 +020039 if ((flag & REF_ISSYMREF) && (flag & REF_ISBROKEN)) {
40 warning("symbolic ref is dangling: %s", path);
41 return 0;
42 }
43
brian m. carlsonc251c832017-05-06 22:10:38 +000044 object = parse_object_or_die(oid, path);
Junio C Hamano94421472007-01-06 02:16:17 -080045 add_pending_object(revs, object, "");
46
47 return 0;
48}
49
Jeff King5f78a432014-10-15 18:37:28 -040050/*
51 * The traversal will have already marked us as SEEN, so we
52 * only need to handle any progress reporting here.
53 */
Jeff Kingc50dca22023-02-24 01:39:22 -050054static void mark_object(struct object *obj UNUSED,
55 const char *name UNUSED,
56 void *data)
Jeff King5f78a432014-10-15 18:37:28 -040057{
58 update_progress(data);
59}
60
61static void mark_commit(struct commit *c, void *data)
62{
Jeff Kingde1e67d2016-02-11 17:28:36 -050063 mark_object(&c->object, NULL, data);
Jeff King5f78a432014-10-15 18:37:28 -040064}
65
Jeff Kingd3038d22014-10-15 18:41:35 -040066struct recent_data {
67 struct rev_info *revs;
Johannes Schindelindddbad72017-04-26 21:29:31 +020068 timestamp_t timestamp;
Taylor Blau2fb90402022-05-20 19:17:54 -040069 report_recent_object_fn *cb;
70 int ignore_in_core_kept_packs;
Taylor Blau4dc16e22023-06-07 18:58:17 -040071
72 struct oidset extra_recent_oids;
73 int extra_recent_oids_loaded;
Jeff Kingd3038d22014-10-15 18:41:35 -040074};
75
Taylor Blau4dc16e22023-06-07 18:58:17 -040076static int run_one_gc_recent_objects_hook(struct oidset *set,
77 const char *args)
78{
79 struct child_process cmd = CHILD_PROCESS_INIT;
80 struct strbuf buf = STRBUF_INIT;
81 FILE *out;
82 int ret = 0;
83
84 cmd.use_shell = 1;
85 cmd.out = -1;
86
87 strvec_push(&cmd.args, args);
88
89 if (start_command(&cmd))
90 return -1;
91
92 out = xfdopen(cmd.out, "r");
93 while (strbuf_getline(&buf, out) != EOF) {
94 struct object_id oid;
95 const char *rest;
96
97 if (parse_oid_hex(buf.buf, &oid, &rest) || *rest) {
98 ret = error(_("invalid extra cruft tip: '%s'"), buf.buf);
99 break;
100 }
101
102 oidset_insert(set, &oid);
103 }
104
105 fclose(out);
106 ret |= finish_command(&cmd);
107
108 strbuf_release(&buf);
109 return ret;
110}
111
112static void load_gc_recent_objects(struct recent_data *data)
113{
114 const struct string_list *programs;
115 int ret = 0;
116 size_t i;
117
118 data->extra_recent_oids_loaded = 1;
119
120 if (git_config_get_string_multi("gc.recentobjectshook", &programs))
121 return;
122
123 for (i = 0; i < programs->nr; i++) {
124 ret = run_one_gc_recent_objects_hook(&data->extra_recent_oids,
125 programs->items[i].string);
126 if (ret)
127 die(_("unable to enumerate additional recent objects"));
128 }
129}
130
Taylor Blau01e9ca42023-06-07 18:58:12 -0400131static int obj_is_recent(const struct object_id *oid, timestamp_t mtime,
132 struct recent_data *data)
133{
Taylor Blau4dc16e22023-06-07 18:58:17 -0400134 if (mtime > data->timestamp)
135 return 1;
136
137 if (!data->extra_recent_oids_loaded)
138 load_gc_recent_objects(data);
139 return oidset_contains(&data->extra_recent_oids, oid);
Taylor Blau01e9ca42023-06-07 18:58:12 -0400140}
141
brian m. carlson76c1d9a2017-02-21 23:47:35 +0000142static void add_recent_object(const struct object_id *oid,
Taylor Blau2fb90402022-05-20 19:17:54 -0400143 struct packed_git *pack,
144 off_t offset,
Johannes Schindelindddbad72017-04-26 21:29:31 +0200145 timestamp_t mtime,
Jeff Kingd3038d22014-10-15 18:41:35 -0400146 struct recent_data *data)
147{
148 struct object *obj;
149 enum object_type type;
150
Taylor Blau01e9ca42023-06-07 18:58:12 -0400151 if (!obj_is_recent(oid, mtime, data))
Jeff Kingd3038d22014-10-15 18:41:35 -0400152 return;
153
154 /*
155 * We do not want to call parse_object here, because
156 * inflating blobs and trees could be very expensive.
157 * However, we do need to know the correct type for
158 * later processing, and the revision machinery expects
159 * commits and tags to have been parsed.
160 */
Stefan Beller0df8e962018-04-25 11:20:59 -0700161 type = oid_object_info(the_repository, oid, NULL);
Jeff Kingd3038d22014-10-15 18:41:35 -0400162 if (type < 0)
brian m. carlson76c1d9a2017-02-21 23:47:35 +0000163 die("unable to get object info for %s", oid_to_hex(oid));
Jeff Kingd3038d22014-10-15 18:41:35 -0400164
165 switch (type) {
166 case OBJ_TAG:
167 case OBJ_COMMIT:
brian m. carlsonc251c832017-05-06 22:10:38 +0000168 obj = parse_object_or_die(oid, NULL);
Jeff Kingd3038d22014-10-15 18:41:35 -0400169 break;
170 case OBJ_TREE:
Stefan Bellerf86bcc72018-06-28 18:21:56 -0700171 obj = (struct object *)lookup_tree(the_repository, oid);
Jeff Kingd3038d22014-10-15 18:41:35 -0400172 break;
173 case OBJ_BLOB:
Stefan Bellerda14a7f2018-06-28 18:21:55 -0700174 obj = (struct object *)lookup_blob(the_repository, oid);
Jeff Kingd3038d22014-10-15 18:41:35 -0400175 break;
176 default:
177 die("unknown object type for %s: %s",
Brandon Williamsdebca9d2018-02-14 10:59:24 -0800178 oid_to_hex(oid), type_name(type));
Jeff Kingd3038d22014-10-15 18:41:35 -0400179 }
180
181 if (!obj)
brian m. carlson76c1d9a2017-02-21 23:47:35 +0000182 die("unable to lookup %s", oid_to_hex(oid));
Jeff Kingd3038d22014-10-15 18:41:35 -0400183
184 add_pending_object(data->revs, obj, "");
Taylor Blau2fb90402022-05-20 19:17:54 -0400185 if (data->cb)
186 data->cb(obj, pack, offset, mtime);
187}
188
189static int want_recent_object(struct recent_data *data,
190 const struct object_id *oid)
191{
192 if (data->ignore_in_core_kept_packs &&
193 has_object_kept_pack(oid, IN_CORE_KEEP_PACKS))
194 return 0;
195 return 1;
Jeff Kingd3038d22014-10-15 18:41:35 -0400196}
197
brian m. carlson76c1d9a2017-02-21 23:47:35 +0000198static int add_recent_loose(const struct object_id *oid,
Jeff Kingd3038d22014-10-15 18:41:35 -0400199 const char *path, void *data)
200{
201 struct stat st;
Taylor Blau2fb90402022-05-20 19:17:54 -0400202 struct object *obj;
203
204 if (!want_recent_object(data, oid))
205 return 0;
206
207 obj = lookup_object(the_repository, oid);
Jeff Kingd3038d22014-10-15 18:41:35 -0400208
209 if (obj && obj->flags & SEEN)
210 return 0;
211
212 if (stat(path, &st) < 0) {
213 /*
214 * It's OK if an object went away during our iteration; this
215 * could be due to a simultaneous repack. But anything else
216 * we should abort, since we might then fail to mark objects
217 * which should not be pruned.
218 */
219 if (errno == ENOENT)
220 return 0;
brian m. carlson76c1d9a2017-02-21 23:47:35 +0000221 return error_errno("unable to stat %s", oid_to_hex(oid));
Jeff Kingd3038d22014-10-15 18:41:35 -0400222 }
223
Taylor Blau2fb90402022-05-20 19:17:54 -0400224 add_recent_object(oid, NULL, 0, st.st_mtime, data);
Jeff Kingd3038d22014-10-15 18:41:35 -0400225 return 0;
226}
227
brian m. carlson76c1d9a2017-02-21 23:47:35 +0000228static int add_recent_packed(const struct object_id *oid,
Jeff Kingbe252d32023-02-24 01:39:24 -0500229 struct packed_git *p,
230 uint32_t pos,
Jeff Kingd3038d22014-10-15 18:41:35 -0400231 void *data)
232{
Taylor Blau2fb90402022-05-20 19:17:54 -0400233 struct object *obj;
Taylor Blaufb546d62022-05-20 19:17:57 -0400234 timestamp_t mtime = p->mtime;
Taylor Blau2fb90402022-05-20 19:17:54 -0400235
236 if (!want_recent_object(data, oid))
237 return 0;
238
239 obj = lookup_object(the_repository, oid);
Jeff Kingd3038d22014-10-15 18:41:35 -0400240
241 if (obj && obj->flags & SEEN)
242 return 0;
Taylor Blaufb546d62022-05-20 19:17:57 -0400243 if (p->is_cruft) {
244 if (load_pack_mtimes(p) < 0)
245 die(_("could not load cruft pack .mtimes"));
246 mtime = nth_packed_mtime(p, pos);
247 }
248 add_recent_object(oid, p, nth_packed_object_offset(p, pos), mtime, data);
Jeff Kingd3038d22014-10-15 18:41:35 -0400249 return 0;
250}
251
Jeff Kingabcb8652014-10-15 18:42:09 -0400252int add_unseen_recent_objects_to_traversal(struct rev_info *revs,
Taylor Blau2fb90402022-05-20 19:17:54 -0400253 timestamp_t timestamp,
254 report_recent_object_fn *cb,
255 int ignore_in_core_kept_packs)
Jeff Kingd3038d22014-10-15 18:41:35 -0400256{
257 struct recent_data data;
Taylor Blau2fb90402022-05-20 19:17:54 -0400258 enum for_each_object_flags flags;
Jeff Kingd3038d22014-10-15 18:41:35 -0400259 int r;
260
261 data.revs = revs;
262 data.timestamp = timestamp;
Taylor Blau2fb90402022-05-20 19:17:54 -0400263 data.cb = cb;
264 data.ignore_in_core_kept_packs = ignore_in_core_kept_packs;
Jeff Kingd3038d22014-10-15 18:41:35 -0400265
Taylor Blau4dc16e22023-06-07 18:58:17 -0400266 oidset_init(&data.extra_recent_oids, 0);
267 data.extra_recent_oids_loaded = 0;
268
Jeff King1385bb72015-03-27 07:32:41 -0400269 r = for_each_loose_object(add_recent_loose, &data,
270 FOR_EACH_OBJECT_LOCAL_ONLY);
Jeff Kingd3038d22014-10-15 18:41:35 -0400271 if (r)
Taylor Blau4dc16e22023-06-07 18:58:17 -0400272 goto done;
Taylor Blau2fb90402022-05-20 19:17:54 -0400273
274 flags = FOR_EACH_OBJECT_LOCAL_ONLY | FOR_EACH_OBJECT_PACK_ORDER;
275 if (ignore_in_core_kept_packs)
276 flags |= FOR_EACH_OBJECT_SKIP_IN_CORE_KEPT_PACKS;
277
Taylor Blau4dc16e22023-06-07 18:58:17 -0400278 r = for_each_packed_object(add_recent_packed, &data, flags);
279
280done:
281 oidset_clear(&data.extra_recent_oids);
282
283 return r;
Jeff Kingd3038d22014-10-15 18:41:35 -0400284}
285
Jeff Kingfde67d62019-02-13 23:37:43 -0500286static int mark_object_seen(const struct object_id *oid,
287 enum object_type type,
Jeff Kingc50dca22023-02-24 01:39:22 -0500288 int exclude UNUSED,
289 uint32_t name_hash UNUSED,
290 struct packed_git *found_pack UNUSED,
291 off_t found_offset UNUSED)
Jeff Kingfde67d62019-02-13 23:37:43 -0500292{
293 struct object *obj = lookup_object_by_type(the_repository, oid, type);
294 if (!obj)
295 die("unable to create object '%s'", oid_to_hex(oid));
296
297 obj->flags |= SEEN;
298 return 0;
299}
300
Nguyễn Thái Ngọc Duydc347192011-11-05 19:00:08 +0700301void mark_reachable_objects(struct rev_info *revs, int mark_reflog,
Johannes Schindelindddbad72017-04-26 21:29:31 +0200302 timestamp_t mark_recent, struct progress *progress)
Junio C Hamano94421472007-01-06 02:16:17 -0800303{
Jeff King0b26abc2011-11-08 00:37:00 -0500304 struct connectivity_progress cp;
Jeff Kingfde67d62019-02-13 23:37:43 -0500305 struct bitmap_index *bitmap_git;
Jeff King0b26abc2011-11-08 00:37:00 -0500306
Junio C Hamano94421472007-01-06 02:16:17 -0800307 /*
308 * Set up revision parsing, and mark us as being interested
309 * in all object types, not just commits.
310 */
311 revs->tag_objects = 1;
312 revs->blob_objects = 1;
313 revs->tree_objects = 1;
314
315 /* Add all refs from the index file */
Jeff King1be111d2014-10-16 20:44:30 -0400316 add_index_objects_to_pending(revs, 0);
Junio C Hamano94421472007-01-06 02:16:17 -0800317
318 /* Add all external refs */
Michael Haggerty635170f2015-05-25 18:39:00 +0000319 for_each_ref(add_one_ref, revs);
Junio C Hamano94421472007-01-06 02:16:17 -0800320
Max Kirillovc40fdd02014-09-03 19:14:10 +0300321 /* detached HEAD is not included in the list above */
Michael Haggerty635170f2015-05-25 18:39:00 +0000322 head_ref(add_one_ref, revs);
Nguyễn Thái Ngọc Duyd0c39a42017-08-23 19:36:59 +0700323 other_head_refs(add_one_ref, revs);
Max Kirillovc40fdd02014-09-03 19:14:10 +0300324
Nicolas Pitreeb8381c2007-02-03 13:25:43 -0500325 /* Add all reflog info */
Junio C Hamano94421472007-01-06 02:16:17 -0800326 if (mark_reflog)
Jeff King718ccc92014-10-15 18:38:31 -0400327 add_reflogs_to_pending(revs, 0);
Junio C Hamano94421472007-01-06 02:16:17 -0800328
Jeff King0b26abc2011-11-08 00:37:00 -0500329 cp.progress = progress;
330 cp.count = 0;
331
Derrick Stolee09d4a792022-03-09 16:01:35 +0000332 bitmap_git = prepare_bitmap_walk(revs, 0);
Jeff Kingfde67d62019-02-13 23:37:43 -0500333 if (bitmap_git) {
Jeff King4eb707e2020-02-14 13:22:27 -0500334 traverse_bitmap_commit_list(bitmap_git, revs, mark_object_seen);
Jeff Kingfde67d62019-02-13 23:37:43 -0500335 free_bitmap_index(bitmap_git);
Jeff King2ba582b2021-04-28 11:42:43 -0400336 } else {
337 if (prepare_revision_walk(revs))
338 die("revision walk setup failed");
339 traverse_commit_list(revs, mark_commit, mark_object, &cp);
Jeff Kingfde67d62019-02-13 23:37:43 -0500340 }
341
Jeff Kingd3038d22014-10-15 18:41:35 -0400342 if (mark_recent) {
343 revs->ignore_missing_links = 1;
Taylor Blau2fb90402022-05-20 19:17:54 -0400344 if (add_unseen_recent_objects_to_traversal(revs, mark_recent,
345 NULL, 0))
Jeff Kingd3038d22014-10-15 18:41:35 -0400346 die("unable to mark recent objects");
347 if (prepare_revision_walk(revs))
348 die("revision walk setup failed");
349 traverse_commit_list(revs, mark_commit, mark_object, &cp);
350 }
351
Jeff King0b26abc2011-11-08 00:37:00 -0500352 display_progress(cp.progress, cp.count);
Junio C Hamano94421472007-01-06 02:16:17 -0800353}