Skip to content

Commit c9ef0d9

Browse files
pcloudsgitster
authored andcommitted
reflog expire: cover reflog from all worktrees
Reported-by: Jeff King <[email protected]> Signed-off-by: Nguyễn Thái Ngọc Duy <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent b29759d commit c9ef0d9

File tree

3 files changed

+63
-5
lines changed

3 files changed

+63
-5
lines changed

Documentation/git-reflog.txt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ depending on the subcommand:
2020
'git reflog' ['show'] [log-options] [<ref>]
2121
'git reflog expire' [--expire=<time>] [--expire-unreachable=<time>]
2222
[--rewrite] [--updateref] [--stale-fix]
23-
[--dry-run | -n] [--verbose] [--all | <refs>...]
23+
[--dry-run | -n] [--verbose] [--all [--single-worktree] | <refs>...]
2424
'git reflog delete' [--rewrite] [--updateref]
2525
[--dry-run | -n] [--verbose] ref@\{specifier\}...
2626
'git reflog exists' <ref>
@@ -72,6 +72,11 @@ Options for `expire`
7272
--all::
7373
Process the reflogs of all references.
7474

75+
--single-worktree::
76+
By default when `--all` is specified, reflogs from all working
77+
trees are processed. This option limits the processing to reflogs
78+
from the current working tree only.
79+
7580
--expire=<time>::
7681
Prune entries older than the specified time. If this option is
7782
not specified, the expiration time is taken from the

builtin/reflog.c

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "diff.h"
1111
#include "revision.h"
1212
#include "reachable.h"
13+
#include "worktree.h"
1314

1415
/* NEEDSWORK: switch to using parse_options */
1516
static const char reflog_expire_usage[] =
@@ -52,6 +53,7 @@ struct collect_reflog_cb {
5253
struct collected_reflog **e;
5354
int alloc;
5455
int nr;
56+
struct worktree *wt;
5557
};
5658

5759
/* Remember to update object flag allocation in object.h */
@@ -330,13 +332,27 @@ static int push_tip_to_list(const char *refname, const struct object_id *oid,
330332
return 0;
331333
}
332334

335+
static int is_head(const char *refname)
336+
{
337+
switch (ref_type(refname)) {
338+
case REF_TYPE_OTHER_PSEUDOREF:
339+
case REF_TYPE_MAIN_PSEUDOREF:
340+
if (parse_worktree_ref(refname, NULL, NULL, &refname))
341+
BUG("not a worktree ref: %s", refname);
342+
break;
343+
default:
344+
break;
345+
}
346+
return !strcmp(refname, "HEAD");
347+
}
348+
333349
static void reflog_expiry_prepare(const char *refname,
334350
const struct object_id *oid,
335351
void *cb_data)
336352
{
337353
struct expire_reflog_policy_cb *cb = cb_data;
338354

339-
if (!cb->cmd.expire_unreachable || !strcmp(refname, "HEAD")) {
355+
if (!cb->cmd.expire_unreachable || is_head(refname)) {
340356
cb->tip_commit = NULL;
341357
cb->unreachable_expire_kind = UE_HEAD;
342358
} else {
@@ -388,8 +404,19 @@ static int collect_reflog(const char *ref, const struct object_id *oid, int unus
388404
{
389405
struct collected_reflog *e;
390406
struct collect_reflog_cb *cb = cb_data;
407+
struct strbuf newref = STRBUF_INIT;
408+
409+
/*
410+
* Avoid collecting the same shared ref multiple times because
411+
* they are available via all worktrees.
412+
*/
413+
if (!cb->wt->is_current && ref_type(ref) == REF_TYPE_NORMAL)
414+
return 0;
415+
416+
strbuf_worktree_ref(cb->wt, &newref, ref);
417+
FLEX_ALLOC_STR(e, reflog, newref.buf);
418+
strbuf_release(&newref);
391419

392-
FLEX_ALLOC_STR(e, reflog, ref);
393420
oidcpy(&e->oid, oid);
394421
ALLOC_GROW(cb->e, cb->nr + 1, cb->alloc);
395422
cb->e[cb->nr++] = e;
@@ -512,7 +539,7 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
512539
{
513540
struct expire_reflog_policy_cb cb;
514541
timestamp_t now = time(NULL);
515-
int i, status, do_all;
542+
int i, status, do_all, all_worktrees = 1;
516543
int explicit_expiry = 0;
517544
unsigned int flags = 0;
518545

@@ -549,6 +576,8 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
549576
flags |= EXPIRE_REFLOGS_UPDATE_REF;
550577
else if (!strcmp(arg, "--all"))
551578
do_all = 1;
579+
else if (!strcmp(arg, "--single-worktree"))
580+
all_worktrees = 0;
552581
else if (!strcmp(arg, "--verbose"))
553582
flags |= EXPIRE_REFLOGS_VERBOSE;
554583
else if (!strcmp(arg, "--")) {
@@ -577,10 +606,19 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
577606

578607
if (do_all) {
579608
struct collect_reflog_cb collected;
609+
struct worktree **worktrees, **p;
580610
int i;
581611

582612
memset(&collected, 0, sizeof(collected));
583-
for_each_reflog(collect_reflog, &collected);
613+
worktrees = get_worktrees(0);
614+
for (p = worktrees; *p; p++) {
615+
if (!all_worktrees && !(*p)->is_current)
616+
continue;
617+
collected.wt = *p;
618+
refs_for_each_reflog(get_worktree_ref_store(*p),
619+
collect_reflog, &collected);
620+
}
621+
free_worktrees(worktrees);
584622
for (i = 0; i < collected.nr; i++) {
585623
struct collected_reflog *e = collected.e[i];
586624
set_reflog_expiry_param(&cb.cmd, explicit_expiry, e->reflog);

t/t1410-reflog.sh

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,4 +368,19 @@ test_expect_success 'continue walking past root commits' '
368368
)
369369
'
370370

371+
test_expect_success 'expire with multiple worktrees' '
372+
git init main-wt &&
373+
(
374+
cd main-wt &&
375+
test_tick &&
376+
test_commit foo &&
377+
git worktree add link-wt &&
378+
test_tick &&
379+
test_commit -C link-wt foobar &&
380+
test_tick &&
381+
git reflog expire --verbose --all --expire=$test_tick &&
382+
test_must_be_empty .git/worktrees/link-wt/logs/HEAD
383+
)
384+
'
385+
371386
test_done

0 commit comments

Comments
 (0)