libify reflog
cover libify reflog
In [1], there was a discussion around a bug report of stash not recovering in the middle of the process. It turned out to not be a bug we need to fix. However, out of that discussion came the idea of libifying reflog. This can stand alone as a code improvement.
stash.c currently shells out to call reflog to delete reflogs. Libify reflog delete and call it from both builtin/reflog.c and builtin/stash.c.
This patch has three parts:
* libify reflog's delete functionality and move some of the helpers into a reflog.c library and export them
* call reflog_delete from builtin/reflog.c
* call reflog_delete from builtin/stash.c
1. https://lore.kernel.org/git/[email protected]/
John Cai (3):
reflog: libify delete reflog function and helpers
reflog: call reflog_delete from reflog.c
stash: call reflog_delete from reflog.c
Makefile | 1 + builtin/reflog.c | 451 +---------------------------------------------- builtin/stash.c | 16 +- reflog.c | 432 +++++++++++++++++++++++++++++++++++++++++++++ reflog.h | 49 +++++ 5 files changed, 490 insertions(+), 459 deletions(-) create mode 100644 reflog.c create mode 100644 reflog.h
base-commit: b80121027d1247a0754b3cc46897fee75c050b44
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-1218%2Fjohn-cai%2Fjc-libify-reflog-v1
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-1218/john-cai/jc-libify-reflog-v1
Pull-Request: https://github.com/git/git/pull/1218
Signature · 1 line
gitgitgadget
PATCH 2/3 reflog: call reflog_delete from reflog.c
From: John Cai <[email protected]>
Now that reflog is libified into reflog.c, we can call reflog_delete from the reflog.c library.
--- builtin/reflog.c | 42 ++---------------------------------------- 1 file changed, 2 insertions(+), 40 deletions(-)
builtin/reflog.c +2 -40
@@ -316,12 +316,10 @@ static const char * reflog_delete_usage[] = {static int cmd_reflog_delete (int argc,const char **argv,const char *prefix) { -struct cmd_reflog_expire_cb cmd = {0 };int i, status =0 ;unsigned int flags =0 ;int verbose =0 ; -reflog_expiry_should_prune_fn *should_prune_fn = should_expire_reflog_ent;const struct option options[] = {OPT_BIT (0 ,"dry-run" , &flags,N_ ("do not actually prune any entries" ),EXPIRE_REFLOGS_DRY_RUN ),
@@ -337,48 +335,12 @@ static int cmd_reflog_delete(int argc, const char **argv, const char *prefix) argc =parse_options (argc, argv, prefix, options, reflog_delete_usage,0 ); -if (verbose) - should_prune_fn = should_expire_reflog_ent_verbose; -if (argc <1 )return error (_ ("no reflog specified to delete" )); -for (i =0 ; i < argc; i++) { -const char *spec =strstr (argv[i],"@{" ); -char *ep, *ref; -int recno; -struct expire_reflog_policy_cb cb = { - .dry_run = !!(flags &EXPIRE_REFLOGS_DRY_RUN ), - }; - -if (!spec) { - status |=error (_ ("not a reflog: %s" ), argv[i]); -continue ; - } - -if (!dwim_log (argv[i], spec - argv[i],NULL , &ref)) { - status |=error (_ ("no reflog for '%s'" ), argv[i]); -continue ; - } - - recno =strtoul (spec +2 , &ep,10 ); -if (*ep =='}' ) { - cmd.recno = -recno; -for_each_reflog_ent (ref, count_reflog_ent, &cmd); - }else { - cmd.expire_total =approxidate (spec +2 ); -for_each_reflog_ent (ref, count_reflog_ent, &cmd); - cmd.expire_total =0 ; - } +for (i =0 ; i < argc; i++) + status |=reflog_delete (argv[i], flags, verbose); - cb.cmd = cmd; - status |=reflog_expire (ref, flags, - reflog_expiry_prepare, - should_prune_fn, - reflog_expiry_cleanup, - &cb); -free (ref); - }return status; }
Signature · 1 line
gitgitgadget
PATCH 3/3 stash: call reflog_delete from reflog.c
In reply to John Cai via GitGitGadgetFrom: John Cai <[email protected]>
Now that cmd_reflog_delete has been libified an exported it into a new reflog.c library so we can call it directly from builtin/stash.c. This not only gives us a performance gain since we don't need to create a subprocess, but it also allows us to use the ref transactions api in the future.
--- builtin/stash.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-)
builtin/stash.c +4 -12
@@ -17,6 +17,7 @@#include "diffcore.h" #include "exec-cmd.h" #include "entry.h" +#include "reflog.h" #define INCLUDE_ALL_FILES 2
@@ -635,18 +636,9 @@ static int reflog_is_empty(const char *refname)static int do_drop_stash (struct stash_info *info,int quiet) {int ret; -struct child_process cp_reflog =CHILD_PROCESS_INIT ; - -/* -* reflog does not provide a simple function for deleting refs. One will -* need to be added to avoid implementing too much reflog code here -*/ - - cp_reflog.git_cmd =1 ; -strvec_pushl (&cp_reflog.args,"reflog" ,"delete" ,"--updateref" , -"--rewrite" ,NULL ); -strvec_push (&cp_reflog.args, info->revision.buf); - ret =run_command (&cp_reflog); + ret =reflog_delete (info->revision.buf, +EXPIRE_REFLOGS_REWRITE |EXPIRE_REFLOGS_REWRITE , +0 );if (!ret) {if (!quiet) printf_ln(_("Dropped %s (%s)"), info->revision.buf,
Signature · 1 line
gitgitgadget
PATCH 1/3 reflog: libify delete reflog function and helpers
In reply to John Cai via GitGitGadgetFrom: John Cai <[email protected]>
Currently stash shells out to reflog in order to delete refs. In an effort to reduce how much we shell out to a subprocess, libify the functionality that stash needs into reflog.c.
Add a reflog_delete function that is pretty much the logic in the while loop in builtin/reflog.c cmd_reflog_delete(). This is a function that builtin/reflog.c and builtin/stash.c can both call.
Also move functions needed by reflog_delete and export them.
--- Makefile | 1 + builtin/reflog.c | 409 +------------------------------------------- reflog.c | 432 +++++++++++++++++++++++++++++++++++++++++++++++ reflog.h | 49 ++++++ 4 files changed, 484 insertions(+), 407 deletions(-) create mode 100644 reflog.c create mode 100644 reflog.h
Makefile +1 -0
@@ -990,6 +990,7 @@ LIB_OBJS += rebase-interactive.o LIB_OBJS += rebase.o LIB_OBJS += ref-filter.o LIB_OBJS += reflog-walk.o +LIB_OBJS += reflog.o LIB_OBJS += refs.o LIB_OBJS += refs/debug.o LIB_OBJS += refs/files-backend.o
builtin/reflog.c +2 -407
444 lines not on this page · raw message
reflog.c new file +432 -0
432 lines not on this page · raw message
reflog.h new file +49 -0
49 lines not on this page · raw message
Signature · 1 line
gitgitgadget
Re: [PATCH 1/3] reflog: libify delete reflog function and helpers
Quoted 6 lines · John Cai via GitGitGadget
From: John Cai <[email protected]>
Currently stash shells out to reflog in order to delete refs. In an effort to reduce how much we shell out to a subprocess, libify the functionality that stash needs into
reflog.c.
Quoted 8 lines
Add a
reflog_deletefunction that is pretty much the logic in the while loop inbuiltin/reflog.ccmd_reflog_delete(). This is a function thatbuiltin/reflog.candbuiltin/stash.ccan both call.Also move functions needed by
reflog_deleteand export them.Signed-off-by John Cai <[email protected]>
Yay! This looks great. Even though I'll need to deal with some conflicts locally .. :)
Quoted 12 lines
reflog.c new file +12
-0+int reflog_delete (const char *rev,int flags,int verbose) +{ +struct cmd_reflog_expire_cb cmd = {0 }; +int status =0 ; +reflog_expiry_should_prune_fn *should_prune_fn = should_expire_reflog_ent; +const char *spec =strstr (rev,"@{" ); +char *ep, *ref; +int recno; +struct expire_reflog_policy_cb cb = { + .dry_run = !!(flags &EXPIRE_REFLOGS_DRY_RUN ), + }; +
reflog.c line 408
Quoted 10 lines
reflog.c new file +10
-0+if (verbose) + should_prune_fn = should_expire_reflog_ent_verbose; + +if (!spec) { + status |=error (_ ("not a reflog: %s" ), rev); + } + +if (!dwim_log (rev, spec - rev,NULL , &ref)) { + status |=error (_ ("no reflog for '%s'" ), rev); + }
For these let's follow our usual style of not having braces for single-line if's.
Buuuut in this case doing so will make the diff move detection less useful for 1..2.
So probably best to leave it, or do some post-cleanup at the end maybe.
Quoted 6 lines
reflog.h new file +6
-0+int reflog_delete (const char *,int ,int ); +void reflog_expiry_cleanup (void *); +void reflog_expiry_prepare (const char *,const struct object_id *, +void *); +int should_expire_reflog_ent(struct object_id *, struct object_id*, + const char *, timestamp_t, int,
reflog.h line 49
Quoted 10 lines
reflog.h new file +10
-0+ const char *, void *); +int count_reflog_ent (struct object_id *ooid,struct object_id *noid, +const char *email,timestamp_t timestamp,int tz, +const char *message,void *cb_data); +int should_expire_reflog_ent_verbose (struct object_id *, +struct object_id *, +const char *, +timestamp_t ,int , +const char *,void *); +#endif /* REFLOG_H */
Just a style preference, but I for one prefer the style where we retain the parameter names, it helps to read these, especially when we add API docs here.
Some of these are mis-indented. We align with the opening "(" with "\t" = 8 chars, so e.g. 2x \t + 5 SP for the count_reflog_ent() arguments etc.
Re: [PATCH 2/3] reflog: call reflog_delete from reflog.c
In reply to John Cai via GitGitGadgetQuoted 68 lines · John Cai via GitGitGadget
From: John Cai <[email protected]>
Now that reflog is libified into
reflog.c, we can callreflog_deletefrom thereflog.clibrary.Signed-off-by John Cai <[email protected]>--- builtin/reflog.c | 42 ++---------------------------------------- 1 file changed, 2 insertions(+), 40 deletions(-)builtin/reflog.c +2
-32@@ -316,12 +316,10 @@ static const char * reflog_delete_usage[] = {static int cmd_reflog_delete (int argc,const char **argv,const char *prefix) { -struct cmd_reflog_expire_cb cmd = {0 };int i, status =0 ;unsigned int flags =0 ;int verbose =0 ; -reflog_expiry_should_prune_fn *should_prune_fn = should_expire_reflog_ent;const struct option options[] = {OPT_BIT (0 ,"dry-run" , &flags,N_ ("do not actually prune any entries" ),EXPIRE_REFLOGS_DRY_RUN ),@@ -337,48 +335,12 @@ static int cmd_reflog_delete(int argc, const char **argv, const char *prefix) argc =parse_options (argc, argv, prefix, options, reflog_delete_usage,0 ); -if (verbose) - should_prune_fn = should_expire_reflog_ent_verbose; -if (argc <1 )return error (_ ("no reflog specified to delete" )); -for (i =0 ; i < argc; i++) { -const char *spec =strstr (argv[i],"@{" ); -char *ep, *ref; -int recno; -struct expire_reflog_policy_cb cb = { - .dry_run = !!(flags &EXPIRE_REFLOGS_DRY_RUN ), - }; - -if (!spec) { - status |=error (_ ("not a reflog: %s" ), argv[i]); -continue ; - } - -if (!dwim_log (argv[i], spec - argv[i],NULL , &ref)) { - status |=error (_ ("no reflog for '%s'" ), argv[i]); -continue ; - } - - recno =strtoul (spec +2 , &ep,10 ); -if (*ep =='}' ) { - cmd.recno = -recno; -for_each_reflog_ent (ref, count_reflog_ent, &cmd); - }else { - cmd.expire_total =approxidate (spec +2 ); -for_each_reflog_ent (ref, count_reflog_ent, &cmd); - cmd.expire_total =0 ; - } +for (i =0 ; i < argc; i++) + status |=reflog_delete (argv[i], flags, verbose);
builtin/reflog.c static int cmd_reflog_delete(int argc, const char **argv, const char *prefix) · line 345
Quoted 10 lines
builtin/reflog.c +0
-8- cb.cmd = cmd; - status |=reflog_expire (ref, flags, - reflog_expiry_prepare, - should_prune_fn, - reflog_expiry_cleanup, - &cb); -free (ref); - }return status; }
Maybe others will disagree, but per my comment on 1/2 I found reviewing this locally much easier with this squashed into 1/2 (without the {} changes I suggested).
I.e. the diff move/rename detection eats up this change & shows that the combinatino of 1/3 and 2/3 is almost entirely just moving around existing code (good!).
But without this squashed 1/3 has a reflog_delete() "addition", that we later can see is mostly just moving things around.
I'll leave it to you to decide what you want to do there, just suggestion on an otherwise very trivial-to-review change :)
Re: [PATCH 3/3] stash: call reflog_delete from reflog.c
In reply to John Cai via GitGitGadgetQuoted 10 lines · John Cai via GitGitGadget
From: John Cai <[email protected]>
Now that
cmd_reflog_deletehas been libified an exported it into a newreflog.clibrary so we can call it directly frombuiltin/stash.c. This not only gives us a performance gain since we don't need to create a subprocess, but it also allows us to use the ref transactions api in the future.Signed-off-by John Cai <[email protected]>
Very nicely done, and nice that despite the ~500 lines added/removed in the diffstat that the "actual" changes in this series are so small.q
Review static int reflog_is_empty(const char *refname) · line 639
Quoted 6 lines
(quoted diff) +0
-2@@ -635,18 +636,9 @@ static int reflog_is_empty(const char *refname) static int do_drop_stash(struct stash_info *info, int quiet) { int ret; - struct child_process cp_reflog = CHILD_PROCESS_INIT; -
Nit: We usually separate variables decls with a \n\n, as is done in the pre-image, but you end up dropping that.
Quoted 6 lines
(quoted diff) +0
-6- /* - * reflog does not provide a simple function for deleting refs. One will - * need to be added to avoid implementing too much reflog code here - */ - - cp_reflog.git_cmd = 1;
Review static int reflog_is_empty(const char *refname) · line 644
Quoted 10 lines
(quoted diff) +3
-4- strvec_pushl(&cp_reflog.args, "reflog", "delete", "--updateref", - "--rewrite", NULL); - strvec_push(&cp_reflog.args, info->revision.buf); - ret = run_command(&cp_reflog); + ret = reflog_delete(info->revision.buf, + EXPIRE_REFLOGS_REWRITE | EXPIRE_REFLOGS_REWRITE, + 0); if (!ret) { if (!quiet) printf_ln(_("Dropped %s (%s)"), info->revision.buf,
I think per the above squashing this in would be nice, i.e. you get rid of the long line & it'sclear that "ret" is not used for anything now:
builtin/stash.c +3 -5
@@ -635,11 +635,9 @@ static int reflog_is_empty(const char *refname)static int do_drop_stash (struct stash_info *info,int quiet) { -int ret; - ret =reflog_delete (info->revision.buf, -EXPIRE_REFLOGS_REWRITE |EXPIRE_REFLOGS_REWRITE , -0 ); -if (!ret) { +unsigned int flags =EXPIRE_REFLOGS_REWRITE |EXPIRE_REFLOGS_REWRITE ; + +if (!reflog_delete (info->revision.buf, flags,0 )) {if (!quiet)printf_ln (_ ("Dropped %s (%s)" ), info->revision.buf,oid_to_hex (&info->w_commit));
But, having written that I notice that we have *_REWRITE twice there, so I almost just carried forward a new bug in 3/3 when composing this :)
So one should be EXPIRE_REFLOGS_UPDATE_REF, presumably.
And perhaps it's a big pain, but that suggests that the code isn't either used at all, or that we're missing a test for it.
So adding a prep commit to this series where we either drop it, or add the missing test would be a very nice addition.
See my quite recent 5ac15ad2509 (reflog tests: add --updateref tests, 2021-10-16) for adding such tests, but in that case I just covered "git reflog" itself, not "git stash". Maybe we can just add something to that for-loop in t1417 (or similar for a new stash test).
Also, a s/unsigned int flags/enum expire_reflog_flags/ while we're at it would be very nice here, but that could be done as another small prep commit. I.e. it's *not* a new issue since cmd_reflog_delete() had it before, but when converting this to a documented API it would be very nice to have it reflect the actual type we end up using.
Quoted 8 lines · John Cai via GitGitGadget
In [1], there was a discussion around a bug report of stash not recovering in the middle of the process. It turned out to not be a bug we need to fix. However, out of that discussion came the idea of libifying reflog. This can stand alone as a code improvement.
stash.ccurrently shells out to call reflog to delete reflogs. Libify reflog delete and call it from bothbuiltin/reflog.candbuiltin/stash.c.
Quoted 8 lines
This patch has three parts:
* libify reflog's delete functionality and move some of the helpers into a
reflog.clibrary and export them
* callreflog_deletefrombuiltin/reflog.c
* callreflog_deletefrombuiltin/stash.c
I just reviewed this in detail, it's very nice to see this done & another shell-out in our code API-ified.
There's at least one bad bug here (but easily fixed), and some nits etc. that I suggested mainly to make the diff easier to look at locally, but aside from those minor adjustments this looks very good to me.
Re: [PATCH 1/3] reflog: libify delete reflog function and helpers
In reply to John Cai via GitGitGadgetQuoted 5 lines · John Cai via GitGitGadget
From: John Cai <[email protected]>
Currently stash shells out to reflog in order to delete refs. In an effort to reduce how much we shell out to a subprocess, libify the functionality that stash needs into
reflog.c.
Sounds great. For other reviewers, looking at this with --color-moved if you have the patches applied locally makes it much easier to see what is going on here, which is basically:
- All of the implementation that used to be in builtin/reflog.c moved to reflog.c.
- The function signatures and structure declarations moved to reflog.h.
Quoted 3 lines
Add a
reflog_deletefunction that is pretty much the logic in the while loop inbuiltin/reflog.ccmd_reflog_delete(). This is a function thatbuiltin/reflog.candbuiltin/stash.ccan both call.
As you mentioned, the reflog_delete() implementation is indeed new. It looks like Ævar reviewed most of it already, so I'll take a look at his message before I end up repeating everything he already said ;).
It's worth noting that the subsequent clean-up to rewrite cmd_reflog_delete() in terms of your new reflog_delete() happens in the subsequent commit. If you end up rerolling this series, mentioning that here may be worthwhile.
One question that I had which I don't see answered already is what the plan is for existing reflog-related functions that live in refs.h. Should or will those functions be moved to the new reflog-specific header, too?
Thanks,
Taylor
Re: [PATCH 1/3] reflog: libify delete reflog function and helpers
In reply to Ævar Arnfjörð BjarmasonQuoted 26 lines · Ævar Arnfjörð Bjarmason
Quoted 12 lines
reflog.c new file +12
-0+int reflog_delete (const char *rev,int flags,int verbose) +{ +struct cmd_reflog_expire_cb cmd = {0 }; +int status =0 ; +reflog_expiry_should_prune_fn *should_prune_fn = should_expire_reflog_ent; +const char *spec =strstr (rev,"@{" ); +char *ep, *ref; +int recno; +struct expire_reflog_policy_cb cb = { + .dry_run = !!(flags &EXPIRE_REFLOGS_DRY_RUN ), + }; +reflog.c line 408
Quoted 10 lines
reflog.c new file +10
-0+if (verbose) + should_prune_fn = should_expire_reflog_ent_verbose; + +if (!spec) { + status |=error (_ ("not a reflog: %s" ), rev); + } + +if (!dwim_log (rev, spec - rev,NULL , &ref)) { + status |=error (_ ("no reflog for '%s'" ), rev); + }For these let's follow our usual style of not having braces for single-line if's.
Quoted 4 lines
Buuuut in this case doing so will make the diff move detection less useful for 1..2.
So probably best to leave it, or do some post-cleanup at the end maybe.
Hmm. I don't think the diff detection mechanism would have an opportunity to kick in here, since the code is added in one patch and then removed in another. I think I may be missing what you're trying to say here ;).
In any case, I don't think it's a huge deal if we can't accurately colorize this with --color-moved, so I'd probably just as soon clean up the style nits in this patch.
Quoted 21 lines
Quoted 6 lines
reflog.h new file +6
-0+int reflog_delete (const char *,int ,int ); +void reflog_expiry_cleanup (void *); +void reflog_expiry_prepare (const char *,const struct object_id *, +void *); +int should_expire_reflog_ent(struct object_id *, struct object_id*, + const char *, timestamp_t, int,reflog.h line 49
Quoted 10 lines
reflog.h new file +10
-0+ const char *, void *); +int count_reflog_ent (struct object_id *ooid,struct object_id *noid, +const char *email,timestamp_t timestamp,int tz, +const char *message,void *cb_data); +int should_expire_reflog_ent_verbose (struct object_id *, +struct object_id *, +const char *, +timestamp_t ,int , +const char *,void *); +#endif /* REFLOG_H */ Just a style preference, but I for one prefer the style where we retain the parameter names, it helps to read these, especially when we add API docs here.
Quoted 3 lines
Some of these are mis-indented. We align with the opening "(" with "\t" = 8 chars, so e.g. 2x \t + 5 SP for the
count_reflog_ent()arguments etc.
Thanks for noting on both.
Thanks,
Taylor
Re: [PATCH 1/3] reflog: libify delete reflog function and helpers
Quoted 32 lines · Taylor Blau
Quoted 26 lines · Ævar Arnfjörð Bjarmason
Quoted 12 lines
reflog.c new file +12
-0+int reflog_delete (const char *rev,int flags,int verbose) +{ +struct cmd_reflog_expire_cb cmd = {0 }; +int status =0 ; +reflog_expiry_should_prune_fn *should_prune_fn = should_expire_reflog_ent; +const char *spec =strstr (rev,"@{" ); +char *ep, *ref; +int recno; +struct expire_reflog_policy_cb cb = { + .dry_run = !!(flags &EXPIRE_REFLOGS_DRY_RUN ), + }; +reflog.c line 408
Quoted 10 lines
reflog.c new file +10
-0+if (verbose) + should_prune_fn = should_expire_reflog_ent_verbose; + +if (!spec) { + status |=error (_ ("not a reflog: %s" ), rev); + } + +if (!dwim_log (rev, spec - rev,NULL , &ref)) { + status |=error (_ ("no reflog for '%s'" ), rev); + }For these let's follow our usual style of not having braces for single-line if's.
Quoted 4 lines
Buuuut in this case doing so will make the diff move detection less useful for 1..2.
So probably best to leave it, or do some post-cleanup at the end maybe.
Quoted 8 lines
Hmm. I don't think the diff detection mechanism would have an opportunity to kick in here, since the code is added in one patch and then removed in another. I think I may be missing what you're trying to say here ;).
In any case, I don't think it's a huge deal if we can't accurately colorize this with
--color-moved, so I'd probably just as soon clean up the style nits in this patch.
Yes, this should really be read in combination with my comment on 2/3 to squash that commit into 1/3 to take full advantage of that, sorry.
Re: [PATCH 1/3] reflog: libify delete reflog function and helpers
In reply to John Cai via GitGitGadgetQuoted 6 lines · John Cai via GitGitGadget
reflog.h new file +0
-0
reflog.h line 10
Quoted 10 lines
reflog.h new file +10
-0@@ -0,0 +1,49 @@ +#ifndef REFLOG_H +#define REFLOG_H + +#include "cache.h" +#include "commit.h" + +/* Remember to update object flag allocation in object.h */ +#define INCOMPLETE (1u<<10) +#define STUDYING (1u<<11) +#define REACHABLE (1u<<12)
These names were unique enough back when they were part of internal implementation detail inside builtin/reflog.c but it no longer is in the scope it is visible. builtin/stash.c (and whatever other things that may want to deal with reflogs in the future) is about stash entries and wants to have a way to differentiate these symbols from others and hint that these are about reflog operation.
Perhaps prefix them with REFLOG_ or something?
Or, do we even NEED to expose these bits outside the implementation of reflog.c? If these three constants are used ONLY by reflog.c and not by builtin/reflog.c (or builtin/stash.c), then moving them to where they are used, i.e. in reflog.c, without exposing them to others in reflog.h, would be a far better thing to do. That way, they can stay with their original name, without having to add a differentiating prefix.
I also checked if any of the following struct's can be left as a private implementation detail, but they are shared between reflog.c and builtin/reflog.c and need to be in reflog.h
Quoted 38 lines
reflog.h new file +38
-0+struct cmd_reflog_expire_cb { +int stalefix; +int explicit_expiry; +timestamp_t expire_total; +timestamp_t expire_unreachable; +int recno; +}; + +struct expire_reflog_policy_cb { +enum { +UE_NORMAL , +UE_ALWAYS , +UE_HEAD + } unreachable_expire_kind; +struct commit_list *mark_list; +unsigned long mark_limit; +struct cmd_reflog_expire_cb cmd; +struct commit *tip_commit; +struct commit_list *tips; +unsigned int dry_run:1 ; +}; + +int reflog_delete (const char *,int ,int ); +void reflog_expiry_cleanup (void *); +void reflog_expiry_prepare (const char *,const struct object_id *, +void *); +int should_expire_reflog_ent (struct object_id *,struct object_id *, +const char *,timestamp_t ,int , +const char *,void *); +int count_reflog_ent (struct object_id *ooid,struct object_id *noid, +const char *email,timestamp_t timestamp,int tz, +const char *message,void *cb_data); +int should_expire_reflog_ent_verbose (struct object_id *, +struct object_id *, +const char *, +timestamp_t ,int , +const char *,void *); +#endif /* REFLOG_H */
Re: [PATCH 1/3] reflog: libify delete reflog function and helpers
In reply to John Cai via GitGitGadgetQuoted 9 lines · John Cai via GitGitGadget
From: John Cai <[email protected]>
Currently stash shells out to reflog in order to delete refs. In an effort to reduce how much we shell out to a subprocess, libify the functionality that stash needs into
reflog.c.Add a
reflog_deletefunction that is pretty much the logic in the while loop inbuiltin/reflog.ccmd_reflog_delete(). This is a function thatbuiltin/reflog.candbuiltin/stash.ccan both call.
I do not quite get this step. Yes, eventually cmd_reflog_delete() and cmd_stash() can both call the new reflog_delete() function, but at this step, cmd_reflog_delete() should ALREADY be able to call it, but I see duplicated code.
Why?
builtin/reflog.c static int cmd_reflog_delete(int argc, const char **argv, const char *prefix) · line 326
Quoted 8 lines
builtin/reflog.c +1
-0@@ -726,6 +320,7 @@ static int cmd_reflog_delete(int argc, const char **argv, const char *prefix)int i, status =0 ;unsigned int flags =0 ;int verbose =0 ; +reflog_expiry_should_prune_fn *should_prune_fn = should_expire_reflog_ent;const struct option options[] = { OPT_BIT(0, "dry-run", &flags, N_("do not actually prune any entries"),
In other words, why the only change this step makes to cmd_reflog_delete() is a style change here, instead of replacing the logic inside its "while loop" with a call to the new helper function, which is introduced ...
reflog.c line 388
Quoted 8 lines
reflog.c new file +2
-0+int reflog_delete (const char *rev,int flags,int verbose) +{
... here?
Quoted 6 lines
reflog.c new file +6
-0+struct cmd_reflog_expire_cb cmd = {0 }; +int status =0 ; +reflog_expiry_should_prune_fn *should_prune_fn = should_expire_reflog_ent; +const char *spec =strstr (rev,"@{" ); +char *ep, *ref; +int recno;
reflog.c line 404
Quoted 10 lines
reflog.c new file +10
-0+struct expire_reflog_policy_cb cb = { + .dry_run = !!(flags &EXPIRE_REFLOGS_DRY_RUN ), + }; + +if (verbose) + should_prune_fn = should_expire_reflog_ent_verbose; + +if (!spec) { + status |=error (_ ("not a reflog: %s" ), rev); + }
If this were "we moved one iteration of an existing loop to a separate function, while trying to keep what the existing code looked like as pristine as possible", then it is fine, but it does not look like that is what is going on (and I do not think it is feasible to do so, as the original being an interation in a loop, it has "continue" here, instead you'd need to arrange to return an error from here to allow the caller to work in a similar way).
So, if the patch is adding an adjusted implementation by removing "continue;" that is not suitable in the context of this helper, it should remove the now-unnecessary {braces} around the single-statement block.
But I think you should keep {braces} around, because the "if spec is NULL" case should not be a single-statement block. You'd need to return or this code is buggy.
reflog.c line 408
Quoted 3 lines
reflog.c new file +3
-0+if (!dwim_log (rev, spec - rev,NULL , &ref)) { + status |=error (_ ("no reflog for '%s'" ), rev); + }
I already hinted that the previous "if spec is NULL" code is buggy because it does not return to allow the original caller to keep working as before. Because you lack an early return there, you'll end up calling dwim_log with spec==NULL here, which does not end well.
Re: [PATCH 2/3] reflog: call reflog_delete from reflog.c
In reply to Ævar Arnfjörð BjarmasonQuoted 3 lines · Ævar Arnfjörð Bjarmason
Maybe others will disagree, but per my comment on 1/2 I found reviewing this locally much easier with this squashed into 1/2 (without the {} changes I suggested).
Oh, I am pretty much on the same page.
The if() block has to retain {} after all but not for the reason you cite (i.e. help "diff --color-moved"), but for correctness reasons it has to have some "early return to avoid using NULL" to replace "continue", which means the body of the if() statement needs to stay a two statement block.
Re: [PATCH 3/3] stash: call reflog_delete from reflog.c
In reply to Ævar Arnfjörð BjarmasonQuoted 20 lines · Ævar Arnfjörð Bjarmason
builtin/stash.c +3
-5@@ -635,11 +635,9 @@ static int reflog_is_empty(const char *refname)static int do_drop_stash (struct stash_info *info,int quiet) { -int ret; - ret =reflog_delete (info->revision.buf, -EXPIRE_REFLOGS_REWRITE |EXPIRE_REFLOGS_REWRITE , -0 ); -if (!ret) { +unsigned int flags =EXPIRE_REFLOGS_REWRITE |EXPIRE_REFLOGS_REWRITE ; + +if (!reflog_delete (info->revision.buf, flags,0 )) {if (!quiet)printf_ln (_ ("Dropped %s (%s)" ), info->revision.buf,oid_to_hex (&info->w_commit));
Quoted 4 lines
But, having written that I notice that we have
*_REWRITEtwice there, so I almost just carried forward a new bug in 3/3 when composing this :)So one should be
EXPIRE_REFLOGS_UPDATE_REF, presumably.
Thanks for pointing it out. Just thinking aloud here, the old code ran:
git reflog delete --updateref --rewrite
where --updateref sets the EXPIRE_REFLOGS_UPDATE_REF bit and -rewrite sets the EXPIRE_REFLOGS_REWRITE bit.
So yep, you and I have the same conclusion there, and one of these flags should be the UPDATE_REF variant.
Quoted 2 lines
And perhaps it's a big pain, but that suggests that the code isn't either used at all, or that we're missing a test for it.
I think this is much more in the "lacking test coverage" category than the "unused features we should remove" one.
Thanks,
Taylor
Re: [PATCH 1/3] reflog: libify delete reflog function and helpers
In reply to Junio C HamanoQuoted 28 lines · Junio C Hamano
Quoted 6 lines · John Cai via GitGitGadget
reflog.h new file +0
-0reflog.h line 10
Quoted 10 lines
reflog.h new file +10
-0@@ -0,0 +1,49 @@ +#ifndef REFLOG_H +#define REFLOG_H + +#include "cache.h" +#include "commit.h" + +/* Remember to update object flag allocation in object.h */ +#define INCOMPLETE (1u<<10) +#define STUDYING (1u<<11) +#define REACHABLE (1u<<12)These names were unique enough back when they were part of internal implementation detail inside
builtin/reflog.cbut it no longer is in the scope it is visible.builtin/stash.c(and whatever other things that may want to deal with reflogs in the future) is about stash entries and wants to have a way to differentiate these symbols from others and hint that these are about reflog operation.Perhaps prefix them with
REFLOG_or something?
Quoted 7 lines
Or, do we even NEED to expose these bits outside the implementation of
reflog.c? If these three constants are used ONLY byreflog.cand not bybuiltin/reflog.c(orbuiltin/stash.c), then moving them to where they are used, i.e. inreflog.c, without exposing them to others inreflog.h, would be a far better thing to do. That way, they can stay with their original name, without having to add a differentiating prefix.
No objection to this, but FWIW the general pattern for these object.h flags is to use these un-prefixed names:
git grep -A20 'Remember to update object flag allocation' | grep define
To be fair the only one that's really comparable is the revision.h ones, but those are very non-namespace-y, with names like SEEN, ADDED, SHOWN etc.
I'd be fine with just leaving these as-is, especially with compilers warning about macro re-definitions.
Re: [PATCH 1/3] reflog: libify delete reflog function and helpers
Quoted 42 lines · Ævar Arnfjörð Bjarmason
Quoted 28 lines · Junio C Hamano
Quoted 6 lines · John Cai via GitGitGadget
reflog.h new file +0
-0reflog.h line 10
Quoted 10 lines
reflog.h new file +10
-0@@ -0,0 +1,49 @@ +#ifndef REFLOG_H +#define REFLOG_H + +#include "cache.h" +#include "commit.h" + +/* Remember to update object flag allocation in object.h */ +#define INCOMPLETE (1u<<10) +#define STUDYING (1u<<11) +#define REACHABLE (1u<<12)These names were unique enough back when they were part of internal implementation detail inside
builtin/reflog.cbut it no longer is in the scope it is visible.builtin/stash.c(and whatever other things that may want to deal with reflogs in the future) is about stash entries and wants to have a way to differentiate these symbols from others and hint that these are about reflog operation.Perhaps prefix them with
REFLOG_or something?Quoted 7 lines
Or, do we even NEED to expose these bits outside the implementation of
reflog.c? If these three constants are used ONLY byreflog.cand not bybuiltin/reflog.c(orbuiltin/stash.c), then moving them to where they are used, i.e. inreflog.c, without exposing them to others inreflog.h, would be a far better thing to do. That way, they can stay with their original name, without having to add a differentiating prefix.No objection to this, but FWIW the general pattern for these
object.hflags is to use these un-prefixed names:
Quoted 8 lines
git grep -A20 'Remember to update object flag allocation' | grep define
To be fair the only one that's really comparable is the
revision.hones, but those are very non-namespace-y, with names like SEEN, ADDED, SHOWN etc.I'd be fine with just leaving these as-is, especially with compilers warning about macro re-definitions.
I think I have a mild preference to avoid polluting the set of macros with something like INCOMPLETE outside of reflog.c's compilation unit when possible. Though I don't really feel strongly either way.
In any case, let's make sure to update object.h's flag allocation table, which as of this patch still indicates that these bits belong to "builtin/reflog.c" (instead of "reflog.h" or "reflog.c", depending on what the outcome of this discussion is).
Thanks,
Taylor
Re: [PATCH 1/3] reflog: libify delete reflog function and helpers
In reply to Ævar Arnfjörð BjarmasonQuoted 10 lines · Ævar Arnfjörð Bjarmason
Quoted 9 lines
Perhaps prefix them with
REFLOG_or something?Or, do we even NEED to expose these bits outside the implementation of
reflog.c? If these three constants are used ONLY byreflog.cand not bybuiltin/reflog.c(orbuiltin/stash.c), then moving them to where they are used, i.e. inreflog.c, without exposing them to others inreflog.h, would be a far better thing to do. That way, they can stay with their original name, without having to add a differentiating prefix.
Quoted 8 lines
No objection to this, but FWIW the general pattern for these
object.hflags is to use these un-prefixed names:git grep -A20 'Remember to update object flag allocation' | grep define
To be fair the only one that's really comparable is the
revision.hones, but those are very non-namespace-y, with names like SEEN, ADDED, SHOWN etc.
Yes, but I consider that revision.h owns the flag bits, and all others that are local to a single *.c files borrow leftover bits (and that is why the allocations can be overlapping).
And that is why my preference is to keep these within reflog.c if we are separating it out of builtin/reflog.c to make sure they do not pollute global namespace.
Re: [PATCH 1/3] reflog: libify delete reflog function and helpers
In reply to Taylor BlauHey Taylor,
Quoted 30 lines · Taylor Blau
Quoted 5 lines · John Cai via GitGitGadget
From: John Cai <[email protected]>
Currently stash shells out to reflog in order to delete refs. In an effort to reduce how much we shell out to a subprocess, libify the functionality that stash needs into
reflog.c.Sounds great. For other reviewers, looking at this with
--color-movedif you have the patches applied locally makes it much easier to see what is going on here, which is basically:- All of the implementation that used to be in
builtin/reflog.cmoved toreflog.c.- The function signatures and structure declarations moved to
reflog.h.Quoted 3 lines
Add a
reflog_deletefunction that is pretty much the logic in the while loop inbuiltin/reflog.ccmd_reflog_delete(). This is a function thatbuiltin/reflog.candbuiltin/stash.ccan both call.As you mentioned, the
reflog_delete()implementation is indeed new. It looks like Ævar reviewed most of it already, so I'll take a look at his message before I end up repeating everything he already said ;).It's worth noting that the subsequent clean-up to rewrite
cmd_reflog_delete()in terms of your newreflog_delete()happens in the subsequent commit. If you end up rerolling this series, mentioning that here may be worthwhile.
Quoted 4 lines
One question that I had which I don't see answered already is what the plan is for existing reflog-related functions that live in
refs.h. Should or will those functions be moved to the new reflog-specific header, too?
Thanks for bringing ths up! Maybe this cleanup can be included in a separate patch series since this one is mainly about getting rid of the shell-out in stash.c. What do you think?
Quoted 3 lines
Thanks,
Taylor
Re: [PATCH 1/3] reflog: libify delete reflog function and helpers
Quoted 8 lines · John Cai
Quoted 4 lines
One question that I had which I don't see answered already is what the plan is for existing reflog-related functions that live in
refs.h. Should or will those functions be moved to the new reflog-specific header, too?Thanks for bringing ths up! Maybe this cleanup can be included in a separate patch series since this one is mainly about getting rid of the shell-out in
stash.c. What do you think?
Yeah; I think that's fine. We don't need to get all reflog-related functions moved into reflog.h in the first series, so I think it's fine to move things as you discover them.
I was just wondering whether it was something you planned to do at some point (as part of this series, or a future one).
Thanks,
Taylor
Re: [PATCH 3/3] stash: call reflog_delete from reflog.c
In reply to Ævar Arnfjörð BjarmasonHi Ævar,
Quoted 74 lines · Ævar Arnfjörð Bjarmason
Quoted 10 lines · John Cai via GitGitGadget
From: John Cai <[email protected]>
Now that
cmd_reflog_deletehas been libified an exported it into a newreflog.clibrary so we can call it directly frombuiltin/stash.c. This not only gives us a performance gain since we don't need to create a subprocess, but it also allows us to use the ref transactions api in the future.Signed-off-by John Cai <[email protected]>Very nicely done, and nice that despite the ~500 lines added/removed in the diffstat that the "actual" changes in this series are so small.q
Review static int reflog_is_empty(const char *refname) · line 639
Quoted 6 lines
(quoted diff) +0
-2@@ -635,18 +636,9 @@ static int reflog_is_empty(const char *refname) static int do_drop_stash(struct stash_info *info, int quiet) { int ret; - struct child_process cp_reflog = CHILD_PROCESS_INIT; -Nit: We usually separate variables decls with a \n\n, as is done in the pre-image, but you end up dropping that.
Quoted 6 lines
(quoted diff) +0
-6- /* - * reflog does not provide a simple function for deleting refs. One will - * need to be added to avoid implementing too much reflog code here - */ - - cp_reflog.git_cmd = 1;Review static int reflog_is_empty(const char *refname) · line 644
Quoted 10 lines
(quoted diff) +3
-4- strvec_pushl(&cp_reflog.args, "reflog", "delete", "--updateref", - "--rewrite", NULL); - strvec_push(&cp_reflog.args, info->revision.buf); - ret = run_command(&cp_reflog); + ret = reflog_delete(info->revision.buf, + EXPIRE_REFLOGS_REWRITE | EXPIRE_REFLOGS_REWRITE, + 0); if (!ret) { if (!quiet) printf_ln(_("Dropped %s (%s)"), info->revision.buf,I think per the above squashing this in would be nice, i.e. you get rid of the long line & it'sclear that "ret" is not used for anything now:
builtin/stash.c +3
-5@@ -635,11 +635,9 @@ static int reflog_is_empty(const char *refname)static int do_drop_stash (struct stash_info *info,int quiet) { -int ret; - ret =reflog_delete (info->revision.buf, -EXPIRE_REFLOGS_REWRITE |EXPIRE_REFLOGS_REWRITE , -0 ); -if (!ret) { +unsigned int flags =EXPIRE_REFLOGS_REWRITE |EXPIRE_REFLOGS_REWRITE ; + +if (!reflog_delete (info->revision.buf, flags,0 )) {if (!quiet)printf_ln (_ ("Dropped %s (%s)" ), info->revision.buf,oid_to_hex (&info->w_commit));But, having written that I notice that we have
*_REWRITEtwice there, so I almost just carried forward a new bug in 3/3 when composing this :)So one should be
EXPIRE_REFLOGS_UPDATE_REF, presumably.And perhaps it's a big pain, but that suggests that the code isn't either used at all, or that we're missing a test for it.
Quoted 7 lines
So adding a prep commit to this series where we either drop it, or add the missing test would be a very nice addition.
See my quite recent
5ac15ad2509(reflog tests: add --updateref tests, 2021-10-16) for adding such tests, but in that case I just covered "git reflog" itself, not "git stash". Maybe we can just add something to that for-loop in t1417 (or similar for a new stash test).
So I was trying to write a test to exercise the reflog --updateref and --rewrite cases. --updateref is pretty straightforward, but with --rewrite I noticed that it rewrites the old sha in the .git/log/refs/stash file. But, I was having trouble finding somewhere that read this value. The test could reach into this file and check the literal contents, but wondering if there is a better way. Any help appreciated!
Quoted 6 lines
Also, a s/unsigned int flags/enum expire_reflog_flags/ while we're at it would be very nice here, but that could be done as another small prep commit. I.e. it's *not* a new issue since
cmd_reflog_delete()had it before, but when converting this to a documented API it would be very nice to have it reflect the actual type we end up using.
Re: [PATCH 3/3] stash: call reflog_delete from reflog.c
Quoted 81 lines · John Cai
Hi Ævar,
Quoted 77 lines · Ævar Arnfjörð Bjarmason
Quoted 10 lines · John Cai via GitGitGadget
From: John Cai <[email protected]>
Now that
cmd_reflog_deletehas been libified an exported it into a newreflog.clibrary so we can call it directly frombuiltin/stash.c. This not only gives us a performance gain since we don't need to create a subprocess, but it also allows us to use the ref transactions api in the future.Signed-off-by John Cai <[email protected]>Very nicely done, and nice that despite the ~500 lines added/removed in the diffstat that the "actual" changes in this series are so small.q
Review static int reflog_is_empty(const char *refname) · line 639
Quoted 6 lines
(quoted diff) +0
-2@@ -635,18 +636,9 @@ static int reflog_is_empty(const char *refname) static int do_drop_stash(struct stash_info *info, int quiet) { int ret; - struct child_process cp_reflog = CHILD_PROCESS_INIT; -Nit: We usually separate variables decls with a \n\n, as is done in the pre-image, but you end up dropping that.
Quoted 6 lines
(quoted diff) +0
-6- /* - * reflog does not provide a simple function for deleting refs. One will - * need to be added to avoid implementing too much reflog code here - */ - - cp_reflog.git_cmd = 1;Review static int reflog_is_empty(const char *refname) · line 644
Quoted 10 lines
(quoted diff) +3
-4- strvec_pushl(&cp_reflog.args, "reflog", "delete", "--updateref", - "--rewrite", NULL); - strvec_push(&cp_reflog.args, info->revision.buf); - ret = run_command(&cp_reflog); + ret = reflog_delete(info->revision.buf, + EXPIRE_REFLOGS_REWRITE | EXPIRE_REFLOGS_REWRITE, + 0); if (!ret) { if (!quiet) printf_ln(_("Dropped %s (%s)"), info->revision.buf,I think per the above squashing this in would be nice, i.e. you get rid of the long line & it'sclear that "ret" is not used for anything now:
builtin/stash.c +3
-5@@ -635,11 +635,9 @@ static int reflog_is_empty(const char *refname)static int do_drop_stash (struct stash_info *info,int quiet) { -int ret; - ret =reflog_delete (info->revision.buf, -EXPIRE_REFLOGS_REWRITE |EXPIRE_REFLOGS_REWRITE , -0 ); -if (!ret) { +unsigned int flags =EXPIRE_REFLOGS_REWRITE |EXPIRE_REFLOGS_REWRITE ; + +if (!reflog_delete (info->revision.buf, flags,0 )) {if (!quiet)printf_ln (_ ("Dropped %s (%s)" ), info->revision.buf,oid_to_hex (&info->w_commit));But, having written that I notice that we have
*_REWRITEtwice there, so I almost just carried forward a new bug in 3/3 when composing this :)So one should be
EXPIRE_REFLOGS_UPDATE_REF, presumably.And perhaps it's a big pain, but that suggests that the code isn't either used at all, or that we're missing a test for it.
So adding a prep commit to this series where we either drop it, or add the missing test would be a very nice addition.
Quoted 10 lines
Quoted 4 lines
See my quite recent
5ac15ad2509(reflog tests: add --updateref tests, 2021-10-16) for adding such tests, but in that case I just covered "git reflog" itself, not "git stash". Maybe we can just add something to that for-loop in t1417 (or similar for a new stash test).So I was trying to write a test to exercise the reflog --updateref and --rewrite cases. --updateref is pretty straightforward, but with --rewrite I noticed that it rewrites the old sha in the .git/log/refs/stash file. But, I was having trouble finding somewhere that read this value. The test could reach into this file and check the literal contents, but wondering if there is a better way. Any help appreciated!
I can check it out, but to make that easier can you share the WIP diff you have for getting the test setup that far?
I think you mean that it munges the SHA-1 on the LHS of .git/refs/logs/stash, I tried to do that now locally and I didn't come up with some way where you could observably make "git stash show", "git stash list" etc. show anything different.
I.e. it'll just promiscuously show whatever OID is on the RHS, even in cases where some of them are turned into "deadbeef..." (i.e. "list", but "show" will die).
So maybe it's just observable with a subsequent "git fsck", but I just tried composing a reflog with these entries:
0000000000000000000000000000000000000000 A
A B
B CAnd then manually changing it to:
0000000000000000000000000000000000000000 A
A B
A CWhich "git fsck" will pass, and only complain if that "A" isn't a valid OID at all.
Anyway, if there isn't a way to get fsck/reflog to spew it out, but we want to assert that it's correct wouldn't this catch it (will need to depend on REFFILES) (untested):
cut -d' ' -f1-2 .git/logs/refs/stash >actual && cat >expect <<-EOF && $(test_oid zero) $(git rev-parse ...) $(git rev-parse ...) $(git rev-parse ...) EOF test_cmp expect actual
I.e. to simply run whatever operation we do now, check that the OIDs match what we expect, and which would be different if one of these flags wasn't given?
Quoted 6 lines
Quoted 6 lines
Also, a s/unsigned int flags/enum expire_reflog_flags/ while we're at it would be very nice here, but that could be done as another small prep commit. I.e. it's *not* a new issue since
cmd_reflog_delete()had it before, but when converting this to a documented API it would be very nice to have it reflect the actual type we end up using.
v2 cover libify reflog
In reply to John Cai via GitGitGadgetIn [1], there was a discussion around a bug report of stash not recovering in the middle of the process when killed with ctl-c. It turned out to not be a bug we need to fix. However, out of that discussion came the idea of libifying reflog. This can stand alone as a code improvement.
stash.c currently shells out to call reflog to delete reflogs. Libify reflog delete and call it from both builtin/reflog.c and builtin/stash.c.
This patch has three parts:
* add missing test coverage for git stash delete
* libify reflog's delete functionality and move some of the helpers into a reflog.c library and call reflog_delete from builtin/reflog.c
* call reflog_delete from builtin/stash.c
Updates since v1:
* added missing test coverage
* squashed 1/3 and 2/3 together
* moved enum into reflog.c
* updated object.h's flag allocation mapping
1. https://lore.kernel.org/git/[email protected]/
John Cai (3):
stash: add test to ensure reflog --rewrite --updatref behavior
reflog: libify delete reflog function and helpers
stash: call reflog_delete() in reflog.c
Makefile | 1 + builtin/reflog.c | 451 +---------------------------------------------- builtin/stash.c | 18 +- object.h | 2 +- reflog.c | 435 +++++++++++++++++++++++++++++++++++++++++++++ reflog.h | 49 +++++ t/t3903-stash.sh | 25 ++- 7 files changed, 518 insertions(+), 463 deletions(-) create mode 100644 reflog.c create mode 100644 reflog.h
base-commit: e6ebfd0e8cbbd10878070c8a356b5ad1b3ca464e
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-1218%2Fjohn-cai%2Fjc-libify-reflog-v2
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-1218/john-cai/jc-libify-reflog-v2
Pull-Request: https://github.com/git/git/pull/1218
Range-diff vs v1:
-: ----------- > 1: 6e136b62ca4 stash: add test to ensure reflog --rewrite --updatref behavior
1: 9e17ece8d89 ! 2: e7c950218b1 reflog: libify delete reflog function and helpers
@@ builtin/reflog.c: static int cmd_reflog_expire(int argc, const char **argv, cons
static const char * reflog_delete_usage[] = {
N_("git reflog delete [--rewrite] [--updateref] "
"[--dry-run | -n] [--verbose] <refs>..."),
-@@ builtin/reflog.c: static int cmd_reflog_delete(int argc, const char **argv, const char *prefix)
+@@ builtin/reflog.c: static const char * reflog_delete_usage[] = {
+
+ static int cmd_reflog_delete(int argc, const char **argv, const char *prefix)
+ {
+- struct cmd_reflog_expire_cb cmd = { 0 };
int i, status = 0;
unsigned int flags = 0;
int verbose = 0;
+- reflog_expiry_should_prune_fn *should_prune_fn = should_expire_reflog_ent;
+
- reflog_expiry_should_prune_fn *should_prune_fn = should_expire_reflog_ent;
const struct option options[] = {
OPT_BIT(0, "dry-run", &flags, N_("do not actually prune any entries"),
+ EXPIRE_REFLOGS_DRY_RUN),
+@@ builtin/reflog.c: static int cmd_reflog_delete(int argc, const char **argv, const char *prefix)
+
+ argc = parse_options(argc, argv, prefix, options, reflog_delete_usage, 0);
+
+- if (verbose)
+- should_prune_fn = should_expire_reflog_ent_verbose;
+-
+ if (argc < 1)
+ return error(_("no reflog specified to delete"));
+
+- for (i = 0; i < argc; i++) {
+- const char *spec = strstr(argv[i], "@{");
+- char *ep, *ref;
+- int recno;
+- struct expire_reflog_policy_cb cb = {
+- .dry_run = !!(flags & EXPIRE_REFLOGS_DRY_RUN),
+- };
+-
+- if (!spec) {
+- status |= error(_("not a reflog: %s"), argv[i]);
+- continue;
+- }
++ for (i = 0; i < argc; i++)
++ status |= reflog_delete(argv[i], flags, verbose);
+
+- if (!dwim_log(argv[i], spec - argv[i], NULL, &ref)) {
+- status |= error(_("no reflog for '%s'"), argv[i]);
+- continue;
+- }
+-
+- recno = strtoul(spec + 2, &ep, 10);
+- if (*ep == '}') {
+- cmd.recno = -recno;
+- for_each_reflog_ent(ref, count_reflog_ent, &cmd);
+- } else {
+- cmd.expire_total = approxidate(spec + 2);
+- for_each_reflog_ent(ref, count_reflog_ent, &cmd);
+- cmd.expire_total = 0;
+- }
+-
+- cb.cmd = cmd;
+- status |= reflog_expire(ref, flags,
+- reflog_expiry_prepare,
+- should_prune_fn,
+- reflog_expiry_cleanup,
+- &cb);
+- free(ref);
+- }
+ return status;
+ }
+
+
+ ## object.h ##
+@@ object.h: struct object_array {
+ * builtin/fsck.c: 0--3
+ * builtin/gc.c: 0
+ * builtin/index-pack.c: 2021
+- * builtin/reflog.c: 10--12
++ * reflog.c: 10--12
+ * builtin/show-branch.c: 0-------------------------------------------26
+ * builtin/unpack-objects.c: 2021
+ */
## reflog.c (new) ##
@@
@@ reflog.c (new)
+#include "tree-walk.h"
+#include "worktree.h"
+
++/* Remember to update object flag allocation in object.h */
++#define INCOMPLETE (1u<<10)
++#define STUDYING (1u<<11)
++#define REACHABLE (1u<<12)
++
+static int tree_is_complete(const struct object_id *oid)
+{
+ struct tree_desc desc;
@@ reflog.c (new)
+ return 0;
+}
+
-+int reflog_delete(const char *rev, int flags, int verbose)
++int reflog_delete(const char *rev, enum expire_reflog_flags flags, int verbose)
+{
+ struct cmd_reflog_expire_cb cmd = { 0 };
+ int status = 0;
@@ reflog.c (new)
+ if (verbose)
+ should_prune_fn = should_expire_reflog_ent_verbose;
+
-+ if (!spec) {
-+ status |= error(_("not a reflog: %s"), rev);
-+ }
++ if (!spec)
++ return error(_("not a reflog: %s"), rev);
+
+ if (!dwim_log(rev, spec - rev, NULL, &ref)) {
+ status |= error(_("no reflog for '%s'"), rev);
++ goto cleanup;
+ }
+
-+ if (status)
-+ return status;
-+
+ recno = strtoul(spec + 2, &ep, 10);
+ if (*ep == '}') {
+ cmd.recno = -recno;
@@ reflog.c (new)
+ should_prune_fn,
+ reflog_expiry_cleanup,
+ &cb);
-+ free(ref);
+
++ cleanup:
++ free(ref);
+ return status;
+}
@@ reflog.h (new)
+#ifndef REFLOG_H
+#define REFLOG_H
+
-+#include "cache.h"
-+#include "commit.h"
-+
-+/* Remember to update object flag allocation in object.h */
-+#define INCOMPLETE (1u<<10)
-+#define STUDYING (1u<<11)
-+#define REACHABLE (1u<<12)
++#include "refs.h"
+
+struct cmd_reflog_expire_cb {
+ int stalefix;
@@ reflog.h (new)
+ unsigned int dry_run:1;
+};
+
-+int reflog_delete(const char*, int, int);
-+void reflog_expiry_cleanup(void *);
-+void reflog_expiry_prepare(const char*, const struct object_id*,
-+ void *);
-+int should_expire_reflog_ent(struct object_id *, struct object_id*,
-+ const char *, timestamp_t, int,
-+ const char *, void *);
++int reflog_delete(const char *rev, enum expire_reflog_flags flags, int verbose);
++
++void reflog_expiry_cleanup(void *cb_data);
++
++void reflog_expiry_prepare(const char *refname, const struct object_id *oid,
++ void *cb_data);
++
++int should_expire_reflog_ent(struct object_id *ooid, struct object_id *noid,
++ const char *email, timestamp_t timestamp, int tz,
++ const char *message, void *cb_data);
++
+int count_reflog_ent(struct object_id *ooid, struct object_id *noid,
-+ const char *email, timestamp_t timestamp, int tz,
-+ const char *message, void *cb_data);
-+int should_expire_reflog_ent_verbose(struct object_id *,
-+ struct object_id *,
-+ const char *,
-+ timestamp_t, int,
-+ const char *, void *);
++ const char *email, timestamp_t timestamp, int tz,
++ const char *message, void *cb_data);
++
++int should_expire_reflog_ent_verbose(struct object_id *ooid,
++ struct object_id *noid,
++ const char *email,
++ timestamp_t timestamp, int tz,
++ const char *message, void *cb_data);
++
+#endif /* REFLOG_H */
2: e4c0047a17c < -: ----------- reflog: call reflog_delete from reflog.c
3: bcc1eae0531 ! 3: a023a70092b stash: call reflog_delete from reflog.c
@@ Metadata
Author: John Cai <[email protected]>
## Commit message ##
- stash: call reflog_delete from reflog.c
+ stash: call reflog_delete() in reflog.c
Now that cmd_reflog_delete has been libified an exported it into a new
reflog.c library so we can call it directly from builtin/stash.c. This
@@ builtin/stash.c
#define INCLUDE_ALL_FILES 2
@@ builtin/stash.c: static int reflog_is_empty(const char *refname)
+
static int do_drop_stash(struct stash_info *info, int quiet)
{
- int ret;
+- int ret;
- struct child_process cp_reflog = CHILD_PROCESS_INIT;
-
- /*
@@ builtin/stash.c: static int reflog_is_empty(const char *refname)
- "--rewrite", NULL);
- strvec_push(&cp_reflog.args, info->revision.buf);
- ret = run_command(&cp_reflog);
-+ ret = reflog_delete(info->revision.buf,
-+ EXPIRE_REFLOGS_REWRITE | EXPIRE_REFLOGS_REWRITE,
-+ 0);
- if (!ret) {
+- if (!ret) {
++ if (!reflog_delete(info->revision.buf,
++ EXPIRE_REFLOGS_REWRITE | EXPIRE_REFLOGS_UPDATE_REF,
++ 0)) {
if (!quiet)
printf_ln(_("Dropped %s (%s)"), info->revision.buf,
+ oid_to_hex(&info->w_commit));Signature · 1 line
gitgitgadget
PATCH v2 1/3 stash: add test to ensure reflog --rewrite --updatref behavior
From: John Cai <[email protected]>
There is missing test coverage to ensure that the resulting reflogs after a git stash drop has had its old oid rewritten if applicable, and if the refs/stash has been updated if applicable.
Add two tests that verify both of these happen.
--- t/t3903-stash.sh | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-)
t/t3903-stash.sh +24 -1
@@ -185,10 +185,33 @@ test_expect_success 'drop middle stash by index' ' test 1 = $(git show HEAD:file) ' +test_expect_success 'drop stash reflog updates refs/stash' ' + git reset --hard && + git rev-parse refs/stash >expect && + echo 9 >file && + git stash && + git stash drop stash@{0} && + git rev-parse refs/stash >actual && + test_cmp expect actual +' + +test_expect_success 'drop stash reflog updates refs/stash with rewrite' ' + git reset --hard && + echo 9 >file && + git stash && + oid="$(git rev-parse stash@{0})" && + git stash drop stash@{1} && + cut -d" " -f1-2 .git/logs/refs/stash >actual && + cat >expect <<-EOF && + $(test_oid zero) $oid + EOF + test_cmp expect actual +' + test_expect_success 'stash pop' ' git reset --hard && git stash pop && - test 3 = $(cat file) && + test 9 = $(cat file) && test 1 = $(git show :file) && test 1 = $(git show HEAD:file) && test 0 = $(git stash list | wc -l)
Signature · 1 line
gitgitgadget
PATCH v2 2/3 reflog: libify delete reflog function and helpers
In reply to John Cai via GitGitGadgetFrom: John Cai <[email protected]>
Currently stash shells out to reflog in order to delete refs. In an effort to reduce how much we shell out to a subprocess, libify the functionality that stash needs into reflog.c.
Add a reflog_delete function that is pretty much the logic in the while loop in builtin/reflog.c cmd_reflog_delete(). This is a function that builtin/reflog.c and builtin/stash.c can both call.
Also move functions needed by reflog_delete and export them.
--- Makefile | 1 + builtin/reflog.c | 451 +---------------------------------------------- object.h | 2 +- reflog.c | 435 +++++++++++++++++++++++++++++++++++++++++++++ reflog.h | 49 +++++ 5 files changed, 490 insertions(+), 448 deletions(-) create mode 100644 reflog.c create mode 100644 reflog.h
Makefile +1 -0
@@ -989,6 +989,7 @@ LIB_OBJS += rebase-interactive.o LIB_OBJS += rebase.o LIB_OBJS += ref-filter.o LIB_OBJS += reflog-walk.o +LIB_OBJS += reflog.o LIB_OBJS += refs.o LIB_OBJS += refs/debug.o LIB_OBJS += refs/files-backend.o
builtin/reflog.c +4 -447
499 lines not on this page · raw message
object.h +1 -1
@@ -75,7 +75,7 @@ struct object_array {* builtin/fsck.c: 0--3 * builtin/gc.c: 0 * builtin/index-pack.c: 2021 -* builtin/reflog.c: 10--12 +* reflog.c: 10--12 * builtin/show-branch.c: 0-------------------------------------------26 * builtin/unpack-objects.c: 2021 */
reflog.c new file +435 -0
435 lines not on this page · raw message
reflog.h new file +49 -0
49 lines not on this page · raw message
Signature · 1 line
gitgitgadget
PATCH v2 3/3 stash: call reflog_delete() in reflog.c
In reply to John Cai via GitGitGadgetFrom: John Cai <[email protected]>
Now that cmd_reflog_delete has been libified an exported it into a new reflog.c library so we can call it directly from builtin/stash.c. This not only gives us a performance gain since we don't need to create a subprocess, but it also allows us to use the ref transactions api in the future.
--- builtin/stash.c | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-)
builtin/stash.c +4 -14
@@ -17,6 +17,7 @@#include "diffcore.h" #include "exec-cmd.h" #include "entry.h" +#include "reflog.h" #define INCLUDE_ALL_FILES 2
@@ -634,20 +635,9 @@ static int reflog_is_empty(const char *refname)static int do_drop_stash (struct stash_info *info,int quiet) { -int ret; -struct child_process cp_reflog =CHILD_PROCESS_INIT ; - -/* -* reflog does not provide a simple function for deleting refs. One will -* need to be added to avoid implementing too much reflog code here -*/ - - cp_reflog.git_cmd =1 ; -strvec_pushl (&cp_reflog.args,"reflog" ,"delete" ,"--updateref" , -"--rewrite" ,NULL ); -strvec_push (&cp_reflog.args, info->revision.buf); - ret =run_command (&cp_reflog); -if (!ret) { +if (!reflog_delete (info->revision.buf, +EXPIRE_REFLOGS_REWRITE |EXPIRE_REFLOGS_UPDATE_REF , +0 )) {if (!quiet)printf_ln (_ ("Dropped %s (%s)" ), info->revision.buf,oid_to_hex (&info->w_commit));
Signature · 1 line
gitgitgadget
Re: [PATCH v2 1/3] stash: add test to ensure reflog --rewrite --updatref behavior
In reply to John Cai via GitGitGadgetQuoted 5 lines · John Cai via GitGitGadget
From: John Cai <[email protected]>
There is missing test coverage to ensure that the resulting reflogs after a git stash drop has had its old oid rewritten if applicable, and if the refs/stash has been updated if applicable.
This test looks good, and if 3/3 is applied and either of the flags you're passing is omitted they'll fail, so we know we have the missing coverage here.
Quoted 13 lines
Signed-off-by John Cai <[email protected]>--- t/t3903-stash.sh | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-)t/t3903-stash.sh +0
-0@@ -185,10 +185,33 @@ test_expect_success 'drop middle stash by index' ' test 1 = $(git show HEAD:file) '
t/t3903-stash.sh test_expect_success 'drop middle stash by index' ' · line 196
Quoted 10 lines
t/t3903-stash.sh +9
-0+test_expect_success 'drop stash reflog updates refs/stash' ' + git reset --hard && + git rev-parse refs/stash >expect && + echo 9 >file && + git stash && + git stash drop stash@{0} && + git rev-parse refs/stash >actual && + test_cmp expect actual +'
This one will be portable to the reftable backend.
t/t3903-stash.sh test_expect_success 'drop middle stash by index' ' · line 197
Quoted 1 line
t/t3903-stash.sh +1
-0+test_expect_success 'drop stash reflog updates refs/stash with rewrite' '
But as I noted in <[email protected]> (but it was easy to miss) this test will need to depend on REFFILES. So just changing this line to:
test_expect_success REFFILES 'drop stash[...]'
t/t3903-stash.sh test_expect_success 'drop middle stash by index' ' · line 208
Quoted 11 lines
t/t3903-stash.sh +11
-0+ git reset --hard && + echo 9 >file && + git stash && + oid="$(git rev-parse stash@{0})" && + git stash drop stash@{1} && + cut -d" " -f1-2 .git/logs/refs/stash >actual && + cat >expect <<-EOF && + $(test_oid zero) $oid + EOF + test_cmp expect actual +'
Then:
t/t3903-stash.sh test_expect_success 'drop middle stash by index' ' · line 215
Quoted 8 lines
t/t3903-stash.sh +1
-1test_expect_success 'stash pop' ' git reset --hard && git stash pop && - test 3 = $(cat file) && + test 9 = $(cat file) && test 1 = $(git show :file) && test 1 = $(git show HEAD:file) && test 0 = $(git stash list | wc -l)
This test was already a bit broken in needing the preceding tests, but it will break now if REFFILES isn't true, which you can reproduce e.g. with:
./t3903-stash.sh --run=1-16,18-50 -vixd
Perhaps the least sucky solution to that is:
t/t3903-stash.sh +8 -2
@@ -205,13 +205,19 @@ test_expect_success 'drop stash reflog updates refs/stash with rewrite' ' cat >expect <<-EOF && $(test_oid zero) $oid EOF - test_cmp expect actual + test_cmp expect actual && + >dropped-stash ' test_expect_success 'stash pop' ' git reset --hard && git stash pop && - test 9 = $(cat file) && + if test -e dropped-stash + then + test 9 = $(cat file) + else + test 3 = $(cat file) + fi && test 1 = $(git show :file) && test 1 = $(git show HEAD:file) && test 0 = $(git stash list | wc -l)
Re: [PATCH v2 2/3] reflog: libify delete reflog function and helpers
In reply to John Cai via GitGitGadgetQuoted 62 lines · John Cai via GitGitGadget
From: John Cai <[email protected]>
Currently stash shells out to reflog in order to delete refs. In an effort to reduce how much we shell out to a subprocess, libify the functionality that stash needs into
reflog.c.Add a
reflog_deletefunction that is pretty much the logic in the while loop inbuiltin/reflog.ccmd_reflog_delete(). This is a function thatbuiltin/reflog.candbuiltin/stash.ccan both call.Also move functions needed by
reflog_deleteand export them.Signed-off-by John Cai <[email protected]>--- Makefile | 1 + builtin/reflog.c | 451 +---------------------------------------------- object.h | 2 +- reflog.c | 435 +++++++++++++++++++++++++++++++++++++++++++++ reflog.h | 49 +++++ 5 files changed, 490 insertions(+), 448 deletions(-) create mode 100644 reflog.c create mode 100644 reflog.hMakefile +1
-0@@ -989,6 +989,7 @@ LIB_OBJS += rebase-interactive.o LIB_OBJS += rebase.o LIB_OBJS += ref-filter.o LIB_OBJS += reflog-walk.o +LIB_OBJS += reflog.o LIB_OBJS += refs.o LIB_OBJS += refs/debug.o LIB_OBJS += refs/files-backend.obuiltin/reflog.c +1
-4@@ -1,16 +1,13 @@#include "builtin.h" #include "config.h" #include "lockfile.h" -#include "object-store.h" #include "repository.h" -#include "commit.h" -#include "refs.h" #include "dir.h" -#include "tree-walk.h" #include "diff.h" #include "revision.h" #include "reachable.h" #include "worktree.h" +#include "reflog.h" reflog.c new file +0
-0
reflog.c line 9
Quoted 9 lines
reflog.c new file +9
-0@@ -0,0 +1,435 @@ +#include "cache.h" +#include "commit.h" +#include "object-store.h" +#include "reachable.h" +#include "reflog.h" +#include "refs.h" +#include "revision.h" +#include "tree-walk.h" +#include "worktree.h"
I think you missed some now-redundant headers, and copied over others we didn't need. This compiles for me with this on top:
builtin/reflog.c +0 -4
@@ -1,9 +1,5 @@#include "builtin.h" #include "config.h" -#include "lockfile.h" -#include "repository.h" -#include "dir.h" -#include "diff.h" #include "revision.h" #include "reachable.h" #include "worktree.h"
reflog.c +0 -3
@@ -1,11 +1,8 @@#include "cache.h" -#include "commit.h" #include "object-store.h" -#include "reachable.h" #include "reflog.h" #include "refs.h" #include "revision.h" -#include "tree-walk.h" #include "worktree.h"
But perhaps some of those are really "needed" but brought in implicitly?
reflog.h line 4
Quoted 11 lines
[...]
reflog.h new file +4
-0@@ -0,0 +1,49 @@ +#ifndef REFLOG_H +#define REFLOG_H + +#include "refs.h"
Just a nit but I think the reflog_delete() should be wrapped (ends up at 80 cols), and the usual style in this project is to not whitespace-pad so much, i.e. this on top:
reflog.h +2 -8
@@ -1,6 +1,5 @@#ifndef REFLOG_H #define REFLOG_H -#include "refs.h" struct cmd_reflog_expire_cb {
@@ -25,25 +24,20 @@ struct expire_reflog_policy_cb { unsigned int dry_run:1; }; -int reflog_delete (const char *rev,enum expire_reflog_flags flags,int verbose); - +int reflog_delete (const char *rev,enum expire_reflog_flags flags, +int verbose);void reflog_expiry_cleanup (void *cb_data); -void reflog_expiry_prepare (const char *refname,const struct object_id *oid,void *cb_data); -int should_expire_reflog_ent (struct object_id *ooid,struct object_id *noid,const char *email,timestamp_t timestamp,int tz,const char *message,void *cb_data); -int count_reflog_ent (struct object_id *ooid,struct object_id *noid,const char *email,timestamp_t timestamp,int tz,const char *message,void *cb_data); -int should_expire_reflog_ent_verbose (struct object_id *ooid,struct object_id *noid,const char *email,timestamp_t timestamp,int tz,const char *message,void *cb_data); -#endif /* REFLOG_H */
Other than all that I really can't find anything at all to comment on, and I see that all the points raised in previous rounds by others were addressed.
Re: [PATCH v2 2/3] reflog: libify delete reflog function and helpers
Hi Ævar,
Thanks for the review!
Quoted 68 lines · Ævar Arnfjörð Bjarmason
Quoted 66 lines · John Cai via GitGitGadget
From: John Cai <[email protected]>
Currently stash shells out to reflog in order to delete refs. In an effort to reduce how much we shell out to a subprocess, libify the functionality that stash needs into
reflog.c.Add a
reflog_deletefunction that is pretty much the logic in the while loop inbuiltin/reflog.ccmd_reflog_delete(). This is a function thatbuiltin/reflog.candbuiltin/stash.ccan both call.Also move functions needed by
reflog_deleteand export them.Signed-off-by John Cai <[email protected]>--- Makefile | 1 + builtin/reflog.c | 451 +---------------------------------------------- object.h | 2 +- reflog.c | 435 +++++++++++++++++++++++++++++++++++++++++++++ reflog.h | 49 +++++ 5 files changed, 490 insertions(+), 448 deletions(-) create mode 100644 reflog.c create mode 100644 reflog.hMakefile +1
-0@@ -989,6 +989,7 @@ LIB_OBJS += rebase-interactive.o LIB_OBJS += rebase.o LIB_OBJS += ref-filter.o LIB_OBJS += reflog-walk.o +LIB_OBJS += reflog.o LIB_OBJS += refs.o LIB_OBJS += refs/debug.o LIB_OBJS += refs/files-backend.obuiltin/reflog.c +1
-4@@ -1,16 +1,13 @@#include "builtin.h" #include "config.h" #include "lockfile.h" -#include "object-store.h" #include "repository.h" -#include "commit.h" -#include "refs.h" #include "dir.h" -#include "tree-walk.h" #include "diff.h" #include "revision.h" #include "reachable.h" #include "worktree.h" +#include "reflog.h" reflog.c new file +4
-0@@ -0,0 +1,435 @@ +#include "cache.h" +#include "commit.h" +#include "object-store.h" +#include "reachable.h"
Quoted 8 lines
reflog.c line 9
Quoted 5 lines
reflog.c new file +5
-0+#include "reflog.h" +#include "refs.h" +#include "revision.h" +#include "tree-walk.h" +#include "worktree.h" I think you missed some now-redundant headers, and copied over others we didn't need. This compiles for me with this on top:
Ah yeah, looks I left these in by mistake. Thanks for catching this.
Quoted 32 lines
builtin/reflog.c +0
-4@@ -1,9 +1,5 @@#include "builtin.h" #include "config.h" -#include "lockfile.h" -#include "repository.h" -#include "dir.h" -#include "diff.h" #include "revision.h" #include "reachable.h" #include "worktree.h" reflog.c +0
-3@@ -1,11 +1,8 @@#include "cache.h" -#include "commit.h" #include "object-store.h" -#include "reachable.h" #include "reflog.h" #include "refs.h" #include "revision.h" -#include "tree-walk.h" #include "worktree.h" But perhaps some of those are really "needed" but brought in implicitly?
Quoted 15 lines
reflog.h line 4
Quoted 11 lines
[...]
reflog.h new file +4
-0@@ -0,0 +1,49 @@ +#ifndef REFLOG_H +#define REFLOG_H + +#include "refs.h" Just a nit but I think the
reflog_delete()should be wrapped (ends up at 80 cols), and the usual style in this project is to not whitespace-pad so much, i.e. this on top:
sounds good!
Quoted 45 lines
reflog.h +2
-8@@ -1,6 +1,5 @@#ifndef REFLOG_H #define REFLOG_H -#include "refs.h" struct cmd_reflog_expire_cb {@@ -25,25 +24,20 @@ struct expire_reflog_policy_cb { unsigned int dry_run:1; }; -int reflog_delete (const char *rev,enum expire_reflog_flags flags,int verbose); - +int reflog_delete (const char *rev,enum expire_reflog_flags flags, +int verbose);void reflog_expiry_cleanup (void *cb_data); -void reflog_expiry_prepare (const char *refname,const struct object_id *oid,void *cb_data); -int should_expire_reflog_ent (struct object_id *ooid,struct object_id *noid,const char *email,timestamp_t timestamp,int tz,const char *message,void *cb_data); -int count_reflog_ent (struct object_id *ooid,struct object_id *noid,const char *email,timestamp_t timestamp,int tz,const char *message,void *cb_data); -int should_expire_reflog_ent_verbose (struct object_id *ooid,struct object_id *noid,const char *email,timestamp_t timestamp,int tz,const char *message,void *cb_data); -#endif /* REFLOG_H */ Other than all that I really can't find anything at all to comment on, and I see that all the points raised in previous rounds by others were addressed.
Re: [PATCH 1/3] reflog: libify delete reflog function and helpers
In reply to Taylor BlauHi Taylor,
Quoted 10 lines · Taylor Blau
Quoted 8 lines · John Cai
Quoted 4 lines
One question that I had which I don't see answered already is what the plan is for existing reflog-related functions that live in
refs.h. Should or will those functions be moved to the new reflog-specific header, too?Thanks for bringing ths up! Maybe this cleanup can be included in a separate patch series since this one is mainly about getting rid of the shell-out in
stash.c. What do you think?
Quoted 6 lines
Yeah; I think that's fine. We don't need to get all reflog-related functions moved into
reflog.hin the first series, so I think it's fine to move things as you discover them.I was just wondering whether it was something you planned to do at some point (as part of this series, or a future one).
Yes I will open a new series for this. I've been looking through refs.h, and as you alluded to there are a number of reflog related functions. But, they also relate to refs. I'm not sure which ones should go into reflog.h versus staying in refs.h. What are your thoughts?
Quoted 3 lines
Thanks,
Taylor
Thanks!
John
Re: [PATCH v2 1/3] stash: add test to ensure reflog --rewrite --updatref behavior
In reply to Ævar Arnfjörð BjarmasonQuoted 13 lines · Ævar Arnfjörð Bjarmason
This test was already a bit broken in needing the preceding tests, but it will break now if REFFILES isn't true, which you can reproduce e.g. with:
./t3903-stash.sh --run=1-16,18-50 -vixdPerhaps the least sucky solution to that is:
t/t3903-stash.sh +0
-0
t/t3903-stash.sh test_expect_success 'drop stash reflog updates refs/stash with rewrite' ' · line 210
Quoted 7 lines
t/t3903-stash.sh +2
-1@@ -205,13 +205,19 @@ test_expect_success 'drop stash reflog updates refs/stash with rewrite' ' cat >expect <<-EOF && $(test_oid zero) $oid EOF - test_cmp expect actual + test_cmp expect actual && + >dropped-stash '
If "git stash drop", invoked in earlier part of this test before the precontext, fails, then test_cmp would fail and we leave dropped-stash untouched, even though we did run "git stash drop" already.
Why does the next test need to depend on what has happened earlier?
Quoted 13 lines
t/t3903-stash.sh +6
-1test_expect_success 'stash pop' ' git reset --hard && git stash pop && - test 9 = $(cat file) && + if test -e dropped-stash + then + test 9 = $(cat file) + else + test 3 = $(cat file) + fi && test 1 = $(git show :file) && test 1 = $(git show HEAD:file) && test 0 = $(git stash list | wc -l)
Re: [PATCH v2 2/3] reflog: libify delete reflog function and helpers
In reply to John Cai via GitGitGadgetQuoted 14 lines · John Cai via GitGitGadget
From: John Cai <[email protected]>
Currently stash shells out to reflog in order to delete refs. In an effort to reduce how much we shell out to a subprocess, libify the functionality that stash needs into
reflog.c.Add a
reflog_deletefunction that is pretty much the logic in the while loop inbuiltin/reflog.ccmd_reflog_delete(). This is a function thatbuiltin/reflog.candbuiltin/stash.ccan both call.Also move functions needed by
reflog_deleteand export them.Signed-off-by John Cai <[email protected]>
Quoted 9 lines
--- Makefile | 1 + builtin/reflog.c | 451 +---------------------------------------------- object.h | 2 +- reflog.c | 435 +++++++++++++++++++++++++++++++++++++++++++++ reflog.h | 49 +++++ 5 files changed, 490 insertions(+), 448 deletions(-) create mode 100644 reflog.c create mode 100644 reflog.h
This round, without polluting global namespace in reflog.h by moving too many things there and instead keeping what is private to the implementation in reflog.c, looks much better than the previous round.
Looking good.
Thanks.
Re: [PATCH v2 1/3] stash: add test to ensure reflog --rewrite --updatref behavior
In reply to Junio C HamanoHi Junio,
Quoted 28 lines · Junio C Hamano
Quoted 13 lines · Ævar Arnfjörð Bjarmason
This test was already a bit broken in needing the preceding tests, but it will break now if REFFILES isn't true, which you can reproduce e.g. with:
./t3903-stash.sh --run=1-16,18-50 -vixdPerhaps the least sucky solution to that is:
t/t3903-stash.sh +0
-0t/t3903-stash.sh test_expect_success 'drop stash reflog updates refs/stash with rewrite' ' · line 210
Quoted 7 lines
t/t3903-stash.sh +2
-1@@ -205,13 +205,19 @@ test_expect_success 'drop stash reflog updates refs/stash with rewrite' ' cat >expect <<-EOF && $(test_oid zero) $oid EOF - test_cmp expect actual + test_cmp expect actual && + >dropped-stash 'If "git stash drop", invoked in earlier part of this test before the precontext, fails, then
test_cmpwould fail and we leave dropped-stash untouched, even though we did run "git stash drop" already.
Quoted 1 line
Why does the next test need to depend on what has happened earlier?
Ideally it shouldn't, but it seems like the way these test have been written makes subsequent tests depend on what previous tests have stashed.
I'm wondering now that while we're at it, if we should just clean up these tests so there are no dependencies between the tests. Otherwise it's quite painful the next time someone needs to add a test here.
We could follow the pattern in 5ac15ad2509 (reflog tests: add --updateref tests, 2021-10-16), where Ævar set up the tests and copied over the repo so each test is isolated from each other.
Quoted 14 lines
Quoted 14 lines
t/t3903-stash.sh +6
-1test_expect_success 'stash pop' ' git reset --hard && git stash pop && - test 9 = $(cat file) && + if test -e dropped-stash + then + test 9 = $(cat file) + else + test 3 = $(cat file) + fi && test 1 = $(git show :file) && test 1 = $(git show HEAD:file) && test 0 = $(git stash list | wc -l)
Re: [PATCH v2 1/3] stash: add test to ensure reflog --rewrite --updatref behavior
In reply to Junio C HamanoQuoted 19 lines · Junio C Hamano
Quoted 17 lines · Ævar Arnfjörð Bjarmason
This test was already a bit broken in needing the preceding tests, but it will break now if REFFILES isn't true, which you can reproduce e.g. with:
./t3903-stash.sh --run=1-16,18-50 -vixdPerhaps the least sucky solution to that is:
t/t3903-stash.sh +0
-1@@ -205,13 +205,19 @@ test_expect_success 'drop stash reflog updates refs/stash with rewrite' ' cat >expect <<-EOF && $(test_oid zero) $oid EOF - test_cmp expect actual
Quoted 8 lines
t/t3903-stash.sh test_expect_success 'drop stash reflog updates refs/stash with rewrite' ' · line 210
Quoted 3 lines
t/t3903-stash.sh +2
-0+ test_cmp expect actual && + >dropped-stash 'If "git stash drop", invoked in earlier part of this test before the precontext, fails, then
test_cmpwould fail and we leave dropped-stash untouched, even though we did run "git stash drop" already.
Yes, that's an edge case that's exposed here, but which I thought wasn't worth bothering with. I.e. if you get such a failure on test N getting N+1 failing as well isn't that big of a deal.
The big deal is rather that we know we're adding a REFFILES dependency to this, which won't run this at all, which will make the "stash pop" below fail.
Quoted 1 line
Why does the next test need to depend on what has happened earlier?
They don't need to, and ideally wouldn't, but most of our test suite has this issue already. Try e.g. running it with:
prove t[0-9]*.sh :: --run=10-20 --immediate
And for this particular file running e.g. this on master:
./t3903-stash.sh --run=1-10,30-40
Will fail 7 tests in the 30-40 range.
So while it's ideal that we can combine tests with arbitrary --run parameters, i.e. all tests would tear down fully, not depend on earlier tests etc. we're really far from that being the case in practice.
So insisting on some general refactoring of this file as part of this series seems a bit overzelous, which is why I'm suggesting the bare minimum to expect and work around the inevitable REFFILES failure, as Han-Wen is actively working in that area.
Quoted 13 lines
Quoted 13 lines
t/t3903-stash.sh +6
-1test_expect_success 'stash pop' ' git reset --hard && git stash pop && - test 9 = $(cat file) && + if test -e dropped-stash + then + test 9 = $(cat file) + else + test 3 = $(cat file) + fi && test 1 = $(git show :file) && test 1 = $(git show HEAD:file) && test 0 = $(git stash list | wc -l)
Re: [PATCH v2 1/3] stash: add test to ensure reflog --rewrite --updatref behavior
In reply to Ævar Arnfjörð BjarmasonQuoted 20 lines · Ævar Arnfjörð Bjarmason
Review
Quoted 9 lines
(quoted diff) +9
-0+test_expect_success 'drop stash reflog updates refs/stash' ' + git reset --hard && + git rev-parse refs/stash >expect && + echo 9 >file && + git stash && + git stash drop stash@{0} && + git rev-parse refs/stash >actual && + test_cmp expect actual +'This one will be portable to the reftable backend.
Quoted 1 line
+test_expect_success 'drop stash reflog updates refs/stash with rewrite' '
But as I noted in <[email protected]> (but it was easy to miss) this test will need to depend on REFFILES. So just changing this line to:
test_expect_successREFFILES 'drop stash[...]'
Quoted 11 lines
Review
Quoted 11 lines
(quoted diff) +11
-0+ git reset --hard && + echo 9 >file && + git stash && + oid="$(git rev-parse stash@{0})" && + git stash drop stash@{1} && + cut -d" " -f1-2 .git/logs/refs/stash >actual && + cat >expect <<-EOF && + $(test_oid zero) $oid + EOF + test_cmp expect actual +'
Why should this be tested with "cut" in the first place, though?
If we start from
stash@{0} = A
stash@{1} = B
stash@{2} = Cand after saying "drop stash@{1}", what we need to check is that
stash@{0} = A
stash@{1} = Cnow holds, which can be done with "git rev-parse", and the fact that the ref-files backend happens to record both before-and-after object IDs is an irrelevant implementation detail, no?
I am still puzzled.
Re: [PATCH v2 1/3] stash: add test to ensure reflog --rewrite --updatref behavior
Hi Junio,
Quoted 38 lines · Junio C Hamano
Quoted 20 lines · Ævar Arnfjörð Bjarmason
Review
Quoted 9 lines
(quoted diff) +9
-0+test_expect_success 'drop stash reflog updates refs/stash' ' + git reset --hard && + git rev-parse refs/stash >expect && + echo 9 >file && + git stash && + git stash drop stash@{0} && + git rev-parse refs/stash >actual && + test_cmp expect actual +'This one will be portable to the reftable backend.
Quoted 1 line
+test_expect_success 'drop stash reflog updates refs/stash with rewrite' '
But as I noted in <[email protected]> (but it was easy to miss) this test will need to depend on REFFILES. So just changing this line to:
test_expect_successREFFILES 'drop stash[...]'Quoted 11 lines
Review
Quoted 11 lines
(quoted diff) +11
-0+ git reset --hard && + echo 9 >file && + git stash && + oid="$(git rev-parse stash@{0})" && + git stash drop stash@{1} && + cut -d" " -f1-2 .git/logs/refs/stash >actual && + cat >expect <<-EOF && + $(test_oid zero) $oid + EOF + test_cmp expect actual +'Why should this be tested with "cut" in the first place, though?
If we start from
Quoted 8 lines
stash@{0} = A stash@{1} = B stash@{2} = Cand after saying "drop stash@{1}", what we need to check is that
stash@{0} = A stash@{1} = C
Yes, this is true but that doesn't seem to test the --rewrite functionality. I could be missing something, but it seems that the reflog --rewrite option will write the LHS old oid value in the .git/logs/refs/stash file. When --rewrite isn't used, the reflog delete still does the right thing to the RHS entry.
I couldn't find any way to check this LFS value other than reaching into the actual file. If there is a way that would be preferable.
Quoted 6 lines
now holds, which can be done with "git rev-parse", and the fact that the ref-files backend happens to record both before-and-after object IDs is an irrelevant implementation detail, no?
I am still puzzled.
Re: [PATCH v2 1/3] stash: add test to ensure reflog --rewrite --updatref behavior
Quoted 8 lines · John Cai
Yes, this is true but that doesn't seem to test the --rewrite functionality. I could be missing something, but it seems that the reflog --rewrite option will write the LHS old oid value in the .git/logs/refs/stash file. When --rewrite isn't used, the reflog delete still does the right thing to the RHS entry.
I couldn't find any way to check this LFS value other than reaching into the actual file. If there is a way that would be preferable.
Ah, that one.
As 2b81fab2 (git-reflog: add option --rewrite to update reflog entries while expiring, 2008-02-22) says, the redundant half of the reflog entry only matters to "certain sanity checks" and would not be even visible to normal ref API users. I wonder why we need to even say "--rewrite" in the first place. Perhaps we should implicitly set it always and eventually deprecate that option.
Re: [PATCH v2 1/3] stash: add test to ensure reflog --rewrite --updatref behavior
In reply to John CaiQuoted 51 lines · John Cai
Hi Junio,
Quoted 38 lines · Junio C Hamano
Quoted 20 lines · Ævar Arnfjörð Bjarmason
Review
Quoted 9 lines
(quoted diff) +9
-0+test_expect_success 'drop stash reflog updates refs/stash' ' + git reset --hard && + git rev-parse refs/stash >expect && + echo 9 >file && + git stash && + git stash drop stash@{0} && + git rev-parse refs/stash >actual && + test_cmp expect actual +'This one will be portable to the reftable backend.
Quoted 1 line
+test_expect_success 'drop stash reflog updates refs/stash with rewrite' '
But as I noted in <[email protected]> (but it was easy to miss) this test will need to depend on REFFILES. So just changing this line to:
test_expect_successREFFILES 'drop stash[...]'Quoted 11 lines
Review
Quoted 11 lines
(quoted diff) +11
-0+ git reset --hard && + echo 9 >file && + git stash && + oid="$(git rev-parse stash@{0})" && + git stash drop stash@{1} && + cut -d" " -f1-2 .git/logs/refs/stash >actual && + cat >expect <<-EOF && + $(test_oid zero) $oid + EOF + test_cmp expect actual +'Why should this be tested with "cut" in the first place, though?
If we start from
Quoted 8 lines
stash@{0} = A stash@{1} = B stash@{2} = Cand after saying "drop stash@{1}", what we need to check is that
stash@{0} = A stash@{1} = C
Quoted 8 lines
Yes, this is true but that doesn't seem to test the --rewrite functionality. I could be missing something, but it seems that the reflog --rewrite option will write the LHS old oid value in the .git/logs/refs/stash file. When --rewrite isn't used, the reflog delete still does the right thing to the RHS entry.
I couldn't find any way to check this LFS value other than reaching into the actual file. If there is a way that would be preferable.
Thanks for that summary that's accurate as far as I know. I think that's how this all works, and I don't know of another way to extract this information than this reaching behind the curtain.
Which, I think is a lot clearer if we amend the test like this. Note that this doesn't really add anything for catching a regression goes, but I think helps guide the human reader through this step-by-step. So perhaps it would be good to fix the test up to have it (or maybe not):
t/t3903-stash.sh +15 -2
@@ -198,12 +198,25 @@ test_expect_success 'drop stash reflog updates refs/stash' ' test_expect_success 'drop stash reflog updates refs/stash with rewrite' ' git reset --hard && echo 9 >file && + + # Our two stashes + old_oid="$(git rev-parse stash@{0})" && git stash && - oid="$(git rev-parse stash@{0})" && + new_oid="$(git rev-parse stash@{0})" && + + # Our stash <old oid>/<new oid> before "drop" + cat >expect <<-EOF && + $(test_oid zero) $old_oid + $old_oid $new_oid + EOF + cut -d" " -f1-2 .git/logs/refs/stash >actual && + test_cmp expect actual && + + # Our stash <old oid>/<new oid> after "drop" git stash drop stash@{1} && cut -d" " -f1-2 .git/logs/refs/stash >actual && cat >expect <<-EOF && - $(test_oid zero) $oid + $(test_oid zero) $new_oid EOF test_cmp expect actual '
If this series is amended to drop the "EXPIRE_REFLOGS_REWRITE" flag then this will fail on that last test_cmp like:
+ diff -u expect actual
--- expect 2022-02-23 23:37:40.438221222 +0000
+++ actual 2022-02-23 23:37:40.434221258 +0000
@@ -1 +1 @@
-0000000000000000000000000000000000000000 236c59f58e239e74e90b6832a98fa4b7f4b33647
+5c6ad4ca28e71ae3a007e6c77043d04bc42fa9ee 236c59f58e239e74e90b6832a98fa4b7f4b33647I.e. our <old oid> is now referring to the now-deleted stash entry we just deleted, since we didn't rewrite it.
And as we can see with some manual inspection the state before we dropped stash@{1} was:
0000000000000000000000000000000000000000 5c6ad4ca28e71ae3a007e6c77043d04bc42fa9ee
5c6ad4ca28e71ae3a007e6c77043d04bc42fa9ee 236c59f58e239e74e90b6832a98fa4b7f4b33647My usual method of checking my assumption about this not being otherwise inspectable would be something like:
diff --git a/refs/files-backend.c b/refs/files-backend.c
index f59589d6cce..590c13e7a2b 100644
--- a/refs/files-backend.c
+++ b/refs/files-backend.c
@@ -3133,7 +3133,7 @@ static int files_reflog_expire(struct ref_store *ref_store,
const struct object_id *oid;
memset(&cb, 0, sizeof(cb));
- cb.rewrite = !!(expire_flags & EXPIRE_REFLOGS_REWRITE);
+ cb.rewrite = 0;
cb.dry_run = !!(expire_flags & EXPIRE_REFLOGS_DRY_RUN);
cb.policy_cb = policy_cb_data;
cb.should_prune_fn = should_prune_fn;I.e. let's intentionally break the flag, and see what else fails (it's set in a few places, but this is the only place where it's checked).
That should normally find the other things that are testing this, maybe there's a better way.
But, no such luck :) The only thing that'll fail is this new test being added here.
So just like my 5ac15ad2509 (reflog tests: add --updateref tests, 2021-10-16) this is covering a true blindspot in the "git reflog" functionality.
The only tests that used --rewrite were a test added in c41a87dd80c (refs: make rev-parse --quiet actually quiet, 2014-09-18), which will pass if --rewrite is omitted.
And the ones I added in 5ac15ad2509, which I added not to test --rewrite per-se, but to test that the --updateref part of it behaved as expected in combination with whatever effect it was having.
Re: [PATCH v2 1/3] stash: add test to ensure reflog --rewrite --updatref behavior
In reply to Junio C HamanoHi Junio,
Quoted 11 lines · Junio C Hamano
Quoted 8 lines · John Cai
Yes, this is true but that doesn't seem to test the --rewrite functionality. I could be missing something, but it seems that the reflog --rewrite option will write the LHS old oid value in the .git/logs/refs/stash file. When --rewrite isn't used, the reflog delete still does the right thing to the RHS entry.
I couldn't find any way to check this LFS value other than reaching into the actual file. If there is a way that would be preferable.
Quoted 8 lines
Ah, that one.
As
2b81fab2(git-reflog: add option --rewrite to update reflog entries while expiring, 2008-02-22) says, the redundant half of the reflog entry only matters to "certain sanity checks" and would not be even visible to normal ref API users. I wonder why we need to even say "--rewrite" in the first place. Perhaps we should implicitly set it always and eventually deprecate that option.
Yeah, that makes sense. I had this thought as I was figuring out how to test this. I can take care of this in a separate patch series
Re: [PATCH v2 1/3] stash: add test to ensure reflog --rewrite --updatref behavior
In reply to Ævar Arnfjörð BjarmasonHi Ævar,
Quoted 51 lines · Ævar Arnfjörð Bjarmason
Quoted 19 lines · Junio C Hamano
Quoted 17 lines · Ævar Arnfjörð Bjarmason
This test was already a bit broken in needing the preceding tests, but it will break now if REFFILES isn't true, which you can reproduce e.g. with:
./t3903-stash.sh --run=1-16,18-50 -vixdPerhaps the least sucky solution to that is:
t/t3903-stash.sh +0
-1@@ -205,13 +205,19 @@ test_expect_success 'drop stash reflog updates refs/stash with rewrite' ' cat >expect <<-EOF && $(test_oid zero) $oid EOF - test_cmp expect actualQuoted 8 lines
t/t3903-stash.sh test_expect_success 'drop stash reflog updates refs/stash with rewrite' ' · line 210
Quoted 3 lines
t/t3903-stash.sh +2
-0+ test_cmp expect actual && + >dropped-stash 'If "git stash drop", invoked in earlier part of this test before the precontext, fails, then
test_cmpwould fail and we leave dropped-stash untouched, even though we did run "git stash drop" already.Yes, that's an edge case that's exposed here, but which I thought wasn't worth bothering with. I.e. if you get such a failure on test N getting N+1 failing as well isn't that big of a deal.
The big deal is rather that we know we're adding a REFFILES dependency to this, which won't run this at all, which will make the "stash pop" below fail.
Quoted 1 line
Why does the next test need to depend on what has happened earlier?
They don't need to, and ideally wouldn't, but most of our test suite has this issue already. Try e.g. running it with:
prove t[0-9]*.sh :: --run=10-20 --immediateAnd for this particular file running e.g. this on master:
./t3903-stash.sh --run=1-10,30-40Will fail 7 tests in the 30-40 range.
Quoted 8 lines
So while it's ideal that we can combine tests with arbitrary --run parameters, i.e. all tests would tear down fully, not depend on earlier tests etc. we're really far from that being the case in practice.
So insisting on some general refactoring of this file as part of this series seems a bit overzelous, which is why I'm suggesting the bare minimum to expect and work around the inevitable REFFILES failure, as Han-Wen is actively working in that area.
Curious what your thoughts are on an effort to isolate these tests from each other. I like your approach in t/t1417 in creating a test repo and copying it over each time. Something like this?
t/t3903-stash.sh +22 -12
@@ -41,7 +41,9 @@ diff_cmp () { rm -f "$1.compare" "$2.compare" } -test_expect_success 'stash some dirty working directory' ' +test_expect_success 'setup' ' + git init repo && + cd repo && echo 1 >file && git add file && echo unrelated >other-file &&
@@ -54,48 +56,54 @@ test_expect_success 'stash some dirty working directory' ' test_tick && git stash && git diff-files --quiet && - git diff-index --cached --quiet HEAD + git diff-index --cached --quiet HEAD && + cat >expect <<-EOF && + diff --git a/file b/file + index 0cfbf08..00750ed 100644 + --- a/file + +++ b/file + @@ -1 +1 @@ + -2 + +3 + EOF + cd ../ ' -cat >expect <<EOF -diff --git a/file b/file -index 0cfbf08..00750ed 100644 ---- a/file -+++ b/file -@@ -1 +1 @@ --2 -+3 -EOF +test_stash () { + cp -R repo copy && + cd copy && + test_expect_success "$@" && + cd ../ && + rm -rf copy +} -test_expect_success 'parents of stash' ' +test_stash 'parents of stash' ' test $(git rev-parse stash^) = $(git rev-parse HEAD) && git diff stash^2..stash >output && diff_cmp expect output '
Not sure if it's worth it though?
Quoted 14 lines
Quoted 14 lines
Quoted 14 lines
t/t3903-stash.sh +6
-1test_expect_success 'stash pop' ' git reset --hard && git stash pop && - test 9 = $(cat file) && + if test -e dropped-stash + then + test 9 = $(cat file) + else + test 3 = $(cat file) + fi && test 1 = $(git show :file) && test 1 = $(git show HEAD:file) && test 0 = $(git stash list | wc -l)
Re: [PATCH v2 1/3] stash: add test to ensure reflog --rewrite --updatref behavior
Quoted 59 lines · John Cai
Hi Ævar,
Quoted 55 lines · Ævar Arnfjörð Bjarmason
Quoted 19 lines · Junio C Hamano
Quoted 17 lines · Ævar Arnfjörð Bjarmason
This test was already a bit broken in needing the preceding tests, but it will break now if REFFILES isn't true, which you can reproduce e.g. with:
./t3903-stash.sh --run=1-16,18-50 -vixdPerhaps the least sucky solution to that is:
t/t3903-stash.sh +0
-1@@ -205,13 +205,19 @@ test_expect_success 'drop stash reflog updates refs/stash with rewrite' ' cat >expect <<-EOF && $(test_oid zero) $oid EOF - test_cmp expect actualQuoted 8 lines
t/t3903-stash.sh test_expect_success 'drop stash reflog updates refs/stash with rewrite' ' · line 210
Quoted 3 lines
t/t3903-stash.sh +2
-0+ test_cmp expect actual && + >dropped-stash 'If "git stash drop", invoked in earlier part of this test before the precontext, fails, then
test_cmpwould fail and we leave dropped-stash untouched, even though we did run "git stash drop" already.Yes, that's an edge case that's exposed here, but which I thought wasn't worth bothering with. I.e. if you get such a failure on test N getting N+1 failing as well isn't that big of a deal.
The big deal is rather that we know we're adding a REFFILES dependency to this, which won't run this at all, which will make the "stash pop" below fail.
Quoted 1 line
Why does the next test need to depend on what has happened earlier?
They don't need to, and ideally wouldn't, but most of our test suite has this issue already. Try e.g. running it with:
prove t[0-9]*.sh :: --run=10-20 --immediateAnd for this particular file running e.g. this on master:
./t3903-stash.sh --run=1-10,30-40Will fail 7 tests in the 30-40 range.
So while it's ideal that we can combine tests with arbitrary --run parameters, i.e. all tests would tear down fully, not depend on earlier tests etc. we're really far from that being the case in practice.
Quoted 8 lines
Quoted 4 lines
So insisting on some general refactoring of this file as part of this series seems a bit overzelous, which is why I'm suggesting the bare minimum to expect and work around the inevitable REFFILES failure, as Han-Wen is actively working in that area.
Curious what your thoughts are on an effort to isolate these tests from each other. I like your approach in t/t1417 in creating a test repo and copying it over each time. Something like this?
That looks good to me if you're willing to do that legwork, probably better in a preceding cleanup commit.
Quoted 16 lines
t/t3903-stash.sh +3
-1@@ -41,7 +41,9 @@ diff_cmp () { rm -f "$1.compare" "$2.compare" } -test_expect_success 'stash some dirty working directory' ' +test_expect_success 'setup' ' + git init repo && + cd repo && echo 1 >file && git add file && echo unrelated >other-file &&
t/t3903-stash.sh test_expect_success 'stash some dirty working directory' ' · line 60
Quoted 6 lines
t/t3903-stash.sh +2
-1@@ -54,48 +56,54 @@ test_expect_success 'stash some dirty working directory' ' test_tick && git stash && git diff-files --quiet && - git diff-index --cached --quiet HEAD + git diff-index --cached --quiet HEAD && + cat >expect <<-EOF &&
nit: you can add \ to that, i.e. <<-\EOF. Helps readability, i.e. it's obvious right away that no variables are in play..
Quoted 25 lines
t/t3903-stash.sh +14
-9+ diff --git a/file b/file + index 0cfbf08..00750ed 100644 + --- a/file + +++ b/file + @@ -1 +1 @@ + -2 + +3 + EOF + cd ../ ' -cat >expect <<EOF -diff --git a/file b/file -index 0cfbf08..00750ed 100644 ---- a/file -+++ b/file -@@ -1 +1 @@ --2 -+3 -EOF +test_stash () { + cp -R repo copy && + cd copy && + test_expect_success "$@" && + cd ../ &&
t/t3903-stash.sh test_expect_success 'stash some dirty working directory' '
Quoted 10 lines
t/t3903-stash.sh +3
-1+ rm -rf copy +} -test_expect_success 'parents of stash' ' +test_stash 'parents of stash' ' test $(git rev-parse stash^) = $(git rev-parse HEAD) && git diff stash^2..stash >output && diff_cmp expect output '
For this sort of thing I think it's usually better to override "test_expect_success" as a last resort, i.e. to have that "test_setup_stash_copy" just be a "setup_stash" or whatever function called from within your test_expect_success.
And instead of the "rm -rf" later, just do:
test_when_finished "rm -rf copy" &&
cp -R repo copy &&
[...]The test still needs to deal with the sub-repo, but it could cd or use "-C".
It's bad to add "cd .." in a &&-chain, because if earlier steps fail we're in the wrong directory for the next test, so either -C or a sub-shell...
Quoted 1 line
Not sure if it's worth it though?
Maybe not, which is why I suggested upthread to maybe go for some smallest possible change here and focus on the lib-ificitaion :)
Quoted 16 lines
Quoted 16 lines
Quoted 16 lines
Quoted 16 lines
t/t3903-stash.sh +6
-1test_expect_success 'stash pop' ' git reset --hard && git stash pop && - test 9 = $(cat file) && + if test -e dropped-stash + then + test 9 = $(cat file) + else + test 3 = $(cat file) + fi && test 1 = $(git show :file) && test 1 = $(git show HEAD:file) && test 0 = $(git stash list | wc -l)
Re: [PATCH v2 1/3] stash: add test to ensure reflog --rewrite --updatref behavior
Quoted 6 lines · Ævar Arnfjörð Bjarmason
Quoted 3 lines
Curious what your thoughts are on an effort to isolate these tests from each other. I like your approach in t/t1417 in creating a test repo and copying it over each time. Something like this?
That looks good to me if you're willing to do that legwork, probably better in a preceding cleanup commit.
Yup. Thanks for helping other contributors. I agree with many things you said in your review.
Quoted 8 lines
Quoted 8 lines
t/t3903-stash.sh +0
-0@@ -41,7 +41,9 @@ diff_cmp () { rm -f "$1.compare" "$2.compare" }
Quoted 4 lines
t/t3903-stash.sh diff_cmp () { · line 46
Quoted 4 lines
t/t3903-stash.sh +3
-1-test_expect_success 'stash some dirty working directory' ' +test_expect_success 'setup' ' + git init repo && + cd repo &&
We do not want to "chdir" around without isolating it in a subprocess. If this test fails after it goes to "repo" but before it does "cd ..", the next test begins in the "repo" directory, but it is most likely not expecting that.
Quoted 8 lines
Quoted 8 lines
t/t3903-stash.sh +0
-8-cat >expect <<EOF -diff --git a/file b/file -index 0cfbf08..00750ed 100644 ---- a/file -+++ b/file -@@ -1 +1 @@ --2 -+3
Quoted 8 lines
t/t3903-stash.sh test_expect_success 'stash some dirty working directory' ' · line 78
Quoted 8 lines
t/t3903-stash.sh +7
-1-EOF +test_stash () { + cp -R repo copy && + cd copy && + test_expect_success "$@" && + cd ../ && + rm -rf copy +}
This will create an anti-pattern, because you would want to have the part between "cd copy" and "cd .." in a subshell, but you do not want to do test_expect_success inside a subshell. Hence, this is a bad helper that does not help and should not be used, I would think.
Quoted 12 lines
t/t3903-stash.sh test_expect_success 'stash some dirty working directory' ' · line 84
Quoted 6 lines
t/t3903-stash.sh +1
-1-test_expect_success 'parents of stash' ' +test_stash 'parents of stash' ' test $(git rev-parse stash^) = $(git rev-parse HEAD) && git diff stash^2..stash >output && diff_cmp expect output 'For this sort of thing I think it's usually better to override "
test_expect_success" as a last resort, i.e. to have that "test_setup_stash_copy" just be a "setup_stash" or whatever function called from within yourtest_expect_success.
Quoted 5 lines
And instead of the "rm -rf" later, just do:
test_when_finished "rm -rf copy" && cp -R repo copy && [...]
Yup. I think this is how we would write it:
test_expect_success 'parents of stash' ' test_when_finished "rm -fr copy" && cp -R repo copy && ( cd copy && ... the real body of the test here, like ... test $(git rev-parse stash^) = $(git rev-parse HEAD) && ) '
Quoted 2 lines
The test still needs to deal with the sub-repo, but it could cd or use "-C".
I am not sure about this. test_expect_success does not take "-C".
PATCH v3 1/3 stash: add tests to ensure reflog --rewrite --updatref behavior
In reply to John Cai via GitGitGadgetFrom: John Cai <[email protected]>
There is missing test coverage to ensure that the resulting reflogs after a git stash drop has had its old oid rewritten if applicable, and if the refs/stash has been updated if applicable.
Add two tests that verify both of these happen.
--- t/t3903-stash.sh | 65 ++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 54 insertions(+), 11 deletions(-)
t/t3903-stash.sh +54 -11
@@ -41,20 +41,29 @@ diff_cmp () { rm -f "$1.compare" "$2.compare" } -test_expect_success 'stash some dirty working directory' ' - echo 1 >file && - git add file && - echo unrelated >other-file && - git add other-file && +setup_stash() { + repo_dir=$1 + if test -z $repo_dir; then + repo_dir="." + fi + + echo 1 >$repo_dir/file && + git -C $repo_dir add file && + echo unrelated >$repo_dir/other-file && + git -C $repo_dir add other-file && test_tick && - git commit -m initial && - echo 2 >file && + git -C $repo_dir commit -m initial && + echo 2 >$repo_dir/file && git add file && - echo 3 >file && + echo 3 >$repo_dir/file && test_tick && - git stash && - git diff-files --quiet && - git diff-index --cached --quiet HEAD + git -C $repo_dir stash && + git -C $repo_dir diff-files --quiet && + git -C $repo_dir diff-index --cached --quiet HEAD +} + +test_expect_success 'stash some dirty working directory' ' + setup_stash ' cat >expect <<EOF
@@ -185,6 +194,40 @@ test_expect_success 'drop middle stash by index' ' test 1 = $(git show HEAD:file) ' +test_expect_success 'drop stash reflog updates refs/stash' ' + git reset --hard && + git rev-parse refs/stash >expect && + echo 9 >file && + git stash && + git stash drop stash@{0} && + git rev-parse refs/stash >actual && + test_cmp expect actual +' + +test_expect_success REFFILES 'drop stash reflog updates refs/stash with rewrite' ' + git init repo && + setup_stash repo && + echo 9 >repo/file && + + old_oid="$(git -C repo rev-parse stash@{0})" && + git -C repo stash && + new_oid="$(git -C repo rev-parse stash@{0})" && + + cat >expect <<-EOF && + $(test_oid zero) $old_oid + $old_oid $new_oid + EOF + cut -d" " -f1-2 repo/.git/logs/refs/stash >actual && + test_cmp expect actual && + + git -C repo stash drop stash@{1} && + cut -d" " -f1-2 repo/.git/logs/refs/stash >actual && + cat >expect <<-EOF && + $(test_oid zero) $new_oid + EOF + test_cmp expect actual +' + test_expect_success 'stash pop' ' git reset --hard && git stash pop &&
Signature · 1 line
gitgitgadget
v3 cover libify reflog
In reply to John Cai via GitGitGadgetIn [1], there was a discussion around a bug report of stash not recovering in the middle of the process when killed with ctl-c. It turned out to not be a bug we need to fix. However, out of that discussion came the idea of libifying reflog. This can stand alone as a code improvement.
stash.c currently shells out to call reflog to delete reflogs. Libify reflog delete and call it from both builtin/reflog.c and builtin/stash.c.
This patch has three parts:
* add missing test coverage for git stash delete
* libify reflog's delete functionality and move some of the helpers into a reflog.c library and call reflog_delete from builtin/reflog.c
* call reflog_delete from builtin/stash.c
Updates since v2:
* removed unnecessary includes
* adjusted wrapping/whitespace in reflog.h
* adjusted test to be isolated from other tests since currently tests for stash depend on each other. There was some discussion around this and even a possibility to refactor the tests. However, it would have been a larger effort than is worth for this series, so instead I just made one of the tests I added be isolated from the others.
Updates since v1:
* added missing test coverage
* squashed 1/3 and 2/3 together
* moved enum into reflog.c
* updated object.h's flag allocation mapping
1. https://lore.kernel.org/git/[email protected]/
John Cai (3):
stash: add tests to ensure reflog --rewrite --updatref behavior
reflog: libify delete reflog function and helpers
stash: call reflog_delete() in reflog.c
Makefile | 1 + builtin/reflog.c | 455 +---------------------------------------------- builtin/stash.c | 18 +- object.h | 2 +- reflog.c | 432 ++++++++++++++++++++++++++++++++++++++++++++ reflog.h | 43 +++++ t/t3903-stash.sh | 65 +++++-- 7 files changed, 539 insertions(+), 477 deletions(-) create mode 100644 reflog.c create mode 100644 reflog.h
base-commit: e6ebfd0e8cbbd10878070c8a356b5ad1b3ca464e
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-1218%2Fjohn-cai%2Fjc-libify-reflog-v3
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-1218/john-cai/jc-libify-reflog-v3
Pull-Request: https://github.com/git/git/pull/1218
Range-diff vs v2:
1: 6e136b62ca4 ! 1: 33299825fc4 stash: add test to ensure reflog --rewrite --updatref behavior
@@ Metadata
Author: John Cai <[email protected]>
## Commit message ##
- stash: add test to ensure reflog --rewrite --updatref behavior
+ stash: add tests to ensure reflog --rewrite --updatref behavior
There is missing test coverage to ensure that the resulting reflogs
after a git stash drop has had its old oid rewritten if applicable, and
@@ Commit message
Signed-off-by: John Cai <[email protected]>
## t/t3903-stash.sh ##
+@@ t/t3903-stash.sh: diff_cmp () {
+ rm -f "$1.compare" "$2.compare"
+ }
+
+-test_expect_success 'stash some dirty working directory' '
+- echo 1 >file &&
+- git add file &&
+- echo unrelated >other-file &&
+- git add other-file &&
++setup_stash() {
++ repo_dir=$1
++ if test -z $repo_dir; then
++ repo_dir="."
++ fi
++
++ echo 1 >$repo_dir/file &&
++ git -C $repo_dir add file &&
++ echo unrelated >$repo_dir/other-file &&
++ git -C $repo_dir add other-file &&
+ test_tick &&
+- git commit -m initial &&
+- echo 2 >file &&
++ git -C $repo_dir commit -m initial &&
++ echo 2 >$repo_dir/file &&
+ git add file &&
+- echo 3 >file &&
++ echo 3 >$repo_dir/file &&
+ test_tick &&
+- git stash &&
+- git diff-files --quiet &&
+- git diff-index --cached --quiet HEAD
++ git -C $repo_dir stash &&
++ git -C $repo_dir diff-files --quiet &&
++ git -C $repo_dir diff-index --cached --quiet HEAD
++}
++
++test_expect_success 'stash some dirty working directory' '
++ setup_stash
+ '
+
+ cat >expect <<EOF
@@ t/t3903-stash.sh: test_expect_success 'drop middle stash by index' '
test 1 = $(git show HEAD:file)
'
@@ t/t3903-stash.sh: test_expect_success 'drop middle stash by index' '
+ test_cmp expect actual
+'
+
-+test_expect_success 'drop stash reflog updates refs/stash with rewrite' '
-+ git reset --hard &&
-+ echo 9 >file &&
-+ git stash &&
-+ oid="$(git rev-parse stash@{0})" &&
-+ git stash drop stash@{1} &&
-+ cut -d" " -f1-2 .git/logs/refs/stash >actual &&
++test_expect_success REFFILES 'drop stash reflog updates refs/stash with rewrite' '
++ git init repo &&
++ setup_stash repo &&
++ echo 9 >repo/file &&
++
++ old_oid="$(git -C repo rev-parse stash@{0})" &&
++ git -C repo stash &&
++ new_oid="$(git -C repo rev-parse stash@{0})" &&
++
++ cat >expect <<-EOF &&
++ $(test_oid zero) $old_oid
++ $old_oid $new_oid
++ EOF
++ cut -d" " -f1-2 repo/.git/logs/refs/stash >actual &&
++ test_cmp expect actual &&
++
++ git -C repo stash drop stash@{1} &&
++ cut -d" " -f1-2 repo/.git/logs/refs/stash >actual &&
+ cat >expect <<-EOF &&
-+ $(test_oid zero) $oid
++ $(test_oid zero) $new_oid
+ EOF
+ test_cmp expect actual
+'
@@ t/t3903-stash.sh: test_expect_success 'drop middle stash by index' '
test_expect_success 'stash pop' '
git reset --hard &&
git stash pop &&
-- test 3 = $(cat file) &&
-+ test 9 = $(cat file) &&
- test 1 = $(git show :file) &&
- test 1 = $(git show HEAD:file) &&
- test 0 = $(git stash list | wc -l)
2: e7c950218b1 ! 2: 33adfee4ca6 reflog: libify delete reflog function and helpers
@@ builtin/reflog.c
@@
#include "builtin.h"
#include "config.h"
- #include "lockfile.h"
+-#include "lockfile.h"
-#include "object-store.h"
- #include "repository.h"
+-#include "repository.h"
-#include "commit.h"
-#include "refs.h"
- #include "dir.h"
+-#include "dir.h"
-#include "tree-walk.h"
- #include "diff.h"
+-#include "diff.h"
#include "revision.h"
#include "reachable.h"
#include "worktree.h"
@@ object.h: struct object_array {
## reflog.c (new) ##
@@
+#include "cache.h"
-+#include "commit.h"
+#include "object-store.h"
-+#include "reachable.h"
+#include "reflog.h"
+#include "refs.h"
+#include "revision.h"
-+#include "tree-walk.h"
+#include "worktree.h"
+
+/* Remember to update object flag allocation in object.h */
@@ reflog.h (new)
@@
+#ifndef REFLOG_H
+#define REFLOG_H
-+
+#include "refs.h"
+
+struct cmd_reflog_expire_cb {
@@ reflog.h (new)
+ unsigned int dry_run:1;
+};
+
-+int reflog_delete(const char *rev, enum expire_reflog_flags flags, int verbose);
-+
++int reflog_delete(const char *rev, enum expire_reflog_flags flags,
++ int verbose);
+void reflog_expiry_cleanup(void *cb_data);
-+
+void reflog_expiry_prepare(const char *refname, const struct object_id *oid,
+ void *cb_data);
-+
+int should_expire_reflog_ent(struct object_id *ooid, struct object_id *noid,
+ const char *email, timestamp_t timestamp, int tz,
+ const char *message, void *cb_data);
-+
+int count_reflog_ent(struct object_id *ooid, struct object_id *noid,
+ const char *email, timestamp_t timestamp, int tz,
+ const char *message, void *cb_data);
-+
+int should_expire_reflog_ent_verbose(struct object_id *ooid,
+ struct object_id *noid,
+ const char *email,
+ timestamp_t timestamp, int tz,
+ const char *message, void *cb_data);
-+
+#endif /* REFLOG_H */ 3: a023a70092b = 3: b17d8e5d43a stash: call reflog_delete() in reflog.c
Signature · 1 line
gitgitgadget
PATCH v3 3/3 stash: call reflog_delete() in reflog.c
From: John Cai <[email protected]>
Now that cmd_reflog_delete has been libified an exported it into a new reflog.c library so we can call it directly from builtin/stash.c. This not only gives us a performance gain since we don't need to create a subprocess, but it also allows us to use the ref transactions api in the future.
--- builtin/stash.c | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-)
builtin/stash.c +4 -14
@@ -17,6 +17,7 @@#include "diffcore.h" #include "exec-cmd.h" #include "entry.h" +#include "reflog.h" #define INCLUDE_ALL_FILES 2
@@ -634,20 +635,9 @@ static int reflog_is_empty(const char *refname)static int do_drop_stash (struct stash_info *info,int quiet) { -int ret; -struct child_process cp_reflog =CHILD_PROCESS_INIT ; - -/* -* reflog does not provide a simple function for deleting refs. One will -* need to be added to avoid implementing too much reflog code here -*/ - - cp_reflog.git_cmd =1 ; -strvec_pushl (&cp_reflog.args,"reflog" ,"delete" ,"--updateref" , -"--rewrite" ,NULL ); -strvec_push (&cp_reflog.args, info->revision.buf); - ret =run_command (&cp_reflog); -if (!ret) { +if (!reflog_delete (info->revision.buf, +EXPIRE_REFLOGS_REWRITE |EXPIRE_REFLOGS_UPDATE_REF , +0 )) {if (!quiet)printf_ln (_ ("Dropped %s (%s)" ), info->revision.buf,oid_to_hex (&info->w_commit));
Signature · 1 line
gitgitgadget
PATCH v3 2/3 reflog: libify delete reflog function and helpers
In reply to John Cai via GitGitGadgetFrom: John Cai <[email protected]>
Currently stash shells out to reflog in order to delete refs. In an effort to reduce how much we shell out to a subprocess, libify the functionality that stash needs into reflog.c.
Add a reflog_delete function that is pretty much the logic in the while loop in builtin/reflog.c cmd_reflog_delete(). This is a function that builtin/reflog.c and builtin/stash.c can both call.
Also move functions needed by reflog_delete and export them.
--- Makefile | 1 + builtin/reflog.c | 455 +---------------------------------------------- object.h | 2 +- reflog.c | 432 ++++++++++++++++++++++++++++++++++++++++++++ reflog.h | 43 +++++ 5 files changed, 481 insertions(+), 452 deletions(-) create mode 100644 reflog.c create mode 100644 reflog.h
Makefile +1 -0
@@ -989,6 +989,7 @@ LIB_OBJS += rebase-interactive.o LIB_OBJS += rebase.o LIB_OBJS += ref-filter.o LIB_OBJS += reflog-walk.o +LIB_OBJS += reflog.o LIB_OBJS += refs.o LIB_OBJS += refs/debug.o LIB_OBJS += refs/files-backend.o
builtin/reflog.c +4 -451
499 lines not on this page · raw message
object.h +1 -1
@@ -75,7 +75,7 @@ struct object_array {* builtin/fsck.c: 0--3 * builtin/gc.c: 0 * builtin/index-pack.c: 2021 -* builtin/reflog.c: 10--12 +* reflog.c: 10--12 * builtin/show-branch.c: 0-------------------------------------------26 * builtin/unpack-objects.c: 2021 */
reflog.c new file +432 -0
432 lines not on this page · raw message
reflog.h new file +43 -0
43 lines not on this page · raw message
Signature · 1 line
gitgitgadget
Quoted 5 lines · John Cai via GitGitGadget
John Cai (3):
stash: add tests to ensure reflog --rewrite --updatref behavior
reflog: libify delete reflog function and helpers
stash: callreflog_delete()inreflog.c
Quoted 10 lines
Makefile | 1 + builtin/reflog.c | 455 +---------------------------------------------- builtin/stash.c | 18 +- object.h | 2 +- reflog.c | 432 ++++++++++++++++++++++++++++++++++++++++++++ reflog.h | 43 +++++ t/t3903-stash.sh | 65 +++++-- 7 files changed, 539 insertions(+), 477 deletions(-) create mode 100644 reflog.c create mode 100644 reflog.h
Thanks; I glossed over the discussion about tests (since it looks like you and Ævar already have a good handle on how things are going there).
The rest of this version of the series (which I looked at more closely) looks good to me.
Thanks
Taylor
Hi,
Just wanted to bump this thread. It'd be good to get another ack on these last set of changes.
Quoted 25 lines · Taylor Blau
Quoted 5 lines · John Cai via GitGitGadget
John Cai (3):
stash: add tests to ensure reflog --rewrite --updatref behavior
reflog: libify delete reflog function and helpers
stash: callreflog_delete()inreflog.cQuoted 10 lines
Makefile | 1 + builtin/reflog.c | 455 +---------------------------------------------- builtin/stash.c | 18 +- object.h | 2 +- reflog.c | 432 ++++++++++++++++++++++++++++++++++++++++++++ reflog.h | 43 +++++ t/t3903-stash.sh | 65 +++++-- 7 files changed, 539 insertions(+), 477 deletions(-) create mode 100644 reflog.c create mode 100644 reflog.hThanks; I glossed over the discussion about tests (since it looks like you and Ævar already have a good handle on how things are going there).
The rest of this version of the series (which I looked at more closely) looks good to me.
Thanks
Taylor
Re: [PATCH v3 1/3] stash: add tests to ensure reflog --rewrite --updatref behavior
In reply to John Cai via GitGitGadgetQuoted 90 lines · John Cai via GitGitGadget
From: John Cai <[email protected]>
There is missing test coverage to ensure that the resulting reflogs after a git stash drop has had its old oid rewritten if applicable, and if the refs/stash has been updated if applicable.
Add two tests that verify both of these happen.
Signed-off-by John Cai <[email protected]>--- t/t3903-stash.sh | 65 ++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 54 insertions(+), 11 deletions(-)t/t3903-stash.sh +47
-11@@ -41,20 +41,29 @@ diff_cmp () { rm -f "$1.compare" "$2.compare" } -test_expect_success 'stash some dirty working directory' ' - echo 1 >file && - git add file && - echo unrelated >other-file && - git add other-file && +setup_stash() { + repo_dir=$1 + if test -z $repo_dir; then + repo_dir="." + fi + + echo 1 >$repo_dir/file && + git -C $repo_dir add file && + echo unrelated >$repo_dir/other-file && + git -C $repo_dir add other-file && test_tick && - git commit -m initial && - echo 2 >file && + git -C $repo_dir commit -m initial && + echo 2 >$repo_dir/file && git add file && - echo 3 >file && + echo 3 >$repo_dir/file && test_tick && - git stash && - git diff-files --quiet && - git diff-index --cached --quiet HEAD + git -C $repo_dir stash && + git -C $repo_dir diff-files --quiet && + git -C $repo_dir diff-index --cached --quiet HEAD +} + +test_expect_success 'stash some dirty working directory' ' + setup_stash ' cat >expect <<EOF@@ -185,6 +194,40 @@ test_expect_success 'drop middle stash by index' ' test 1 = $(git show HEAD:file) ' +test_expect_success 'drop stash reflog updates refs/stash' ' + git reset --hard && + git rev-parse refs/stash >expect && + echo 9 >file && + git stash && + git stash drop stash@{0} && + git rev-parse refs/stash >actual && + test_cmp expect actual +' + +test_expect_success REFFILES 'drop stash reflog updates refs/stash with rewrite' ' + git init repo && + setup_stash repo && + echo 9 >repo/file && + + old_oid="$(git -C repo rev-parse stash@{0})" && + git -C repo stash && + new_oid="$(git -C repo rev-parse stash@{0})" && + + cat >expect <<-EOF && + $(test_oid zero) $old_oid + $old_oid $new_oid + EOF + cut -d" " -f1-2 repo/.git/logs/refs/stash >actual && + test_cmp expect actual && + + git -C repo stash drop stash@{1} &&
t/t3903-stash.sh test_expect_success 'drop middle stash by index' ' · line 233
Quoted 10 lines
t/t3903-stash.sh +7
-0+ cut -d" " -f1-2 repo/.git/logs/refs/stash >actual && + cat >expect <<-EOF && + $(test_oid zero) $new_oid + EOF + test_cmp expect actual +' + test_expect_success 'stash pop' ' git reset --hard && git stash pop &&
I just looked at the post-image of this and didn't notice it was altered existing code at first, so I was going to suggest just this:
diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh
index 73785cf862f..422d1f7a306 100755
--- a/t/t3903-stash.sh
+++ b/t/t3903-stash.sh
@@ -42,24 +42,14 @@ diff_cmp () {
}
setup_stash() {
- repo_dir=$1
- if test -z $repo_dir; then
- repo_dir="."
- fi
-
- echo 1 >$repo_dir/file &&
- git -C $repo_dir add file &&
- echo unrelated >$repo_dir/other-file &&
- git -C $repo_dir add other-file &&
- test_tick &&
- git -C $repo_dir commit -m initial &&
- echo 2 >$repo_dir/file &&
+ test_commit initial file 1 &&
+ test_commit second other-file unrelated &&
+ echo 2 >file &&
git add file &&
- echo 3 >$repo_dir/file &&
- test_tick &&
- git -C $repo_dir stash &&
- git -C $repo_dir diff-files --quiet &&
- git -C $repo_dir diff-index --cached --quiet HEAD
+ echo 3 >file &&
+ git stash &&
+ git diff-files --quiet &&
+ git diff-index --cached --quiet HEAD
}
test_expect_success 'stash some dirty working directory' '
@@ -206,7 +196,10 @@ test_expect_success 'drop stash reflog updates refs/stash' '
test_expect_success REFFILES 'drop stash reflog updates refs/stash with rewrite' '
git init repo &&
- setup_stash repo &&
+ (
+ cd repo &&
+ setup_stash repo
+ ) &&
echo 9 >repo/file &&
old_oid="$(git -C repo rev-parse stash@{0})" &&But I think much better as a replacement is:
diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh
index b149e2af441..9dd05a497bc 100755
--- a/t/t3903-stash.sh
+++ b/t/t3903-stash.sh
@@ -41,7 +41,7 @@ diff_cmp () {
rm -f "$1.compare" "$2.compare"
}
-test_expect_success 'stash some dirty working directory' '
+setup_stash() {
echo 1 >file &&
git add file &&
echo unrelated >other-file &&
@@ -55,6 +55,10 @@ test_expect_success 'stash some dirty working directory' '
git stash &&
git diff-files --quiet &&
git diff-index --cached --quiet HEAD
+}
+
+test_expect_success 'stash some dirty working directory' '
+ setup_stash
'
cat >expect <<EOF
@@ -185,6 +189,43 @@ test_expect_success 'drop middle stash by index' '
test 1 = $(git show HEAD:file)
'
+test_expect_success 'drop stash reflog updates refs/stash' '
+ git reset --hard &&
+ git rev-parse refs/stash >expect &&
+ echo 9 >file &&
+ git stash &&
+ git stash drop stash@{0} &&
+ git rev-parse refs/stash >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success REFFILES 'drop stash reflog updates refs/stash with rewrite' '
+ git init repo &&
+ (
+ cd repo &&
+ setup_stash repo
+ ) &&
+ echo 9 >repo/file &&
+
+ old_oid="$(git -C repo rev-parse stash@{0})" &&
+ git -C repo stash &&
+ new_oid="$(git -C repo rev-parse stash@{0})" &&
+
+ cat >expect <<-EOF &&
+ $(test_oid zero) $old_oid
+ $old_oid $new_oid
+ EOF
+ cut -d" " -f1-2 repo/.git/logs/refs/stash >actual &&
+ test_cmp expect actual &&
+
+ git -C repo stash drop stash@{1} &&
+ cut -d" " -f1-2 repo/.git/logs/refs/stash >actual &&
+ cat >expect <<-EOF &&
+ $(test_oid zero) $new_oid
+ EOF
+ test_cmp expect actual
+'
+
test_expect_success 'stash pop' '
git reset --hard &&
git stash pop &&I>e. the only reason you need to add that -C etc. is because you'd like to set it up in a subdirectory. Easier to just add the tiny bity of logic to make that a sub-shell instead.
Quoted 2 lines · John Cai
Just wanted to bump this thread. It'd be good to get another ack on these last set of changes.
Hi. Sorry that I didn't look at it earlier.
This looks good to me and I think everything that's been brought up has been addressed.
I left a nit on 1/3 suggesting a way to make that diff a bit smaller by using a subshell instead of refactoring an existing function.
But I think with or without that & a ro-roll this would be good to advance to "next" etc.
Thanks!
v4 cover libify reflog
In reply to John Cai via GitGitGadgetIn [1], there was a discussion around a bug report of stash not recovering in the middle of the process when killed with ctl-c. It turned out to not be a bug we need to fix. However, out of that discussion came the idea of libifying reflog. This can stand alone as a code improvement.
stash.c currently shells out to call reflog to delete reflogs. Libify reflog delete and call it from both builtin/reflog.c and builtin/stash.c.
This patch has three parts:
* add missing test coverage for git stash delete
* libify reflog's delete functionality and move some of the helpers into a reflog.c library and call reflog_delete from builtin/reflog.c
* call reflog_delete from builtin/stash.c
Updates since v3:
* refactored test to have a smaller diff
Updates since v2:
* removed unnecessary includes
* adjusted wrapping/whitespace in reflog.h
* adjusted test to be isolated from other tests since currently tests for stash depend on each other. There was some discussion around this and even a possibility to refactor the tests. However, it would have been a larger effort than is worth for this series, so instead I just made one of the tests I added be isolated from the others.
Updates since v1:
* added missing test coverage
* squashed 1/3 and 2/3 together
* moved enum into reflog.c
* updated object.h's flag allocation mapping
1. https://lore.kernel.org/git/[email protected]/
John Cai (3):
stash: add tests to ensure reflog --rewrite --updatref behavior
reflog: libify delete reflog function and helpers
stash: call reflog_delete() in reflog.c
Makefile | 1 + builtin/reflog.c | 455 +---------------------------------------------- builtin/stash.c | 18 +- object.h | 2 +- reflog.c | 432 ++++++++++++++++++++++++++++++++++++++++++++ reflog.h | 43 +++++ t/t3903-stash.sh | 43 ++++- 7 files changed, 527 insertions(+), 467 deletions(-) create mode 100644 reflog.c create mode 100644 reflog.h
base-commit: e6ebfd0e8cbbd10878070c8a356b5ad1b3ca464e
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-1218%2Fjohn-cai%2Fjc-libify-reflog-v4
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-1218/john-cai/jc-libify-reflog-v4
Pull-Request: https://github.com/git/git/pull/1218
Range-diff vs v3:
1: 33299825fc4 ! 1: 08bb8d3a9b9 stash: add tests to ensure reflog --rewrite --updatref behavior
@@ t/t3903-stash.sh: diff_cmp () {
}
-test_expect_success 'stash some dirty working directory' '
-- echo 1 >file &&
-- git add file &&
-- echo unrelated >other-file &&
-- git add other-file &&
+setup_stash() {
-+ repo_dir=$1
-+ if test -z $repo_dir; then
-+ repo_dir="."
-+ fi
-+
-+ echo 1 >$repo_dir/file &&
-+ git -C $repo_dir add file &&
-+ echo unrelated >$repo_dir/other-file &&
-+ git -C $repo_dir add other-file &&
- test_tick &&
-- git commit -m initial &&
-- echo 2 >file &&
-+ git -C $repo_dir commit -m initial &&
-+ echo 2 >$repo_dir/file &&
+ echo 1 >file &&
git add file &&
-- echo 3 >file &&
-+ echo 3 >$repo_dir/file &&
- test_tick &&
-- git stash &&
-- git diff-files --quiet &&
-- git diff-index --cached --quiet HEAD
-+ git -C $repo_dir stash &&
-+ git -C $repo_dir diff-files --quiet &&
-+ git -C $repo_dir diff-index --cached --quiet HEAD
+ echo unrelated >other-file &&
+@@ t/t3903-stash.sh: test_expect_success 'stash some dirty working directory' '
+ git stash &&
+ git diff-files --quiet &&
+ git diff-index --cached --quiet HEAD
+}
+
+test_expect_success 'stash some dirty working directory' '
@@ t/t3903-stash.sh: test_expect_success 'drop middle stash by index' '
+
+test_expect_success REFFILES 'drop stash reflog updates refs/stash with rewrite' '
+ git init repo &&
-+ setup_stash repo &&
++ (
++ cd repo &&
++ setup_stash
++ ) &&
+ echo 9 >repo/file &&
+
+ old_oid="$(git -C repo rev-parse stash@{0})" &&
2: 33adfee4ca6 = 2: 50471c2ee6f reflog: libify delete reflog function and helpers
3: b17d8e5d43a = 3: cb32d9bfe60 stash: call reflog_delete() in reflog.cSignature · 1 line
gitgitgadget
PATCH v4 1/3 stash: add tests to ensure reflog --rewrite --updatref behavior
From: John Cai <[email protected]>
There is missing test coverage to ensure that the resulting reflogs after a git stash drop has had its old oid rewritten if applicable, and if the refs/stash has been updated if applicable.
Add two tests that verify both of these happen.
--- t/t3903-stash.sh | 43 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-)
t/t3903-stash.sh +42 -1
@@ -41,7 +41,7 @@ diff_cmp () { rm -f "$1.compare" "$2.compare" } -test_expect_success 'stash some dirty working directory' ' +setup_stash() { echo 1 >file && git add file && echo unrelated >other-file &&
@@ -55,6 +55,10 @@ test_expect_success 'stash some dirty working directory' ' git stash && git diff-files --quiet && git diff-index --cached --quiet HEAD +} + +test_expect_success 'stash some dirty working directory' ' + setup_stash ' cat >expect <<EOF
@@ -185,6 +189,43 @@ test_expect_success 'drop middle stash by index' ' test 1 = $(git show HEAD:file) ' +test_expect_success 'drop stash reflog updates refs/stash' ' + git reset --hard && + git rev-parse refs/stash >expect && + echo 9 >file && + git stash && + git stash drop stash@{0} && + git rev-parse refs/stash >actual && + test_cmp expect actual +' + +test_expect_success REFFILES 'drop stash reflog updates refs/stash with rewrite' ' + git init repo && + ( + cd repo && + setup_stash + ) && + echo 9 >repo/file && + + old_oid="$(git -C repo rev-parse stash@{0})" && + git -C repo stash && + new_oid="$(git -C repo rev-parse stash@{0})" && + + cat >expect <<-EOF && + $(test_oid zero) $old_oid + $old_oid $new_oid + EOF + cut -d" " -f1-2 repo/.git/logs/refs/stash >actual && + test_cmp expect actual && + + git -C repo stash drop stash@{1} && + cut -d" " -f1-2 repo/.git/logs/refs/stash >actual && + cat >expect <<-EOF && + $(test_oid zero) $new_oid + EOF + test_cmp expect actual +' + test_expect_success 'stash pop' ' git reset --hard && git stash pop &&
Signature · 1 line
gitgitgadget
PATCH v4 3/3 stash: call reflog_delete() in reflog.c
In reply to John Cai via GitGitGadgetFrom: John Cai <[email protected]>
Now that cmd_reflog_delete has been libified an exported it into a new reflog.c library so we can call it directly from builtin/stash.c. This not only gives us a performance gain since we don't need to create a subprocess, but it also allows us to use the ref transactions api in the future.
--- builtin/stash.c | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-)
builtin/stash.c +4 -14
@@ -17,6 +17,7 @@#include "diffcore.h" #include "exec-cmd.h" #include "entry.h" +#include "reflog.h" #define INCLUDE_ALL_FILES 2
@@ -634,20 +635,9 @@ static int reflog_is_empty(const char *refname)static int do_drop_stash (struct stash_info *info,int quiet) { -int ret; -struct child_process cp_reflog =CHILD_PROCESS_INIT ; - -/* -* reflog does not provide a simple function for deleting refs. One will -* need to be added to avoid implementing too much reflog code here -*/ - - cp_reflog.git_cmd =1 ; -strvec_pushl (&cp_reflog.args,"reflog" ,"delete" ,"--updateref" , -"--rewrite" ,NULL ); -strvec_push (&cp_reflog.args, info->revision.buf); - ret =run_command (&cp_reflog); -if (!ret) { +if (!reflog_delete (info->revision.buf, +EXPIRE_REFLOGS_REWRITE |EXPIRE_REFLOGS_UPDATE_REF , +0 )) {if (!quiet)printf_ln (_ ("Dropped %s (%s)" ), info->revision.buf,oid_to_hex (&info->w_commit));
Signature · 1 line
gitgitgadget
PATCH v4 2/3 reflog: libify delete reflog function and helpers
In reply to John Cai via GitGitGadgetFrom: John Cai <[email protected]>
Currently stash shells out to reflog in order to delete refs. In an effort to reduce how much we shell out to a subprocess, libify the functionality that stash needs into reflog.c.
Add a reflog_delete function that is pretty much the logic in the while loop in builtin/reflog.c cmd_reflog_delete(). This is a function that builtin/reflog.c and builtin/stash.c can both call.
Also move functions needed by reflog_delete and export them.
--- Makefile | 1 + builtin/reflog.c | 455 +---------------------------------------------- object.h | 2 +- reflog.c | 432 ++++++++++++++++++++++++++++++++++++++++++++ reflog.h | 43 +++++ 5 files changed, 481 insertions(+), 452 deletions(-) create mode 100644 reflog.c create mode 100644 reflog.h
Makefile +1 -0
@@ -989,6 +989,7 @@ LIB_OBJS += rebase-interactive.o LIB_OBJS += rebase.o LIB_OBJS += ref-filter.o LIB_OBJS += reflog-walk.o +LIB_OBJS += reflog.o LIB_OBJS += refs.o LIB_OBJS += refs/debug.o LIB_OBJS += refs/files-backend.o
builtin/reflog.c +4 -451
499 lines not on this page · raw message
object.h +1 -1
@@ -75,7 +75,7 @@ struct object_array {* builtin/fsck.c: 0--3 * builtin/gc.c: 0 * builtin/index-pack.c: 2021 -* builtin/reflog.c: 10--12 +* reflog.c: 10--12 * builtin/show-branch.c: 0-------------------------------------------26 * builtin/unpack-objects.c: 2021 */
reflog.c new file +432 -0
432 lines not on this page · raw message
reflog.h new file +43 -0
43 lines not on this page · raw message
Signature · 1 line
gitgitgadget
Quoted 3 lines · John Cai via GitGitGadget
This patch has three parts:
* add missing test coverage for git stash delete
This looking better, relative to the previous iteration.
Quoted 2 lines
* libify reflog's delete functionality and move some of the helpers into a
reflog.clibrary and callreflog_deletefrombuiltin/reflog.c
This part hasn't changed since the implementation in the previous round I've looked at; looked sane.
Quoted 1 line
* call
reflog_deletefrombuiltin/stash.c
Likewise.
Thanks. Will queue.
Re: [PATCH v4 1/3] stash: add tests to ensure reflog --rewrite --updatref behavior
In reply to John Cai via GitGitGadgetQuoted 19 lines · John Cai via GitGitGadget
From: John Cai <[email protected]>
There is missing test coverage to ensure that the resulting reflogs after a git stash drop has had its old oid rewritten if applicable, and if the refs/stash has been updated if applicable.
Add two tests that verify both of these happen.
Signed-off-by John Cai <[email protected]>--- t/t3903-stash.sh | 43 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-)t/t3903-stash.sh +0
-0
t/t3903-stash.sh diff_cmp () { · line 44
Quoted 5 lines
t/t3903-stash.sh +1
-1@@ -41,7 +41,7 @@ diff_cmp () { rm -f "$1.compare" "$2.compare" } -test_expect_success 'stash some dirty working directory' ' +setup_stash() {
Style.
setup_stash () {but more importantly, is this really setting up "stash"? "setup_stash_test" or something, perhaps?
t/t3903-stash.sh test_expect_success 'stash some dirty working directory' ' · line 62
Quoted 3 lines
t/t3903-stash.sh +2
-0+test_expect_success 'stash some dirty working directory' ' + setup_stash '
OK.
Quoted 6 lines
t/t3903-stash.sh +6
-0+test_expect_success 'drop stash reflog updates refs/stash' ' + git reset --hard && + git rev-parse refs/stash >expect && + echo 9 >file && + git stash && + git stash drop stash@{0} &&
t/t3903-stash.sh test_expect_success 'drop middle stash by index' ' · line 207
Quoted 10 lines
t/t3903-stash.sh +10
-0+ git rev-parse refs/stash >actual && + test_cmp expect actual +' + +test_expect_success REFFILES 'drop stash reflog updates refs/stash with rewrite' ' + git init repo && + ( + cd repo && + setup_stash + ) &&
Hmph, so this is done inside the subdirectory. The implementation of the helper in this iteration does look cleaner than in the previous iteration.
But these many references to "repo/" and "-C repo" we see below makes me wonder why we do not put the whole thing inside the subshell we started earlier.
i.e.
git init repo &&
(
cd repo &&
setup_stash_test &&
echo 9 >file &&
old=$(git rev-parse stash@{0}) &&
git stash &&
new=$(git rev-parse stash@{0}) &&
...
test_cmp expect actual
)Quoted 24 lines
t/t3903-stash.sh +21
-0+ echo 9 >repo/file && + + old_oid="$(git -C repo rev-parse stash@{0})" && + git -C repo stash && + new_oid="$(git -C repo rev-parse stash@{0})" && + + cat >expect <<-EOF && + $(test_oid zero) $old_oid + $old_oid $new_oid + EOF + cut -d" " -f1-2 repo/.git/logs/refs/stash >actual && + test_cmp expect actual && + + git -C repo stash drop stash@{1} && + cut -d" " -f1-2 repo/.git/logs/refs/stash >actual && + cat >expect <<-EOF && + $(test_oid zero) $new_oid + EOF + test_cmp expect actual +' + test_expect_success 'stash pop' ' git reset --hard && git stash pop &&
Re: [PATCH v4 1/3] stash: add tests to ensure reflog --rewrite --updatref behavior
Hi Junio,
Quoted 67 lines · Junio C Hamano
Quoted 19 lines · John Cai via GitGitGadget
From: John Cai <[email protected]>
There is missing test coverage to ensure that the resulting reflogs after a git stash drop has had its old oid rewritten if applicable, and if the refs/stash has been updated if applicable.
Add two tests that verify both of these happen.
Signed-off-by John Cai <[email protected]>--- t/t3903-stash.sh | 43 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-)t/t3903-stash.sh +0
-0t/t3903-stash.sh diff_cmp () { · line 44
Quoted 5 lines
t/t3903-stash.sh +1
-1@@ -41,7 +41,7 @@ diff_cmp () { rm -f "$1.compare" "$2.compare" } -test_expect_success 'stash some dirty working directory' ' +setup_stash() {Style.
setup_stash () {but more importantly, is this really setting up "stash"? "
setup_stash_test" or something, perhaps?t/t3903-stash.sh test_expect_success 'stash some dirty working directory' ' · line 62
Quoted 3 lines
t/t3903-stash.sh +2
-0+test_expect_success 'stash some dirty working directory' ' + setup_stash 'OK.
Quoted 6 lines
t/t3903-stash.sh +6
-0+test_expect_success 'drop stash reflog updates refs/stash' ' + git reset --hard && + git rev-parse refs/stash >expect && + echo 9 >file && + git stash && + git stash drop stash@{0} &&t/t3903-stash.sh test_expect_success 'drop middle stash by index' ' · line 207
Quoted 10 lines
t/t3903-stash.sh +10
-0+ git rev-parse refs/stash >actual && + test_cmp expect actual +' + +test_expect_success REFFILES 'drop stash reflog updates refs/stash with rewrite' ' + git init repo && + ( + cd repo && + setup_stash + ) &&Hmph, so this is done inside the subdirectory. The implementation of the helper in this iteration does look cleaner than in the previous iteration.
But these many references to "repo/" and "-C repo" we see below makes me wonder why we do not put the whole thing inside the subshell we started earlier.
i.e.
Quoted 14 lines
git init repo &&
(
cd repo &&
setup_stash_test &&
echo 9 >file &&
old=$(git rev-parse stash@{0}) &&
git stash &&
new=$(git rev-parse stash@{0}) &&
...
test_cmp expect actual
)makes sense to me. Is this worth a re-roll and sending out another series to the list? or is it sufficient to make the change on my branch?
Quoted 24 lines
Quoted 24 lines
t/t3903-stash.sh +21
-0+ echo 9 >repo/file && + + old_oid="$(git -C repo rev-parse stash@{0})" && + git -C repo stash && + new_oid="$(git -C repo rev-parse stash@{0})" && + + cat >expect <<-EOF && + $(test_oid zero) $old_oid + $old_oid $new_oid + EOF + cut -d" " -f1-2 repo/.git/logs/refs/stash >actual && + test_cmp expect actual && + + git -C repo stash drop stash@{1} && + cut -d" " -f1-2 repo/.git/logs/refs/stash >actual && + cat >expect <<-EOF && + $(test_oid zero) $new_oid + EOF + test_cmp expect actual +' + test_expect_success 'stash pop' ' git reset --hard && git stash pop &&
Re: [PATCH v4 1/3] stash: add tests to ensure reflog --rewrite --updatref behavior
In reply to Junio C HamanoQuoted 19 lines · Junio C Hamano
"John Cai via GitGitGadget" <[email protected]> writes:
[...]t/t3903-stash.sh test_expect_success 'drop middle stash by index' ' · line 207
Quoted 6 lines
t/t3903-stash.sh +6
-0+test_expect_success REFFILES 'drop stash reflog updates refs/stash with rewrite' ' + git init repo && + ( + cd repo && + setup_stash + ) &&Hmph, so this is done inside the subdirectory. The implementation of the helper in this iteration does look cleaner than in the previous iteration.
But these many references to "repo/" and "-C repo" we see below makes me wonder why we do not put the whole thing inside the subshell we started earlier.
i.e.
Quoted 14 lines
git init repo &&
(
cd repo &&
setup_stash_test &&
echo 9 >file &&
old=$(git rev-parse stash@{0}) &&
git stash &&
new=$(git rev-parse stash@{0}) &&
...
test_cmp expect actual
)I wonder if we could avoid the subshell entirely and avoid relying on REFFILES (assuming we're not trying to test the implementation details of that refs backend) by doing something like
test_expect_success 'drop stash reflog updates refs/stash with rewrite' '
old=$(git rev-parse stash@{0}) &&
setup_stash_test &&
git rev-list -g stash >tmp &&
sed /$old/d tmp >expect &&
git rev-list -g stash >actual &&
test_cmp expect actual'
Best Wishes
Phillip
Quoted 24 lines
Quoted 24 lines
t/t3903-stash.sh +21
-0+ echo 9 >repo/file && + + old_oid="$(git -C repo rev-parse stash@{0})" && + git -C repo stash && + new_oid="$(git -C repo rev-parse stash@{0})" && + + cat >expect <<-EOF && + $(test_oid zero) $old_oid + $old_oid $new_oid + EOF + cut -d" " -f1-2 repo/.git/logs/refs/stash >actual && + test_cmp expect actual && + + git -C repo stash drop stash@{1} && + cut -d" " -f1-2 repo/.git/logs/refs/stash >actual && + cat >expect <<-EOF && + $(test_oid zero) $new_oid + EOF + test_cmp expect actual +' + test_expect_success 'stash pop' ' git reset --hard && git stash pop &&
Re: [PATCH v4 1/3] stash: add tests to ensure reflog --rewrite --updatref behavior
Quoted 33 lines · Phillip Wood
Quoted 15 lines · Junio C Hamano
"John Cai via GitGitGadget" <[email protected]> writes:
[...]t/t3903-stash.sh test_expect_success 'drop middle stash by index' ' · line 207
Quoted 6 lines
t/t3903-stash.sh +6
-0+test_expect_success REFFILES 'drop stash reflog updates refs/stash with rewrite' ' + git init repo && + ( + cd repo && + setup_stash + ) &&Hmph, so this is done inside the subdirectory. The implementation of the helper in this iteration does look cleaner than in the previous iteration.
But these many references to "repo/" and "-C repo" we see below makes me wonder why we do not put the whole thing inside the subshell we started earlier.
i.e.Quoted 12 lines
git init repo && ( cd repo && setup_stash_test && echo 9 >file && old=$(git rev-parse stash@{0}) && git stash && new=$(git rev-parse stash@{0}) && ... test_cmp expect actual )I wonder if we could avoid the subshell entirely and avoid relying on REFFILES (assuming we're not trying to test the implementation details of that refs backend) by doing something like
Quoted 8 lines
test_expect_success'drop stash reflog updates refs/stash with rewrite' 'old=$(git rev-parse stash@{0}) && setup_stash_test && git rev-list -g stash >tmp && sed /$old/d tmp >expect && git rev-list -g stash >actual && test_cmp expect actual'
Unless I'm missing something that "rev-list -g" will emit only the RHS of the stash logs, i.e. no "0000..." etc.
And if we only look at that the difference with specifying the flag isn't visible, no?
Quoted 24 lines
Quoted 24 lines
Quoted 24 lines
t/t3903-stash.sh +21
-0+ echo 9 >repo/file && + + old_oid="$(git -C repo rev-parse stash@{0})" && + git -C repo stash && + new_oid="$(git -C repo rev-parse stash@{0})" && + + cat >expect <<-EOF && + $(test_oid zero) $old_oid + $old_oid $new_oid + EOF + cut -d" " -f1-2 repo/.git/logs/refs/stash >actual && + test_cmp expect actual && + + git -C repo stash drop stash@{1} && + cut -d" " -f1-2 repo/.git/logs/refs/stash >actual && + cat >expect <<-EOF && + $(test_oid zero) $new_oid + EOF + test_cmp expect actual +' + test_expect_success 'stash pop' ' git reset --hard && git stash pop &&
Re: [PATCH v4 1/3] stash: add tests to ensure reflog --rewrite --updatref behavior
Quoted 45 lines · Ævar Arnfjörð Bjarmason
Quoted 33 lines · Phillip Wood
Quoted 15 lines · Junio C Hamano
"John Cai via GitGitGadget" <[email protected]> writes:
[...]t/t3903-stash.sh test_expect_success 'drop middle stash by index' ' · line 207
Quoted 6 lines
t/t3903-stash.sh +6
-0+test_expect_success REFFILES 'drop stash reflog updates refs/stash with rewrite' ' + git init repo && + ( + cd repo && + setup_stash + ) &&Hmph, so this is done inside the subdirectory. The implementation of the helper in this iteration does look cleaner than in the previous iteration.
But these many references to "repo/" and "-C repo" we see below makes me wonder why we do not put the whole thing inside the subshell we started earlier.
i.e.Quoted 12 lines
git init repo && ( cd repo && setup_stash_test && echo 9 >file && old=$(git rev-parse stash@{0}) && git stash && new=$(git rev-parse stash@{0}) && ... test_cmp expect actual )I wonder if we could avoid the subshell entirely and avoid relying on REFFILES (assuming we're not trying to test the implementation details of that refs backend) by doing something like
Quoted 8 lines
test_expect_success'drop stash reflog updates refs/stash with rewrite' 'old=$(git rev-parse stash@{0}) && setup_stash_test && git rev-list -g stash >tmp && sed /$old/d tmp >expect && git rev-list -g stash >actual && test_cmp expect actual'
Quoted 5 lines
Unless I'm missing something that "rev-list -g" will emit only the RHS of the stash logs, i.e. no "0000..." etc.
And if we only look at that the difference with specifying the flag isn't visible, no?
Maybe I'm missing what this test is actually needs to do. I thought it just needed to check that the deleted stash is removed from the reflog and the others are unchanged. You're right that it wont show the LHS and if that is important then you need to read the log file directly.
Best Wishes
Phillip
Quoted 25 lines
Quoted 24 lines
Quoted 24 lines
Quoted 24 lines
t/t3903-stash.sh +21
-0+ echo 9 >repo/file && + + old_oid="$(git -C repo rev-parse stash@{0})" && + git -C repo stash && + new_oid="$(git -C repo rev-parse stash@{0})" && + + cat >expect <<-EOF && + $(test_oid zero) $old_oid + $old_oid $new_oid + EOF + cut -d" " -f1-2 repo/.git/logs/refs/stash >actual && + test_cmp expect actual && + + git -C repo stash drop stash@{1} && + cut -d" " -f1-2 repo/.git/logs/refs/stash >actual && + cat >expect <<-EOF && + $(test_oid zero) $new_oid + EOF + test_cmp expect actual +' + test_expect_success 'stash pop' ' git reset --hard && git stash pop &&
Re: [PATCH v4 1/3] stash: add tests to ensure reflog --rewrite --updatref behavior
Hi Phillip,
Quoted 46 lines · Phillip Wood
Quoted 45 lines · Ævar Arnfjörð Bjarmason
Quoted 41 lines · Phillip Wood
Quoted 15 lines · Junio C Hamano
"John Cai via GitGitGadget" <[email protected]> writes:
[...]t/t3903-stash.sh test_expect_success 'drop middle stash by index' ' · line 207
Quoted 6 lines
t/t3903-stash.sh +6
-0+test_expect_success REFFILES 'drop stash reflog updates refs/stash with rewrite' ' + git init repo && + ( + cd repo && + setup_stash + ) &&Hmph, so this is done inside the subdirectory. The implementation of the helper in this iteration does look cleaner than in the previous iteration.
But these many references to "repo/" and "-C repo" we see below makes me wonder why we do not put the whole thing inside the subshell we started earlier.
i.e.Quoted 12 lines
git init repo && ( cd repo && setup_stash_test && echo 9 >file && old=$(git rev-parse stash@{0}) && git stash && new=$(git rev-parse stash@{0}) && ... test_cmp expect actual )I wonder if we could avoid the subshell entirely and avoid relying on REFFILES (assuming we're not trying to test the implementation details of that refs backend) by doing something like
test_expect_success'drop stash reflog updates refs/stash with rewrite' 'old=$(git rev-parse stash@{0}) && setup_stash_test && git rev-list -g stash >tmp && sed /$old/d tmp >expect && git rev-list -g stash >actual && test_cmp expect actual'
Quoted 7 lines
Quoted 5 lines
Unless I'm missing something that "rev-list -g" will emit only the RHS of the stash logs, i.e. no "0000..." etc.
And if we only look at that the difference with specifying the flag isn't visible, no?
Maybe I'm missing what this test is actually needs to do. I thought it just needed to check that the deleted stash is removed from the reflog and the others are unchanged. You're right that it wont show the LHS and if that is important then you need to read the log file directly.
We had discussed this briefly in [1], but the --rewrite option for reflog delete will rewrite the LHS, which is not visible to normal ref API users. So the only way to test that this happened is to reach inside of the file.
1. https://lore.kernel.org/git/[email protected]/
Quoted 4 lines
Best Wishes
Phillip
thanks,
John
Quoted 27 lines
Quoted 27 lines
Quoted 26 lines
Quoted 26 lines
Quoted 26 lines
t/t3903-stash.sh +21
-0+ echo 9 >repo/file && + + old_oid="$(git -C repo rev-parse stash@{0})" && + git -C repo stash && + new_oid="$(git -C repo rev-parse stash@{0})" && + + cat >expect <<-EOF && + $(test_oid zero) $old_oid + $old_oid $new_oid + EOF + cut -d" " -f1-2 repo/.git/logs/refs/stash >actual && + test_cmp expect actual && + + git -C repo stash drop stash@{1} && + cut -d" " -f1-2 repo/.git/logs/refs/stash >actual && + cat >expect <<-EOF && + $(test_oid zero) $new_oid + EOF + test_cmp expect actual +' + test_expect_success 'stash pop' ' git reset --hard && git stash pop &&
Re: [PATCH v4 1/3] stash: add tests to ensure reflog --rewrite --updatref behavior
Hi John
Quoted 53 lines · John Cai
Hi Phillip,
Quoted 49 lines · Phillip Wood
Quoted 48 lines · Ævar Arnfjörð Bjarmason
Quoted 33 lines · Phillip Wood
Quoted 15 lines · Junio C Hamano
"John Cai via GitGitGadget" <[email protected]> writes:
[...]t/t3903-stash.sh test_expect_success 'drop middle stash by index' ' · line 207
Quoted 6 lines
t/t3903-stash.sh +6
-0+test_expect_success REFFILES 'drop stash reflog updates refs/stash with rewrite' ' + git init repo && + ( + cd repo && + setup_stash + ) &&Hmph, so this is done inside the subdirectory. The implementation of the helper in this iteration does look cleaner than in the previous iteration.
But these many references to "repo/" and "-C repo" we see below makes me wonder why we do not put the whole thing inside the subshell we started earlier.
i.e.Quoted 12 lines
git init repo && ( cd repo && setup_stash_test && echo 9 >file && old=$(git rev-parse stash@{0}) && git stash && new=$(git rev-parse stash@{0}) && ... test_cmp expect actual )I wonder if we could avoid the subshell entirely and avoid relying on REFFILES (assuming we're not trying to test the implementation details of that refs backend) by doing something like
Quoted 8 lines
test_expect_success'drop stash reflog updates refs/stash with rewrite' 'old=$(git rev-parse stash@{0}) && setup_stash_test && git rev-list -g stash >tmp && sed /$old/d tmp >expect && git rev-list -g stash >actual && test_cmp expect actual'
Unless I'm missing something that "rev-list -g" will emit only the RHS of the stash logs, i.e. no "0000..." etc.
Quoted 8 lines
Quoted 4 lines
Quoted 2 lines
And if we only look at that the difference with specifying the flag isn't visible, no?
Maybe I'm missing what this test is actually needs to do. I thought it just needed to check that the deleted stash is removed from the reflog and the others are unchanged. You're right that it wont show the LHS and if that is important then you need to read the log file directly.
We had discussed this briefly in [1], but the --rewrite option for reflog delete will rewrite the LHS, which is not visible to normal ref API users. So the only way to test that this happened is to reach inside of the file.
Thanks for the pointer, that was useful context that could maybe be added to the commit message to explain why the test needs to check the lhs of the reflog if you reroll.
Best Wishes
Phillip
Quoted 35 lines
Quoted 4 lines
Best Wishes
Phillip
thanks,
JohnQuoted 27 lines
Quoted 27 lines
Quoted 26 lines
Quoted 26 lines
Quoted 26 lines
t/t3903-stash.sh +21
-0+ echo 9 >repo/file && + + old_oid="$(git -C repo rev-parse stash@{0})" && + git -C repo stash && + new_oid="$(git -C repo rev-parse stash@{0})" && + + cat >expect <<-EOF && + $(test_oid zero) $old_oid + $old_oid $new_oid + EOF + cut -d" " -f1-2 repo/.git/logs/refs/stash >actual && + test_cmp expect actual && + + git -C repo stash drop stash@{1} && + cut -d" " -f1-2 repo/.git/logs/refs/stash >actual && + cat >expect <<-EOF && + $(test_oid zero) $new_oid + EOF + test_cmp expect actual +' + test_expect_success 'stash pop' ' git reset --hard && git stash pop &&
Re: [PATCH v4 1/3] stash: add tests to ensure reflog --rewrite --updatref behavior
Hi Phillip,
Quoted 59 lines · Phillip Wood
Hi John
Quoted 56 lines · John Cai
Hi Phillip,
Quoted 52 lines · Phillip Wood
Quoted 50 lines · Ævar Arnfjörð Bjarmason
Quoted 33 lines · Phillip Wood
Quoted 15 lines · Junio C Hamano
"John Cai via GitGitGadget" <[email protected]> writes:
[...]Review
Quoted 6 lines
(quoted diff) +6
-0+test_expect_success REFFILES 'drop stash reflog updates refs/stash with rewrite' ' + git init repo && + ( + cd repo && + setup_stash + ) &&Hmph, so this is done inside the subdirectory. The implementation of the helper in this iteration does look cleaner than in the previous iteration.
But these many references to "repo/" and "-C repo" we see below makes me wonder why we do not put the whole thing inside the subshell we started earlier.
i.e.Quoted 12 lines
git init repo && ( cd repo && setup_stash_test && echo 9 >file && old=$(git rev-parse stash@{0}) && git stash && new=$(git rev-parse stash@{0}) && ... test_cmp expect actual )I wonder if we could avoid the subshell entirely and avoid relying on REFFILES (assuming we're not trying to test the implementation details of that refs backend) by doing something like
Quoted 8 lines
test_expect_success'drop stash reflog updates refs/stash with rewrite' 'old=$(git rev-parse stash@{0}) && setup_stash_test && git rev-list -g stash >tmp && sed /$old/d tmp >expect && git rev-list -g stash >actual && test_cmp expect actual'
Unless I'm missing something that "rev-list -g" will emit only the RHS of the stash logs, i.e. no "0000..." etc.
And if we only look at that the difference with specifying the flag isn't visible, no?
Quoted 7 lines
Quoted 5 lines
Quoted 1 line
Maybe I'm missing what this test is actually needs to do. I thought it just needed to check that the deleted stash is removed from the reflog and the others are unchanged. You're right that it wont show the LHS and if that is important then you need to read the log file directly.
We had discussed this briefly in [1], but the --rewrite option for reflog delete will rewrite the LHS, which is not visible to normal ref API users. So the only way to test that this happened is to reach inside of the file.
Thanks for the pointer, that was useful context that could maybe be added to the commit message to explain why the test needs to check the lhs of the reflog if you reroll.
Good point. that would be helpful context since it took me a while to figure it out myself--will re-roll, thanks!
Quoted 40 lines
Best Wishes
Phillip
Quoted 35 lines
Quoted 4 lines
Best Wishes
Phillip
thanks,
JohnQuoted 27 lines
Quoted 27 lines
Quoted 26 lines
Quoted 26 lines
Quoted 26 lines
(quoted diff) +21
-0+ echo 9 >repo/file && + + old_oid="$(git -C repo rev-parse stash@{0})" && + git -C repo stash && + new_oid="$(git -C repo rev-parse stash@{0})" && + + cat >expect <<-EOF && + $(test_oid zero) $old_oid + $old_oid $new_oid + EOF + cut -d" " -f1-2 repo/.git/logs/refs/stash >actual && + test_cmp expect actual && + + git -C repo stash drop stash@{1} && + cut -d" " -f1-2 repo/.git/logs/refs/stash >actual && + cat >expect <<-EOF && + $(test_oid zero) $new_oid + EOF + test_cmp expect actual +' + test_expect_success 'stash pop' ' git reset --hard && git stash pop &&