The sixteenth batch
[git/gitster.git] / reflog.c
blob9a68524df8896c33208254f8fa59c804d2352d8b
1 #define USE_THE_REPOSITORY_VARIABLE
2 #define DISABLE_SIGN_COMPARE_WARNINGS
4 #include "git-compat-util.h"
5 #include "config.h"
6 #include "gettext.h"
7 #include "parse-options.h"
8 #include "odb.h"
9 #include "reflog.h"
10 #include "refs.h"
11 #include "revision.h"
12 #include "tree.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))
26 return ent;
28 FLEX_ALLOC_MEM(ent, pattern, pattern, len);
29 *opts->entries_tail = ent;
30 opts->entries_tail = &(ent->next);
31 return ent;
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;
39 size_t pattern_len;
40 timestamp_t expire;
41 int slot;
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))
50 return -1;
51 } else if (!strcmp(key, "reflogexpireunreachable")) {
52 slot = REFLOG_EXPIRE_UNREACH;
53 if (git_config_expiry_date(&expire, var, value))
54 return -1;
55 } else
56 return git_default_config(var, value, ctx, cb);
58 if (!pattern) {
59 switch (slot) {
60 case REFLOG_EXPIRE_TOTAL:
61 opts->default_expire_total = expire;
62 break;
63 case REFLOG_EXPIRE_UNREACH:
64 opts->default_expire_unreachable = expire;
65 break;
67 return 0;
70 ent = find_cfg_ent(opts, pattern, pattern_len);
71 if (!ent)
72 return -1;
73 switch (slot) {
74 case REFLOG_EXPIRE_TOTAL:
75 ent->expire_total = expire;
76 break;
77 case REFLOG_EXPIRE_UNREACH:
78 ent->expire_unreachable = expire;
79 break;
81 return 0;
84 void reflog_clear_expire_config(struct reflog_expire_options *opts)
86 struct reflog_expire_entry_option *ent = opts->entries, *tmp;
88 while (ent) {
89 tmp = ent;
90 ent = ent->next;
91 free(tmp);
94 opts->entries = NULL;
95 opts->entries_tail = NULL;
98 void reflog_expire_options_set_refname(struct reflog_expire_options *cb,
99 const char *ref)
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;
112 return;
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;
124 return;
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;
143 int complete;
144 struct tree *tree;
146 tree = lookup_tree(the_repository, oid);
147 if (!tree)
148 return 0;
149 if (tree->object.flags & SEEN)
150 return 1;
151 if (tree->object.flags & INCOMPLETE)
152 return 0;
154 if (!tree->buffer) {
155 enum object_type type;
156 unsigned long size;
157 void *data = odb_read_object(the_repository->objects, oid,
158 &type, &size);
159 if (!data) {
160 tree->object.flags |= INCOMPLETE;
161 return 0;
163 tree->buffer = data;
164 tree->size = size;
166 init_tree_desc(&desc, &tree->object.oid, tree->buffer, tree->size);
167 complete = 1;
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;
173 complete = 0;
176 free_tree_buffer(tree);
178 if (complete)
179 tree->object.flags |= SEEN;
180 return complete;
183 static int commit_is_complete(struct commit *commit)
185 struct object_array study;
186 struct object_array found;
187 int is_incomplete = 0;
188 int i;
190 /* early return */
191 if (commit->object.flags & SEEN)
192 return 1;
193 if (commit->object.flags & INCOMPLETE)
194 return 0;
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;
207 while (study.nr) {
208 struct commit *c;
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) {
216 is_incomplete = 1;
217 break;
219 else if (c->object.flags & SEEN)
220 continue;
221 for (parent = c->parents; parent; parent = parent->next) {
222 struct commit *p = parent->item;
223 if (p->object.flags & STUDYING)
224 continue;
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
233 * necessary objects.
235 for (i = 0; i < found.nr; i++) {
236 struct commit *c =
237 (struct commit *)found.objects[i].item;
238 if (!tree_is_complete(get_commit_tree_oid(c))) {
239 is_incomplete = 1;
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;
252 if (is_incomplete)
253 commit->object.flags |= INCOMPLETE;
254 else {
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))
277 return 1;
278 commit = lookup_commit_reference_gently(the_repository, oid, 1);
279 if (!commit)
280 return 0;
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
288 * SEEN as well.
290 if (!commit_is_complete(commit))
291 return 0;
292 *it = commit;
293 return 1;
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;
312 while (pending) {
313 struct commit_list *parent;
314 struct commit *commit = pop_commit(&pending);
315 if (commit->object.flags & REACHABLE)
316 continue;
317 if (repo_parse_commit(the_repository, commit))
318 continue;
319 commit->object.flags |= REACHABLE;
320 if (commit->date < expire_limit) {
321 commit_list_insert(commit, &leftover);
322 continue;
324 parent = commit->parents;
325 while (parent) {
326 commit = parent->item;
327 parent = parent->next;
328 if (commit->object.flags & REACHABLE)
329 continue;
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.
342 if (!commit) {
343 if (is_null_oid(oid))
344 return 0;
346 commit = lookup_commit_reference_gently(the_repository, oid,
349 /* Not a commit -- keep it */
350 if (!commit)
351 return 0;
354 /* Reachable from the current ref? Don't prune. */
355 if (commit->object.flags & REACHABLE)
356 return 0;
358 if (cb->mark_list && cb->mark_limit) {
359 cb->mark_limit = 0; /* dig down to the root */
360 mark_reachable(cb);
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)
378 return 1;
380 old_commit = new_commit = NULL;
381 if (cb->opts.stalefix &&
382 (!keep_entry(&old_commit, ooid) || !keep_entry(&new_commit, noid)))
383 return 1;
385 if (timestamp < cb->opts.expire_unreachable) {
386 switch (cb->unreachable_expire_kind) {
387 case UE_ALWAYS:
388 return 1;
389 case UE_NORMAL:
390 case UE_HEAD:
391 if (is_unreachable(cb, old_commit, ooid) || is_unreachable(cb, new_commit, noid))
392 return 1;
393 break;
397 if (cb->opts.recno && --(cb->opts.recno) == 0)
398 return 1;
400 return 0;
403 int should_expire_reflog_ent_verbose(struct object_id *ooid,
404 struct object_id *noid,
405 const char *email,
406 timestamp_t timestamp, int tz,
407 const char *message, void *cb_data)
409 struct expire_reflog_policy_cb *cb = cb_data;
410 int expire;
412 expire = should_expire_reflog_ent(ooid, noid, email, timestamp, tz,
413 message, cb);
415 if (!expire)
416 printf("keep %s", message);
417 else if (cb->dry_run)
418 printf("would prune %s", message);
419 else
420 printf("prune %s", message);
422 return expire;
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)
433 return 0;
434 tip_commit = lookup_commit_reference_gently(the_repository, oid, 1);
435 if (!tip_commit)
436 return 0;
437 commit_list_insert(tip_commit, list);
438 return 0;
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,
450 void *cb_data)
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;
458 } else {
459 commit = lookup_commit_reference_gently(the_repository,
460 oid, 1);
461 if (commit && is_null_oid(&commit->object.oid))
462 commit = NULL;
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) {
470 case UE_ALWAYS:
471 return;
472 case UE_HEAD:
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);
477 break;
478 case UE_NORMAL:
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;
484 mark_reachable(cb);
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) {
493 case UE_ALWAYS:
494 return;
495 case UE_HEAD:
496 for (elem = cb->tips; elem; elem = elem->next)
497 clear_commit_marks(elem->item, REACHABLE);
498 free_commit_list(cb->tips);
499 break;
500 case UE_NORMAL:
501 clear_commit_marks(cb->tip_commit, REACHABLE);
502 break;
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)
517 cb->recno++;
518 return 0;
521 int reflog_delete(const char *rev, enum expire_reflog_flags flags, int verbose)
523 struct reflog_expire_options opts = { 0 };
524 int status = 0;
525 reflog_expiry_should_prune_fn *should_prune_fn = should_expire_reflog_ent;
526 const char *spec = strstr(rev, "@{");
527 char *ep, *ref;
528 int recno;
529 struct expire_reflog_policy_cb cb = {
530 .dry_run = !!(flags & EXPIRE_REFLOGS_DRY_RUN),
533 if (verbose)
534 should_prune_fn = should_expire_reflog_ent_verbose;
536 if (!spec)
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);
541 goto cleanup;
544 recno = strtoul(spec + 2, &ep, 10);
545 if (*ep == '}') {
546 opts.recno = -recno;
547 refs_for_each_reflog_ent(get_main_ref_store(the_repository),
548 ref, count_reflog_ent, &opts);
549 } else {
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;
556 cb.opts = opts;
557 status |= refs_reflog_expire(get_main_ref_store(the_repository), ref,
558 flags,
559 reflog_expiry_prepare,
560 should_prune_fn,
561 reflog_expiry_cleanup,
562 &cb);
564 cleanup:
565 free(ref);
566 return status;