4 #include "repository.h"
10 #include "parse-options.h"
12 #define BUILTIN_REFLOG_SHOW_USAGE \
13 N_("git reflog [show] [<log-options>] [<ref>]")
15 #define BUILTIN_REFLOG_EXPIRE_USAGE \
16 N_("git reflog expire [--expire=<time>] [--expire-unreachable=<time>]\n" \
17 " [--rewrite] [--updateref] [--stale-fix]\n" \
18 " [--dry-run | -n] [--verbose] [--all [--single-worktree] | <refs>...]")
20 #define BUILTIN_REFLOG_DELETE_USAGE \
21 N_("git reflog delete [--rewrite] [--updateref]\n" \
22 " [--dry-run | -n] [--verbose] <ref>@{<specifier>}...")
24 #define BUILTIN_REFLOG_EXISTS_USAGE \
25 N_("git reflog exists <ref>")
27 static const char *const reflog_show_usage
[] = {
28 BUILTIN_REFLOG_SHOW_USAGE
,
32 static const char *const reflog_expire_usage
[] = {
33 BUILTIN_REFLOG_EXPIRE_USAGE
,
37 static const char *const reflog_delete_usage
[] = {
38 BUILTIN_REFLOG_DELETE_USAGE
,
42 static const char *const reflog_exists_usage
[] = {
43 BUILTIN_REFLOG_EXISTS_USAGE
,
47 static const char *const reflog_usage
[] = {
48 BUILTIN_REFLOG_SHOW_USAGE
,
49 BUILTIN_REFLOG_EXPIRE_USAGE
,
50 BUILTIN_REFLOG_DELETE_USAGE
,
51 BUILTIN_REFLOG_EXISTS_USAGE
,
55 static timestamp_t default_reflog_expire
;
56 static timestamp_t default_reflog_expire_unreachable
;
58 struct worktree_reflogs
{
59 struct worktree
*worktree
;
60 struct string_list reflogs
;
63 static int collect_reflog(const char *ref
, const struct object_id
*oid UNUSED
,
64 int flags UNUSED
, void *cb_data
)
66 struct worktree_reflogs
*cb
= cb_data
;
67 struct worktree
*worktree
= cb
->worktree
;
68 struct strbuf newref
= STRBUF_INIT
;
71 * Avoid collecting the same shared ref multiple times because
72 * they are available via all worktrees.
74 if (!worktree
->is_current
&&
75 parse_worktree_ref(ref
, NULL
, NULL
, NULL
) == REF_WORKTREE_SHARED
)
78 strbuf_worktree_ref(worktree
, &newref
, ref
);
79 string_list_append_nodup(&cb
->reflogs
, strbuf_detach(&newref
, NULL
));
84 static struct reflog_expire_cfg
{
85 struct reflog_expire_cfg
*next
;
86 timestamp_t expire_total
;
87 timestamp_t expire_unreachable
;
88 char pattern
[FLEX_ARRAY
];
89 } *reflog_expire_cfg
, **reflog_expire_cfg_tail
;
91 static struct reflog_expire_cfg
*find_cfg_ent(const char *pattern
, size_t len
)
93 struct reflog_expire_cfg
*ent
;
95 if (!reflog_expire_cfg_tail
)
96 reflog_expire_cfg_tail
= &reflog_expire_cfg
;
98 for (ent
= reflog_expire_cfg
; ent
; ent
= ent
->next
)
99 if (!xstrncmpz(ent
->pattern
, pattern
, len
))
102 FLEX_ALLOC_MEM(ent
, pattern
, pattern
, len
);
103 *reflog_expire_cfg_tail
= ent
;
104 reflog_expire_cfg_tail
= &(ent
->next
);
108 /* expiry timer slot */
109 #define EXPIRE_TOTAL 01
110 #define EXPIRE_UNREACH 02
112 static int reflog_expire_config(const char *var
, const char *value
,
113 const struct config_context
*ctx
, void *cb
)
115 const char *pattern
, *key
;
119 struct reflog_expire_cfg
*ent
;
121 if (parse_config_key(var
, "gc", &pattern
, &pattern_len
, &key
) < 0)
122 return git_default_config(var
, value
, ctx
, cb
);
124 if (!strcmp(key
, "reflogexpire")) {
126 if (git_config_expiry_date(&expire
, var
, value
))
128 } else if (!strcmp(key
, "reflogexpireunreachable")) {
129 slot
= EXPIRE_UNREACH
;
130 if (git_config_expiry_date(&expire
, var
, value
))
133 return git_default_config(var
, value
, ctx
, cb
);
138 default_reflog_expire
= expire
;
141 default_reflog_expire_unreachable
= expire
;
147 ent
= find_cfg_ent(pattern
, pattern_len
);
152 ent
->expire_total
= expire
;
155 ent
->expire_unreachable
= expire
;
161 static void set_reflog_expiry_param(struct cmd_reflog_expire_cb
*cb
, const char *ref
)
163 struct reflog_expire_cfg
*ent
;
165 if (cb
->explicit_expiry
== (EXPIRE_TOTAL
|EXPIRE_UNREACH
))
166 return; /* both given explicitly -- nothing to tweak */
168 for (ent
= reflog_expire_cfg
; ent
; ent
= ent
->next
) {
169 if (!wildmatch(ent
->pattern
, ref
, 0)) {
170 if (!(cb
->explicit_expiry
& EXPIRE_TOTAL
))
171 cb
->expire_total
= ent
->expire_total
;
172 if (!(cb
->explicit_expiry
& EXPIRE_UNREACH
))
173 cb
->expire_unreachable
= ent
->expire_unreachable
;
179 * If unconfigured, make stash never expire
181 if (!strcmp(ref
, "refs/stash")) {
182 if (!(cb
->explicit_expiry
& EXPIRE_TOTAL
))
183 cb
->expire_total
= 0;
184 if (!(cb
->explicit_expiry
& EXPIRE_UNREACH
))
185 cb
->expire_unreachable
= 0;
189 /* Nothing matched -- use the default value */
190 if (!(cb
->explicit_expiry
& EXPIRE_TOTAL
))
191 cb
->expire_total
= default_reflog_expire
;
192 if (!(cb
->explicit_expiry
& EXPIRE_UNREACH
))
193 cb
->expire_unreachable
= default_reflog_expire_unreachable
;
196 static int expire_unreachable_callback(const struct option
*opt
,
200 struct cmd_reflog_expire_cb
*cmd
= opt
->value
;
202 BUG_ON_OPT_NEG(unset
);
204 if (parse_expiry_date(arg
, &cmd
->expire_unreachable
))
205 die(_("invalid timestamp '%s' given to '--%s'"),
206 arg
, opt
->long_name
);
208 cmd
->explicit_expiry
|= EXPIRE_UNREACH
;
212 static int expire_total_callback(const struct option
*opt
,
216 struct cmd_reflog_expire_cb
*cmd
= opt
->value
;
218 BUG_ON_OPT_NEG(unset
);
220 if (parse_expiry_date(arg
, &cmd
->expire_total
))
221 die(_("invalid timestamp '%s' given to '--%s'"),
222 arg
, opt
->long_name
);
224 cmd
->explicit_expiry
|= EXPIRE_TOTAL
;
228 static int cmd_reflog_show(int argc
, const char **argv
, const char *prefix
)
230 struct option options
[] = {
234 parse_options(argc
, argv
, prefix
, options
, reflog_show_usage
,
235 PARSE_OPT_KEEP_DASHDASH
| PARSE_OPT_KEEP_ARGV0
|
236 PARSE_OPT_KEEP_UNKNOWN_OPT
);
238 return cmd_log_reflog(argc
, argv
, prefix
);
241 static int cmd_reflog_expire(int argc
, const char **argv
, const char *prefix
)
243 struct cmd_reflog_expire_cb cmd
= { 0 };
244 timestamp_t now
= time(NULL
);
245 int i
, status
, do_all
, single_worktree
= 0;
246 unsigned int flags
= 0;
248 reflog_expiry_should_prune_fn
*should_prune_fn
= should_expire_reflog_ent
;
249 const struct option options
[] = {
250 OPT_BIT('n', "dry-run", &flags
, N_("do not actually prune any entries"),
251 EXPIRE_REFLOGS_DRY_RUN
),
252 OPT_BIT(0, "rewrite", &flags
,
253 N_("rewrite the old SHA1 with the new SHA1 of the entry that now precedes it"),
254 EXPIRE_REFLOGS_REWRITE
),
255 OPT_BIT(0, "updateref", &flags
,
256 N_("update the reference to the value of the top reflog entry"),
257 EXPIRE_REFLOGS_UPDATE_REF
),
258 OPT_BOOL(0, "verbose", &verbose
, N_("print extra information on screen")),
259 OPT_CALLBACK_F(0, "expire", &cmd
, N_("timestamp"),
260 N_("prune entries older than the specified time"),
262 expire_total_callback
),
263 OPT_CALLBACK_F(0, "expire-unreachable", &cmd
, N_("timestamp"),
264 N_("prune entries older than <time> that are not reachable from the current tip of the branch"),
266 expire_unreachable_callback
),
267 OPT_BOOL(0, "stale-fix", &cmd
.stalefix
,
268 N_("prune any reflog entries that point to broken commits")),
269 OPT_BOOL(0, "all", &do_all
, N_("process the reflogs of all references")),
270 OPT_BOOL(0, "single-worktree", &single_worktree
,
271 N_("limits processing to reflogs from the current worktree only")),
275 default_reflog_expire_unreachable
= now
- 30 * 24 * 3600;
276 default_reflog_expire
= now
- 90 * 24 * 3600;
277 git_config(reflog_expire_config
, NULL
);
279 save_commit_buffer
= 0;
282 cmd
.explicit_expiry
= 0;
283 cmd
.expire_total
= default_reflog_expire
;
284 cmd
.expire_unreachable
= default_reflog_expire_unreachable
;
286 argc
= parse_options(argc
, argv
, prefix
, options
, reflog_expire_usage
, 0);
289 should_prune_fn
= should_expire_reflog_ent_verbose
;
292 * We can trust the commits and objects reachable from refs
293 * even in older repository. We cannot trust what's reachable
294 * from reflog if the repository was pruned with older git.
297 struct rev_info revs
;
299 repo_init_revisions(the_repository
, &revs
, prefix
);
300 revs
.do_not_die_on_missing_objects
= 1;
301 revs
.ignore_missing
= 1;
302 revs
.ignore_missing_links
= 1;
304 printf(_("Marking reachable objects..."));
305 mark_reachable_objects(&revs
, 0, 0, NULL
);
306 release_revisions(&revs
);
312 struct worktree_reflogs collected
= {
313 .reflogs
= STRING_LIST_INIT_DUP
,
315 struct string_list_item
*item
;
316 struct worktree
**worktrees
, **p
;
318 worktrees
= get_worktrees();
319 for (p
= worktrees
; *p
; p
++) {
320 if (single_worktree
&& !(*p
)->is_current
)
322 collected
.worktree
= *p
;
323 refs_for_each_reflog(get_worktree_ref_store(*p
),
324 collect_reflog
, &collected
);
326 free_worktrees(worktrees
);
328 for_each_string_list_item(item
, &collected
.reflogs
) {
329 struct expire_reflog_policy_cb cb
= {
331 .dry_run
= !!(flags
& EXPIRE_REFLOGS_DRY_RUN
),
334 set_reflog_expiry_param(&cb
.cmd
, item
->string
);
335 status
|= reflog_expire(item
->string
, flags
,
336 reflog_expiry_prepare
,
338 reflog_expiry_cleanup
,
341 string_list_clear(&collected
.reflogs
, 0);
344 for (i
= 0; i
< argc
; i
++) {
346 struct expire_reflog_policy_cb cb
= { .cmd
= cmd
};
348 if (!dwim_log(argv
[i
], strlen(argv
[i
]), NULL
, &ref
)) {
349 status
|= error(_("%s points nowhere!"), argv
[i
]);
352 set_reflog_expiry_param(&cb
.cmd
, ref
);
353 status
|= reflog_expire(ref
, flags
,
354 reflog_expiry_prepare
,
356 reflog_expiry_cleanup
,
363 static int cmd_reflog_delete(int argc
, const char **argv
, const char *prefix
)
366 unsigned int flags
= 0;
369 const struct option options
[] = {
370 OPT_BIT('n', "dry-run", &flags
, N_("do not actually prune any entries"),
371 EXPIRE_REFLOGS_DRY_RUN
),
372 OPT_BIT(0, "rewrite", &flags
,
373 N_("rewrite the old SHA1 with the new SHA1 of the entry that now precedes it"),
374 EXPIRE_REFLOGS_REWRITE
),
375 OPT_BIT(0, "updateref", &flags
,
376 N_("update the reference to the value of the top reflog entry"),
377 EXPIRE_REFLOGS_UPDATE_REF
),
378 OPT_BOOL(0, "verbose", &verbose
, N_("print extra information on screen")),
382 argc
= parse_options(argc
, argv
, prefix
, options
, reflog_delete_usage
, 0);
385 return error(_("no reflog specified to delete"));
387 for (i
= 0; i
< argc
; i
++)
388 status
|= reflog_delete(argv
[i
], flags
, verbose
);
393 static int cmd_reflog_exists(int argc
, const char **argv
, const char *prefix
)
395 struct option options
[] = {
400 argc
= parse_options(argc
, argv
, prefix
, options
, reflog_exists_usage
,
403 usage_with_options(reflog_exists_usage
, options
);
406 if (check_refname_format(refname
, REFNAME_ALLOW_ONELEVEL
))
407 die(_("invalid ref format: %s"), refname
);
408 return !reflog_exists(refname
);
415 int cmd_reflog(int argc
, const char **argv
, const char *prefix
)
417 parse_opt_subcommand_fn
*fn
= NULL
;
418 struct option options
[] = {
419 OPT_SUBCOMMAND("show", &fn
, cmd_reflog_show
),
420 OPT_SUBCOMMAND("expire", &fn
, cmd_reflog_expire
),
421 OPT_SUBCOMMAND("delete", &fn
, cmd_reflog_delete
),
422 OPT_SUBCOMMAND("exists", &fn
, cmd_reflog_exists
),
426 argc
= parse_options(argc
, argv
, prefix
, options
, reflog_usage
,
427 PARSE_OPT_SUBCOMMAND_OPTIONAL
|
428 PARSE_OPT_KEEP_DASHDASH
| PARSE_OPT_KEEP_ARGV0
|
429 PARSE_OPT_KEEP_UNKNOWN_OPT
);
431 return fn(argc
- 1, argv
+ 1, prefix
);
433 return cmd_log_reflog(argc
, argv
, prefix
);