Raw
1 #define USE_THE_REPOSITORY_VARIABLE
2 #define DISABLE_SIGN_COMPARE_WARNINGS
3
4 #include "git-compat-util.h"
5 #include "config.h"
6 #include "environment.h"
7 #include "gettext.h"
8 #include "parse-options.h"
9 #include "odb.h"
10 #include "reflog.h"
11 #include "refs.h"
12 #include "revision.h"
13 #include "tree.h"
14 #include "tree-walk.h"
15 #include "wildmatch.h"
16
17 static struct reflog_expire_entry_option *find_cfg_ent(struct reflog_expire_options *opts,
18 const char *pattern, size_t len)
19 {
20 struct reflog_expire_entry_option *ent;
21
22 if (!opts->entries_tail)
23 opts->entries_tail = &opts->entries;
24
25 for (ent = opts->entries; ent; ent = ent->next)
26 if (!xstrncmpz(ent->pattern, pattern, len))
27 return ent;
28
29 FLEX_ALLOC_MEM(ent, pattern, pattern, len);
30 *opts->entries_tail = ent;
31 opts->entries_tail = &(ent->next);
32 return ent;
33 }
34
35 int reflog_expire_config(const char *var, const char *value,
36 const struct config_context *ctx, void *cb)
37 {
38 struct reflog_expire_options *opts = cb;
39 const char *pattern, *key;
40 size_t pattern_len;
41 timestamp_t expire;
42 int slot;
43 struct reflog_expire_entry_option *ent;
44
45 if (parse_config_key(var, "gc", &pattern, &pattern_len, &key) < 0)
46 return git_default_config(var, value, ctx, cb);
47
48 if (!strcmp(key, "reflogexpire")) {
49 slot = REFLOG_EXPIRE_TOTAL;
50 if (git_config_expiry_date(&expire, var, value))
51 return -1;
52 } else if (!strcmp(key, "reflogexpireunreachable")) {
53 slot = REFLOG_EXPIRE_UNREACH;
54 if (git_config_expiry_date(&expire, var, value))
55 return -1;
56 } else
57 return git_default_config(var, value, ctx, cb);
58
59 if (!pattern) {
60 switch (slot) {
61 case REFLOG_EXPIRE_TOTAL:
62 opts->default_expire_total = expire;
63 break;
64 case REFLOG_EXPIRE_UNREACH:
65 opts->default_expire_unreachable = expire;
66 break;
67 }
68 return 0;
69 }
70
71 ent = find_cfg_ent(opts, pattern, pattern_len);
72 if (!ent)
73 return -1;
74 switch (slot) {
75 case REFLOG_EXPIRE_TOTAL:
76 ent->expire_total = expire;
77 break;
78 case REFLOG_EXPIRE_UNREACH:
79 ent->expire_unreachable = expire;
80 break;
81 }
82 return 0;
83 }
84
85 void reflog_clear_expire_config(struct reflog_expire_options *opts)
86 {
87 struct reflog_expire_entry_option *ent = opts->entries, *tmp;
88
89 while (ent) {
90 tmp = ent;
91 ent = ent->next;
92 free(tmp);
93 }
94
95 opts->entries = NULL;
96 opts->entries_tail = NULL;
97 }
98
99 void reflog_expire_options_set_refname(struct reflog_expire_options *cb,
100 const char *ref)
101 {
102 struct reflog_expire_entry_option *ent;
103
104 if (cb->explicit_expiry == (REFLOG_EXPIRE_TOTAL|REFLOG_EXPIRE_UNREACH))
105 return; /* both given explicitly -- nothing to tweak */
106
107 for (ent = cb->entries; ent; ent = ent->next) {
108 if (!wildmatch(ent->pattern, ref, 0)) {
109 if (!(cb->explicit_expiry & REFLOG_EXPIRE_TOTAL))
110 cb->expire_total = ent->expire_total;
111 if (!(cb->explicit_expiry & REFLOG_EXPIRE_UNREACH))
112 cb->expire_unreachable = ent->expire_unreachable;
113 return;
114 }
115 }
116
117 /*
118 * If unconfigured, make stash never expire
119 */
120 if (!strcmp(ref, "refs/stash")) {
121 if (!(cb->explicit_expiry & REFLOG_EXPIRE_TOTAL))
122 cb->expire_total = 0;
123 if (!(cb->explicit_expiry & REFLOG_EXPIRE_UNREACH))
124 cb->expire_unreachable = 0;
125 return;
126 }
127
128 /* Nothing matched -- use the default value */
129 if (!(cb->explicit_expiry & REFLOG_EXPIRE_TOTAL))
130 cb->expire_total = cb->default_expire_total;
131 if (!(cb->explicit_expiry & REFLOG_EXPIRE_UNREACH))
132 cb->expire_unreachable = cb->default_expire_unreachable;
133 }
134
135 /* Remember to update object flag allocation in object.h */
136 #define INCOMPLETE (1u<<10)
137 #define STUDYING (1u<<11)
138 #define REACHABLE (1u<<12)
139
140 static int tree_is_complete(const struct object_id *oid)
141 {
142 struct tree_desc desc;
143 struct name_entry entry;
144 int complete;
145 struct tree *tree;
146
147 tree = lookup_tree(the_repository, oid);
148 if (!tree)
149 return 0;
150 if (tree->object.flags & SEEN)
151 return 1;
152 if (tree->object.flags & INCOMPLETE)
153 return 0;
154
155 if (!tree->buffer) {
156 enum object_type type;
157 size_t size;
158 void *data = odb_read_object(the_repository->objects, oid,
159 &type, &size);
160 if (!data) {
161 tree->object.flags |= INCOMPLETE;
162 return 0;
163 }
164 tree->buffer = data;
165 tree->size = size;
166 }
167 init_tree_desc(&desc, &tree->object.oid, tree->buffer, tree->size);
168 complete = 1;
169 while (tree_entry(&desc, &entry)) {
170 if (!odb_has_object(the_repository->objects, &entry.oid,
171 ODB_HAS_OBJECT_RECHECK_PACKED | ODB_HAS_OBJECT_FETCH_PROMISOR) ||
172 (S_ISDIR(entry.mode) && !tree_is_complete(&entry.oid))) {
173 tree->object.flags |= INCOMPLETE;
174 complete = 0;
175 }
176 }
177 free_tree_buffer(tree);
178
179 if (complete)
180 tree->object.flags |= SEEN;
181 return complete;
182 }
183
184 static int commit_is_complete(struct commit *commit)
185 {
186 struct object_array study;
187 struct object_array found;
188 int is_incomplete = 0;
189 int i;
190
191 /* early return */
192 if (commit->object.flags & SEEN)
193 return 1;
194 if (commit->object.flags & INCOMPLETE)
195 return 0;
196 /*
197 * Find all commits that are reachable and are not marked as
198 * SEEN. Then make sure the trees and blobs contained are
199 * complete. After that, mark these commits also as SEEN.
200 * If some of the objects that are needed to complete this
201 * commit are missing, mark this commit as INCOMPLETE.
202 */
203 memset(&study, 0, sizeof(study));
204 memset(&found, 0, sizeof(found));
205 add_object_array(&commit->object, NULL, &study);
206 add_object_array(&commit->object, NULL, &found);
207 commit->object.flags |= STUDYING;
208 while (study.nr) {
209 struct commit *c;
210 struct commit_list *parent;
211
212 c = (struct commit *)object_array_pop(&study);
213 if (!c->object.parsed && !parse_object(the_repository, &c->object.oid))
214 c->object.flags |= INCOMPLETE;
215
216 if (c->object.flags & INCOMPLETE) {
217 is_incomplete = 1;
218 break;
219 }
220 else if (c->object.flags & SEEN)
221 continue;
222 for (parent = c->parents; parent; parent = parent->next) {
223 struct commit *p = parent->item;
224 if (p->object.flags & STUDYING)
225 continue;
226 p->object.flags |= STUDYING;
227 add_object_array(&p->object, NULL, &study);
228 add_object_array(&p->object, NULL, &found);
229 }
230 }
231 if (!is_incomplete) {
232 /*
233 * make sure all commits in "found" array have all the
234 * necessary objects.
235 */
236 for (i = 0; i < found.nr; i++) {
237 struct commit *c =
238 (struct commit *)found.objects[i].item;
239 if (!tree_is_complete(get_commit_tree_oid(c))) {
240 is_incomplete = 1;
241 c->object.flags |= INCOMPLETE;
242 }
243 }
244 if (!is_incomplete) {
245 /* mark all found commits as complete, iow SEEN */
246 for (i = 0; i < found.nr; i++)
247 found.objects[i].item->flags |= SEEN;
248 }
249 }
250 /* clear flags from the objects we traversed */
251 for (i = 0; i < found.nr; i++)
252 found.objects[i].item->flags &= ~STUDYING;
253 if (is_incomplete)
254 commit->object.flags |= INCOMPLETE;
255 else {
256 /*
257 * If we come here, we have (1) traversed the ancestry chain
258 * from the "commit" until we reach SEEN commits (which are
259 * known to be complete), and (2) made sure that the commits
260 * encountered during the above traversal refer to trees that
261 * are complete. Which means that we know *all* the commits
262 * we have seen during this process are complete.
263 */
264 for (i = 0; i < found.nr; i++)
265 found.objects[i].item->flags |= SEEN;
266 }
267 /* free object arrays */
268 object_array_clear(&study);
269 object_array_clear(&found);
270 return !is_incomplete;
271 }
272
273 static int keep_entry(struct commit **it, struct object_id *oid)
274 {
275 struct commit *commit;
276
277 if (is_null_oid(oid))
278 return 1;
279 commit = lookup_commit_reference_gently(the_repository, oid, 1);
280 if (!commit)
281 return 0;
282
283 /*
284 * Make sure everything in this commit exists.
285 *
286 * We have walked all the objects reachable from the refs
287 * and cache earlier. The commits reachable by this commit
288 * must meet SEEN commits -- and then we should mark them as
289 * SEEN as well.
290 */
291 if (!commit_is_complete(commit))
292 return 0;
293 *it = commit;
294 return 1;
295 }
296
297 /*
298 * Starting from commits in the cb->mark_list, mark commits that are
299 * reachable from them. Stop the traversal at commits older than
300 * the expire_limit and queue them back, so that the caller can call
301 * us again to restart the traversal with longer expire_limit.
302 */
303 static void mark_reachable(struct expire_reflog_policy_cb *cb)
304 {
305 struct commit_list *pending;
306 timestamp_t expire_limit = cb->mark_limit;
307 struct commit_list *leftover = NULL;
308
309 for (pending = cb->mark_list; pending; pending = pending->next)
310 pending->item->object.flags &= ~REACHABLE;
311
312 pending = cb->mark_list;
313 while (pending) {
314 struct commit_list *parent;
315 struct commit *commit = pop_commit(&pending);
316 if (commit->object.flags & REACHABLE)
317 continue;
318 if (repo_parse_commit(the_repository, commit))
319 continue;
320 commit->object.flags |= REACHABLE;
321 if (commit->date < expire_limit) {
322 commit_list_insert(commit, &leftover);
323 continue;
324 }
325 parent = commit->parents;
326 while (parent) {
327 commit = parent->item;
328 parent = parent->next;
329 if (commit->object.flags & REACHABLE)
330 continue;
331 commit_list_insert(commit, &pending);
332 }
333 }
334 cb->mark_list = leftover;
335 }
336
337 static int is_unreachable(struct expire_reflog_policy_cb *cb, struct commit *commit, struct object_id *oid)
338 {
339 /*
340 * We may or may not have the commit yet - if not, look it
341 * up using the supplied sha1.
342 */
343 if (!commit) {
344 if (is_null_oid(oid))
345 return 0;
346
347 commit = lookup_commit_reference_gently(the_repository, oid,
348 1);
349
350 /* Not a commit -- keep it */
351 if (!commit)
352 return 0;
353 }
354
355 /* Reachable from the current ref? Don't prune. */
356 if (commit->object.flags & REACHABLE)
357 return 0;
358
359 if (cb->mark_list && cb->mark_limit) {
360 cb->mark_limit = 0; /* dig down to the root */
361 mark_reachable(cb);
362 }
363
364 return !(commit->object.flags & REACHABLE);
365 }
366
367 /*
368 * Return true iff the specified reflog entry should be expired.
369 */
370 int should_expire_reflog_ent(struct object_id *ooid, struct object_id *noid,
371 const char *email UNUSED,
372 timestamp_t timestamp, int tz UNUSED,
373 const char *message UNUSED, void *cb_data)
374 {
375 struct expire_reflog_policy_cb *cb = cb_data;
376 struct commit *old_commit, *new_commit;
377
378 if (timestamp < cb->opts.expire_total)
379 return 1;
380
381 old_commit = new_commit = NULL;
382 if (cb->opts.stalefix &&
383 (!keep_entry(&old_commit, ooid) || !keep_entry(&new_commit, noid)))
384 return 1;
385
386 if (timestamp < cb->opts.expire_unreachable) {
387 switch (cb->unreachable_expire_kind) {
388 case UE_ALWAYS:
389 return 1;
390 case UE_NORMAL:
391 case UE_HEAD:
392 if (is_unreachable(cb, old_commit, ooid) || is_unreachable(cb, new_commit, noid))
393 return 1;
394 break;
395 }
396 }
397
398 if (cb->opts.recno && --(cb->opts.recno) == 0)
399 return 1;
400
401 return 0;
402 }
403
404 int should_expire_reflog_ent_verbose(struct object_id *ooid,
405 struct object_id *noid,
406 const char *email,
407 timestamp_t timestamp, int tz,
408 const char *message, void *cb_data)
409 {
410 struct expire_reflog_policy_cb *cb = cb_data;
411 int expire;
412
413 expire = should_expire_reflog_ent(ooid, noid, email, timestamp, tz,
414 message, cb);
415
416 if (!expire)
417 printf("keep %s", message);
418 else if (cb->dry_run)
419 printf("would prune %s", message);
420 else
421 printf("prune %s", message);
422
423 return expire;
424 }
425
426 static int push_tip_to_list(const struct reference *ref, void *cb_data)
427 {
428 struct commit_list **list = cb_data;
429 struct commit *tip_commit;
430 if (ref->flags & REF_ISSYMREF)
431 return 0;
432 tip_commit = lookup_commit_reference_gently(the_repository, ref->oid, 1);
433 if (!tip_commit)
434 return 0;
435 commit_list_insert(tip_commit, list);
436 return 0;
437 }
438
439 static int is_head(const char *refname)
440 {
441 const char *stripped_refname;
442 parse_worktree_ref(refname, NULL, NULL, &stripped_refname);
443 return !strcmp(stripped_refname, "HEAD");
444 }
445
446 void reflog_expiry_prepare(const char *refname,
447 const struct object_id *oid,
448 void *cb_data)
449 {
450 struct expire_reflog_policy_cb *cb = cb_data;
451 struct commit_list *elem;
452 struct commit *commit = NULL;
453
454 if (!cb->opts.expire_unreachable || is_head(refname)) {
455 cb->unreachable_expire_kind = UE_HEAD;
456 } else {
457 commit = lookup_commit_reference_gently(the_repository,
458 oid, 1);
459 if (commit && is_null_oid(&commit->object.oid))
460 commit = NULL;
461 cb->unreachable_expire_kind = commit ? UE_NORMAL : UE_ALWAYS;
462 }
463
464 if (cb->opts.expire_unreachable <= cb->opts.expire_total)
465 cb->unreachable_expire_kind = UE_ALWAYS;
466
467 switch (cb->unreachable_expire_kind) {
468 case UE_ALWAYS:
469 return;
470 case UE_HEAD:
471 refs_for_each_ref(get_main_ref_store(the_repository),
472 push_tip_to_list, &cb->tips);
473 for (elem = cb->tips; elem; elem = elem->next)
474 commit_list_insert(elem->item, &cb->mark_list);
475 break;
476 case UE_NORMAL:
477 commit_list_insert(commit, &cb->mark_list);
478 /* For reflog_expiry_cleanup() below */
479 cb->tip_commit = commit;
480 }
481 cb->mark_limit = cb->opts.expire_total;
482 mark_reachable(cb);
483 }
484
485 void reflog_expiry_cleanup(void *cb_data)
486 {
487 struct expire_reflog_policy_cb *cb = cb_data;
488 struct commit_list *elem;
489
490 switch (cb->unreachable_expire_kind) {
491 case UE_ALWAYS:
492 return;
493 case UE_HEAD:
494 for (elem = cb->tips; elem; elem = elem->next)
495 clear_commit_marks(elem->item, REACHABLE);
496 commit_list_free(cb->tips);
497 break;
498 case UE_NORMAL:
499 clear_commit_marks(cb->tip_commit, REACHABLE);
500 break;
501 }
502 for (elem = cb->mark_list; elem; elem = elem->next)
503 clear_commit_marks(elem->item, REACHABLE);
504 commit_list_free(cb->mark_list);
505 }
506
507 int count_reflog_ent(const char *refname UNUSED,
508 struct object_id *ooid UNUSED,
509 struct object_id *noid UNUSED,
510 const char *email UNUSED,
511 timestamp_t timestamp, int tz UNUSED,
512 const char *message UNUSED, void *cb_data)
513 {
514 struct reflog_expire_options *cb = cb_data;
515 if (!cb->expire_total || timestamp < cb->expire_total)
516 cb->recno++;
517 return 0;
518 }
519
520 int reflog_delete(const char *rev, enum expire_reflog_flags flags, int verbose)
521 {
522 struct reflog_expire_options opts = { 0 };
523 int status = 0;
524 reflog_expiry_should_prune_fn *should_prune_fn = should_expire_reflog_ent;
525 const char *spec = strstr(rev, "@{");
526 char *ep, *ref;
527 int recno;
528 struct expire_reflog_policy_cb cb = {
529 .dry_run = !!(flags & EXPIRE_REFLOGS_DRY_RUN),
530 };
531
532 if (verbose)
533 should_prune_fn = should_expire_reflog_ent_verbose;
534
535 if (!spec)
536 return error(_("not a reflog: %s"), rev);
537
538 if (!repo_dwim_log(the_repository, rev, spec - rev, NULL, &ref)) {
539 status |= error(_("no reflog for '%s'"), rev);
540 goto cleanup;
541 }
542
543 recno = strtoul(spec + 2, &ep, 10);
544 if (*ep == '}') {
545 opts.recno = -recno;
546 refs_for_each_reflog_ent(get_main_ref_store(the_repository),
547 ref, count_reflog_ent, &opts);
548 } else {
549 opts.expire_total = approxidate(spec + 2);
550 refs_for_each_reflog_ent(get_main_ref_store(the_repository),
551 ref, count_reflog_ent, &opts);
552 opts.expire_total = 0;
553 }
554
555 cb.opts = opts;
556 status |= refs_reflog_expire(get_main_ref_store(the_repository), ref,
557 flags,
558 reflog_expiry_prepare,
559 should_prune_fn,
560 reflog_expiry_cleanup,
561 &cb);
562
563 cleanup:
564 free(ref);
565 return status;
566 }