1 #define USE_THE_REPOSITORY_VARIABLE
2 #define DISABLE_SIGN_COMPARE_WARNINGS
4 #include "git-compat-util.h"
7 #include "parse-options.h"
13 #include "tree-walk.h"
14 #include "wildmatch.h"
16 static struct reflog_expire_entry_option
*find_cfg_ent(struct reflog_expire_options
*opts
,
17 const char *pattern
, size_t len
)
19 struct reflog_expire_entry_option
*ent
;
21 if (!opts
->entries_tail
)
22 opts
->entries_tail
= &opts
->entries
;
24 for (ent
= opts
->entries
; ent
; ent
= ent
->next
)
25 if (!xstrncmpz(ent
->pattern
, pattern
, len
))
28 FLEX_ALLOC_MEM(ent
, pattern
, pattern
, len
);
29 *opts
->entries_tail
= ent
;
30 opts
->entries_tail
= &(ent
->next
);
34 int reflog_expire_config(const char *var
, const char *value
,
35 const struct config_context
*ctx
, void *cb
)
37 struct reflog_expire_options
*opts
= cb
;
38 const char *pattern
, *key
;
42 struct reflog_expire_entry_option
*ent
;
44 if (parse_config_key(var
, "gc", &pattern
, &pattern_len
, &key
) < 0)
45 return git_default_config(var
, value
, ctx
, cb
);
47 if (!strcmp(key
, "reflogexpire")) {
48 slot
= REFLOG_EXPIRE_TOTAL
;
49 if (git_config_expiry_date(&expire
, var
, value
))
51 } else if (!strcmp(key
, "reflogexpireunreachable")) {
52 slot
= REFLOG_EXPIRE_UNREACH
;
53 if (git_config_expiry_date(&expire
, var
, value
))
56 return git_default_config(var
, value
, ctx
, cb
);
60 case REFLOG_EXPIRE_TOTAL
:
61 opts
->default_expire_total
= expire
;
63 case REFLOG_EXPIRE_UNREACH
:
64 opts
->default_expire_unreachable
= expire
;
70 ent
= find_cfg_ent(opts
, pattern
, pattern_len
);
74 case REFLOG_EXPIRE_TOTAL
:
75 ent
->expire_total
= expire
;
77 case REFLOG_EXPIRE_UNREACH
:
78 ent
->expire_unreachable
= expire
;
84 void reflog_clear_expire_config(struct reflog_expire_options
*opts
)
86 struct reflog_expire_entry_option
*ent
= opts
->entries
, *tmp
;
95 opts
->entries_tail
= NULL
;
98 void reflog_expire_options_set_refname(struct reflog_expire_options
*cb
,
101 struct reflog_expire_entry_option
*ent
;
103 if (cb
->explicit_expiry
== (REFLOG_EXPIRE_TOTAL
|REFLOG_EXPIRE_UNREACH
))
104 return; /* both given explicitly -- nothing to tweak */
106 for (ent
= cb
->entries
; ent
; ent
= ent
->next
) {
107 if (!wildmatch(ent
->pattern
, ref
, 0)) {
108 if (!(cb
->explicit_expiry
& REFLOG_EXPIRE_TOTAL
))
109 cb
->expire_total
= ent
->expire_total
;
110 if (!(cb
->explicit_expiry
& REFLOG_EXPIRE_UNREACH
))
111 cb
->expire_unreachable
= ent
->expire_unreachable
;
117 * If unconfigured, make stash never expire
119 if (!strcmp(ref
, "refs/stash")) {
120 if (!(cb
->explicit_expiry
& REFLOG_EXPIRE_TOTAL
))
121 cb
->expire_total
= 0;
122 if (!(cb
->explicit_expiry
& REFLOG_EXPIRE_UNREACH
))
123 cb
->expire_unreachable
= 0;
127 /* Nothing matched -- use the default value */
128 if (!(cb
->explicit_expiry
& REFLOG_EXPIRE_TOTAL
))
129 cb
->expire_total
= cb
->default_expire_total
;
130 if (!(cb
->explicit_expiry
& REFLOG_EXPIRE_UNREACH
))
131 cb
->expire_unreachable
= cb
->default_expire_unreachable
;
134 /* Remember to update object flag allocation in object.h */
135 #define INCOMPLETE (1u<<10)
136 #define STUDYING (1u<<11)
137 #define REACHABLE (1u<<12)
139 static int tree_is_complete(const struct object_id
*oid
)
141 struct tree_desc desc
;
142 struct name_entry entry
;
146 tree
= lookup_tree(the_repository
, oid
);
149 if (tree
->object
.flags
& SEEN
)
151 if (tree
->object
.flags
& INCOMPLETE
)
155 enum object_type type
;
157 void *data
= odb_read_object(the_repository
->objects
, oid
,
160 tree
->object
.flags
|= INCOMPLETE
;
166 init_tree_desc(&desc
, &tree
->object
.oid
, tree
->buffer
, tree
->size
);
168 while (tree_entry(&desc
, &entry
)) {
169 if (!odb_has_object(the_repository
->objects
, &entry
.oid
,
170 HAS_OBJECT_RECHECK_PACKED
| HAS_OBJECT_FETCH_PROMISOR
) ||
171 (S_ISDIR(entry
.mode
) && !tree_is_complete(&entry
.oid
))) {
172 tree
->object
.flags
|= INCOMPLETE
;
176 free_tree_buffer(tree
);
179 tree
->object
.flags
|= SEEN
;
183 static int commit_is_complete(struct commit
*commit
)
185 struct object_array study
;
186 struct object_array found
;
187 int is_incomplete
= 0;
191 if (commit
->object
.flags
& SEEN
)
193 if (commit
->object
.flags
& INCOMPLETE
)
196 * Find all commits that are reachable and are not marked as
197 * SEEN. Then make sure the trees and blobs contained are
198 * complete. After that, mark these commits also as SEEN.
199 * If some of the objects that are needed to complete this
200 * commit are missing, mark this commit as INCOMPLETE.
202 memset(&study
, 0, sizeof(study
));
203 memset(&found
, 0, sizeof(found
));
204 add_object_array(&commit
->object
, NULL
, &study
);
205 add_object_array(&commit
->object
, NULL
, &found
);
206 commit
->object
.flags
|= STUDYING
;
209 struct commit_list
*parent
;
211 c
= (struct commit
*)object_array_pop(&study
);
212 if (!c
->object
.parsed
&& !parse_object(the_repository
, &c
->object
.oid
))
213 c
->object
.flags
|= INCOMPLETE
;
215 if (c
->object
.flags
& INCOMPLETE
) {
219 else if (c
->object
.flags
& SEEN
)
221 for (parent
= c
->parents
; parent
; parent
= parent
->next
) {
222 struct commit
*p
= parent
->item
;
223 if (p
->object
.flags
& STUDYING
)
225 p
->object
.flags
|= STUDYING
;
226 add_object_array(&p
->object
, NULL
, &study
);
227 add_object_array(&p
->object
, NULL
, &found
);
230 if (!is_incomplete
) {
232 * make sure all commits in "found" array have all the
235 for (i
= 0; i
< found
.nr
; i
++) {
237 (struct commit
*)found
.objects
[i
].item
;
238 if (!tree_is_complete(get_commit_tree_oid(c
))) {
240 c
->object
.flags
|= INCOMPLETE
;
243 if (!is_incomplete
) {
244 /* mark all found commits as complete, iow SEEN */
245 for (i
= 0; i
< found
.nr
; i
++)
246 found
.objects
[i
].item
->flags
|= SEEN
;
249 /* clear flags from the objects we traversed */
250 for (i
= 0; i
< found
.nr
; i
++)
251 found
.objects
[i
].item
->flags
&= ~STUDYING
;
253 commit
->object
.flags
|= INCOMPLETE
;
256 * If we come here, we have (1) traversed the ancestry chain
257 * from the "commit" until we reach SEEN commits (which are
258 * known to be complete), and (2) made sure that the commits
259 * encountered during the above traversal refer to trees that
260 * are complete. Which means that we know *all* the commits
261 * we have seen during this process are complete.
263 for (i
= 0; i
< found
.nr
; i
++)
264 found
.objects
[i
].item
->flags
|= SEEN
;
266 /* free object arrays */
267 object_array_clear(&study
);
268 object_array_clear(&found
);
269 return !is_incomplete
;
272 static int keep_entry(struct commit
**it
, struct object_id
*oid
)
274 struct commit
*commit
;
276 if (is_null_oid(oid
))
278 commit
= lookup_commit_reference_gently(the_repository
, oid
, 1);
283 * Make sure everything in this commit exists.
285 * We have walked all the objects reachable from the refs
286 * and cache earlier. The commits reachable by this commit
287 * must meet SEEN commits -- and then we should mark them as
290 if (!commit_is_complete(commit
))
297 * Starting from commits in the cb->mark_list, mark commits that are
298 * reachable from them. Stop the traversal at commits older than
299 * the expire_limit and queue them back, so that the caller can call
300 * us again to restart the traversal with longer expire_limit.
302 static void mark_reachable(struct expire_reflog_policy_cb
*cb
)
304 struct commit_list
*pending
;
305 timestamp_t expire_limit
= cb
->mark_limit
;
306 struct commit_list
*leftover
= NULL
;
308 for (pending
= cb
->mark_list
; pending
; pending
= pending
->next
)
309 pending
->item
->object
.flags
&= ~REACHABLE
;
311 pending
= cb
->mark_list
;
313 struct commit_list
*parent
;
314 struct commit
*commit
= pop_commit(&pending
);
315 if (commit
->object
.flags
& REACHABLE
)
317 if (repo_parse_commit(the_repository
, commit
))
319 commit
->object
.flags
|= REACHABLE
;
320 if (commit
->date
< expire_limit
) {
321 commit_list_insert(commit
, &leftover
);
324 parent
= commit
->parents
;
326 commit
= parent
->item
;
327 parent
= parent
->next
;
328 if (commit
->object
.flags
& REACHABLE
)
330 commit_list_insert(commit
, &pending
);
333 cb
->mark_list
= leftover
;
336 static int is_unreachable(struct expire_reflog_policy_cb
*cb
, struct commit
*commit
, struct object_id
*oid
)
339 * We may or may not have the commit yet - if not, look it
340 * up using the supplied sha1.
343 if (is_null_oid(oid
))
346 commit
= lookup_commit_reference_gently(the_repository
, oid
,
349 /* Not a commit -- keep it */
354 /* Reachable from the current ref? Don't prune. */
355 if (commit
->object
.flags
& REACHABLE
)
358 if (cb
->mark_list
&& cb
->mark_limit
) {
359 cb
->mark_limit
= 0; /* dig down to the root */
363 return !(commit
->object
.flags
& REACHABLE
);
367 * Return true iff the specified reflog entry should be expired.
369 int should_expire_reflog_ent(struct object_id
*ooid
, struct object_id
*noid
,
370 const char *email UNUSED
,
371 timestamp_t timestamp
, int tz UNUSED
,
372 const char *message UNUSED
, void *cb_data
)
374 struct expire_reflog_policy_cb
*cb
= cb_data
;
375 struct commit
*old_commit
, *new_commit
;
377 if (timestamp
< cb
->opts
.expire_total
)
380 old_commit
= new_commit
= NULL
;
381 if (cb
->opts
.stalefix
&&
382 (!keep_entry(&old_commit
, ooid
) || !keep_entry(&new_commit
, noid
)))
385 if (timestamp
< cb
->opts
.expire_unreachable
) {
386 switch (cb
->unreachable_expire_kind
) {
391 if (is_unreachable(cb
, old_commit
, ooid
) || is_unreachable(cb
, new_commit
, noid
))
397 if (cb
->opts
.recno
&& --(cb
->opts
.recno
) == 0)
403 int should_expire_reflog_ent_verbose(struct object_id
*ooid
,
404 struct object_id
*noid
,
406 timestamp_t timestamp
, int tz
,
407 const char *message
, void *cb_data
)
409 struct expire_reflog_policy_cb
*cb
= cb_data
;
412 expire
= should_expire_reflog_ent(ooid
, noid
, email
, timestamp
, tz
,
416 printf("keep %s", message
);
417 else if (cb
->dry_run
)
418 printf("would prune %s", message
);
420 printf("prune %s", message
);
425 static int push_tip_to_list(const char *refname UNUSED
,
426 const char *referent UNUSED
,
427 const struct object_id
*oid
,
428 int flags
, void *cb_data
)
430 struct commit_list
**list
= cb_data
;
431 struct commit
*tip_commit
;
432 if (flags
& REF_ISSYMREF
)
434 tip_commit
= lookup_commit_reference_gently(the_repository
, oid
, 1);
437 commit_list_insert(tip_commit
, list
);
441 static int is_head(const char *refname
)
443 const char *stripped_refname
;
444 parse_worktree_ref(refname
, NULL
, NULL
, &stripped_refname
);
445 return !strcmp(stripped_refname
, "HEAD");
448 void reflog_expiry_prepare(const char *refname
,
449 const struct object_id
*oid
,
452 struct expire_reflog_policy_cb
*cb
= cb_data
;
453 struct commit_list
*elem
;
454 struct commit
*commit
= NULL
;
456 if (!cb
->opts
.expire_unreachable
|| is_head(refname
)) {
457 cb
->unreachable_expire_kind
= UE_HEAD
;
459 commit
= lookup_commit_reference_gently(the_repository
,
461 if (commit
&& is_null_oid(&commit
->object
.oid
))
463 cb
->unreachable_expire_kind
= commit
? UE_NORMAL
: UE_ALWAYS
;
466 if (cb
->opts
.expire_unreachable
<= cb
->opts
.expire_total
)
467 cb
->unreachable_expire_kind
= UE_ALWAYS
;
469 switch (cb
->unreachable_expire_kind
) {
473 refs_for_each_ref(get_main_ref_store(the_repository
),
474 push_tip_to_list
, &cb
->tips
);
475 for (elem
= cb
->tips
; elem
; elem
= elem
->next
)
476 commit_list_insert(elem
->item
, &cb
->mark_list
);
479 commit_list_insert(commit
, &cb
->mark_list
);
480 /* For reflog_expiry_cleanup() below */
481 cb
->tip_commit
= commit
;
483 cb
->mark_limit
= cb
->opts
.expire_total
;
487 void reflog_expiry_cleanup(void *cb_data
)
489 struct expire_reflog_policy_cb
*cb
= cb_data
;
490 struct commit_list
*elem
;
492 switch (cb
->unreachable_expire_kind
) {
496 for (elem
= cb
->tips
; elem
; elem
= elem
->next
)
497 clear_commit_marks(elem
->item
, REACHABLE
);
498 free_commit_list(cb
->tips
);
501 clear_commit_marks(cb
->tip_commit
, REACHABLE
);
504 for (elem
= cb
->mark_list
; elem
; elem
= elem
->next
)
505 clear_commit_marks(elem
->item
, REACHABLE
);
506 free_commit_list(cb
->mark_list
);
509 int count_reflog_ent(struct object_id
*ooid UNUSED
,
510 struct object_id
*noid UNUSED
,
511 const char *email UNUSED
,
512 timestamp_t timestamp
, int tz UNUSED
,
513 const char *message UNUSED
, void *cb_data
)
515 struct reflog_expire_options
*cb
= cb_data
;
516 if (!cb
->expire_total
|| timestamp
< cb
->expire_total
)
521 int reflog_delete(const char *rev
, enum expire_reflog_flags flags
, int verbose
)
523 struct reflog_expire_options opts
= { 0 };
525 reflog_expiry_should_prune_fn
*should_prune_fn
= should_expire_reflog_ent
;
526 const char *spec
= strstr(rev
, "@{");
529 struct expire_reflog_policy_cb cb
= {
530 .dry_run
= !!(flags
& EXPIRE_REFLOGS_DRY_RUN
),
534 should_prune_fn
= should_expire_reflog_ent_verbose
;
537 return error(_("not a reflog: %s"), rev
);
539 if (!repo_dwim_log(the_repository
, rev
, spec
- rev
, NULL
, &ref
)) {
540 status
|= error(_("no reflog for '%s'"), rev
);
544 recno
= strtoul(spec
+ 2, &ep
, 10);
547 refs_for_each_reflog_ent(get_main_ref_store(the_repository
),
548 ref
, count_reflog_ent
, &opts
);
550 opts
.expire_total
= approxidate(spec
+ 2);
551 refs_for_each_reflog_ent(get_main_ref_store(the_repository
),
552 ref
, count_reflog_ent
, &opts
);
553 opts
.expire_total
= 0;
557 status
|= refs_reflog_expire(get_main_ref_store(the_repository
), ref
,
559 reflog_expiry_prepare
,
561 reflog_expiry_cleanup
,