8 static const char reflog_exists_usage
[] =
9 N_("git reflog exists <ref>");
11 static timestamp_t default_reflog_expire
;
12 static timestamp_t default_reflog_expire_unreachable
;
14 struct worktree_reflogs
{
15 struct worktree
*worktree
;
16 struct string_list reflogs
;
19 static int collect_reflog(const char *ref
, const struct object_id
*oid
, int unused
, void *cb_data
)
21 struct worktree_reflogs
*cb
= cb_data
;
22 struct worktree
*worktree
= cb
->worktree
;
23 struct strbuf newref
= STRBUF_INIT
;
26 * Avoid collecting the same shared ref multiple times because
27 * they are available via all worktrees.
29 if (!worktree
->is_current
&& ref_type(ref
) == REF_TYPE_NORMAL
)
32 strbuf_worktree_ref(worktree
, &newref
, ref
);
33 string_list_append_nodup(&cb
->reflogs
, strbuf_detach(&newref
, NULL
));
38 static struct reflog_expire_cfg
{
39 struct reflog_expire_cfg
*next
;
40 timestamp_t expire_total
;
41 timestamp_t expire_unreachable
;
42 char pattern
[FLEX_ARRAY
];
43 } *reflog_expire_cfg
, **reflog_expire_cfg_tail
;
45 static struct reflog_expire_cfg
*find_cfg_ent(const char *pattern
, size_t len
)
47 struct reflog_expire_cfg
*ent
;
49 if (!reflog_expire_cfg_tail
)
50 reflog_expire_cfg_tail
= &reflog_expire_cfg
;
52 for (ent
= reflog_expire_cfg
; ent
; ent
= ent
->next
)
53 if (!strncmp(ent
->pattern
, pattern
, len
) &&
54 ent
->pattern
[len
] == '\0')
57 FLEX_ALLOC_MEM(ent
, pattern
, pattern
, len
);
58 *reflog_expire_cfg_tail
= ent
;
59 reflog_expire_cfg_tail
= &(ent
->next
);
63 /* expiry timer slot */
64 #define EXPIRE_TOTAL 01
65 #define EXPIRE_UNREACH 02
67 static int reflog_expire_config(const char *var
, const char *value
, void *cb
)
69 const char *pattern
, *key
;
73 struct reflog_expire_cfg
*ent
;
75 if (parse_config_key(var
, "gc", &pattern
, &pattern_len
, &key
) < 0)
76 return git_default_config(var
, value
, cb
);
78 if (!strcmp(key
, "reflogexpire")) {
80 if (git_config_expiry_date(&expire
, var
, value
))
82 } else if (!strcmp(key
, "reflogexpireunreachable")) {
83 slot
= EXPIRE_UNREACH
;
84 if (git_config_expiry_date(&expire
, var
, value
))
87 return git_default_config(var
, value
, cb
);
92 default_reflog_expire
= expire
;
95 default_reflog_expire_unreachable
= expire
;
101 ent
= find_cfg_ent(pattern
, pattern_len
);
106 ent
->expire_total
= expire
;
109 ent
->expire_unreachable
= expire
;
115 static void set_reflog_expiry_param(struct cmd_reflog_expire_cb
*cb
, const char *ref
)
117 struct reflog_expire_cfg
*ent
;
119 if (cb
->explicit_expiry
== (EXPIRE_TOTAL
|EXPIRE_UNREACH
))
120 return; /* both given explicitly -- nothing to tweak */
122 for (ent
= reflog_expire_cfg
; ent
; ent
= ent
->next
) {
123 if (!wildmatch(ent
->pattern
, ref
, 0)) {
124 if (!(cb
->explicit_expiry
& EXPIRE_TOTAL
))
125 cb
->expire_total
= ent
->expire_total
;
126 if (!(cb
->explicit_expiry
& EXPIRE_UNREACH
))
127 cb
->expire_unreachable
= ent
->expire_unreachable
;
133 * If unconfigured, make stash never expire
135 if (!strcmp(ref
, "refs/stash")) {
136 if (!(cb
->explicit_expiry
& EXPIRE_TOTAL
))
137 cb
->expire_total
= 0;
138 if (!(cb
->explicit_expiry
& EXPIRE_UNREACH
))
139 cb
->expire_unreachable
= 0;
143 /* Nothing matched -- use the default value */
144 if (!(cb
->explicit_expiry
& EXPIRE_TOTAL
))
145 cb
->expire_total
= default_reflog_expire
;
146 if (!(cb
->explicit_expiry
& EXPIRE_UNREACH
))
147 cb
->expire_unreachable
= default_reflog_expire_unreachable
;
150 static const char * reflog_expire_usage
[] = {
151 N_("git reflog expire [--expire=<time>] "
152 "[--expire-unreachable=<time>] "
153 "[--rewrite] [--updateref] [--stale-fix] [--dry-run | -n] "
154 "[--verbose] [--all] <refs>..."),
158 static int expire_unreachable_callback(const struct option
*opt
,
162 struct cmd_reflog_expire_cb
*cmd
= opt
->value
;
164 if (parse_expiry_date(arg
, &cmd
->expire_unreachable
))
165 die(_("invalid timestamp '%s' given to '--%s'"),
166 arg
, opt
->long_name
);
168 cmd
->explicit_expiry
|= EXPIRE_UNREACH
;
172 static int expire_total_callback(const struct option
*opt
,
176 struct cmd_reflog_expire_cb
*cmd
= opt
->value
;
178 if (parse_expiry_date(arg
, &cmd
->expire_total
))
179 die(_("invalid timestamp '%s' given to '--%s'"),
180 arg
, opt
->long_name
);
182 cmd
->explicit_expiry
|= EXPIRE_TOTAL
;
186 static int cmd_reflog_expire(int argc
, const char **argv
, const char *prefix
)
188 struct cmd_reflog_expire_cb cmd
= { 0 };
189 timestamp_t now
= time(NULL
);
190 int i
, status
, do_all
, all_worktrees
= 1;
191 unsigned int flags
= 0;
193 reflog_expiry_should_prune_fn
*should_prune_fn
= should_expire_reflog_ent
;
194 const struct option options
[] = {
195 OPT_BIT(0, "dry-run", &flags
, N_("do not actually prune any entries"),
196 EXPIRE_REFLOGS_DRY_RUN
),
197 OPT_BIT(0, "rewrite", &flags
,
198 N_("rewrite the old SHA1 with the new SHA1 of the entry that now precedes it"),
199 EXPIRE_REFLOGS_REWRITE
),
200 OPT_BIT(0, "updateref", &flags
,
201 N_("update the reference to the value of the top reflog entry"),
202 EXPIRE_REFLOGS_UPDATE_REF
),
203 OPT_BOOL(0, "verbose", &verbose
, N_("print extra information on screen.")),
204 OPT_CALLBACK_F(0, "expire", &cmd
, N_("timestamp"),
205 N_("prune entries older than the specified time"),
207 expire_total_callback
),
208 OPT_CALLBACK_F(0, "expire-unreachable", &cmd
, N_("timestamp"),
209 N_("prune entries older than <time> that are not reachable from the current tip of the branch"),
211 expire_unreachable_callback
),
212 OPT_BOOL(0, "stale-fix", &cmd
.stalefix
,
213 N_("prune any reflog entries that point to broken commits")),
214 OPT_BOOL(0, "all", &do_all
, N_("process the reflogs of all references")),
215 OPT_BOOL(1, "single-worktree", &all_worktrees
,
216 N_("limits processing to reflogs from the current worktree only.")),
220 default_reflog_expire_unreachable
= now
- 30 * 24 * 3600;
221 default_reflog_expire
= now
- 90 * 24 * 3600;
222 git_config(reflog_expire_config
, NULL
);
224 save_commit_buffer
= 0;
227 cmd
.explicit_expiry
= 0;
228 cmd
.expire_total
= default_reflog_expire
;
229 cmd
.expire_unreachable
= default_reflog_expire_unreachable
;
231 argc
= parse_options(argc
, argv
, prefix
, options
, reflog_expire_usage
, 0);
234 should_prune_fn
= should_expire_reflog_ent_verbose
;
237 * We can trust the commits and objects reachable from refs
238 * even in older repository. We cannot trust what's reachable
239 * from reflog if the repository was pruned with older git.
242 struct rev_info revs
;
244 repo_init_revisions(the_repository
, &revs
, prefix
);
245 revs
.do_not_die_on_missing_tree
= 1;
246 revs
.ignore_missing
= 1;
247 revs
.ignore_missing_links
= 1;
249 printf(_("Marking reachable objects..."));
250 mark_reachable_objects(&revs
, 0, 0, NULL
);
256 struct worktree_reflogs collected
= {
257 .reflogs
= STRING_LIST_INIT_DUP
,
259 struct string_list_item
*item
;
260 struct worktree
**worktrees
, **p
;
262 worktrees
= get_worktrees();
263 for (p
= worktrees
; *p
; p
++) {
264 if (!all_worktrees
&& !(*p
)->is_current
)
266 collected
.worktree
= *p
;
267 refs_for_each_reflog(get_worktree_ref_store(*p
),
268 collect_reflog
, &collected
);
270 free_worktrees(worktrees
);
272 for_each_string_list_item(item
, &collected
.reflogs
) {
273 struct expire_reflog_policy_cb cb
= {
275 .dry_run
= !!(flags
& EXPIRE_REFLOGS_DRY_RUN
),
278 set_reflog_expiry_param(&cb
.cmd
, item
->string
);
279 status
|= reflog_expire(item
->string
, flags
,
280 reflog_expiry_prepare
,
282 reflog_expiry_cleanup
,
285 string_list_clear(&collected
.reflogs
, 0);
288 for (i
= 0; i
< argc
; i
++) {
290 struct expire_reflog_policy_cb cb
= { .cmd
= cmd
};
292 if (!dwim_log(argv
[i
], strlen(argv
[i
]), NULL
, &ref
)) {
293 status
|= error(_("%s points nowhere!"), argv
[i
]);
296 set_reflog_expiry_param(&cb
.cmd
, ref
);
297 status
|= reflog_expire(ref
, flags
,
298 reflog_expiry_prepare
,
300 reflog_expiry_cleanup
,
307 static const char * reflog_delete_usage
[] = {
308 N_("git reflog delete [--rewrite] [--updateref] "
309 "[--dry-run | -n] [--verbose] <refs>..."),
313 static int cmd_reflog_delete(int argc
, const char **argv
, const char *prefix
)
316 unsigned int flags
= 0;
319 const struct option options
[] = {
320 OPT_BIT(0, "dry-run", &flags
, N_("do not actually prune any entries"),
321 EXPIRE_REFLOGS_DRY_RUN
),
322 OPT_BIT(0, "rewrite", &flags
,
323 N_("rewrite the old SHA1 with the new SHA1 of the entry that now precedes it"),
324 EXPIRE_REFLOGS_REWRITE
),
325 OPT_BIT(0, "updateref", &flags
,
326 N_("update the reference to the value of the top reflog entry"),
327 EXPIRE_REFLOGS_UPDATE_REF
),
328 OPT_BOOL(0, "verbose", &verbose
, N_("print extra information on screen.")),
332 argc
= parse_options(argc
, argv
, prefix
, options
, reflog_delete_usage
, 0);
335 return error(_("no reflog specified to delete"));
337 for (i
= 0; i
< argc
; i
++)
338 status
|= reflog_delete(argv
[i
], flags
, verbose
);
343 static int cmd_reflog_exists(int argc
, const char **argv
, const char *prefix
)
347 for (i
= 1; i
< argc
; i
++) {
348 const char *arg
= argv
[i
];
349 if (!strcmp(arg
, "--")) {
353 else if (arg
[0] == '-')
354 usage(_(reflog_exists_usage
));
361 if (argc
- start
!= 1)
362 usage(_(reflog_exists_usage
));
364 if (check_refname_format(argv
[start
], REFNAME_ALLOW_ONELEVEL
))
365 die(_("invalid ref format: %s"), argv
[start
]);
366 return !reflog_exists(argv
[start
]);
373 static const char reflog_usage
[] =
374 "git reflog [ show | expire | delete | exists ]";
376 int cmd_reflog(int argc
, const char **argv
, const char *prefix
)
378 if (argc
> 1 && !strcmp(argv
[1], "-h"))
379 usage(_(reflog_usage
));
381 /* With no command, we default to showing it. */
382 if (argc
< 2 || *argv
[1] == '-')
383 return cmd_log_reflog(argc
, argv
, prefix
);
385 if (!strcmp(argv
[1], "show"))
386 return cmd_log_reflog(argc
- 1, argv
+ 1, prefix
);
388 if (!strcmp(argv
[1], "expire"))
389 return cmd_reflog_expire(argc
- 1, argv
+ 1, prefix
);
391 if (!strcmp(argv
[1], "delete"))
392 return cmd_reflog_delete(argc
- 1, argv
+ 1, prefix
);
394 if (!strcmp(argv
[1], "exists"))
395 return cmd_reflog_exists(argc
- 1, argv
+ 1, prefix
);
397 return cmd_log_reflog(argc
, argv
, prefix
);