8 #define BUILTIN_REFLOG_SHOW_USAGE \
9 N_("git reflog [show] [<log-options>] [<ref>]")
11 #define BUILTIN_REFLOG_EXPIRE_USAGE \
12 N_("git reflog expire [--expire=<time>] [--expire-unreachable=<time>]\n" \
13 " [--rewrite] [--updateref] [--stale-fix]\n" \
14 " [--dry-run | -n] [--verbose] [--all [--single-worktree] | <refs>...]")
16 #define BUILTIN_REFLOG_DELETE_USAGE \
17 N_("git reflog delete [--rewrite] [--updateref]\n" \
18 " [--dry-run | -n] [--verbose] <ref>@{<specifier>}...")
20 #define BUILTIN_REFLOG_EXISTS_USAGE \
21 N_("git reflog exists <ref>")
23 static const char *const reflog_show_usage
[] = {
24 BUILTIN_REFLOG_SHOW_USAGE
,
28 static const char *const reflog_expire_usage
[] = {
29 BUILTIN_REFLOG_EXPIRE_USAGE
,
33 static const char *const reflog_delete_usage
[] = {
34 BUILTIN_REFLOG_DELETE_USAGE
,
38 static const char *const reflog_exists_usage
[] = {
39 BUILTIN_REFLOG_EXISTS_USAGE
,
43 static const char *const reflog_usage
[] = {
44 BUILTIN_REFLOG_SHOW_USAGE
,
45 BUILTIN_REFLOG_EXPIRE_USAGE
,
46 BUILTIN_REFLOG_DELETE_USAGE
,
47 BUILTIN_REFLOG_EXISTS_USAGE
,
51 static timestamp_t default_reflog_expire
;
52 static timestamp_t default_reflog_expire_unreachable
;
54 struct worktree_reflogs
{
55 struct worktree
*worktree
;
56 struct string_list reflogs
;
59 static int collect_reflog(const char *ref
, const struct object_id
*oid
, int unused
, void *cb_data
)
61 struct worktree_reflogs
*cb
= cb_data
;
62 struct worktree
*worktree
= cb
->worktree
;
63 struct strbuf newref
= STRBUF_INIT
;
66 * Avoid collecting the same shared ref multiple times because
67 * they are available via all worktrees.
69 if (!worktree
->is_current
&& ref_type(ref
) == REF_TYPE_NORMAL
)
72 strbuf_worktree_ref(worktree
, &newref
, ref
);
73 string_list_append_nodup(&cb
->reflogs
, strbuf_detach(&newref
, NULL
));
78 static struct reflog_expire_cfg
{
79 struct reflog_expire_cfg
*next
;
80 timestamp_t expire_total
;
81 timestamp_t expire_unreachable
;
82 char pattern
[FLEX_ARRAY
];
83 } *reflog_expire_cfg
, **reflog_expire_cfg_tail
;
85 static struct reflog_expire_cfg
*find_cfg_ent(const char *pattern
, size_t len
)
87 struct reflog_expire_cfg
*ent
;
89 if (!reflog_expire_cfg_tail
)
90 reflog_expire_cfg_tail
= &reflog_expire_cfg
;
92 for (ent
= reflog_expire_cfg
; ent
; ent
= ent
->next
)
93 if (!strncmp(ent
->pattern
, pattern
, len
) &&
94 ent
->pattern
[len
] == '\0')
97 FLEX_ALLOC_MEM(ent
, pattern
, pattern
, len
);
98 *reflog_expire_cfg_tail
= ent
;
99 reflog_expire_cfg_tail
= &(ent
->next
);
103 /* expiry timer slot */
104 #define EXPIRE_TOTAL 01
105 #define EXPIRE_UNREACH 02
107 static int reflog_expire_config(const char *var
, const char *value
, void *cb
)
109 const char *pattern
, *key
;
113 struct reflog_expire_cfg
*ent
;
115 if (parse_config_key(var
, "gc", &pattern
, &pattern_len
, &key
) < 0)
116 return git_default_config(var
, value
, cb
);
118 if (!strcmp(key
, "reflogexpire")) {
120 if (git_config_expiry_date(&expire
, var
, value
))
122 } else if (!strcmp(key
, "reflogexpireunreachable")) {
123 slot
= EXPIRE_UNREACH
;
124 if (git_config_expiry_date(&expire
, var
, value
))
127 return git_default_config(var
, value
, cb
);
132 default_reflog_expire
= expire
;
135 default_reflog_expire_unreachable
= expire
;
141 ent
= find_cfg_ent(pattern
, pattern_len
);
146 ent
->expire_total
= expire
;
149 ent
->expire_unreachable
= expire
;
155 static void set_reflog_expiry_param(struct cmd_reflog_expire_cb
*cb
, const char *ref
)
157 struct reflog_expire_cfg
*ent
;
159 if (cb
->explicit_expiry
== (EXPIRE_TOTAL
|EXPIRE_UNREACH
))
160 return; /* both given explicitly -- nothing to tweak */
162 for (ent
= reflog_expire_cfg
; ent
; ent
= ent
->next
) {
163 if (!wildmatch(ent
->pattern
, ref
, 0)) {
164 if (!(cb
->explicit_expiry
& EXPIRE_TOTAL
))
165 cb
->expire_total
= ent
->expire_total
;
166 if (!(cb
->explicit_expiry
& EXPIRE_UNREACH
))
167 cb
->expire_unreachable
= ent
->expire_unreachable
;
173 * If unconfigured, make stash never expire
175 if (!strcmp(ref
, "refs/stash")) {
176 if (!(cb
->explicit_expiry
& EXPIRE_TOTAL
))
177 cb
->expire_total
= 0;
178 if (!(cb
->explicit_expiry
& EXPIRE_UNREACH
))
179 cb
->expire_unreachable
= 0;
183 /* Nothing matched -- use the default value */
184 if (!(cb
->explicit_expiry
& EXPIRE_TOTAL
))
185 cb
->expire_total
= default_reflog_expire
;
186 if (!(cb
->explicit_expiry
& EXPIRE_UNREACH
))
187 cb
->expire_unreachable
= default_reflog_expire_unreachable
;
190 static int expire_unreachable_callback(const struct option
*opt
,
194 struct cmd_reflog_expire_cb
*cmd
= opt
->value
;
196 if (parse_expiry_date(arg
, &cmd
->expire_unreachable
))
197 die(_("invalid timestamp '%s' given to '--%s'"),
198 arg
, opt
->long_name
);
200 cmd
->explicit_expiry
|= EXPIRE_UNREACH
;
204 static int expire_total_callback(const struct option
*opt
,
208 struct cmd_reflog_expire_cb
*cmd
= opt
->value
;
210 if (parse_expiry_date(arg
, &cmd
->expire_total
))
211 die(_("invalid timestamp '%s' given to '--%s'"),
212 arg
, opt
->long_name
);
214 cmd
->explicit_expiry
|= EXPIRE_TOTAL
;
218 static int cmd_reflog_show(int argc
, const char **argv
, const char *prefix
)
220 struct option options
[] = {
224 parse_options(argc
, argv
, prefix
, options
, reflog_show_usage
,
225 PARSE_OPT_KEEP_DASHDASH
| PARSE_OPT_KEEP_ARGV0
|
226 PARSE_OPT_KEEP_UNKNOWN
);
228 return cmd_log_reflog(argc
, argv
, prefix
);
231 static int cmd_reflog_expire(int argc
, const char **argv
, const char *prefix
)
233 struct cmd_reflog_expire_cb cmd
= { 0 };
234 timestamp_t now
= time(NULL
);
235 int i
, status
, do_all
, all_worktrees
= 1;
236 unsigned int flags
= 0;
238 reflog_expiry_should_prune_fn
*should_prune_fn
= should_expire_reflog_ent
;
239 const struct option options
[] = {
240 OPT_BIT(0, "dry-run", &flags
, N_("do not actually prune any entries"),
241 EXPIRE_REFLOGS_DRY_RUN
),
242 OPT_BIT(0, "rewrite", &flags
,
243 N_("rewrite the old SHA1 with the new SHA1 of the entry that now precedes it"),
244 EXPIRE_REFLOGS_REWRITE
),
245 OPT_BIT(0, "updateref", &flags
,
246 N_("update the reference to the value of the top reflog entry"),
247 EXPIRE_REFLOGS_UPDATE_REF
),
248 OPT_BOOL(0, "verbose", &verbose
, N_("print extra information on screen")),
249 OPT_CALLBACK_F(0, "expire", &cmd
, N_("timestamp"),
250 N_("prune entries older than the specified time"),
252 expire_total_callback
),
253 OPT_CALLBACK_F(0, "expire-unreachable", &cmd
, N_("timestamp"),
254 N_("prune entries older than <time> that are not reachable from the current tip of the branch"),
256 expire_unreachable_callback
),
257 OPT_BOOL(0, "stale-fix", &cmd
.stalefix
,
258 N_("prune any reflog entries that point to broken commits")),
259 OPT_BOOL(0, "all", &do_all
, N_("process the reflogs of all references")),
260 OPT_BOOL(1, "single-worktree", &all_worktrees
,
261 N_("limits processing to reflogs from the current worktree only")),
265 default_reflog_expire_unreachable
= now
- 30 * 24 * 3600;
266 default_reflog_expire
= now
- 90 * 24 * 3600;
267 git_config(reflog_expire_config
, NULL
);
269 save_commit_buffer
= 0;
272 cmd
.explicit_expiry
= 0;
273 cmd
.expire_total
= default_reflog_expire
;
274 cmd
.expire_unreachable
= default_reflog_expire_unreachable
;
276 argc
= parse_options(argc
, argv
, prefix
, options
, reflog_expire_usage
, 0);
279 should_prune_fn
= should_expire_reflog_ent_verbose
;
282 * We can trust the commits and objects reachable from refs
283 * even in older repository. We cannot trust what's reachable
284 * from reflog if the repository was pruned with older git.
287 struct rev_info revs
;
289 repo_init_revisions(the_repository
, &revs
, prefix
);
290 revs
.do_not_die_on_missing_tree
= 1;
291 revs
.ignore_missing
= 1;
292 revs
.ignore_missing_links
= 1;
294 printf(_("Marking reachable objects..."));
295 mark_reachable_objects(&revs
, 0, 0, NULL
);
301 struct worktree_reflogs collected
= {
302 .reflogs
= STRING_LIST_INIT_DUP
,
304 struct string_list_item
*item
;
305 struct worktree
**worktrees
, **p
;
307 worktrees
= get_worktrees();
308 for (p
= worktrees
; *p
; p
++) {
309 if (!all_worktrees
&& !(*p
)->is_current
)
311 collected
.worktree
= *p
;
312 refs_for_each_reflog(get_worktree_ref_store(*p
),
313 collect_reflog
, &collected
);
315 free_worktrees(worktrees
);
317 for_each_string_list_item(item
, &collected
.reflogs
) {
318 struct expire_reflog_policy_cb cb
= {
320 .dry_run
= !!(flags
& EXPIRE_REFLOGS_DRY_RUN
),
323 set_reflog_expiry_param(&cb
.cmd
, item
->string
);
324 status
|= reflog_expire(item
->string
, flags
,
325 reflog_expiry_prepare
,
327 reflog_expiry_cleanup
,
330 string_list_clear(&collected
.reflogs
, 0);
333 for (i
= 0; i
< argc
; i
++) {
335 struct expire_reflog_policy_cb cb
= { .cmd
= cmd
};
337 if (!dwim_log(argv
[i
], strlen(argv
[i
]), NULL
, &ref
)) {
338 status
|= error(_("%s points nowhere!"), argv
[i
]);
341 set_reflog_expiry_param(&cb
.cmd
, ref
);
342 status
|= reflog_expire(ref
, flags
,
343 reflog_expiry_prepare
,
345 reflog_expiry_cleanup
,
352 static int cmd_reflog_delete(int argc
, const char **argv
, const char *prefix
)
355 unsigned int flags
= 0;
358 const struct option options
[] = {
359 OPT_BIT(0, "dry-run", &flags
, N_("do not actually prune any entries"),
360 EXPIRE_REFLOGS_DRY_RUN
),
361 OPT_BIT(0, "rewrite", &flags
,
362 N_("rewrite the old SHA1 with the new SHA1 of the entry that now precedes it"),
363 EXPIRE_REFLOGS_REWRITE
),
364 OPT_BIT(0, "updateref", &flags
,
365 N_("update the reference to the value of the top reflog entry"),
366 EXPIRE_REFLOGS_UPDATE_REF
),
367 OPT_BOOL(0, "verbose", &verbose
, N_("print extra information on screen")),
371 argc
= parse_options(argc
, argv
, prefix
, options
, reflog_delete_usage
, 0);
374 return error(_("no reflog specified to delete"));
376 for (i
= 0; i
< argc
; i
++)
377 status
|= reflog_delete(argv
[i
], flags
, verbose
);
382 static int cmd_reflog_exists(int argc
, const char **argv
, const char *prefix
)
384 struct option options
[] = {
389 argc
= parse_options(argc
, argv
, prefix
, options
, reflog_exists_usage
,
392 usage_with_options(reflog_exists_usage
, options
);
395 if (check_refname_format(refname
, REFNAME_ALLOW_ONELEVEL
))
396 die(_("invalid ref format: %s"), refname
);
397 return !reflog_exists(refname
);
404 int cmd_reflog(int argc
, const char **argv
, const char *prefix
)
406 struct option options
[] = {
410 argc
= parse_options(argc
, argv
, prefix
, options
, reflog_usage
,
411 PARSE_OPT_KEEP_DASHDASH
| PARSE_OPT_KEEP_ARGV0
|
412 PARSE_OPT_KEEP_UNKNOWN
|
413 PARSE_OPT_NO_INTERNAL_HELP
);
416 * With "git reflog" we default to showing it. !argc is
417 * impossible with PARSE_OPT_KEEP_ARGV0.
422 if (!strcmp(argv
[1], "-h"))
423 usage_with_options(reflog_usage
, options
);
424 else if (*argv
[1] == '-')
427 if (!strcmp(argv
[1], "show"))
428 return cmd_reflog_show(argc
- 1, argv
+ 1, prefix
);
429 else if (!strcmp(argv
[1], "expire"))
430 return cmd_reflog_expire(argc
- 1, argv
+ 1, prefix
);
431 else if (!strcmp(argv
[1], "delete"))
432 return cmd_reflog_delete(argc
- 1, argv
+ 1, prefix
);
433 else if (!strcmp(argv
[1], "exists"))
434 return cmd_reflog_exists(argc
- 1, argv
+ 1, prefix
);
437 * Fall-through for e.g. "git reflog -1", "git reflog master",
438 * as well as the plain "git reflog" above goto above.
441 return cmd_log_reflog(argc
, argv
, prefix
);