1 #define USE_THE_REPOSITORY_VARIABLE
3 #include "git-compat-util.h"
11 #include "reachable.h"
12 #include "cache-tree.h"
14 #include "list-objects.h"
17 #include "object-file.h"
18 #include "pack-bitmap.h"
19 #include "pack-mtimes.h"
21 #include "run-command.h"
22 #include "sequencer.h"
24 struct connectivity_progress
{
25 struct progress
*progress
;
29 static void update_progress(struct connectivity_progress
*cp
)
32 if ((cp
->count
& 1023) == 0)
33 display_progress(cp
->progress
, cp
->count
);
36 static void add_one_file(const char *path
, struct rev_info
*revs
)
38 struct strbuf buf
= STRBUF_INIT
;
40 struct object
*object
;
42 if (!read_oneliner(&buf
, path
, READ_ONELINER_SKIP_IF_EMPTY
)) {
47 if (!get_oid_hex(buf
.buf
, &oid
)) {
48 object
= parse_object_or_die(the_repository
, &oid
, buf
.buf
);
49 add_pending_object(revs
, object
, "");
54 /* Mark objects recorded in rebase state files as reachable. */
55 static void add_rebase_files(struct rev_info
*revs
)
57 struct strbuf buf
= STRBUF_INIT
;
59 const char *path
[] = {
60 "rebase-apply/autostash",
61 "rebase-apply/orig-head",
62 "rebase-merge/autostash",
63 "rebase-merge/orig-head",
65 struct worktree
**worktrees
= get_worktrees();
67 for (struct worktree
**wt
= worktrees
; *wt
; wt
++) {
68 char *wt_gitdir
= get_worktree_git_dir(*wt
);
71 strbuf_addstr(&buf
, wt_gitdir
);
72 strbuf_complete(&buf
, '/');
74 for (size_t i
= 0; i
< ARRAY_SIZE(path
); i
++) {
75 strbuf_setlen(&buf
, len
);
76 strbuf_addstr(&buf
, path
[i
]);
77 add_one_file(buf
.buf
, revs
);
83 free_worktrees(worktrees
);
86 static int add_one_ref(const char *path
, const char *referent UNUSED
, const struct object_id
*oid
,
87 int flag
, void *cb_data
)
89 struct rev_info
*revs
= (struct rev_info
*)cb_data
;
90 struct object
*object
;
92 if ((flag
& REF_ISSYMREF
) && (flag
& REF_ISBROKEN
)) {
93 warning("symbolic ref is dangling: %s", path
);
97 object
= parse_object_or_die(the_repository
, oid
, path
);
98 add_pending_object(revs
, object
, "");
104 * The traversal will have already marked us as SEEN, so we
105 * only need to handle any progress reporting here.
107 static void mark_object(struct object
*obj UNUSED
,
108 const char *name UNUSED
,
111 update_progress(data
);
114 static void mark_commit(struct commit
*c
, void *data
)
116 mark_object(&c
->object
, NULL
, data
);
120 struct rev_info
*revs
;
121 timestamp_t timestamp
;
122 report_recent_object_fn
*cb
;
123 int ignore_in_core_kept_packs
;
125 struct oidset extra_recent_oids
;
126 int extra_recent_oids_loaded
;
129 static int run_one_gc_recent_objects_hook(struct oidset
*set
,
132 struct child_process cmd
= CHILD_PROCESS_INIT
;
133 struct strbuf buf
= STRBUF_INIT
;
140 strvec_push(&cmd
.args
, args
);
142 if (start_command(&cmd
))
145 out
= xfdopen(cmd
.out
, "r");
146 while (strbuf_getline(&buf
, out
) != EOF
) {
147 struct object_id oid
;
150 if (parse_oid_hex(buf
.buf
, &oid
, &rest
) || *rest
) {
151 ret
= error(_("invalid extra cruft tip: '%s'"), buf
.buf
);
155 oidset_insert(set
, &oid
);
159 ret
|= finish_command(&cmd
);
161 strbuf_release(&buf
);
165 static void load_gc_recent_objects(struct recent_data
*data
)
167 const struct string_list
*programs
;
171 data
->extra_recent_oids_loaded
= 1;
173 if (git_config_get_string_multi("gc.recentobjectshook", &programs
))
176 for (i
= 0; i
< programs
->nr
; i
++) {
177 ret
= run_one_gc_recent_objects_hook(&data
->extra_recent_oids
,
178 programs
->items
[i
].string
);
180 die(_("unable to enumerate additional recent objects"));
184 static int obj_is_recent(const struct object_id
*oid
, timestamp_t mtime
,
185 struct recent_data
*data
)
187 if (mtime
> data
->timestamp
)
190 if (!data
->extra_recent_oids_loaded
)
191 load_gc_recent_objects(data
);
192 return oidset_contains(&data
->extra_recent_oids
, oid
);
195 static void add_recent_object(const struct object_id
*oid
,
196 struct packed_git
*pack
,
199 struct recent_data
*data
)
202 enum object_type type
;
204 if (!obj_is_recent(oid
, mtime
, data
))
208 * We do not want to call parse_object here, because
209 * inflating blobs and trees could be very expensive.
210 * However, we do need to know the correct type for
211 * later processing, and the revision machinery expects
212 * commits and tags to have been parsed.
214 type
= odb_read_object_info(the_repository
->objects
, oid
, NULL
);
216 die("unable to get object info for %s", oid_to_hex(oid
));
221 obj
= parse_object_or_die(the_repository
, oid
, NULL
);
224 obj
= (struct object
*)lookup_tree(the_repository
, oid
);
227 obj
= (struct object
*)lookup_blob(the_repository
, oid
);
230 die("unknown object type for %s: %s",
231 oid_to_hex(oid
), type_name(type
));
235 die("unable to lookup %s", oid_to_hex(oid
));
237 add_pending_object(data
->revs
, obj
, "");
239 data
->cb(obj
, pack
, offset
, mtime
);
242 static int want_recent_object(struct recent_data
*data
,
243 const struct object_id
*oid
)
245 if (data
->ignore_in_core_kept_packs
&&
246 has_object_kept_pack(data
->revs
->repo
, oid
, IN_CORE_KEEP_PACKS
))
251 static int add_recent_loose(const struct object_id
*oid
,
252 const char *path
, void *data
)
257 if (!want_recent_object(data
, oid
))
260 obj
= lookup_object(the_repository
, oid
);
262 if (obj
&& obj
->flags
& SEEN
)
265 if (stat(path
, &st
) < 0) {
267 * It's OK if an object went away during our iteration; this
268 * could be due to a simultaneous repack. But anything else
269 * we should abort, since we might then fail to mark objects
270 * which should not be pruned.
274 return error_errno("unable to stat %s", oid_to_hex(oid
));
277 add_recent_object(oid
, NULL
, 0, st
.st_mtime
, data
);
281 static int add_recent_packed(const struct object_id
*oid
,
282 struct packed_git
*p
,
287 timestamp_t mtime
= p
->mtime
;
289 if (!want_recent_object(data
, oid
))
292 obj
= lookup_object(the_repository
, oid
);
294 if (obj
&& obj
->flags
& SEEN
)
297 if (load_pack_mtimes(p
) < 0)
298 die(_("could not load cruft pack .mtimes"));
299 mtime
= nth_packed_mtime(p
, pos
);
301 add_recent_object(oid
, p
, nth_packed_object_offset(p
, pos
), mtime
, data
);
305 int add_unseen_recent_objects_to_traversal(struct rev_info
*revs
,
306 timestamp_t timestamp
,
307 report_recent_object_fn
*cb
,
308 int ignore_in_core_kept_packs
)
310 struct recent_data data
;
311 enum for_each_object_flags flags
;
315 data
.timestamp
= timestamp
;
317 data
.ignore_in_core_kept_packs
= ignore_in_core_kept_packs
;
319 oidset_init(&data
.extra_recent_oids
, 0);
320 data
.extra_recent_oids_loaded
= 0;
322 r
= for_each_loose_object(add_recent_loose
, &data
,
323 FOR_EACH_OBJECT_LOCAL_ONLY
);
327 flags
= FOR_EACH_OBJECT_LOCAL_ONLY
| FOR_EACH_OBJECT_PACK_ORDER
;
328 if (ignore_in_core_kept_packs
)
329 flags
|= FOR_EACH_OBJECT_SKIP_IN_CORE_KEPT_PACKS
;
331 r
= for_each_packed_object(revs
->repo
, add_recent_packed
, &data
, flags
);
334 oidset_clear(&data
.extra_recent_oids
);
339 static int mark_object_seen(const struct object_id
*oid
,
340 enum object_type type
,
342 uint32_t name_hash UNUSED
,
343 struct packed_git
*found_pack UNUSED
,
344 off_t found_offset UNUSED
,
345 void *payload UNUSED
)
347 struct object
*obj
= lookup_object_by_type(the_repository
, oid
, type
);
349 die("unable to create object '%s'", oid_to_hex(oid
));
355 void mark_reachable_objects(struct rev_info
*revs
, int mark_reflog
,
356 timestamp_t mark_recent
, struct progress
*progress
)
358 struct connectivity_progress cp
;
359 struct bitmap_index
*bitmap_git
;
362 * Set up revision parsing, and mark us as being interested
363 * in all object types, not just commits.
365 revs
->tag_objects
= 1;
366 revs
->blob_objects
= 1;
367 revs
->tree_objects
= 1;
369 /* Add all refs from the index file */
370 add_index_objects_to_pending(revs
, 0);
372 /* Add all external refs */
373 refs_for_each_ref(get_main_ref_store(the_repository
), add_one_ref
,
376 /* detached HEAD is not included in the list above */
377 refs_head_ref(get_main_ref_store(the_repository
), add_one_ref
, revs
);
378 other_head_refs(add_one_ref
, revs
);
380 /* rebase autostash and orig-head */
381 add_rebase_files(revs
);
383 /* Add all reflog info */
385 add_reflogs_to_pending(revs
, 0);
387 cp
.progress
= progress
;
390 bitmap_git
= prepare_bitmap_walk(revs
, 0);
392 traverse_bitmap_commit_list(bitmap_git
, revs
, mark_object_seen
);
393 free_bitmap_index(bitmap_git
);
395 if (prepare_revision_walk(revs
))
396 die("revision walk setup failed");
397 traverse_commit_list(revs
, mark_commit
, mark_object
, &cp
);
401 revs
->ignore_missing_links
= 1;
402 if (add_unseen_recent_objects_to_traversal(revs
, mark_recent
,
404 die("unable to mark recent objects");
405 if (prepare_revision_walk(revs
))
406 die("revision walk setup failed");
407 traverse_commit_list(revs
, mark_commit
, mark_object
, &cp
);
410 display_progress(cp
.progress
, cp
.count
);