reflog expire: cover reflog from all worktrees
Reported-by: Jeff King <peff@peff.net> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:

committed by
Junio C Hamano

parent
b29759d89a
commit
c9ef0d95eb
@ -20,7 +20,7 @@ depending on the subcommand:
|
|||||||
'git reflog' ['show'] [log-options] [<ref>]
|
'git reflog' ['show'] [log-options] [<ref>]
|
||||||
'git reflog expire' [--expire=<time>] [--expire-unreachable=<time>]
|
'git reflog expire' [--expire=<time>] [--expire-unreachable=<time>]
|
||||||
[--rewrite] [--updateref] [--stale-fix]
|
[--rewrite] [--updateref] [--stale-fix]
|
||||||
[--dry-run | -n] [--verbose] [--all | <refs>...]
|
[--dry-run | -n] [--verbose] [--all [--single-worktree] | <refs>...]
|
||||||
'git reflog delete' [--rewrite] [--updateref]
|
'git reflog delete' [--rewrite] [--updateref]
|
||||||
[--dry-run | -n] [--verbose] ref@\{specifier\}...
|
[--dry-run | -n] [--verbose] ref@\{specifier\}...
|
||||||
'git reflog exists' <ref>
|
'git reflog exists' <ref>
|
||||||
@ -72,6 +72,11 @@ Options for `expire`
|
|||||||
--all::
|
--all::
|
||||||
Process the reflogs of all references.
|
Process the reflogs of all references.
|
||||||
|
|
||||||
|
--single-worktree::
|
||||||
|
By default when `--all` is specified, reflogs from all working
|
||||||
|
trees are processed. This option limits the processing to reflogs
|
||||||
|
from the current working tree only.
|
||||||
|
|
||||||
--expire=<time>::
|
--expire=<time>::
|
||||||
Prune entries older than the specified time. If this option is
|
Prune entries older than the specified time. If this option is
|
||||||
not specified, the expiration time is taken from the
|
not specified, the expiration time is taken from the
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#include "diff.h"
|
#include "diff.h"
|
||||||
#include "revision.h"
|
#include "revision.h"
|
||||||
#include "reachable.h"
|
#include "reachable.h"
|
||||||
|
#include "worktree.h"
|
||||||
|
|
||||||
/* NEEDSWORK: switch to using parse_options */
|
/* NEEDSWORK: switch to using parse_options */
|
||||||
static const char reflog_expire_usage[] =
|
static const char reflog_expire_usage[] =
|
||||||
@ -52,6 +53,7 @@ struct collect_reflog_cb {
|
|||||||
struct collected_reflog **e;
|
struct collected_reflog **e;
|
||||||
int alloc;
|
int alloc;
|
||||||
int nr;
|
int nr;
|
||||||
|
struct worktree *wt;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Remember to update object flag allocation in object.h */
|
/* 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,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int is_head(const char *refname)
|
||||||
|
{
|
||||||
|
switch (ref_type(refname)) {
|
||||||
|
case REF_TYPE_OTHER_PSEUDOREF:
|
||||||
|
case REF_TYPE_MAIN_PSEUDOREF:
|
||||||
|
if (parse_worktree_ref(refname, NULL, NULL, &refname))
|
||||||
|
BUG("not a worktree ref: %s", refname);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return !strcmp(refname, "HEAD");
|
||||||
|
}
|
||||||
|
|
||||||
static void reflog_expiry_prepare(const char *refname,
|
static void reflog_expiry_prepare(const char *refname,
|
||||||
const struct object_id *oid,
|
const struct object_id *oid,
|
||||||
void *cb_data)
|
void *cb_data)
|
||||||
{
|
{
|
||||||
struct expire_reflog_policy_cb *cb = cb_data;
|
struct expire_reflog_policy_cb *cb = cb_data;
|
||||||
|
|
||||||
if (!cb->cmd.expire_unreachable || !strcmp(refname, "HEAD")) {
|
if (!cb->cmd.expire_unreachable || is_head(refname)) {
|
||||||
cb->tip_commit = NULL;
|
cb->tip_commit = NULL;
|
||||||
cb->unreachable_expire_kind = UE_HEAD;
|
cb->unreachable_expire_kind = UE_HEAD;
|
||||||
} else {
|
} else {
|
||||||
@ -388,8 +404,19 @@ static int collect_reflog(const char *ref, const struct object_id *oid, int unus
|
|||||||
{
|
{
|
||||||
struct collected_reflog *e;
|
struct collected_reflog *e;
|
||||||
struct collect_reflog_cb *cb = cb_data;
|
struct collect_reflog_cb *cb = cb_data;
|
||||||
|
struct strbuf newref = STRBUF_INIT;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Avoid collecting the same shared ref multiple times because
|
||||||
|
* they are available via all worktrees.
|
||||||
|
*/
|
||||||
|
if (!cb->wt->is_current && ref_type(ref) == REF_TYPE_NORMAL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
strbuf_worktree_ref(cb->wt, &newref, ref);
|
||||||
|
FLEX_ALLOC_STR(e, reflog, newref.buf);
|
||||||
|
strbuf_release(&newref);
|
||||||
|
|
||||||
FLEX_ALLOC_STR(e, reflog, ref);
|
|
||||||
oidcpy(&e->oid, oid);
|
oidcpy(&e->oid, oid);
|
||||||
ALLOC_GROW(cb->e, cb->nr + 1, cb->alloc);
|
ALLOC_GROW(cb->e, cb->nr + 1, cb->alloc);
|
||||||
cb->e[cb->nr++] = e;
|
cb->e[cb->nr++] = e;
|
||||||
@ -512,7 +539,7 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
|
|||||||
{
|
{
|
||||||
struct expire_reflog_policy_cb cb;
|
struct expire_reflog_policy_cb cb;
|
||||||
timestamp_t now = time(NULL);
|
timestamp_t now = time(NULL);
|
||||||
int i, status, do_all;
|
int i, status, do_all, all_worktrees = 1;
|
||||||
int explicit_expiry = 0;
|
int explicit_expiry = 0;
|
||||||
unsigned int flags = 0;
|
unsigned int flags = 0;
|
||||||
|
|
||||||
@ -549,6 +576,8 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
|
|||||||
flags |= EXPIRE_REFLOGS_UPDATE_REF;
|
flags |= EXPIRE_REFLOGS_UPDATE_REF;
|
||||||
else if (!strcmp(arg, "--all"))
|
else if (!strcmp(arg, "--all"))
|
||||||
do_all = 1;
|
do_all = 1;
|
||||||
|
else if (!strcmp(arg, "--single-worktree"))
|
||||||
|
all_worktrees = 0;
|
||||||
else if (!strcmp(arg, "--verbose"))
|
else if (!strcmp(arg, "--verbose"))
|
||||||
flags |= EXPIRE_REFLOGS_VERBOSE;
|
flags |= EXPIRE_REFLOGS_VERBOSE;
|
||||||
else if (!strcmp(arg, "--")) {
|
else if (!strcmp(arg, "--")) {
|
||||||
@ -577,10 +606,19 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
|
|||||||
|
|
||||||
if (do_all) {
|
if (do_all) {
|
||||||
struct collect_reflog_cb collected;
|
struct collect_reflog_cb collected;
|
||||||
|
struct worktree **worktrees, **p;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
memset(&collected, 0, sizeof(collected));
|
memset(&collected, 0, sizeof(collected));
|
||||||
for_each_reflog(collect_reflog, &collected);
|
worktrees = get_worktrees(0);
|
||||||
|
for (p = worktrees; *p; p++) {
|
||||||
|
if (!all_worktrees && !(*p)->is_current)
|
||||||
|
continue;
|
||||||
|
collected.wt = *p;
|
||||||
|
refs_for_each_reflog(get_worktree_ref_store(*p),
|
||||||
|
collect_reflog, &collected);
|
||||||
|
}
|
||||||
|
free_worktrees(worktrees);
|
||||||
for (i = 0; i < collected.nr; i++) {
|
for (i = 0; i < collected.nr; i++) {
|
||||||
struct collected_reflog *e = collected.e[i];
|
struct collected_reflog *e = collected.e[i];
|
||||||
set_reflog_expiry_param(&cb.cmd, explicit_expiry, e->reflog);
|
set_reflog_expiry_param(&cb.cmd, explicit_expiry, e->reflog);
|
||||||
|
@ -368,4 +368,19 @@ test_expect_success 'continue walking past root commits' '
|
|||||||
)
|
)
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success 'expire with multiple worktrees' '
|
||||||
|
git init main-wt &&
|
||||||
|
(
|
||||||
|
cd main-wt &&
|
||||||
|
test_tick &&
|
||||||
|
test_commit foo &&
|
||||||
|
git worktree add link-wt &&
|
||||||
|
test_tick &&
|
||||||
|
test_commit -C link-wt foobar &&
|
||||||
|
test_tick &&
|
||||||
|
git reflog expire --verbose --all --expire=$test_tick &&
|
||||||
|
test_must_be_empty .git/worktrees/link-wt/logs/HEAD
|
||||||
|
)
|
||||||
|
'
|
||||||
|
|
||||||
test_done
|
test_done
|
||||||
|
Reference in New Issue
Block a user