4 #include "repository.h"
11 #include "parse-options.h"
13 #define BUILTIN_REFLOG_SHOW_USAGE \
14 N_("git reflog [show] [<log-options>] [<ref>]")
16 #define BUILTIN_REFLOG_LIST_USAGE \
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>...]")
24 #define BUILTIN_REFLOG_DELETE_USAGE \
25 N_("git reflog delete [--rewrite] [--updateref]\n" \
26 " [--dry-run | -n] [--verbose] <ref>@{<specifier>}...")
28 #define BUILTIN_REFLOG_EXISTS_USAGE \
29 N_("git reflog exists <ref>")
31 static const char *const reflog_show_usage
[] = {
32 BUILTIN_REFLOG_SHOW_USAGE
,
36 static const char *const reflog_list_usage
[] = {
37 BUILTIN_REFLOG_LIST_USAGE
,
41 static const char *const reflog_expire_usage
[] = {
42 BUILTIN_REFLOG_EXPIRE_USAGE
,
46 static const char *const reflog_delete_usage
[] = {
47 BUILTIN_REFLOG_DELETE_USAGE
,
51 static const char *const reflog_exists_usage
[] = {
52 BUILTIN_REFLOG_EXISTS_USAGE
,
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
,
65 static timestamp_t default_reflog_expire
;
66 static timestamp_t default_reflog_expire_unreachable
;
68 struct worktree_reflogs
{
69 struct worktree
*worktree
;
70 struct string_list reflogs
;
73 static int collect_reflog(const char *ref
, void *cb_data
)
75 struct worktree_reflogs
*cb
= cb_data
;
76 struct worktree
*worktree
= cb
->worktree
;
77 struct strbuf newref
= STRBUF_INIT
;
80 * Avoid collecting the same shared ref multiple times because
81 * they are available via all worktrees.
83 if (!worktree
->is_current
&&
84 parse_worktree_ref(ref
, NULL
, NULL
, NULL
) == REF_WORKTREE_SHARED
)
87 strbuf_worktree_ref(worktree
, &newref
, ref
);
88 string_list_append_nodup(&cb
->reflogs
, strbuf_detach(&newref
, NULL
));
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
;
100 static struct reflog_expire_cfg
*find_cfg_ent(const char *pattern
, size_t len
)
102 struct reflog_expire_cfg
*ent
;
104 if (!reflog_expire_cfg_tail
)
105 reflog_expire_cfg_tail
= &reflog_expire_cfg
;
107 for (ent
= reflog_expire_cfg
; ent
; ent
= ent
->next
)
108 if (!xstrncmpz(ent
->pattern
, pattern
, len
))
111 FLEX_ALLOC_MEM(ent
, pattern
, pattern
, len
);
112 *reflog_expire_cfg_tail
= ent
;
113 reflog_expire_cfg_tail
= &(ent
->next
);
117 /* expiry timer slot */
118 #define EXPIRE_TOTAL 01
119 #define EXPIRE_UNREACH 02
121 static int reflog_expire_config(const char *var
, const char *value
,
122 const struct config_context
*ctx
, void *cb
)
124 const char *pattern
, *key
;
128 struct reflog_expire_cfg
*ent
;
130 if (parse_config_key(var
, "gc", &pattern
, &pattern_len
, &key
) < 0)
131 return git_default_config(var
, value
, ctx
, cb
);
133 if (!strcmp(key
, "reflogexpire")) {
135 if (git_config_expiry_date(&expire
, var
, value
))
137 } else if (!strcmp(key
, "reflogexpireunreachable")) {
138 slot
= EXPIRE_UNREACH
;
139 if (git_config_expiry_date(&expire
, var
, value
))
142 return git_default_config(var
, value
, ctx
, cb
);
147 default_reflog_expire
= expire
;
150 default_reflog_expire_unreachable
= expire
;
156 ent
= find_cfg_ent(pattern
, pattern_len
);
161 ent
->expire_total
= expire
;
164 ent
->expire_unreachable
= expire
;
170 static void set_reflog_expiry_param(struct cmd_reflog_expire_cb
*cb
, const char *ref
)
172 struct reflog_expire_cfg
*ent
;
174 if (cb
->explicit_expiry
== (EXPIRE_TOTAL
|EXPIRE_UNREACH
))
175 return; /* both given explicitly -- nothing to tweak */
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
;
188 * If unconfigured, make stash never expire
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;
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
;
205 static int expire_unreachable_callback(const struct option
*opt
,
209 struct cmd_reflog_expire_cb
*cmd
= opt
->value
;
211 BUG_ON_OPT_NEG(unset
);
213 if (parse_expiry_date(arg
, &cmd
->expire_unreachable
))
214 die(_("invalid timestamp '%s' given to '--%s'"),
215 arg
, opt
->long_name
);
217 cmd
->explicit_expiry
|= EXPIRE_UNREACH
;
221 static int expire_total_callback(const struct option
*opt
,
225 struct cmd_reflog_expire_cb
*cmd
= opt
->value
;
227 BUG_ON_OPT_NEG(unset
);
229 if (parse_expiry_date(arg
, &cmd
->expire_total
))
230 die(_("invalid timestamp '%s' given to '--%s'"),
231 arg
, opt
->long_name
);
233 cmd
->explicit_expiry
|= EXPIRE_TOTAL
;
237 static int cmd_reflog_show(int argc
, const char **argv
, const char *prefix
)
239 struct option options
[] = {
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
);
247 return cmd_log_reflog(argc
, argv
, prefix
);
250 static int show_reflog(const char *refname
, void *cb_data UNUSED
)
252 printf("%s\n", refname
);
256 static int cmd_reflog_list(int argc
, const char **argv
, const char *prefix
)
258 struct option options
[] = {
261 struct ref_store
*ref_store
;
263 argc
= parse_options(argc
, argv
, prefix
, options
, reflog_list_usage
, 0);
265 return error(_("%s does not accept arguments: '%s'"),
268 ref_store
= get_main_ref_store(the_repository
);
270 return refs_for_each_reflog(ref_store
, show_reflog
, NULL
);
273 static int cmd_reflog_expire(int argc
, const char **argv
, const char *prefix
)
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;
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"),
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"),
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")),
307 default_reflog_expire_unreachable
= now
- 30 * 24 * 3600;
308 default_reflog_expire
= now
- 90 * 24 * 3600;
309 git_config(reflog_expire_config
, NULL
);
311 save_commit_buffer
= 0;
314 cmd
.explicit_expiry
= 0;
315 cmd
.expire_total
= default_reflog_expire
;
316 cmd
.expire_unreachable
= default_reflog_expire_unreachable
;
318 argc
= parse_options(argc
, argv
, prefix
, options
, reflog_expire_usage
, 0);
321 should_prune_fn
= should_expire_reflog_ent_verbose
;
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.
329 struct rev_info revs
;
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;
336 printf(_("Marking reachable objects..."));
337 mark_reachable_objects(&revs
, 0, 0, NULL
);
338 release_revisions(&revs
);
344 struct worktree_reflogs collected
= {
345 .reflogs
= STRING_LIST_INIT_DUP
,
347 struct string_list_item
*item
;
348 struct worktree
**worktrees
, **p
;
350 worktrees
= get_worktrees();
351 for (p
= worktrees
; *p
; p
++) {
352 if (single_worktree
&& !(*p
)->is_current
)
354 collected
.worktree
= *p
;
355 refs_for_each_reflog(get_worktree_ref_store(*p
),
356 collect_reflog
, &collected
);
358 free_worktrees(worktrees
);
360 for_each_string_list_item(item
, &collected
.reflogs
) {
361 struct expire_reflog_policy_cb cb
= {
363 .dry_run
= !!(flags
& EXPIRE_REFLOGS_DRY_RUN
),
366 set_reflog_expiry_param(&cb
.cmd
, item
->string
);
367 status
|= refs_reflog_expire(get_main_ref_store(the_repository
),
369 reflog_expiry_prepare
,
371 reflog_expiry_cleanup
,
374 string_list_clear(&collected
.reflogs
, 0);
377 for (i
= 0; i
< argc
; i
++) {
379 struct expire_reflog_policy_cb cb
= { .cmd
= cmd
};
381 if (!dwim_log(argv
[i
], strlen(argv
[i
]), NULL
, &ref
)) {
382 status
|= error(_("%s points nowhere!"), argv
[i
]);
385 set_reflog_expiry_param(&cb
.cmd
, ref
);
386 status
|= refs_reflog_expire(get_main_ref_store(the_repository
),
388 reflog_expiry_prepare
,
390 reflog_expiry_cleanup
,
397 static int cmd_reflog_delete(int argc
, const char **argv
, const char *prefix
)
400 unsigned int flags
= 0;
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")),
416 argc
= parse_options(argc
, argv
, prefix
, options
, reflog_delete_usage
, 0);
419 return error(_("no reflog specified to delete"));
421 for (i
= 0; i
< argc
; i
++)
422 status
|= reflog_delete(argv
[i
], flags
, verbose
);
427 static int cmd_reflog_exists(int argc
, const char **argv
, const char *prefix
)
429 struct option options
[] = {
434 argc
= parse_options(argc
, argv
, prefix
, options
, reflog_exists_usage
,
437 usage_with_options(reflog_exists_usage
, options
);
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
),
450 int cmd_reflog(int argc
, const char **argv
, const char *prefix
)
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
),
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
);
467 return fn(argc
- 1, argv
+ 1, prefix
);
469 return cmd_log_reflog(argc
, argv
, prefix
);