blob: 81dfd563c0d937eb8943f84493d2d48e8af15f1b [file] [log] [blame]
Junio C Hamano4264dc12006-12-19 00:23:12 -08001#include "builtin.h"
Brandon Williamsb2141fc2017-06-14 11:07:36 -07002#include "config.h"
Michael Haggerty697cc8e2014-10-01 12:28:42 +02003#include "lockfile.h"
Stefan Bellercbd53a22018-05-15 16:42:15 -07004#include "object-store.h"
Stefan Beller109cd762018-06-28 18:21:51 -07005#include "repository.h"
Junio C Hamano4264dc12006-12-19 00:23:12 -08006#include "commit.h"
7#include "refs.h"
8#include "dir.h"
Junio C Hamano8d8b9f62006-12-22 00:46:33 -08009#include "tree-walk.h"
Junio C Hamano1389d9d2007-01-06 02:16:19 -080010#include "diff.h"
11#include "revision.h"
12#include "reachable.h"
Nguyễn Thái Ngọc Duyc9ef0d92018-10-21 10:08:59 +020013#include "worktree.h"
Junio C Hamano1389d9d2007-01-06 02:16:19 -080014
Michael Haggertyfe2a1812015-03-03 12:43:15 +010015/* NEEDSWORK: switch to using parse_options */
Junio C Hamano1389d9d2007-01-06 02:16:19 -080016static const char reflog_expire_usage[] =
Nguyễn Thái Ngọc Duydd509db2018-11-10 06:16:07 +010017N_("git reflog expire [--expire=<time>] "
18 "[--expire-unreachable=<time>] "
19 "[--rewrite] [--updateref] [--stale-fix] [--dry-run | -n] "
20 "[--verbose] [--all] <refs>...");
Brandon Casey3c386aa2008-02-22 15:08:59 -060021static const char reflog_delete_usage[] =
Nguyễn Thái Ngọc Duydd509db2018-11-10 06:16:07 +010022N_("git reflog delete [--rewrite] [--updateref] "
23 "[--dry-run | -n] [--verbose] <refs>...");
David Turnerafcb2e72015-07-21 17:04:53 -040024static const char reflog_exists_usage[] =
Nguyễn Thái Ngọc Duydd509db2018-11-10 06:16:07 +010025N_("git reflog exists <ref>");
Junio C Hamano4264dc12006-12-19 00:23:12 -080026
Johannes Schindelindddbad72017-04-26 21:29:31 +020027static timestamp_t default_reflog_expire;
28static timestamp_t default_reflog_expire_unreachable;
Junio C Hamano4aec56d2006-12-27 01:47:57 -080029
Junio C Hamano1389d9d2007-01-06 02:16:19 -080030struct cmd_reflog_expire_cb {
31 struct rev_info revs;
Junio C Hamano1389d9d2007-01-06 02:16:19 -080032 int stalefix;
Johannes Schindelindddbad72017-04-26 21:29:31 +020033 timestamp_t expire_total;
34 timestamp_t expire_unreachable;
Johannes Schindelin552cecc2007-10-17 02:50:45 +010035 int recno;
Junio C Hamano1389d9d2007-01-06 02:16:19 -080036};
37
Michael Haggertyea7b4f62014-12-12 09:56:52 +010038struct expire_reflog_policy_cb {
Junio C Hamano03cb91b2010-04-09 13:20:02 -070039 enum {
40 UE_NORMAL,
41 UE_ALWAYS,
42 UE_HEAD
43 } unreachable_expire_kind;
Junio C Hamanob4ca1db2010-04-07 11:09:12 -070044 struct commit_list *mark_list;
45 unsigned long mark_limit;
Michael Haggertyb729eff2014-12-12 09:56:58 +010046 struct cmd_reflog_expire_cb cmd;
Michael Haggertyc48a1632014-12-12 09:56:48 +010047 struct commit *tip_commit;
48 struct commit_list *tips;
Junio C Hamano4264dc12006-12-19 00:23:12 -080049};
50
Junio C Hamanobda3a312008-01-25 23:53:05 -080051struct collected_reflog {
brian m. carlsonb8acac52017-10-15 22:06:58 +000052 struct object_id oid;
Junio C Hamanobda3a312008-01-25 23:53:05 -080053 char reflog[FLEX_ARRAY];
54};
Michael Haggertyddd64c52014-12-12 09:56:53 +010055
Junio C Hamanobda3a312008-01-25 23:53:05 -080056struct collect_reflog_cb {
57 struct collected_reflog **e;
58 int alloc;
59 int nr;
Nguyễn Thái Ngọc Duyc9ef0d92018-10-21 10:08:59 +020060 struct worktree *wt;
Junio C Hamanobda3a312008-01-25 23:53:05 -080061};
62
Nguyễn Thái Ngọc Duy95308d62018-03-06 17:16:14 +070063/* Remember to update object flag allocation in object.h */
Junio C Hamanocd1f9c32007-01-06 22:32:41 -080064#define INCOMPLETE (1u<<10)
65#define STUDYING (1u<<11)
Junio Hamano494fbfe2009-03-30 21:34:14 -070066#define REACHABLE (1u<<12)
Junio C Hamanocd1f9c32007-01-06 22:32:41 -080067
brian m. carlson49a09e72017-05-06 22:10:16 +000068static int tree_is_complete(const struct object_id *oid)
Junio C Hamano8d8b9f62006-12-22 00:46:33 -080069{
70 struct tree_desc desc;
Junio C Hamanocd1f9c32007-01-06 22:32:41 -080071 struct name_entry entry;
72 int complete;
73 struct tree *tree;
Junio C Hamano8d8b9f62006-12-22 00:46:33 -080074
Stefan Bellerf86bcc72018-06-28 18:21:56 -070075 tree = lookup_tree(the_repository, oid);
Junio C Hamanocd1f9c32007-01-06 22:32:41 -080076 if (!tree)
Junio C Hamano8d8b9f62006-12-22 00:46:33 -080077 return 0;
Junio C Hamanocd1f9c32007-01-06 22:32:41 -080078 if (tree->object.flags & SEEN)
79 return 1;
80 if (tree->object.flags & INCOMPLETE)
81 return 0;
Junio C Hamano8d8b9f62006-12-22 00:46:33 -080082
Linus Torvalds6fda5e52007-03-21 10:08:25 -070083 if (!tree->buffer) {
Nicolas Pitre21666f12007-02-26 14:55:59 -050084 enum object_type type;
Linus Torvalds6fda5e52007-03-21 10:08:25 -070085 unsigned long size;
brian m. carlsonb4f5aca2018-03-12 02:27:53 +000086 void *data = read_object_file(oid, &type, &size);
Junio C Hamanocd1f9c32007-01-06 22:32:41 -080087 if (!data) {
88 tree->object.flags |= INCOMPLETE;
Junio C Hamano8d8b9f62006-12-22 00:46:33 -080089 return 0;
90 }
Junio C Hamanocd1f9c32007-01-06 22:32:41 -080091 tree->buffer = data;
Linus Torvalds6fda5e52007-03-21 10:08:25 -070092 tree->size = size;
Junio C Hamano8d8b9f62006-12-22 00:46:33 -080093 }
Linus Torvalds6fda5e52007-03-21 10:08:25 -070094 init_tree_desc(&desc, tree->buffer, tree->size);
Junio C Hamanocd1f9c32007-01-06 22:32:41 -080095 complete = 1;
96 while (tree_entry(&desc, &entry)) {
Junio C Hamanocba595a2019-02-06 22:05:27 -080097 if (!has_object_file(&entry.oid) ||
brian m. carlsonea82b2a2019-01-15 00:39:44 +000098 (S_ISDIR(entry.mode) && !tree_is_complete(&entry.oid))) {
Junio C Hamanocd1f9c32007-01-06 22:32:41 -080099 tree->object.flags |= INCOMPLETE;
100 complete = 0;
101 }
102 }
Jeff King6e454b92013-06-05 18:37:39 -0400103 free_tree_buffer(tree);
Junio C Hamano8d8b9f62006-12-22 00:46:33 -0800104
Junio C Hamanocd1f9c32007-01-06 22:32:41 -0800105 if (complete)
106 tree->object.flags |= SEEN;
107 return complete;
108}
Junio C Hamano1389d9d2007-01-06 02:16:19 -0800109
110static int commit_is_complete(struct commit *commit)
111{
112 struct object_array study;
113 struct object_array found;
114 int is_incomplete = 0;
115 int i;
116
117 /* early return */
118 if (commit->object.flags & SEEN)
119 return 1;
120 if (commit->object.flags & INCOMPLETE)
121 return 0;
122 /*
123 * Find all commits that are reachable and are not marked as
124 * SEEN. Then make sure the trees and blobs contained are
125 * complete. After that, mark these commits also as SEEN.
126 * If some of the objects that are needed to complete this
127 * commit are missing, mark this commit as INCOMPLETE.
128 */
129 memset(&study, 0, sizeof(study));
130 memset(&found, 0, sizeof(found));
131 add_object_array(&commit->object, NULL, &study);
132 add_object_array(&commit->object, NULL, &found);
133 commit->object.flags |= STUDYING;
134 while (study.nr) {
135 struct commit *c;
136 struct commit_list *parent;
137
Martin Ågren71992032017-09-23 01:34:53 +0200138 c = (struct commit *)object_array_pop(&study);
Stefan Beller109cd762018-06-28 18:21:51 -0700139 if (!c->object.parsed && !parse_object(the_repository, &c->object.oid))
Junio C Hamano1389d9d2007-01-06 02:16:19 -0800140 c->object.flags |= INCOMPLETE;
141
142 if (c->object.flags & INCOMPLETE) {
143 is_incomplete = 1;
144 break;
145 }
146 else if (c->object.flags & SEEN)
147 continue;
148 for (parent = c->parents; parent; parent = parent->next) {
149 struct commit *p = parent->item;
150 if (p->object.flags & STUDYING)
151 continue;
152 p->object.flags |= STUDYING;
153 add_object_array(&p->object, NULL, &study);
154 add_object_array(&p->object, NULL, &found);
155 }
156 }
157 if (!is_incomplete) {
Junio C Hamanocd1f9c32007-01-06 22:32:41 -0800158 /*
159 * make sure all commits in "found" array have all the
Junio C Hamano1389d9d2007-01-06 02:16:19 -0800160 * necessary objects.
161 */
Junio C Hamanocd1f9c32007-01-06 22:32:41 -0800162 for (i = 0; i < found.nr; i++) {
Junio C Hamano1389d9d2007-01-06 02:16:19 -0800163 struct commit *c =
164 (struct commit *)found.objects[i].item;
Derrick Stolee2e27bd72018-04-06 19:09:38 +0000165 if (!tree_is_complete(get_commit_tree_oid(c))) {
Junio C Hamano1389d9d2007-01-06 02:16:19 -0800166 is_incomplete = 1;
Junio C Hamanocd1f9c32007-01-06 22:32:41 -0800167 c->object.flags |= INCOMPLETE;
168 }
Junio C Hamano1389d9d2007-01-06 02:16:19 -0800169 }
170 if (!is_incomplete) {
171 /* mark all found commits as complete, iow SEEN */
172 for (i = 0; i < found.nr; i++)
173 found.objects[i].item->flags |= SEEN;
174 }
175 }
176 /* clear flags from the objects we traversed */
177 for (i = 0; i < found.nr; i++)
178 found.objects[i].item->flags &= ~STUDYING;
179 if (is_incomplete)
180 commit->object.flags |= INCOMPLETE;
Junio C Hamanocd1f9c32007-01-06 22:32:41 -0800181 else {
182 /*
183 * If we come here, we have (1) traversed the ancestry chain
184 * from the "commit" until we reach SEEN commits (which are
185 * known to be complete), and (2) made sure that the commits
186 * encountered during the above traversal refer to trees that
187 * are complete. Which means that we know *all* the commits
188 * we have seen during this process are complete.
189 */
190 for (i = 0; i < found.nr; i++)
191 found.objects[i].item->flags |= SEEN;
192 }
Junio C Hamano1389d9d2007-01-06 02:16:19 -0800193 /* free object arrays */
Martin Ågrendcb572a2017-09-23 01:34:52 +0200194 object_array_clear(&study);
195 object_array_clear(&found);
Junio C Hamano1389d9d2007-01-06 02:16:19 -0800196 return !is_incomplete;
197}
198
brian m. carlson43224782017-05-06 22:10:00 +0000199static int keep_entry(struct commit **it, struct object_id *oid)
Junio C Hamano4264dc12006-12-19 00:23:12 -0800200{
Junio C Hamano8d8b9f62006-12-22 00:46:33 -0800201 struct commit *commit;
202
brian m. carlson43224782017-05-06 22:10:00 +0000203 if (is_null_oid(oid))
Junio C Hamano4264dc12006-12-19 00:23:12 -0800204 return 1;
Stefan Beller21e1ee82018-06-28 18:21:57 -0700205 commit = lookup_commit_reference_gently(the_repository, oid, 1);
Junio C Hamano8d8b9f62006-12-22 00:46:33 -0800206 if (!commit)
207 return 0;
208
Junio C Hamano1389d9d2007-01-06 02:16:19 -0800209 /*
210 * Make sure everything in this commit exists.
211 *
212 * We have walked all the objects reachable from the refs
213 * and cache earlier. The commits reachable by this commit
214 * must meet SEEN commits -- and then we should mark them as
215 * SEEN as well.
216 */
217 if (!commit_is_complete(commit))
Junio C Hamano8d8b9f62006-12-22 00:46:33 -0800218 return 0;
219 *it = commit;
220 return 1;
Junio C Hamano4264dc12006-12-19 00:23:12 -0800221}
222
Junio C Hamanob4ca1db2010-04-07 11:09:12 -0700223/*
224 * Starting from commits in the cb->mark_list, mark commits that are
225 * reachable from them. Stop the traversal at commits older than
226 * the expire_limit and queue them back, so that the caller can call
227 * us again to restart the traversal with longer expire_limit.
228 */
Michael Haggertyea7b4f62014-12-12 09:56:52 +0100229static void mark_reachable(struct expire_reflog_policy_cb *cb)
Junio C Hamanob4ca1db2010-04-07 11:09:12 -0700230{
Junio C Hamanob4ca1db2010-04-07 11:09:12 -0700231 struct commit_list *pending;
Johannes Schindelindddbad72017-04-26 21:29:31 +0200232 timestamp_t expire_limit = cb->mark_limit;
Junio C Hamanob4ca1db2010-04-07 11:09:12 -0700233 struct commit_list *leftover = NULL;
234
235 for (pending = cb->mark_list; pending; pending = pending->next)
236 pending->item->object.flags &= ~REACHABLE;
237
238 pending = cb->mark_list;
239 while (pending) {
Junio C Hamanob4ca1db2010-04-07 11:09:12 -0700240 struct commit_list *parent;
René Scharfee510ab82015-10-24 18:21:31 +0200241 struct commit *commit = pop_commit(&pending);
Junio C Hamanob4ca1db2010-04-07 11:09:12 -0700242 if (commit->object.flags & REACHABLE)
243 continue;
244 if (parse_commit(commit))
245 continue;
246 commit->object.flags |= REACHABLE;
247 if (commit->date < expire_limit) {
248 commit_list_insert(commit, &leftover);
249 continue;
250 }
251 commit->object.flags |= REACHABLE;
252 parent = commit->parents;
253 while (parent) {
254 commit = parent->item;
255 parent = parent->next;
256 if (commit->object.flags & REACHABLE)
257 continue;
258 commit_list_insert(commit, &pending);
259 }
260 }
261 cb->mark_list = leftover;
262}
263
brian m. carlson43224782017-05-06 22:10:00 +0000264static int unreachable(struct expire_reflog_policy_cb *cb, struct commit *commit, struct object_id *oid)
Linus Torvalds666e07e2009-03-31 09:45:22 -0700265{
266 /*
267 * We may or may not have the commit yet - if not, look it
268 * up using the supplied sha1.
269 */
270 if (!commit) {
brian m. carlson43224782017-05-06 22:10:00 +0000271 if (is_null_oid(oid))
Linus Torvalds666e07e2009-03-31 09:45:22 -0700272 return 0;
273
Stefan Beller21e1ee82018-06-28 18:21:57 -0700274 commit = lookup_commit_reference_gently(the_repository, oid,
275 1);
Linus Torvalds666e07e2009-03-31 09:45:22 -0700276
277 /* Not a commit -- keep it */
278 if (!commit)
279 return 0;
280 }
281
282 /* Reachable from the current ref? Don't prune. */
Junio Hamano494fbfe2009-03-30 21:34:14 -0700283 if (commit->object.flags & REACHABLE)
284 return 0;
Linus Torvalds666e07e2009-03-31 09:45:22 -0700285
Junio C Hamanob4ca1db2010-04-07 11:09:12 -0700286 if (cb->mark_list && cb->mark_limit) {
287 cb->mark_limit = 0; /* dig down to the root */
288 mark_reachable(cb);
Junio Hamano494fbfe2009-03-30 21:34:14 -0700289 }
Junio C Hamanob4ca1db2010-04-07 11:09:12 -0700290
291 return !(commit->object.flags & REACHABLE);
Junio Hamano494fbfe2009-03-30 21:34:14 -0700292}
293
Michael Haggerty60cc3c42014-12-12 09:56:47 +0100294/*
295 * Return true iff the specified reflog entry should be expired.
296 */
brian m. carlson43224782017-05-06 22:10:00 +0000297static int should_expire_reflog_ent(struct object_id *ooid, struct object_id *noid,
Johannes Schindelindddbad72017-04-26 21:29:31 +0200298 const char *email, timestamp_t timestamp, int tz,
Michael Haggerty60cc3c42014-12-12 09:56:47 +0100299 const char *message, void *cb_data)
Junio C Hamano4264dc12006-12-19 00:23:12 -0800300{
Michael Haggertyea7b4f62014-12-12 09:56:52 +0100301 struct expire_reflog_policy_cb *cb = cb_data;
Brandon Williamsdfa59902018-02-14 10:59:34 -0800302 struct commit *old_commit, *new_commit;
Junio C Hamano4264dc12006-12-19 00:23:12 -0800303
Michael Haggertyb729eff2014-12-12 09:56:58 +0100304 if (timestamp < cb->cmd.expire_total)
Michael Haggerty60cc3c42014-12-12 09:56:47 +0100305 return 1;
Brandon Casey2b81fab2008-02-22 12:56:50 -0600306
Brandon Williamsdfa59902018-02-14 10:59:34 -0800307 old_commit = new_commit = NULL;
Michael Haggertyb729eff2014-12-12 09:56:58 +0100308 if (cb->cmd.stalefix &&
Brandon Williamsdfa59902018-02-14 10:59:34 -0800309 (!keep_entry(&old_commit, ooid) || !keep_entry(&new_commit, noid)))
Michael Haggerty60cc3c42014-12-12 09:56:47 +0100310 return 1;
Junio C Hamano4264dc12006-12-19 00:23:12 -0800311
Michael Haggertyb729eff2014-12-12 09:56:58 +0100312 if (timestamp < cb->cmd.expire_unreachable) {
Junio C Hamano03cb91b2010-04-09 13:20:02 -0700313 if (cb->unreachable_expire_kind == UE_ALWAYS)
Michael Haggerty60cc3c42014-12-12 09:56:47 +0100314 return 1;
Brandon Williamsdfa59902018-02-14 10:59:34 -0800315 if (unreachable(cb, old_commit, ooid) || unreachable(cb, new_commit, noid))
Michael Haggerty60cc3c42014-12-12 09:56:47 +0100316 return 1;
Junio C Hamano9bbaa6c2007-01-11 19:56:43 -0800317 }
Junio C Hamano4264dc12006-12-19 00:23:12 -0800318
Michael Haggertyb729eff2014-12-12 09:56:58 +0100319 if (cb->cmd.recno && --(cb->cmd.recno) == 0)
Michael Haggerty60cc3c42014-12-12 09:56:47 +0100320 return 1;
Johannes Schindelin552cecc2007-10-17 02:50:45 +0100321
Junio C Hamano4264dc12006-12-19 00:23:12 -0800322 return 0;
Michael Haggerty60cc3c42014-12-12 09:56:47 +0100323}
324
Michael Haggerty5bcad1b2015-05-25 18:38:40 +0000325static int push_tip_to_list(const char *refname, const struct object_id *oid,
Michael Haggertyea7b4f62014-12-12 09:56:52 +0100326 int flags, void *cb_data)
Junio C Hamano03cb91b2010-04-09 13:20:02 -0700327{
328 struct commit_list **list = cb_data;
329 struct commit *tip_commit;
330 if (flags & REF_ISSYMREF)
331 return 0;
Stefan Beller21e1ee82018-06-28 18:21:57 -0700332 tip_commit = lookup_commit_reference_gently(the_repository, oid, 1);
Junio C Hamano03cb91b2010-04-09 13:20:02 -0700333 if (!tip_commit)
334 return 0;
335 commit_list_insert(tip_commit, list);
336 return 0;
337}
338
Nguyễn Thái Ngọc Duyc9ef0d92018-10-21 10:08:59 +0200339static int is_head(const char *refname)
340{
341 switch (ref_type(refname)) {
342 case REF_TYPE_OTHER_PSEUDOREF:
343 case REF_TYPE_MAIN_PSEUDOREF:
344 if (parse_worktree_ref(refname, NULL, NULL, &refname))
345 BUG("not a worktree ref: %s", refname);
346 break;
347 default:
348 break;
349 }
350 return !strcmp(refname, "HEAD");
351}
352
Michael Haggertyc48a1632014-12-12 09:56:48 +0100353static void reflog_expiry_prepare(const char *refname,
brian m. carlson43224782017-05-06 22:10:00 +0000354 const struct object_id *oid,
Michael Haggertyb729eff2014-12-12 09:56:58 +0100355 void *cb_data)
Michael Haggertyc48a1632014-12-12 09:56:48 +0100356{
Michael Haggertyb729eff2014-12-12 09:56:58 +0100357 struct expire_reflog_policy_cb *cb = cb_data;
358
Nguyễn Thái Ngọc Duyc9ef0d92018-10-21 10:08:59 +0200359 if (!cb->cmd.expire_unreachable || is_head(refname)) {
Michael Haggertyc48a1632014-12-12 09:56:48 +0100360 cb->tip_commit = NULL;
361 cb->unreachable_expire_kind = UE_HEAD;
362 } else {
Stefan Beller21e1ee82018-06-28 18:21:57 -0700363 cb->tip_commit = lookup_commit_reference_gently(the_repository,
364 oid, 1);
Michael Haggertyc48a1632014-12-12 09:56:48 +0100365 if (!cb->tip_commit)
366 cb->unreachable_expire_kind = UE_ALWAYS;
367 else
368 cb->unreachable_expire_kind = UE_NORMAL;
369 }
370
Michael Haggertyb729eff2014-12-12 09:56:58 +0100371 if (cb->cmd.expire_unreachable <= cb->cmd.expire_total)
Michael Haggertyc48a1632014-12-12 09:56:48 +0100372 cb->unreachable_expire_kind = UE_ALWAYS;
373
374 cb->mark_list = NULL;
375 cb->tips = NULL;
376 if (cb->unreachable_expire_kind != UE_ALWAYS) {
377 if (cb->unreachable_expire_kind == UE_HEAD) {
378 struct commit_list *elem;
Michael Haggerty2b2a5be2015-05-25 18:38:28 +0000379
Michael Haggerty5bcad1b2015-05-25 18:38:40 +0000380 for_each_ref(push_tip_to_list, &cb->tips);
Michael Haggertyc48a1632014-12-12 09:56:48 +0100381 for (elem = cb->tips; elem; elem = elem->next)
382 commit_list_insert(elem->item, &cb->mark_list);
383 } else {
384 commit_list_insert(cb->tip_commit, &cb->mark_list);
385 }
Michael Haggertyb729eff2014-12-12 09:56:58 +0100386 cb->mark_limit = cb->cmd.expire_total;
Michael Haggertyc48a1632014-12-12 09:56:48 +0100387 mark_reachable(cb);
388 }
389}
390
Michael Haggertyb729eff2014-12-12 09:56:58 +0100391static void reflog_expiry_cleanup(void *cb_data)
Michael Haggertyc48a1632014-12-12 09:56:48 +0100392{
Michael Haggertyb729eff2014-12-12 09:56:58 +0100393 struct expire_reflog_policy_cb *cb = cb_data;
394
Michael Haggertyc48a1632014-12-12 09:56:48 +0100395 if (cb->unreachable_expire_kind != UE_ALWAYS) {
396 if (cb->unreachable_expire_kind == UE_HEAD) {
397 struct commit_list *elem;
398 for (elem = cb->tips; elem; elem = elem->next)
399 clear_commit_marks(elem->item, REACHABLE);
400 free_commit_list(cb->tips);
401 } else {
402 clear_commit_marks(cb->tip_commit, REACHABLE);
403 }
404 }
405}
406
Michael Haggerty5bcad1b2015-05-25 18:38:40 +0000407static int collect_reflog(const char *ref, const struct object_id *oid, int unused, void *cb_data)
Junio C Hamanobda3a312008-01-25 23:53:05 -0800408{
409 struct collected_reflog *e;
410 struct collect_reflog_cb *cb = cb_data;
Nguyễn Thái Ngọc Duyc9ef0d92018-10-21 10:08:59 +0200411 struct strbuf newref = STRBUF_INIT;
Junio C Hamanobda3a312008-01-25 23:53:05 -0800412
Nguyễn Thái Ngọc Duyc9ef0d92018-10-21 10:08:59 +0200413 /*
414 * Avoid collecting the same shared ref multiple times because
415 * they are available via all worktrees.
416 */
417 if (!cb->wt->is_current && ref_type(ref) == REF_TYPE_NORMAL)
418 return 0;
419
420 strbuf_worktree_ref(cb->wt, &newref, ref);
421 FLEX_ALLOC_STR(e, reflog, newref.buf);
422 strbuf_release(&newref);
423
brian m. carlsonb8acac52017-10-15 22:06:58 +0000424 oidcpy(&e->oid, oid);
Junio C Hamanobda3a312008-01-25 23:53:05 -0800425 ALLOC_GROW(cb->e, cb->nr + 1, cb->alloc);
426 cb->e[cb->nr++] = e;
427 return 0;
428}
429
Junio C Hamano3cb22b82008-06-15 23:48:46 -0700430static struct reflog_expire_cfg {
431 struct reflog_expire_cfg *next;
Johannes Schindelindddbad72017-04-26 21:29:31 +0200432 timestamp_t expire_total;
433 timestamp_t expire_unreachable;
Junio C Hamano3cb22b82008-06-15 23:48:46 -0700434 char pattern[FLEX_ARRAY];
435} *reflog_expire_cfg, **reflog_expire_cfg_tail;
436
437static struct reflog_expire_cfg *find_cfg_ent(const char *pattern, size_t len)
438{
439 struct reflog_expire_cfg *ent;
440
441 if (!reflog_expire_cfg_tail)
442 reflog_expire_cfg_tail = &reflog_expire_cfg;
443
444 for (ent = reflog_expire_cfg; ent; ent = ent->next)
Jeff Kingc3a700f2016-02-19 06:21:08 -0500445 if (!strncmp(ent->pattern, pattern, len) &&
446 ent->pattern[len] == '\0')
Junio C Hamano3cb22b82008-06-15 23:48:46 -0700447 return ent;
448
Jeff King96ffc062016-02-22 17:44:32 -0500449 FLEX_ALLOC_MEM(ent, pattern, pattern, len);
Junio C Hamano3cb22b82008-06-15 23:48:46 -0700450 *reflog_expire_cfg_tail = ent;
451 reflog_expire_cfg_tail = &(ent->next);
452 return ent;
453}
454
Junio C Hamano3cb22b82008-06-15 23:48:46 -0700455/* expiry timer slot */
456#define EXPIRE_TOTAL 01
457#define EXPIRE_UNREACH 02
458
Johannes Schindelinef90d6d2008-05-14 18:46:53 +0100459static int reflog_expire_config(const char *var, const char *value, void *cb)
Junio C Hamano4aec56d2006-12-27 01:47:57 -0800460{
Jeff Kingb3873c32013-01-23 01:27:37 -0500461 const char *pattern, *key;
462 int pattern_len;
Johannes Schindelindddbad72017-04-26 21:29:31 +0200463 timestamp_t expire;
Junio C Hamano3cb22b82008-06-15 23:48:46 -0700464 int slot;
465 struct reflog_expire_cfg *ent;
466
Jeff Kingb3873c32013-01-23 01:27:37 -0500467 if (parse_config_key(var, "gc", &pattern, &pattern_len, &key) < 0)
Junio C Hamano3cb22b82008-06-15 23:48:46 -0700468 return git_default_config(var, value, cb);
469
Jeff Kingb3873c32013-01-23 01:27:37 -0500470 if (!strcmp(key, "reflogexpire")) {
Junio C Hamano3cb22b82008-06-15 23:48:46 -0700471 slot = EXPIRE_TOTAL;
Haaris Mehmood5f967422017-11-18 02:27:27 +0000472 if (git_config_expiry_date(&expire, var, value))
Junio C Hamano3cb22b82008-06-15 23:48:46 -0700473 return -1;
Jeff Kingb3873c32013-01-23 01:27:37 -0500474 } else if (!strcmp(key, "reflogexpireunreachable")) {
Junio C Hamano3cb22b82008-06-15 23:48:46 -0700475 slot = EXPIRE_UNREACH;
Haaris Mehmood5f967422017-11-18 02:27:27 +0000476 if (git_config_expiry_date(&expire, var, value))
Junio C Hamano3cb22b82008-06-15 23:48:46 -0700477 return -1;
478 } else
479 return git_default_config(var, value, cb);
480
Jeff Kingb3873c32013-01-23 01:27:37 -0500481 if (!pattern) {
Junio C Hamano3cb22b82008-06-15 23:48:46 -0700482 switch (slot) {
483 case EXPIRE_TOTAL:
484 default_reflog_expire = expire;
485 break;
486 case EXPIRE_UNREACH:
487 default_reflog_expire_unreachable = expire;
488 break;
489 }
Junio C Hamano4f342b92008-02-11 10:50:06 -0800490 return 0;
491 }
Junio C Hamano3cb22b82008-06-15 23:48:46 -0700492
Jeff Kingb3873c32013-01-23 01:27:37 -0500493 ent = find_cfg_ent(pattern, pattern_len);
Junio C Hamano3cb22b82008-06-15 23:48:46 -0700494 if (!ent)
495 return -1;
496 switch (slot) {
497 case EXPIRE_TOTAL:
498 ent->expire_total = expire;
499 break;
500 case EXPIRE_UNREACH:
501 ent->expire_unreachable = expire;
502 break;
Junio C Hamano4f342b92008-02-11 10:50:06 -0800503 }
Junio C Hamano3cb22b82008-06-15 23:48:46 -0700504 return 0;
505}
506
507static void set_reflog_expiry_param(struct cmd_reflog_expire_cb *cb, int slot, const char *ref)
508{
509 struct reflog_expire_cfg *ent;
510
511 if (slot == (EXPIRE_TOTAL|EXPIRE_UNREACH))
512 return; /* both given explicitly -- nothing to tweak */
513
514 for (ent = reflog_expire_cfg; ent; ent = ent->next) {
Ævar Arnfjörð Bjarmason55d34262017-06-22 21:38:08 +0000515 if (!wildmatch(ent->pattern, ref, 0)) {
Junio C Hamano3cb22b82008-06-15 23:48:46 -0700516 if (!(slot & EXPIRE_TOTAL))
517 cb->expire_total = ent->expire_total;
518 if (!(slot & EXPIRE_UNREACH))
519 cb->expire_unreachable = ent->expire_unreachable;
520 return;
521 }
522 }
523
Junio C Hamano60bce2b2008-06-28 22:24:49 -0700524 /*
525 * If unconfigured, make stash never expire
526 */
527 if (!strcmp(ref, "refs/stash")) {
528 if (!(slot & EXPIRE_TOTAL))
529 cb->expire_total = 0;
530 if (!(slot & EXPIRE_UNREACH))
531 cb->expire_unreachable = 0;
532 return;
533 }
534
Junio C Hamano3cb22b82008-06-15 23:48:46 -0700535 /* Nothing matched -- use the default value */
536 if (!(slot & EXPIRE_TOTAL))
537 cb->expire_total = default_reflog_expire;
538 if (!(slot & EXPIRE_UNREACH))
539 cb->expire_unreachable = default_reflog_expire_unreachable;
Junio C Hamano4aec56d2006-12-27 01:47:57 -0800540}
541
Junio C Hamano4264dc12006-12-19 00:23:12 -0800542static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
543{
Michael Haggertyb729eff2014-12-12 09:56:58 +0100544 struct expire_reflog_policy_cb cb;
Johannes Schindelindddbad72017-04-26 21:29:31 +0200545 timestamp_t now = time(NULL);
Nguyễn Thái Ngọc Duyc9ef0d92018-10-21 10:08:59 +0200546 int i, status, do_all, all_worktrees = 1;
Junio C Hamano3cb22b82008-06-15 23:48:46 -0700547 int explicit_expiry = 0;
Michael Haggertyaba56c82014-12-12 09:56:49 +0100548 unsigned int flags = 0;
Junio C Hamano4264dc12006-12-19 00:23:12 -0800549
Adam Simpkins4a9f4392010-02-26 19:50:03 -0800550 default_reflog_expire_unreachable = now - 30 * 24 * 3600;
551 default_reflog_expire = now - 90 * 24 * 3600;
Johannes Schindelinef90d6d2008-05-14 18:46:53 +0100552 git_config(reflog_expire_config, NULL);
Junio C Hamano4aec56d2006-12-27 01:47:57 -0800553
Junio C Hamano4264dc12006-12-19 00:23:12 -0800554 save_commit_buffer = 0;
555 do_all = status = 0;
556 memset(&cb, 0, sizeof(cb));
Junio C Hamano4aec56d2006-12-27 01:47:57 -0800557
Michael Haggertyb729eff2014-12-12 09:56:58 +0100558 cb.cmd.expire_total = default_reflog_expire;
559 cb.cmd.expire_unreachable = default_reflog_expire_unreachable;
Junio C Hamano4264dc12006-12-19 00:23:12 -0800560
561 for (i = 1; i < argc; i++) {
562 const char *arg = argv[i];
Junio C Hamano145136a2020-01-30 11:35:46 -0800563
Junio C Hamano4264dc12006-12-19 00:23:12 -0800564 if (!strcmp(arg, "--dry-run") || !strcmp(arg, "-n"))
Michael Haggerty98f31d82014-12-12 09:56:50 +0100565 flags |= EXPIRE_REFLOGS_DRY_RUN;
Junio C Hamano145136a2020-01-30 11:35:46 -0800566 else if (skip_prefix(arg, "--expire=", &arg)) {
567 if (parse_expiry_date(arg, &cb.cmd.expire_total))
Junio C Hamano3d27b9b2013-04-17 15:38:08 -0700568 die(_("'%s' is not a valid timestamp"), arg);
Junio C Hamano3cb22b82008-06-15 23:48:46 -0700569 explicit_expiry |= EXPIRE_TOTAL;
570 }
Junio C Hamano145136a2020-01-30 11:35:46 -0800571 else if (skip_prefix(arg, "--expire-unreachable=", &arg)) {
572 if (parse_expiry_date(arg, &cb.cmd.expire_unreachable))
Junio C Hamano3d27b9b2013-04-17 15:38:08 -0700573 die(_("'%s' is not a valid timestamp"), arg);
Junio C Hamano3cb22b82008-06-15 23:48:46 -0700574 explicit_expiry |= EXPIRE_UNREACH;
575 }
Junio C Hamano1389d9d2007-01-06 02:16:19 -0800576 else if (!strcmp(arg, "--stale-fix"))
Michael Haggertyb729eff2014-12-12 09:56:58 +0100577 cb.cmd.stalefix = 1;
Brandon Casey2b81fab2008-02-22 12:56:50 -0600578 else if (!strcmp(arg, "--rewrite"))
Michael Haggerty553daf12014-12-12 09:56:56 +0100579 flags |= EXPIRE_REFLOGS_REWRITE;
Brandon Casey55f10562008-02-22 13:04:12 -0600580 else if (!strcmp(arg, "--updateref"))
Michael Haggertyc4c4fbf2014-12-12 09:56:51 +0100581 flags |= EXPIRE_REFLOGS_UPDATE_REF;
Junio C Hamano4264dc12006-12-19 00:23:12 -0800582 else if (!strcmp(arg, "--all"))
583 do_all = 1;
Nguyễn Thái Ngọc Duyc9ef0d92018-10-21 10:08:59 +0200584 else if (!strcmp(arg, "--single-worktree"))
585 all_worktrees = 0;
Junio C Hamano1389d9d2007-01-06 02:16:19 -0800586 else if (!strcmp(arg, "--verbose"))
Michael Haggertybc111552014-12-12 09:56:55 +0100587 flags |= EXPIRE_REFLOGS_VERBOSE;
Junio C Hamano4264dc12006-12-19 00:23:12 -0800588 else if (!strcmp(arg, "--")) {
589 i++;
590 break;
591 }
592 else if (arg[0] == '-')
Nguyễn Thái Ngọc Duydd509db2018-11-10 06:16:07 +0100593 usage(_(reflog_expire_usage));
Junio C Hamano4264dc12006-12-19 00:23:12 -0800594 else
595 break;
596 }
Junio C Hamano3cb22b82008-06-15 23:48:46 -0700597
598 /*
599 * We can trust the commits and objects reachable from refs
600 * even in older repository. We cannot trust what's reachable
601 * from reflog if the repository was pruned with older git.
602 */
Michael Haggertyb729eff2014-12-12 09:56:58 +0100603 if (cb.cmd.stalefix) {
Nguyễn Thái Ngọc Duy2abf3502018-09-21 17:57:38 +0200604 repo_init_revisions(the_repository, &cb.cmd.revs, prefix);
Michael Haggertybc111552014-12-12 09:56:55 +0100605 if (flags & EXPIRE_REFLOGS_VERBOSE)
Nguyễn Thái Ngọc Duydd509db2018-11-10 06:16:07 +0100606 printf(_("Marking reachable objects..."));
Michael Haggertyb729eff2014-12-12 09:56:58 +0100607 mark_reachable_objects(&cb.cmd.revs, 0, 0, NULL);
Michael Haggertybc111552014-12-12 09:56:55 +0100608 if (flags & EXPIRE_REFLOGS_VERBOSE)
Junio C Hamano1389d9d2007-01-06 02:16:19 -0800609 putchar('\n');
610 }
611
Junio C Hamanobda3a312008-01-25 23:53:05 -0800612 if (do_all) {
613 struct collect_reflog_cb collected;
Nguyễn Thái Ngọc Duyc9ef0d92018-10-21 10:08:59 +0200614 struct worktree **worktrees, **p;
Junio C Hamanobda3a312008-01-25 23:53:05 -0800615 int i;
616
617 memset(&collected, 0, sizeof(collected));
Nguyễn Thái Ngọc Duyc9ef0d92018-10-21 10:08:59 +0200618 worktrees = get_worktrees(0);
619 for (p = worktrees; *p; p++) {
620 if (!all_worktrees && !(*p)->is_current)
621 continue;
622 collected.wt = *p;
623 refs_for_each_reflog(get_worktree_ref_store(*p),
624 collect_reflog, &collected);
625 }
626 free_worktrees(worktrees);
Junio C Hamanobda3a312008-01-25 23:53:05 -0800627 for (i = 0; i < collected.nr; i++) {
628 struct collected_reflog *e = collected.e[i];
Michael Haggertyb729eff2014-12-12 09:56:58 +0100629 set_reflog_expiry_param(&cb.cmd, explicit_expiry, e->reflog);
brian m. carlson0155f712017-10-15 22:07:04 +0000630 status |= reflog_expire(e->reflog, &e->oid, flags,
Michael Haggertyfa5b1832014-12-12 09:56:59 +0100631 reflog_expiry_prepare,
632 should_expire_reflog_ent,
633 reflog_expiry_cleanup,
634 &cb);
Junio C Hamanobda3a312008-01-25 23:53:05 -0800635 free(e);
636 }
637 free(collected.e);
638 }
639
Pieter de Bie90fb46e2008-08-10 22:22:21 +0200640 for (; i < argc; i++) {
641 char *ref;
brian m. carlsonb8acac52017-10-15 22:06:58 +0000642 struct object_id oid;
brian m. carlson334dc522017-10-15 22:06:59 +0000643 if (!dwim_log(argv[i], strlen(argv[i]), &oid, &ref)) {
Nguyễn Thái Ngọc Duydd509db2018-11-10 06:16:07 +0100644 status |= error(_("%s points nowhere!"), argv[i]);
Junio C Hamano4264dc12006-12-19 00:23:12 -0800645 continue;
646 }
Michael Haggertyb729eff2014-12-12 09:56:58 +0100647 set_reflog_expiry_param(&cb.cmd, explicit_expiry, ref);
brian m. carlson0155f712017-10-15 22:07:04 +0000648 status |= reflog_expire(ref, &oid, flags,
Michael Haggertyfa5b1832014-12-12 09:56:59 +0100649 reflog_expiry_prepare,
650 should_expire_reflog_ent,
651 reflog_expiry_cleanup,
652 &cb);
Junio C Hamano4264dc12006-12-19 00:23:12 -0800653 }
654 return status;
655}
656
brian m. carlson9461d272017-02-21 23:47:32 +0000657static int count_reflog_ent(struct object_id *ooid, struct object_id *noid,
Johannes Schindelindddbad72017-04-26 21:29:31 +0200658 const char *email, timestamp_t timestamp, int tz,
Johannes Schindelin552cecc2007-10-17 02:50:45 +0100659 const char *message, void *cb_data)
660{
Michael Haggertyb729eff2014-12-12 09:56:58 +0100661 struct expire_reflog_policy_cb *cb = cb_data;
662 if (!cb->cmd.expire_total || timestamp < cb->cmd.expire_total)
663 cb->cmd.recno++;
Johannes Schindelin552cecc2007-10-17 02:50:45 +0100664 return 0;
665}
666
667static int cmd_reflog_delete(int argc, const char **argv, const char *prefix)
668{
Michael Haggertyb729eff2014-12-12 09:56:58 +0100669 struct expire_reflog_policy_cb cb;
Johannes Schindelin552cecc2007-10-17 02:50:45 +0100670 int i, status = 0;
Michael Haggertyaba56c82014-12-12 09:56:49 +0100671 unsigned int flags = 0;
Johannes Schindelin552cecc2007-10-17 02:50:45 +0100672
Johannes Schindelin552cecc2007-10-17 02:50:45 +0100673 memset(&cb, 0, sizeof(cb));
674
675 for (i = 1; i < argc; i++) {
Brandon Casey3c386aa2008-02-22 15:08:59 -0600676 const char *arg = argv[i];
677 if (!strcmp(arg, "--dry-run") || !strcmp(arg, "-n"))
Michael Haggerty98f31d82014-12-12 09:56:50 +0100678 flags |= EXPIRE_REFLOGS_DRY_RUN;
Brandon Casey2b81fab2008-02-22 12:56:50 -0600679 else if (!strcmp(arg, "--rewrite"))
Michael Haggerty553daf12014-12-12 09:56:56 +0100680 flags |= EXPIRE_REFLOGS_REWRITE;
Brandon Casey55f10562008-02-22 13:04:12 -0600681 else if (!strcmp(arg, "--updateref"))
Michael Haggertyc4c4fbf2014-12-12 09:56:51 +0100682 flags |= EXPIRE_REFLOGS_UPDATE_REF;
Brandon Casey3c386aa2008-02-22 15:08:59 -0600683 else if (!strcmp(arg, "--verbose"))
Michael Haggertybc111552014-12-12 09:56:55 +0100684 flags |= EXPIRE_REFLOGS_VERBOSE;
Brandon Casey3c386aa2008-02-22 15:08:59 -0600685 else if (!strcmp(arg, "--")) {
686 i++;
687 break;
688 }
689 else if (arg[0] == '-')
Nguyễn Thái Ngọc Duydd509db2018-11-10 06:16:07 +0100690 usage(_(reflog_delete_usage));
Brandon Casey3c386aa2008-02-22 15:08:59 -0600691 else
692 break;
693 }
694
695 if (argc - i < 1)
Nguyễn Thái Ngọc Duydd509db2018-11-10 06:16:07 +0100696 return error(_("no reflog specified to delete"));
Brandon Casey3c386aa2008-02-22 15:08:59 -0600697
698 for ( ; i < argc; i++) {
Johannes Schindelin552cecc2007-10-17 02:50:45 +0100699 const char *spec = strstr(argv[i], "@{");
brian m. carlsonb8acac52017-10-15 22:06:58 +0000700 struct object_id oid;
Johannes Schindelin552cecc2007-10-17 02:50:45 +0100701 char *ep, *ref;
702 int recno;
703
704 if (!spec) {
Nguyễn Thái Ngọc Duydd509db2018-11-10 06:16:07 +0100705 status |= error(_("not a reflog: %s"), argv[i]);
Johannes Schindelin552cecc2007-10-17 02:50:45 +0100706 continue;
707 }
708
brian m. carlson334dc522017-10-15 22:06:59 +0000709 if (!dwim_log(argv[i], spec - argv[i], &oid, &ref)) {
Nguyễn Thái Ngọc Duydd509db2018-11-10 06:16:07 +0100710 status |= error(_("no reflog for '%s'"), argv[i]);
Johannes Schindelin552cecc2007-10-17 02:50:45 +0100711 continue;
712 }
713
714 recno = strtoul(spec + 2, &ep, 10);
715 if (*ep == '}') {
Michael Haggertyb729eff2014-12-12 09:56:58 +0100716 cb.cmd.recno = -recno;
Johannes Schindelin552cecc2007-10-17 02:50:45 +0100717 for_each_reflog_ent(ref, count_reflog_ent, &cb);
718 } else {
Michael Haggertyb729eff2014-12-12 09:56:58 +0100719 cb.cmd.expire_total = approxidate(spec + 2);
Johannes Schindelin552cecc2007-10-17 02:50:45 +0100720 for_each_reflog_ent(ref, count_reflog_ent, &cb);
Michael Haggertyb729eff2014-12-12 09:56:58 +0100721 cb.cmd.expire_total = 0;
Johannes Schindelin552cecc2007-10-17 02:50:45 +0100722 }
723
brian m. carlson0155f712017-10-15 22:07:04 +0000724 status |= reflog_expire(ref, &oid, flags,
Michael Haggertyfa5b1832014-12-12 09:56:59 +0100725 reflog_expiry_prepare,
726 should_expire_reflog_ent,
727 reflog_expiry_cleanup,
728 &cb);
Johannes Schindelin552cecc2007-10-17 02:50:45 +0100729 free(ref);
730 }
731 return status;
732}
733
David Turnerafcb2e72015-07-21 17:04:53 -0400734static int cmd_reflog_exists(int argc, const char **argv, const char *prefix)
735{
736 int i, start = 0;
737
738 for (i = 1; i < argc; i++) {
739 const char *arg = argv[i];
740 if (!strcmp(arg, "--")) {
741 i++;
742 break;
743 }
744 else if (arg[0] == '-')
Nguyễn Thái Ngọc Duydd509db2018-11-10 06:16:07 +0100745 usage(_(reflog_exists_usage));
David Turnerafcb2e72015-07-21 17:04:53 -0400746 else
747 break;
748 }
749
750 start = i;
751
752 if (argc - start != 1)
Nguyễn Thái Ngọc Duydd509db2018-11-10 06:16:07 +0100753 usage(_(reflog_exists_usage));
David Turnerafcb2e72015-07-21 17:04:53 -0400754
755 if (check_refname_format(argv[start], REFNAME_ALLOW_ONELEVEL))
Nguyễn Thái Ngọc Duydd509db2018-11-10 06:16:07 +0100756 die(_("invalid ref format: %s"), argv[start]);
David Turnerafcb2e72015-07-21 17:04:53 -0400757 return !reflog_exists(argv[start]);
758}
759
Junio C Hamano1389d9d2007-01-06 02:16:19 -0800760/*
761 * main "reflog"
762 */
763
Junio C Hamano4264dc12006-12-19 00:23:12 -0800764static const char reflog_usage[] =
Nguyễn Thái Ngọc Duydd509db2018-11-10 06:16:07 +0100765N_("git reflog [ show | expire | delete | exists ]");
Junio C Hamano4264dc12006-12-19 00:23:12 -0800766
767int cmd_reflog(int argc, const char **argv, const char *prefix)
768{
Jonathan Nieder99caeed2009-11-09 09:05:01 -0600769 if (argc > 1 && !strcmp(argv[1], "-h"))
Nguyễn Thái Ngọc Duydd509db2018-11-10 06:16:07 +0100770 usage(_(reflog_usage));
Jonathan Nieder99caeed2009-11-09 09:05:01 -0600771
Linus Torvaldscf39f542007-02-08 09:51:56 -0800772 /* With no command, we default to showing it. */
773 if (argc < 2 || *argv[1] == '-')
774 return cmd_log_reflog(argc, argv, prefix);
775
776 if (!strcmp(argv[1], "show"))
777 return cmd_log_reflog(argc - 1, argv + 1, prefix);
778
779 if (!strcmp(argv[1], "expire"))
Junio C Hamano4264dc12006-12-19 00:23:12 -0800780 return cmd_reflog_expire(argc - 1, argv + 1, prefix);
Linus Torvaldscf39f542007-02-08 09:51:56 -0800781
Johannes Schindelin552cecc2007-10-17 02:50:45 +0100782 if (!strcmp(argv[1], "delete"))
783 return cmd_reflog_delete(argc - 1, argv + 1, prefix);
784
David Turnerafcb2e72015-07-21 17:04:53 -0400785 if (!strcmp(argv[1], "exists"))
786 return cmd_reflog_exists(argc - 1, argv + 1, prefix);
787
Michael Schubertbf01d4a2011-08-01 13:20:42 +0200788 return cmd_log_reflog(argc, argv, prefix);
Junio C Hamano4264dc12006-12-19 00:23:12 -0800789}