]> git.scripts.mit.edu Git - git.git/blob - builtin/reflog.c
Sync with 'maint'
[git.git] / builtin / reflog.c
1 #include "builtin.h"
2 #include "config.h"
3 #include "gettext.h"
4 #include "repository.h"
5 #include "revision.h"
6 #include "reachable.h"
7 #include "wildmatch.h"
8 #include "worktree.h"
9 #include "reflog.h"
10 #include "refs.h"
11 #include "parse-options.h"
12
13 #define BUILTIN_REFLOG_SHOW_USAGE \
14         N_("git reflog [show] [<log-options>] [<ref>]")
15
16 #define BUILTIN_REFLOG_LIST_USAGE \
17         N_("git reflog list")
18
19 #define BUILTIN_REFLOG_EXPIRE_USAGE \
20         N_("git reflog expire [--expire=<time>] [--expire-unreachable=<time>]\n" \
21            "                  [--rewrite] [--updateref] [--stale-fix]\n" \
22            "                  [--dry-run | -n] [--verbose] [--all [--single-worktree] | <refs>...]")
23
24 #define BUILTIN_REFLOG_DELETE_USAGE \
25         N_("git reflog delete [--rewrite] [--updateref]\n" \
26            "                  [--dry-run | -n] [--verbose] <ref>@{<specifier>}...")
27
28 #define BUILTIN_REFLOG_EXISTS_USAGE \
29         N_("git reflog exists <ref>")
30
31 static const char *const reflog_show_usage[] = {
32         BUILTIN_REFLOG_SHOW_USAGE,
33         NULL,
34 };
35
36 static const char *const reflog_list_usage[] = {
37         BUILTIN_REFLOG_LIST_USAGE,
38         NULL,
39 };
40
41 static const char *const reflog_expire_usage[] = {
42         BUILTIN_REFLOG_EXPIRE_USAGE,
43         NULL
44 };
45
46 static const char *const reflog_delete_usage[] = {
47         BUILTIN_REFLOG_DELETE_USAGE,
48         NULL
49 };
50
51 static const char *const reflog_exists_usage[] = {
52         BUILTIN_REFLOG_EXISTS_USAGE,
53         NULL,
54 };
55
56 static const char *const reflog_usage[] = {
57         BUILTIN_REFLOG_SHOW_USAGE,
58         BUILTIN_REFLOG_LIST_USAGE,
59         BUILTIN_REFLOG_EXPIRE_USAGE,
60         BUILTIN_REFLOG_DELETE_USAGE,
61         BUILTIN_REFLOG_EXISTS_USAGE,
62         NULL
63 };
64
65 static timestamp_t default_reflog_expire;
66 static timestamp_t default_reflog_expire_unreachable;
67
68 struct worktree_reflogs {
69         struct worktree *worktree;
70         struct string_list reflogs;
71 };
72
73 static int collect_reflog(const char *ref, void *cb_data)
74 {
75         struct worktree_reflogs *cb = cb_data;
76         struct worktree *worktree = cb->worktree;
77         struct strbuf newref = STRBUF_INIT;
78
79         /*
80          * Avoid collecting the same shared ref multiple times because
81          * they are available via all worktrees.
82          */
83         if (!worktree->is_current &&
84             parse_worktree_ref(ref, NULL, NULL, NULL) == REF_WORKTREE_SHARED)
85                 return 0;
86
87         strbuf_worktree_ref(worktree, &newref, ref);
88         string_list_append_nodup(&cb->reflogs, strbuf_detach(&newref, NULL));
89
90         return 0;
91 }
92
93 static struct reflog_expire_cfg {
94         struct reflog_expire_cfg *next;
95         timestamp_t expire_total;
96         timestamp_t expire_unreachable;
97         char pattern[FLEX_ARRAY];
98 } *reflog_expire_cfg, **reflog_expire_cfg_tail;
99
100 static struct reflog_expire_cfg *find_cfg_ent(const char *pattern, size_t len)
101 {
102         struct reflog_expire_cfg *ent;
103
104         if (!reflog_expire_cfg_tail)
105                 reflog_expire_cfg_tail = &reflog_expire_cfg;
106
107         for (ent = reflog_expire_cfg; ent; ent = ent->next)
108                 if (!xstrncmpz(ent->pattern, pattern, len))
109                         return ent;
110
111         FLEX_ALLOC_MEM(ent, pattern, pattern, len);
112         *reflog_expire_cfg_tail = ent;
113         reflog_expire_cfg_tail = &(ent->next);
114         return ent;
115 }
116
117 /* expiry timer slot */
118 #define EXPIRE_TOTAL   01
119 #define EXPIRE_UNREACH 02
120
121 static int reflog_expire_config(const char *var, const char *value,
122                                 const struct config_context *ctx, void *cb)
123 {
124         const char *pattern, *key;
125         size_t pattern_len;
126         timestamp_t expire;
127         int slot;
128         struct reflog_expire_cfg *ent;
129
130         if (parse_config_key(var, "gc", &pattern, &pattern_len, &key) < 0)
131                 return git_default_config(var, value, ctx, cb);
132
133         if (!strcmp(key, "reflogexpire")) {
134                 slot = EXPIRE_TOTAL;
135                 if (git_config_expiry_date(&expire, var, value))
136                         return -1;
137         } else if (!strcmp(key, "reflogexpireunreachable")) {
138                 slot = EXPIRE_UNREACH;
139                 if (git_config_expiry_date(&expire, var, value))
140                         return -1;
141         } else
142                 return git_default_config(var, value, ctx, cb);
143
144         if (!pattern) {
145                 switch (slot) {
146                 case EXPIRE_TOTAL:
147                         default_reflog_expire = expire;
148                         break;
149                 case EXPIRE_UNREACH:
150                         default_reflog_expire_unreachable = expire;
151                         break;
152                 }
153                 return 0;
154         }
155
156         ent = find_cfg_ent(pattern, pattern_len);
157         if (!ent)
158                 return -1;
159         switch (slot) {
160         case EXPIRE_TOTAL:
161                 ent->expire_total = expire;
162                 break;
163         case EXPIRE_UNREACH:
164                 ent->expire_unreachable = expire;
165                 break;
166         }
167         return 0;
168 }
169
170 static void set_reflog_expiry_param(struct cmd_reflog_expire_cb *cb, const char *ref)
171 {
172         struct reflog_expire_cfg *ent;
173
174         if (cb->explicit_expiry == (EXPIRE_TOTAL|EXPIRE_UNREACH))
175                 return; /* both given explicitly -- nothing to tweak */
176
177         for (ent = reflog_expire_cfg; ent; ent = ent->next) {
178                 if (!wildmatch(ent->pattern, ref, 0)) {
179                         if (!(cb->explicit_expiry & EXPIRE_TOTAL))
180                                 cb->expire_total = ent->expire_total;
181                         if (!(cb->explicit_expiry & EXPIRE_UNREACH))
182                                 cb->expire_unreachable = ent->expire_unreachable;
183                         return;
184                 }
185         }
186
187         /*
188          * If unconfigured, make stash never expire
189          */
190         if (!strcmp(ref, "refs/stash")) {
191                 if (!(cb->explicit_expiry & EXPIRE_TOTAL))
192                         cb->expire_total = 0;
193                 if (!(cb->explicit_expiry & EXPIRE_UNREACH))
194                         cb->expire_unreachable = 0;
195                 return;
196         }
197
198         /* Nothing matched -- use the default value */
199         if (!(cb->explicit_expiry & EXPIRE_TOTAL))
200                 cb->expire_total = default_reflog_expire;
201         if (!(cb->explicit_expiry & EXPIRE_UNREACH))
202                 cb->expire_unreachable = default_reflog_expire_unreachable;
203 }
204
205 static int expire_unreachable_callback(const struct option *opt,
206                                  const char *arg,
207                                  int unset)
208 {
209         struct cmd_reflog_expire_cb *cmd = opt->value;
210
211         BUG_ON_OPT_NEG(unset);
212
213         if (parse_expiry_date(arg, &cmd->expire_unreachable))
214                 die(_("invalid timestamp '%s' given to '--%s'"),
215                     arg, opt->long_name);
216
217         cmd->explicit_expiry |= EXPIRE_UNREACH;
218         return 0;
219 }
220
221 static int expire_total_callback(const struct option *opt,
222                                  const char *arg,
223                                  int unset)
224 {
225         struct cmd_reflog_expire_cb *cmd = opt->value;
226
227         BUG_ON_OPT_NEG(unset);
228
229         if (parse_expiry_date(arg, &cmd->expire_total))
230                 die(_("invalid timestamp '%s' given to '--%s'"),
231                     arg, opt->long_name);
232
233         cmd->explicit_expiry |= EXPIRE_TOTAL;
234         return 0;
235 }
236
237 static int cmd_reflog_show(int argc, const char **argv, const char *prefix)
238 {
239         struct option options[] = {
240                 OPT_END()
241         };
242
243         parse_options(argc, argv, prefix, options, reflog_show_usage,
244                       PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_ARGV0 |
245                       PARSE_OPT_KEEP_UNKNOWN_OPT);
246
247         return cmd_log_reflog(argc, argv, prefix);
248 }
249
250 static int show_reflog(const char *refname, void *cb_data UNUSED)
251 {
252         printf("%s\n", refname);
253         return 0;
254 }
255
256 static int cmd_reflog_list(int argc, const char **argv, const char *prefix)
257 {
258         struct option options[] = {
259                 OPT_END()
260         };
261         struct ref_store *ref_store;
262
263         argc = parse_options(argc, argv, prefix, options, reflog_list_usage, 0);
264         if (argc)
265                 return error(_("%s does not accept arguments: '%s'"),
266                              "list", argv[0]);
267
268         ref_store = get_main_ref_store(the_repository);
269
270         return refs_for_each_reflog(ref_store, show_reflog, NULL);
271 }
272
273 static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
274 {
275         struct cmd_reflog_expire_cb cmd = { 0 };
276         timestamp_t now = time(NULL);
277         int i, status, do_all, single_worktree = 0;
278         unsigned int flags = 0;
279         int verbose = 0;
280         reflog_expiry_should_prune_fn *should_prune_fn = should_expire_reflog_ent;
281         const struct option options[] = {
282                 OPT_BIT('n', "dry-run", &flags, N_("do not actually prune any entries"),
283                         EXPIRE_REFLOGS_DRY_RUN),
284                 OPT_BIT(0, "rewrite", &flags,
285                         N_("rewrite the old SHA1 with the new SHA1 of the entry that now precedes it"),
286                         EXPIRE_REFLOGS_REWRITE),
287                 OPT_BIT(0, "updateref", &flags,
288                         N_("update the reference to the value of the top reflog entry"),
289                         EXPIRE_REFLOGS_UPDATE_REF),
290                 OPT_BOOL(0, "verbose", &verbose, N_("print extra information on screen")),
291                 OPT_CALLBACK_F(0, "expire", &cmd, N_("timestamp"),
292                                N_("prune entries older than the specified time"),
293                                PARSE_OPT_NONEG,
294                                expire_total_callback),
295                 OPT_CALLBACK_F(0, "expire-unreachable", &cmd, N_("timestamp"),
296                                N_("prune entries older than <time> that are not reachable from the current tip of the branch"),
297                                PARSE_OPT_NONEG,
298                                expire_unreachable_callback),
299                 OPT_BOOL(0, "stale-fix", &cmd.stalefix,
300                          N_("prune any reflog entries that point to broken commits")),
301                 OPT_BOOL(0, "all", &do_all, N_("process the reflogs of all references")),
302                 OPT_BOOL(0, "single-worktree", &single_worktree,
303                          N_("limits processing to reflogs from the current worktree only")),
304                 OPT_END()
305         };
306
307         default_reflog_expire_unreachable = now - 30 * 24 * 3600;
308         default_reflog_expire = now - 90 * 24 * 3600;
309         git_config(reflog_expire_config, NULL);
310
311         save_commit_buffer = 0;
312         do_all = status = 0;
313
314         cmd.explicit_expiry = 0;
315         cmd.expire_total = default_reflog_expire;
316         cmd.expire_unreachable = default_reflog_expire_unreachable;
317
318         argc = parse_options(argc, argv, prefix, options, reflog_expire_usage, 0);
319
320         if (verbose)
321                 should_prune_fn = should_expire_reflog_ent_verbose;
322
323         /*
324          * We can trust the commits and objects reachable from refs
325          * even in older repository.  We cannot trust what's reachable
326          * from reflog if the repository was pruned with older git.
327          */
328         if (cmd.stalefix) {
329                 struct rev_info revs;
330
331                 repo_init_revisions(the_repository, &revs, prefix);
332                 revs.do_not_die_on_missing_objects = 1;
333                 revs.ignore_missing = 1;
334                 revs.ignore_missing_links = 1;
335                 if (verbose)
336                         printf(_("Marking reachable objects..."));
337                 mark_reachable_objects(&revs, 0, 0, NULL);
338                 release_revisions(&revs);
339                 if (verbose)
340                         putchar('\n');
341         }
342
343         if (do_all) {
344                 struct worktree_reflogs collected = {
345                         .reflogs = STRING_LIST_INIT_DUP,
346                 };
347                 struct string_list_item *item;
348                 struct worktree **worktrees, **p;
349
350                 worktrees = get_worktrees();
351                 for (p = worktrees; *p; p++) {
352                         if (single_worktree && !(*p)->is_current)
353                                 continue;
354                         collected.worktree = *p;
355                         refs_for_each_reflog(get_worktree_ref_store(*p),
356                                              collect_reflog, &collected);
357                 }
358                 free_worktrees(worktrees);
359
360                 for_each_string_list_item(item, &collected.reflogs) {
361                         struct expire_reflog_policy_cb cb = {
362                                 .cmd = cmd,
363                                 .dry_run = !!(flags & EXPIRE_REFLOGS_DRY_RUN),
364                         };
365
366                         set_reflog_expiry_param(&cb.cmd,  item->string);
367                         status |= refs_reflog_expire(get_main_ref_store(the_repository),
368                                                      item->string, flags,
369                                                      reflog_expiry_prepare,
370                                                      should_prune_fn,
371                                                      reflog_expiry_cleanup,
372                                                      &cb);
373                 }
374                 string_list_clear(&collected.reflogs, 0);
375         }
376
377         for (i = 0; i < argc; i++) {
378                 char *ref;
379                 struct expire_reflog_policy_cb cb = { .cmd = cmd };
380
381                 if (!repo_dwim_log(the_repository, argv[i], strlen(argv[i]), NULL, &ref)) {
382                         status |= error(_("%s points nowhere!"), argv[i]);
383                         continue;
384                 }
385                 set_reflog_expiry_param(&cb.cmd, ref);
386                 status |= refs_reflog_expire(get_main_ref_store(the_repository),
387                                              ref, flags,
388                                              reflog_expiry_prepare,
389                                              should_prune_fn,
390                                              reflog_expiry_cleanup,
391                                              &cb);
392                 free(ref);
393         }
394         return status;
395 }
396
397 static int cmd_reflog_delete(int argc, const char **argv, const char *prefix)
398 {
399         int i, status = 0;
400         unsigned int flags = 0;
401         int verbose = 0;
402
403         const struct option options[] = {
404                 OPT_BIT('n', "dry-run", &flags, N_("do not actually prune any entries"),
405                         EXPIRE_REFLOGS_DRY_RUN),
406                 OPT_BIT(0, "rewrite", &flags,
407                         N_("rewrite the old SHA1 with the new SHA1 of the entry that now precedes it"),
408                         EXPIRE_REFLOGS_REWRITE),
409                 OPT_BIT(0, "updateref", &flags,
410                         N_("update the reference to the value of the top reflog entry"),
411                         EXPIRE_REFLOGS_UPDATE_REF),
412                 OPT_BOOL(0, "verbose", &verbose, N_("print extra information on screen")),
413                 OPT_END()
414         };
415
416         argc = parse_options(argc, argv, prefix, options, reflog_delete_usage, 0);
417
418         if (argc < 1)
419                 return error(_("no reflog specified to delete"));
420
421         for (i = 0; i < argc; i++)
422                 status |= reflog_delete(argv[i], flags, verbose);
423
424         return status;
425 }
426
427 static int cmd_reflog_exists(int argc, const char **argv, const char *prefix)
428 {
429         struct option options[] = {
430                 OPT_END()
431         };
432         const char *refname;
433
434         argc = parse_options(argc, argv, prefix, options, reflog_exists_usage,
435                              0);
436         if (!argc)
437                 usage_with_options(reflog_exists_usage, options);
438
439         refname = argv[0];
440         if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL))
441                 die(_("invalid ref format: %s"), refname);
442         return !refs_reflog_exists(get_main_ref_store(the_repository),
443                                    refname);
444 }
445
446 /*
447  * main "reflog"
448  */
449
450 int cmd_reflog(int argc, const char **argv, const char *prefix)
451 {
452         parse_opt_subcommand_fn *fn = NULL;
453         struct option options[] = {
454                 OPT_SUBCOMMAND("show", &fn, cmd_reflog_show),
455                 OPT_SUBCOMMAND("list", &fn, cmd_reflog_list),
456                 OPT_SUBCOMMAND("expire", &fn, cmd_reflog_expire),
457                 OPT_SUBCOMMAND("delete", &fn, cmd_reflog_delete),
458                 OPT_SUBCOMMAND("exists", &fn, cmd_reflog_exists),
459                 OPT_END()
460         };
461
462         argc = parse_options(argc, argv, prefix, options, reflog_usage,
463                              PARSE_OPT_SUBCOMMAND_OPTIONAL |
464                              PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_ARGV0 |
465                              PARSE_OPT_KEEP_UNKNOWN_OPT);
466         if (fn)
467                 return fn(argc - 1, argv + 1, prefix);
468         else
469                 return cmd_log_reflog(argc, argv, prefix);
470 }