Skip to content

Commit 4d16673

Browse files
committed
Merge branch 'kn/reflog-drop' into jch
* kn/reflog-drop: reflog: implement subcommand to drop reflogs
2 parents f6765ef + 9a085e9 commit 4d16673

File tree

3 files changed

+140
-5
lines changed

3 files changed

+140
-5
lines changed

Documentation/git-reflog.adoc

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ SYNOPSIS
1616
[--dry-run | -n] [--verbose] [--all [--single-worktree] | <refs>...]
1717
'git reflog delete' [--rewrite] [--updateref]
1818
[--dry-run | -n] [--verbose] <ref>@{<specifier>}...
19+
'git reflog drop' [--all | <refs>...]
1920
'git reflog exists' <ref>
2021

2122
DESCRIPTION
@@ -48,15 +49,19 @@ and not reachable from the current tip, are removed from the reflog.
4849
This is typically not used directly by end users -- instead, see
4950
linkgit:git-gc[1].
5051

51-
The "delete" subcommand deletes single entries from the reflog. Its
52-
argument must be an _exact_ entry (e.g. "`git reflog delete
53-
master@{2}`"). This subcommand is also typically not used directly by
54-
end users.
52+
The "delete" subcommand deletes single entries from the reflog, but
53+
not the reflog itself. Its argument must be an _exact_ entry (e.g. "`git
54+
reflog delete master@{2}`"). This subcommand is also typically not used
55+
directly by end users.
5556

5657
The "exists" subcommand checks whether a ref has a reflog. It exits
5758
with zero status if the reflog exists, and non-zero status if it does
5859
not.
5960

61+
The "drop" subcommand completely removes the reflog for the specified
62+
references. This is in contrast to "expire" and "delete", both of which
63+
can be used to delete reflog entries, but not the reflog itself.
64+
6065
OPTIONS
6166
-------
6267

@@ -132,6 +137,11 @@ Options for `delete`
132137
`--dry-run`, and `--verbose`, with the same meanings as when they are
133138
used with `expire`.
134139

140+
Options for `drop`
141+
~~~~~~~~~~~~~~~~~~~~
142+
143+
--all::
144+
Drop the reflogs of all references from all worktrees.
135145

136146
GIT
137147
---

builtin/reflog.c

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@
2929
#define BUILTIN_REFLOG_EXISTS_USAGE \
3030
N_("git reflog exists <ref>")
3131

32+
#define BUILTIN_REFLOG_DROP_USAGE \
33+
N_("git reflog drop [--all | <refs>...]")
34+
3235
static const char *const reflog_show_usage[] = {
3336
BUILTIN_REFLOG_SHOW_USAGE,
3437
NULL,
@@ -54,11 +57,17 @@ static const char *const reflog_exists_usage[] = {
5457
NULL,
5558
};
5659

60+
static const char *const reflog_drop_usage[] = {
61+
BUILTIN_REFLOG_DROP_USAGE,
62+
NULL,
63+
};
64+
5765
static const char *const reflog_usage[] = {
5866
BUILTIN_REFLOG_SHOW_USAGE,
5967
BUILTIN_REFLOG_LIST_USAGE,
6068
BUILTIN_REFLOG_EXPIRE_USAGE,
6169
BUILTIN_REFLOG_DELETE_USAGE,
70+
BUILTIN_REFLOG_DROP_USAGE,
6271
BUILTIN_REFLOG_EXISTS_USAGE,
6372
NULL
6473
};
@@ -328,10 +337,58 @@ static int cmd_reflog_exists(int argc, const char **argv, const char *prefix,
328337
refname);
329338
}
330339

340+
static int cmd_reflog_drop(int argc, const char **argv, const char *prefix,
341+
struct repository *repo)
342+
{
343+
int ret = 0, do_all = 0;
344+
const struct option options[] = {
345+
OPT_BOOL(0, "all", &do_all, N_("process the reflogs of all references")),
346+
OPT_END()
347+
};
348+
349+
argc = parse_options(argc, argv, prefix, options, reflog_drop_usage, 0);
350+
351+
if (argc && do_all)
352+
die(_("references specified along with --all"));
353+
354+
if (do_all) {
355+
struct worktree_reflogs collected = {
356+
.reflogs = STRING_LIST_INIT_DUP,
357+
};
358+
struct string_list_item *item;
359+
struct worktree **worktrees, **p;
360+
361+
worktrees = get_worktrees();
362+
for (p = worktrees; *p; p++) {
363+
collected.worktree = *p;
364+
refs_for_each_reflog(get_worktree_ref_store(*p),
365+
collect_reflog, &collected);
366+
}
367+
free_worktrees(worktrees);
368+
369+
for_each_string_list_item(item, &collected.reflogs)
370+
ret |= refs_delete_reflog(get_main_ref_store(repo),
371+
item->string);
372+
string_list_clear(&collected.reflogs, 0);
373+
}
374+
375+
for (int i = 0; i < argc; i++) {
376+
char *ref;
377+
if (!repo_dwim_log(repo, argv[i], strlen(argv[i]), NULL, &ref)) {
378+
ret |= error(_("%s points nowhere!"), argv[i]);
379+
continue;
380+
}
381+
382+
ret |= refs_delete_reflog(get_main_ref_store(repo), ref);
383+
free(ref);
384+
}
385+
386+
return ret;
387+
}
388+
331389
/*
332390
* main "reflog"
333391
*/
334-
335392
int cmd_reflog(int argc,
336393
const char **argv,
337394
const char *prefix,
@@ -344,6 +401,7 @@ int cmd_reflog(int argc,
344401
OPT_SUBCOMMAND("expire", &fn, cmd_reflog_expire),
345402
OPT_SUBCOMMAND("delete", &fn, cmd_reflog_delete),
346403
OPT_SUBCOMMAND("exists", &fn, cmd_reflog_exists),
404+
OPT_SUBCOMMAND("drop", &fn, cmd_reflog_drop),
347405
OPT_END()
348406
};
349407

t/t1410-reflog.sh

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -551,4 +551,71 @@ test_expect_success 'reflog with invalid object ID can be listed' '
551551
)
552552
'
553553

554+
test_expect_success 'reflog drop non-existent ref' '
555+
test_when_finished "rm -rf repo" &&
556+
git init repo &&
557+
(
558+
cd repo &&
559+
test_must_fail git reflog exists refs/heads/non-existent &&
560+
test_must_fail git reflog drop refs/heads/non-existent 2>stderr &&
561+
test_grep "error: refs/heads/non-existent points nowhere!" stderr
562+
)
563+
'
564+
565+
test_expect_success 'reflog drop' '
566+
test_when_finished "rm -rf repo" &&
567+
git init repo &&
568+
(
569+
cd repo &&
570+
test_commit A &&
571+
test_commit_bulk --ref=refs/heads/branch 1 &&
572+
git reflog exists refs/heads/main &&
573+
git reflog exists refs/heads/branch &&
574+
git reflog drop refs/heads/main &&
575+
test_must_fail git reflog exists refs/heads/main &&
576+
git reflog exists refs/heads/branch
577+
)
578+
'
579+
580+
test_expect_success 'reflog drop multiple references' '
581+
test_when_finished "rm -rf repo" &&
582+
git init repo &&
583+
(
584+
cd repo &&
585+
test_commit A &&
586+
test_commit_bulk --ref=refs/heads/branch 1 &&
587+
git reflog exists refs/heads/main &&
588+
git reflog exists refs/heads/branch &&
589+
git reflog drop refs/heads/main refs/heads/branch &&
590+
test_must_fail git reflog exists refs/heads/main &&
591+
test_must_fail git reflog exists refs/heads/branch
592+
)
593+
'
594+
595+
test_expect_success 'reflog drop --all' '
596+
test_when_finished "rm -rf repo" &&
597+
git init repo &&
598+
(
599+
cd repo &&
600+
test_commit A &&
601+
test_commit_bulk --ref=refs/heads/branch 1 &&
602+
git reflog exists refs/heads/main &&
603+
git reflog exists refs/heads/branch &&
604+
git reflog drop --all &&
605+
test_must_fail git reflog exists refs/heads/main &&
606+
test_must_fail git reflog exists refs/heads/branch
607+
)
608+
'
609+
610+
test_expect_success 'reflog drop --all with reference' '
611+
test_when_finished "rm -rf repo" &&
612+
git init repo &&
613+
(
614+
cd repo &&
615+
test_commit A &&
616+
test_must_fail git reflog drop --all refs/heads/main 2>stderr &&
617+
test_grep "fatal: references specified along with --all" stderr
618+
)
619+
'
620+
554621
test_done

0 commit comments

Comments
 (0)