From: Karthik Nayak <karthik.188@gmail.com>
To: Patrick Steinhardt <ps@pks.im>
Cc: git@vger.kernel.org
Subject: Re: [PATCH 2/2] reflog: implement subcommand to drop reflogs
Date: Fri, 7 Mar 2025 06:53:31 -0600 [thread overview]
Message-ID: <CAOLa=ZSMLwt53TwziCe71UbKWgRyNgg5VvUwTUUDkN60ymmFPA@mail.gmail.com> (raw)
In-Reply-To: <Z8rdg90kxmKHHbyh@pks.im>
[-- Attachment #1: Type: text/plain, Size: 6951 bytes --]
Patrick Steinhardt <ps@pks.im> writes:
> On Fri, Mar 07, 2025 at 12:17:26PM +0100, Karthik Nayak wrote:
>> Add a new 'drop' subcommand to git-reflog that allows users to delete
>> the entire reflog for a specified reference. Include a '--all' flag to
>> enable dropping all reflogs in a repository.
>>
>> While 'git-reflog(1)' currently allows users to expire reflogs and
>> delete individual entries, it lacks functionality to completely remove
>> reflogs for specific references. This becomes problematic in
>> repositories where reflogs are not needed but continue to accumulate
>> entries despite setting 'core.logAllRefUpdates=false'.
>
> I think the order of the two paragraphs should be switched: we tend to
> first explain the problem before explaining how to address it.
>
That makes sense, let me do that.
>> While here, remove an erranous newline in the file.
>
> I suspet this should either be "extraneous" or "erroneous"? I cannot
> quite tell which of both it shuld be :)
>
I was thinking similar but decided to go with the latter (sans typo).
Will fix it.
>
>>
>> Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
>> ---
>> Documentation/git-reflog.adoc | 6 +++++
>> builtin/reflog.c | 58 ++++++++++++++++++++++++++++++++++++++++++-
>> t/t1410-reflog.sh | 55 ++++++++++++++++++++++++++++++++++++++++
>> 3 files changed, 118 insertions(+), 1 deletion(-)
>>
>> diff --git a/Documentation/git-reflog.adoc b/Documentation/git-reflog.adoc
>> index a929c52982..4ecee297de 100644
>> --- a/Documentation/git-reflog.adoc
>> +++ b/Documentation/git-reflog.adoc
>> @@ -17,6 +17,7 @@ SYNOPSIS
>> 'git reflog delete' [--rewrite] [--updateref]
>> [--dry-run | -n] [--verbose] <ref>@{<specifier>}...
>> 'git reflog exists' <ref>
>> +'git reflog drop' [--all | <refs>...]
>
> Should we put the command next to `delete`?
>
I would have like it if they were actually alphabetically sorted, but I
guess this is good alternative to cluster similar sub-commands.
>> DESCRIPTION
>> -----------
>> @@ -57,6 +58,11 @@ The "exists" subcommand checks whether a ref has a reflog. It exits
>> with zero status if the reflog exists, and non-zero status if it does
>> not.
>>
>> +The "drop" subcommand removes the reflog for the specified references.
>> +In contrast, "expire" can be used to prune all entries from a reflog,
>> +but the reflog itself will still exist for that reference. To fully
>> +remove the reflog for specific references, use the "drop" subcommand.
>
> The last sentence feels like pointless duplication to me. We should
> likely also point out how it is different from "delete". How about:
>
> The "drop" subcommand completely removes the reflog for the
> specified references. This is in contrast to "expire" and "delete",
> both of which can be used to delete reflog entries, but not the
> reflog itself.
>
> It might also be useful to add a comment to "delete" to say that it
> deletes entries, but not the reflog.
>
Thanks, this does look better and I agree, we should call out "delete"
too.
>> OPTIONS
>> -------
>>
>> diff --git a/builtin/reflog.c b/builtin/reflog.c
>> index f92258f6b6..232602c1a6 100644
>> --- a/builtin/reflog.c
>> +++ b/builtin/reflog.c
>> @@ -27,6 +27,9 @@
>> #define BUILTIN_REFLOG_EXISTS_USAGE \
>> N_("git reflog exists <ref>")
>>
>> +#define BUILTIN_REFLOG_DROP_USAGE \
>> + N_("git reflog drop [--all | <refs>...]")
>> +
>> static const char *const reflog_show_usage[] = {
>> BUILTIN_REFLOG_SHOW_USAGE,
>> NULL,
>> @@ -52,12 +55,18 @@ static const char *const reflog_exists_usage[] = {
>> NULL,
>> };
>>
>> +static const char *const reflog_drop_usage[] = {
>> + BUILTIN_REFLOG_DROP_USAGE,
>> + NULL,
>> +};
>> +
>> static const char *const reflog_usage[] = {
>> BUILTIN_REFLOG_SHOW_USAGE,
>> BUILTIN_REFLOG_LIST_USAGE,
>> BUILTIN_REFLOG_EXPIRE_USAGE,
>> BUILTIN_REFLOG_DELETE_USAGE,
>> BUILTIN_REFLOG_EXISTS_USAGE,
>> + BUILTIN_REFLOG_DROP_USAGE,
>> NULL
>> };
>>
>> @@ -447,10 +456,56 @@ static int cmd_reflog_exists(int argc, const char **argv, const char *prefix,
>> refname);
>> }
>>
>> +static int cmd_reflog_drop(int argc, const char **argv, const char *prefix,
>> + struct repository *repo)
>> +{
>> + int i, ret, do_all;
>> + const struct option options[] = {
>> + OPT_BOOL(0, "all", &do_all, N_("process the reflogs of all references")),
>> + OPT_END()
>> + };
>> +
>> + do_all = ret = 0;
>
> Can't we initiailize the variables directly when declaring them?
>
We can, let me fix it! I'll also move the initialization of 'i' down to
the loop while we're here.
>> + argc = parse_options(argc, argv, prefix, options, reflog_drop_usage, 0);
>> +
>> + if (do_all) {
>
> `do_all` and `argc > 0` should be mutually exclusive from my point of
> view, as the combination does not make any sense. We should likely die
> if we see both to be non-zero. Similarly, I think we should abort on
> `!do_all && !argc`.
>
Makes sense, let me add a 'die()' there.
>> + struct worktree_reflogs collected = {
>> + .reflogs = STRING_LIST_INIT_DUP,
>> + };
>> + struct string_list_item *item;
>> + struct worktree **worktrees, **p;
>
> Would it be useful to point out in the docs that we also prune logs of
> worktrees?
>
Yes it would, will add.
>> + worktrees = get_worktrees();
>> + for (p = worktrees; *p; p++) {
>> + collected.worktree = *p;
>> + refs_for_each_reflog(get_worktree_ref_store(*p),
>> + collect_reflog, &collected);
>> + }
>> + free_worktrees(worktrees);
>> +
>> + for_each_string_list_item(item, &collected.reflogs)
>> + ret |= refs_delete_reflog(get_main_ref_store(repo),
>> + item->string);
>> + string_list_clear(&collected.reflogs, 0);
>> + }
>> +
>> + for (i = 0; i < argc; i++) {
>> + char *ref;
>> + if (!repo_dwim_log(repo, argv[i], strlen(argv[i]), NULL, &ref)) {
>> + ret |= error(_("%s points nowhere!"), argv[i]);
>> + continue;
>> + }
>
> Is there a particular reason why we have to double check that the reflog
> that we just enumerated really exists? It feels rather unnecessary to
> me.
>
You mean we could directly do `(get_main_ref_store(repo), argv[i]);` ?
The issue is that this returns '0', even when the reflog doesn't exist.
So to notify the user correctly, we do this check.
>> diff --git a/t/t1410-reflog.sh b/t/t1410-reflog.sh
>> index 388fdf9ae5..b6e44ce6b9 100755
>> --- a/t/t1410-reflog.sh
>> +++ b/t/t1410-reflog.sh
>> @@ -551,4 +551,59 @@ test_expect_success 'reflog with invalid object ID can be listed' '
>> )
>> '
>>
>> +test_expect_success 'reflog drop non-existent ref' '
>> + test_when_finished "rm -rf repo" &&
>> + git init repo &&
>> + (
>> + cd repo &&
>> + test_must_fail git reflog exists refs/heads/non-existent &&
>> + test_must_fail git reflog drop refs/heads/non-existent
>
> Do we want to check the error message of the latter command?
>
That would be nice addittion, will add.
> Patrick
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 690 bytes --]
next prev parent reply other threads:[~2025-03-07 12:53 UTC|newest]
Thread overview: 30+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-03-07 11:17 [PATCH 0/2] EDITME: cover title for 493-add-command-to-purge-reflog-entries Karthik Nayak
2025-03-07 11:17 ` [PATCH 1/2] reflog: drop usage of global variables Karthik Nayak
2025-03-07 21:19 ` Junio C Hamano
2025-03-10 11:41 ` Karthik Nayak
2025-03-10 15:24 ` Junio C Hamano
2025-03-13 13:30 ` Karthik Nayak
2025-03-07 11:17 ` [PATCH 2/2] reflog: implement subcommand to drop reflogs Karthik Nayak
2025-03-07 11:50 ` Patrick Steinhardt
2025-03-07 12:53 ` Karthik Nayak [this message]
2025-03-07 12:59 ` Patrick Steinhardt
2025-03-07 13:28 ` Karthik Nayak
2025-03-07 13:28 ` Karthik Nayak
2025-03-07 21:28 ` Junio C Hamano
2025-03-10 11:28 ` Karthik Nayak
2025-03-10 7:39 ` [PATCH 0/2] EDITME: cover title for 493-add-command-to-purge-reflog-entries Kristoffer Haugsbakk
2025-03-10 12:34 ` Karthik Nayak
2025-03-10 15:28 ` Junio C Hamano
2025-03-10 12:36 ` [PATCH v2] reflog: implement subcommand to drop reflogs Karthik Nayak
2025-03-12 7:15 ` Patrick Steinhardt
2025-03-13 14:24 ` Karthik Nayak
2025-03-13 14:45 ` Patrick Steinhardt
2025-03-14 8:40 ` [PATCH v3 0/2] " Karthik Nayak
2025-03-14 8:40 ` [PATCH v3 1/2] reflog: improve error for when reflog is not found Karthik Nayak
2025-03-14 8:40 ` [PATCH v3 2/2] reflog: implement subcommand to drop reflogs Karthik Nayak
2025-03-18 14:01 ` Christian Couder
2025-03-18 17:44 ` Junio C Hamano
2025-03-19 8:17 ` Christian Couder
2025-03-19 9:06 ` Karthik Nayak
2025-03-18 15:56 ` Toon Claes
2025-03-19 9:16 ` Karthik Nayak
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to='CAOLa=ZSMLwt53TwziCe71UbKWgRyNgg5VvUwTUUDkN60ymmFPA@mail.gmail.com' \
--to=karthik.188@gmail.com \
--cc=git@vger.kernel.org \
--cc=ps@pks.im \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).