]> git.ipfire.org Git - thirdparty/git.git/blame - builtin/reflog.c
The eighth batch
[thirdparty/git.git] / builtin / reflog.c
CommitLineData
03eae9af 1#define USE_THE_REPOSITORY_VARIABLE
41f43b82 2
4264dc15 3#include "builtin.h"
b2141fc1 4#include "config.h"
f394e093 5#include "gettext.h"
1389d9dd
JH
6#include "revision.h"
7#include "reachable.h"
dd77d587 8#include "wildmatch.h"
c9ef0d95 9#include "worktree.h"
7d3d226e 10#include "reflog.h"
d699d15c 11#include "refs.h"
49fd5511 12#include "parse-options.h"
1389d9dd 13
fbc15b13
ÆAB
14#define BUILTIN_REFLOG_SHOW_USAGE \
15 N_("git reflog [show] [<log-options>] [<ref>]")
16
d699d15c
PS
17#define BUILTIN_REFLOG_LIST_USAGE \
18 N_("git reflog list")
19
1e91d3fa 20#define BUILTIN_REFLOG_EXPIRE_USAGE \
cbe48529
ÆAB
21 N_("git reflog expire [--expire=<time>] [--expire-unreachable=<time>]\n" \
22 " [--rewrite] [--updateref] [--stale-fix]\n" \
23 " [--dry-run | -n] [--verbose] [--all [--single-worktree] | <refs>...]")
1e91d3fa
ÆAB
24
25#define BUILTIN_REFLOG_DELETE_USAGE \
cbe48529
ÆAB
26 N_("git reflog delete [--rewrite] [--updateref]\n" \
27 " [--dry-run | -n] [--verbose] <ref>@{<specifier>}...")
1e91d3fa
ÆAB
28
29#define BUILTIN_REFLOG_EXISTS_USAGE \
30 N_("git reflog exists <ref>")
31
d1270689
KN
32#define BUILTIN_REFLOG_DROP_USAGE \
33 N_("git reflog drop [--all [--single-worktree] | <refs>...]")
34
fbc15b13
ÆAB
35static const char *const reflog_show_usage[] = {
36 BUILTIN_REFLOG_SHOW_USAGE,
37 NULL,
38};
39
d699d15c
PS
40static const char *const reflog_list_usage[] = {
41 BUILTIN_REFLOG_LIST_USAGE,
42 NULL,
43};
44
1e91d3fa
ÆAB
45static const char *const reflog_expire_usage[] = {
46 BUILTIN_REFLOG_EXPIRE_USAGE,
47 NULL
48};
49
50static const char *const reflog_delete_usage[] = {
51 BUILTIN_REFLOG_DELETE_USAGE,
52 NULL
53};
54
a34393f5
ÆAB
55static const char *const reflog_exists_usage[] = {
56 BUILTIN_REFLOG_EXISTS_USAGE,
57 NULL,
58};
4264dc15 59
d1270689
KN
60static const char *const reflog_drop_usage[] = {
61 BUILTIN_REFLOG_DROP_USAGE,
62 NULL,
63};
64
e3c36758 65static const char *const reflog_usage[] = {
fbc15b13 66 BUILTIN_REFLOG_SHOW_USAGE,
d699d15c 67 BUILTIN_REFLOG_LIST_USAGE,
e3c36758
ÆAB
68 BUILTIN_REFLOG_EXPIRE_USAGE,
69 BUILTIN_REFLOG_DELETE_USAGE,
d1270689 70 BUILTIN_REFLOG_DROP_USAGE,
e3c36758
ÆAB
71 BUILTIN_REFLOG_EXISTS_USAGE,
72 NULL
73};
74
f2919bae
ÆAB
75struct worktree_reflogs {
76 struct worktree *worktree;
77 struct string_list reflogs;
bda3a31c
JH
78};
79
31f89839 80static int collect_reflog(const char *ref, void *cb_data)
bda3a31c 81{
f2919bae
ÆAB
82 struct worktree_reflogs *cb = cb_data;
83 struct worktree *worktree = cb->worktree;
c9ef0d95
NTND
84 struct strbuf newref = STRBUF_INIT;
85
86 /*
87 * Avoid collecting the same shared ref multiple times because
88 * they are available via all worktrees.
89 */
71e54734
HWN
90 if (!worktree->is_current &&
91 parse_worktree_ref(ref, NULL, NULL, NULL) == REF_WORKTREE_SHARED)
c9ef0d95
NTND
92 return 0;
93
f2919bae
ÆAB
94 strbuf_worktree_ref(worktree, &newref, ref);
95 string_list_append_nodup(&cb->reflogs, strbuf_detach(&newref, NULL));
bda3a31c 96
bda3a31c
JH
97 return 0;
98}
99
33d7bdd6
JC
100static int expire_unreachable_callback(const struct option *opt,
101 const char *arg,
102 int unset)
103{
2ed80083 104 struct reflog_expire_options *opts = opt->value;
33d7bdd6 105
ee610f00
JK
106 BUG_ON_OPT_NEG(unset);
107
2ed80083 108 if (parse_expiry_date(arg, &opts->expire_unreachable))
33d7bdd6
JC
109 die(_("invalid timestamp '%s' given to '--%s'"),
110 arg, opt->long_name);
111
d20fc193 112 opts->explicit_expiry |= REFLOG_EXPIRE_UNREACH;
33d7bdd6
JC
113 return 0;
114}
115
116static int expire_total_callback(const struct option *opt,
117 const char *arg,
118 int unset)
119{
2ed80083 120 struct reflog_expire_options *opts = opt->value;
33d7bdd6 121
ee610f00
JK
122 BUG_ON_OPT_NEG(unset);
123
2ed80083 124 if (parse_expiry_date(arg, &opts->expire_total))
33d7bdd6
JC
125 die(_("invalid timestamp '%s' given to '--%s'"),
126 arg, opt->long_name);
127
d20fc193 128 opts->explicit_expiry |= REFLOG_EXPIRE_TOTAL;
33d7bdd6
JC
129 return 0;
130}
131
6f33d8e2
KN
132static int cmd_reflog_show(int argc, const char **argv, const char *prefix,
133 struct repository *repo UNUSED)
fbc15b13
ÆAB
134{
135 struct option options[] = {
136 OPT_END()
137 };
138
139 parse_options(argc, argv, prefix, options, reflog_show_usage,
140 PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_ARGV0 |
99d86d60 141 PARSE_OPT_KEEP_UNKNOWN_OPT);
fbc15b13 142
9b1cb507 143 return cmd_log_reflog(argc, argv, prefix, the_repository);
fbc15b13
ÆAB
144}
145
d699d15c
PS
146static int show_reflog(const char *refname, void *cb_data UNUSED)
147{
148 printf("%s\n", refname);
149 return 0;
150}
151
6f33d8e2
KN
152static int cmd_reflog_list(int argc, const char **argv, const char *prefix,
153 struct repository *repo UNUSED)
d699d15c
PS
154{
155 struct option options[] = {
156 OPT_END()
157 };
158 struct ref_store *ref_store;
159
160 argc = parse_options(argc, argv, prefix, options, reflog_list_usage, 0);
161 if (argc)
162 return error(_("%s does not accept arguments: '%s'"),
163 "list", argv[0]);
164
165 ref_store = get_main_ref_store(the_repository);
166
167 return refs_for_each_reflog(ref_store, show_reflog, NULL);
168}
169
6f33d8e2
KN
170static int cmd_reflog_expire(int argc, const char **argv, const char *prefix,
171 struct repository *repo UNUSED)
4264dc15 172{
dddbad72 173 timestamp_t now = time(NULL);
85658275 174 struct reflog_expire_options opts = REFLOG_EXPIRE_OPTIONS_INIT(now);
26d4c51d 175 int i, status, do_all, single_worktree = 0;
aba56c89 176 unsigned int flags = 0;
fcd2c3d9
ÆAB
177 int verbose = 0;
178 reflog_expiry_should_prune_fn *should_prune_fn = should_expire_reflog_ent;
33d7bdd6 179 const struct option options[] = {
cbf498eb 180 OPT_BIT('n', "dry-run", &flags, N_("do not actually prune any entries"),
33d7bdd6
JC
181 EXPIRE_REFLOGS_DRY_RUN),
182 OPT_BIT(0, "rewrite", &flags,
183 N_("rewrite the old SHA1 with the new SHA1 of the entry that now precedes it"),
184 EXPIRE_REFLOGS_REWRITE),
185 OPT_BIT(0, "updateref", &flags,
186 N_("update the reference to the value of the top reflog entry"),
187 EXPIRE_REFLOGS_UPDATE_REF),
9e1f22c8 188 OPT_BOOL(0, "verbose", &verbose, N_("print extra information on screen")),
2ed80083 189 OPT_CALLBACK_F(0, "expire", &opts, N_("timestamp"),
33d7bdd6
JC
190 N_("prune entries older than the specified time"),
191 PARSE_OPT_NONEG,
192 expire_total_callback),
2ed80083 193 OPT_CALLBACK_F(0, "expire-unreachable", &opts, N_("timestamp"),
33d7bdd6
JC
194 N_("prune entries older than <time> that are not reachable from the current tip of the branch"),
195 PARSE_OPT_NONEG,
196 expire_unreachable_callback),
2ed80083 197 OPT_BOOL(0, "stale-fix", &opts.stalefix,
33d7bdd6
JC
198 N_("prune any reflog entries that point to broken commits")),
199 OPT_BOOL(0, "all", &do_all, N_("process the reflogs of all references")),
26d4c51d 200 OPT_BOOL(0, "single-worktree", &single_worktree,
9e1f22c8 201 N_("limits processing to reflogs from the current worktree only")),
33d7bdd6
JC
202 OPT_END()
203 };
4264dc15 204
85658275 205 git_config(reflog_expire_config, &opts);
4aec56d1 206
4264dc15
JH
207 save_commit_buffer = 0;
208 do_all = status = 0;
4aec56d1 209
33d7bdd6 210 argc = parse_options(argc, argv, prefix, options, reflog_expire_usage, 0);
3cb22b8e 211
fcd2c3d9
ÆAB
212 if (verbose)
213 should_prune_fn = should_expire_reflog_ent_verbose;
214
3cb22b8e
JH
215 /*
216 * We can trust the commits and objects reachable from refs
217 * even in older repository. We cannot trust what's reachable
218 * from reflog if the repository was pruned with older git.
219 */
2ed80083 220 if (opts.stalefix) {
994b328f
ÆAB
221 struct rev_info revs;
222
223 repo_init_revisions(the_repository, &revs, prefix);
ca556f47 224 revs.do_not_die_on_missing_objects = 1;
994b328f
ÆAB
225 revs.ignore_missing = 1;
226 revs.ignore_missing_links = 1;
fcd2c3d9 227 if (verbose)
dd509db3 228 printf(_("Marking reachable objects..."));
994b328f 229 mark_reachable_objects(&revs, 0, 0, NULL);
2108fe4a 230 release_revisions(&revs);
fcd2c3d9 231 if (verbose)
1389d9dd
JH
232 putchar('\n');
233 }
234
bda3a31c 235 if (do_all) {
f2919bae
ÆAB
236 struct worktree_reflogs collected = {
237 .reflogs = STRING_LIST_INIT_DUP,
238 };
239 struct string_list_item *item;
c9ef0d95 240 struct worktree **worktrees, **p;
bda3a31c 241
03f2465b 242 worktrees = get_worktrees();
c9ef0d95 243 for (p = worktrees; *p; p++) {
26d4c51d 244 if (single_worktree && !(*p)->is_current)
c9ef0d95 245 continue;
f2919bae 246 collected.worktree = *p;
c9ef0d95
NTND
247 refs_for_each_reflog(get_worktree_ref_store(*p),
248 collect_reflog, &collected);
249 }
250 free_worktrees(worktrees);
f2919bae
ÆAB
251
252 for_each_string_list_item(item, &collected.reflogs) {
fcd2c3d9 253 struct expire_reflog_policy_cb cb = {
2ed80083 254 .opts = opts,
fcd2c3d9
ÆAB
255 .dry_run = !!(flags & EXPIRE_REFLOGS_DRY_RUN),
256 };
ae35e16c 257
d20fc193 258 reflog_expire_options_set_refname(&cb.opts, item->string);
2e5c4758
PS
259 status |= refs_reflog_expire(get_main_ref_store(the_repository),
260 item->string, flags,
261 reflog_expiry_prepare,
262 should_prune_fn,
263 reflog_expiry_cleanup,
264 &cb);
bda3a31c 265 }
f2919bae 266 string_list_clear(&collected.reflogs, 0);
bda3a31c
JH
267 }
268
33d7bdd6 269 for (i = 0; i < argc; i++) {
90fb46ec 270 char *ref;
2ed80083 271 struct expire_reflog_policy_cb cb = { .opts = opts };
46fbe418 272
2bb444b1 273 if (!repo_dwim_log(the_repository, argv[i], strlen(argv[i]), NULL, &ref)) {
52f2dfb0 274 status |= error(_("reflog could not be found: '%s'"), argv[i]);
4264dc15
JH
275 continue;
276 }
d20fc193 277 reflog_expire_options_set_refname(&cb.opts, ref);
2e5c4758
PS
278 status |= refs_reflog_expire(get_main_ref_store(the_repository),
279 ref, flags,
280 reflog_expiry_prepare,
281 should_prune_fn,
282 reflog_expiry_cleanup,
283 &cb);
3c815049 284 free(ref);
4264dc15
JH
285 }
286 return status;
287}
288
6f33d8e2
KN
289static int cmd_reflog_delete(int argc, const char **argv, const char *prefix,
290 struct repository *repo UNUSED)
552cecc2 291{
552cecc2 292 int i, status = 0;
aba56c89 293 unsigned int flags = 0;
fcd2c3d9 294 int verbose = 0;
7d3d226e 295
33d7bdd6 296 const struct option options[] = {
cbf498eb 297 OPT_BIT('n', "dry-run", &flags, N_("do not actually prune any entries"),
33d7bdd6
JC
298 EXPIRE_REFLOGS_DRY_RUN),
299 OPT_BIT(0, "rewrite", &flags,
300 N_("rewrite the old SHA1 with the new SHA1 of the entry that now precedes it"),
301 EXPIRE_REFLOGS_REWRITE),
302 OPT_BIT(0, "updateref", &flags,
303 N_("update the reference to the value of the top reflog entry"),
304 EXPIRE_REFLOGS_UPDATE_REF),
9e1f22c8 305 OPT_BOOL(0, "verbose", &verbose, N_("print extra information on screen")),
33d7bdd6
JC
306 OPT_END()
307 };
308
309 argc = parse_options(argc, argv, prefix, options, reflog_delete_usage, 0);
3c386aa3 310
33d7bdd6 311 if (argc < 1)
dd509db3 312 return error(_("no reflog specified to delete"));
3c386aa3 313
7d3d226e
JC
314 for (i = 0; i < argc; i++)
315 status |= reflog_delete(argv[i], flags, verbose);
552cecc2 316
552cecc2
JS
317 return status;
318}
319
6f33d8e2
KN
320static int cmd_reflog_exists(int argc, const char **argv, const char *prefix,
321 struct repository *repo UNUSED)
afcb2e7a 322{
a34393f5
ÆAB
323 struct option options[] = {
324 OPT_END()
325 };
326 const char *refname;
afcb2e7a 327
a34393f5
ÆAB
328 argc = parse_options(argc, argv, prefix, options, reflog_exists_usage,
329 0);
330 if (!argc)
331 usage_with_options(reflog_exists_usage, options);
afcb2e7a 332
a34393f5
ÆAB
333 refname = argv[0];
334 if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL))
335 die(_("invalid ref format: %s"), refname);
2e5c4758
PS
336 return !refs_reflog_exists(get_main_ref_store(the_repository),
337 refname);
afcb2e7a
DT
338}
339
d1270689
KN
340static int cmd_reflog_drop(int argc, const char **argv, const char *prefix,
341 struct repository *repo)
342{
343 int ret = 0, do_all = 0, single_worktree = 0;
344 const struct option options[] = {
345 OPT_BOOL(0, "all", &do_all, N_("drop the reflogs of all references")),
346 OPT_BOOL(0, "single-worktree", &single_worktree,
347 N_("drop reflogs from the current worktree only")),
348 OPT_END()
349 };
350
351 argc = parse_options(argc, argv, prefix, options, reflog_drop_usage, 0);
352
353 if (argc && do_all)
354 usage(_("references specified along with --all"));
355
356 if (do_all) {
357 struct worktree_reflogs collected = {
358 .reflogs = STRING_LIST_INIT_DUP,
359 };
360 struct string_list_item *item;
361 struct worktree **worktrees, **p;
362
363 worktrees = get_worktrees();
364 for (p = worktrees; *p; p++) {
365 if (single_worktree && !(*p)->is_current)
366 continue;
367 collected.worktree = *p;
368 refs_for_each_reflog(get_worktree_ref_store(*p),
369 collect_reflog, &collected);
370 }
371 free_worktrees(worktrees);
372
373 for_each_string_list_item(item, &collected.reflogs)
374 ret |= refs_delete_reflog(get_main_ref_store(repo),
375 item->string);
376 string_list_clear(&collected.reflogs, 0);
377
378 return ret;
379 }
380
381 for (int i = 0; i < argc; i++) {
382 char *ref;
383 if (!repo_dwim_log(repo, argv[i], strlen(argv[i]), NULL, &ref)) {
384 ret |= error(_("reflog could not be found: '%s'"), argv[i]);
385 continue;
386 }
387
388 ret |= refs_delete_reflog(get_main_ref_store(repo), ref);
389 free(ref);
390 }
391
392 return ret;
393}
394
1389d9dd
JH
395/*
396 * main "reflog"
397 */
9b1cb507
JC
398int cmd_reflog(int argc,
399 const char **argv,
400 const char *prefix,
401 struct repository *repository)
4264dc15 402{
729b9733 403 parse_opt_subcommand_fn *fn = NULL;
e3c36758 404 struct option options[] = {
729b9733 405 OPT_SUBCOMMAND("show", &fn, cmd_reflog_show),
d699d15c 406 OPT_SUBCOMMAND("list", &fn, cmd_reflog_list),
729b9733
SG
407 OPT_SUBCOMMAND("expire", &fn, cmd_reflog_expire),
408 OPT_SUBCOMMAND("delete", &fn, cmd_reflog_delete),
409 OPT_SUBCOMMAND("exists", &fn, cmd_reflog_exists),
d1270689 410 OPT_SUBCOMMAND("drop", &fn, cmd_reflog_drop),
e3c36758
ÆAB
411 OPT_END()
412 };
413
414 argc = parse_options(argc, argv, prefix, options, reflog_usage,
729b9733 415 PARSE_OPT_SUBCOMMAND_OPTIONAL |
e3c36758 416 PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_ARGV0 |
729b9733
SG
417 PARSE_OPT_KEEP_UNKNOWN_OPT);
418 if (fn)
6f33d8e2 419 return fn(argc - 1, argv + 1, prefix, repository);
729b9733 420 else
9b1cb507 421 return cmd_log_reflog(argc, argv, prefix, repository);
4264dc15 422}