From: Junio C Hamano <hidden> Date: 2016-06-15 22:52:09
René Scharfe [off-list ref] writes:
quoted hunk
Hi Martin,
Am 29.09.2011 22:11, schrieb Martin Fick:
quoted
Your patch works well for me. It achieves about the same
gains as Julian's patch. Thanks!
OK, and what happens if you apply the following patch on top of my first
one? It avoids going through all the refs a second time during cleanup,
at the cost of going through the list of all known objects. I wonder if
that's any faster in your case.
...
static void describe_one_orphan(struct strbuf *sb, struct commit *commit)
The function already clears all the flag bits from commits near the tip of
all the refs (i.e. whatever commit it traverses until it gets to the fork
point), so it cannot be reused in other contexts where the caller
- first marks commit objects with some flag bits for its own purpose,
unrelated to the "orphaned"-ness check;
- calls this function to issue a warning; and then
- use the flag it earlier set to do something useful.
which requires "cleaning after yourself, by clearing only the bits you
used without disturbing other bits that you do not use" pattern.
It might be a better solution to not bother to clear the marks at all;
would it break anything in this codepath?
From: René Scharfe <hidden> Date: 2016-06-15 22:52:09
Am 30.09.2011 18:52, schrieb Junio C Hamano:
René Scharfe [off-list ref] writes:
quoted
Hi Martin,
Am 29.09.2011 22:11, schrieb Martin Fick:
quoted
Your patch works well for me. It achieves about the same
gains as Julian's patch. Thanks!
OK, and what happens if you apply the following patch on top of my first
one? It avoids going through all the refs a second time during cleanup,
at the cost of going through the list of all known objects. I wonder if
that's any faster in your case.
...
static void describe_one_orphan(struct strbuf *sb, struct commit *commit)
The function already clears all the flag bits from commits near the tip of
all the refs (i.e. whatever commit it traverses until it gets to the fork
point), so it cannot be reused in other contexts where the caller
- first marks commit objects with some flag bits for its own purpose,
unrelated to the "orphaned"-ness check;
- calls this function to issue a warning; and then
- use the flag it earlier set to do something useful.
which requires "cleaning after yourself, by clearing only the bits you
used without disturbing other bits that you do not use" pattern.
Yes, clear_commit_marks_for_all is a bit brutal. Callers could clear
specfic bits (e.g. SEEN|UNINTERESTING) instead of ALL_REV_FLAGS, though.
It might be a better solution to not bother to clear the marks at all;
would it break anything in this codepath?
Unfortunately, yes; the cleanup part was added by 5c08dc48 later, when
it become apparent that it's really needed.
However, since the patch only buys us a 5% speedup I'm not sure it's
worth it in its current form.
René
From: René Scharfe <hidden> Date: 2016-06-15 22:52:09
Am 30.09.2011 20:17, schrieb René Scharfe:
Am 30.09.2011 18:52, schrieb Junio C Hamano:
quoted
It might be a better solution to not bother to clear the marks at
all; would it break anything in this codepath?
Unfortunately, yes; the cleanup part was added by 5c08dc48 later,
when it become apparent that it's really needed.
However, since the patch only buys us a 5% speedup I'm not sure it's
worth it in its current form.
I found something better: A trick used by bisect and bundle. They copy
the list of pending objects from rev_info before calling
prepare_revision_walk and then go through it to clean up the commit
marks without going through the refs again. And I think we can even
improve it a little.
The following patches tighten some orphan/detached head tests a little,
then comes a resend of my first patch on this topic, only split up into
two, then four patches that introduce the trick mentioned above (which
could be squashed together perhaps) and the last one is a bonus
refactoring patch.
bisect.c | 20 +++++++-------
builtin/checkout.c | 58 +++++++++++++------------------------------
bundle.c | 11 +++-----
commit.c | 14 ++++++++++
commit.h | 1 +
revision.c | 14 +++++++---
revision.h | 2 +
t/t2020-checkout-detach.sh | 7 ++++-
8 files changed, 64 insertions(+), 63 deletions(-)
René
From: René Scharfe <hidden> Date: 2016-06-15 22:52:09
If we leave a detached head, exactly one of two things happens: either
checkout warns about it being an orphan or describes it as a courtesy.
Test t2020 already checked that the warning is shown as needed. This
patch also checks for the description.
Signed-off-by: Rene Scharfe <redacted>
---
t/t2020-checkout-detach.sh | 7 +++++--
1 files changed, 5 insertions(+), 2 deletions(-)
From: René Scharfe <hidden> Date: 2016-06-15 22:52:09
This function is a combination of the static get_reference and
add_pending_object. It can be used to easily queue objects by hash.
Signed-off-by: Rene Scharfe <redacted>
---
The next patch is going to use it in checkout.
revision.c | 11 ++++++++---
revision.h | 1 +
2 files changed, 9 insertions(+), 3 deletions(-)
From: René Scharfe <hidden> Date: 2016-06-15 22:52:09
Instead of building a list of textual arguments for setup_revisions, use
add_pending_object and add_pending_sha1 to queue the objects directly.
This is both faster and simpler.
Signed-off-by: Rene Scharfe <redacted>
---
builtin/checkout.c | 39 ++++++++++++---------------------------
1 files changed, 12 insertions(+), 27 deletions(-)
@@ -685,19 +672,17 @@ static void suggest_reattach(struct commit *commit, struct rev_info *revs)*/staticvoidorphaned_commit_warning(structcommit*commit){-structrev_list_argsargs={0,0,NULL};structrev_inforevs;--add_one_rev_list_arg(&args,"(internal)");-add_one_rev_list_arg(&args,sha1_to_hex(commit->object.sha1));-add_one_rev_list_arg(&args,"--not");-for_each_ref(add_one_ref_to_rev_list_arg,&args);-add_one_rev_list_arg(&args,"--");-add_one_rev_list_arg(&args,NULL);+structobject*object=&commit->object;init_revisions(&revs,NULL);-if(setup_revisions(args.argc-1,args.argv,&revs,NULL)!=1)-die(_("internal error: only -- alone should have been left"));+setup_revisions(0,NULL,&revs,NULL);++object->flags&=~UNINTERESTING;+add_pending_object(&revs,object,sha1_to_hex(object->sha1));++for_each_ref(add_pending_uninteresting_ref,&revs);+if(prepare_revision_walk(&revs))die(_("internal error in revision walk"));if(!(commit->object.flags&UNINTERESTING))
From: René Scharfe <hidden> Date: 2016-06-15 22:52:09
The new flag leak_pending in struct rev_info can be used to prevent
prepare_revision_walk from freeing the list of pending objects. It
will still forget about them, so it really is leaked. This behaviour
may look weird at first, but it can be useful if the pointer to the
list is saved before calling prepare_revision_walk.
Signed-off-by: Rene Scharfe <redacted>
---
The next three patches are going to use this flag.
revision.c | 3 ++-
revision.h | 1 +
2 files changed, 3 insertions(+), 1 deletions(-)
From: René Scharfe <hidden> Date: 2016-06-15 22:52:09
Instead of creating a copy of the list of pending objects, copy the
struct object_array that points to it, turn on leak_pending, and thus
cause prepare_revision_walk to leave it to us. And free it once
we're done.
Signed-off-by: Rene Scharfe <redacted>
---
bisect.c | 13 ++++++++-----
1 files changed, 8 insertions(+), 5 deletions(-)
@@ -831,12 +831,14 @@ static int check_ancestors(const char *prefix)bisect_rev_setup(&revs,prefix,"^%s","%s",0);/* Save pending objects, so they can be cleaned up later. */-memset(&pending_copy,0,sizeof(pending_copy));-for(i=0;i<revs.pending.nr;i++)-add_object_array(revs.pending.objects[i].item,-revs.pending.objects[i].name,-&pending_copy);+pending_copy=revs.pending;+revs.leak_pending=1;+/*+*bisect_commoncallsprepare_revision_walkrightaway,which+*(togetherwith.leak_pending=1)makesusthesoleownerof+*thelistofpendingobjects.+*/bisect_common(&revs);res=(revs.commits!=NULL);
@@ -845,6 +847,7 @@ static int check_ancestors(const char *prefix)structobject*o=pending_copy.objects[i].item;clear_commit_marks((structcommit*)o,ALL_REV_FLAGS);}+free(pending_copy.objects);returnres;}
From: René Scharfe <hidden> Date: 2016-06-15 22:52:09
Instead of creating a copy of the list of pending objects, copy the
struct object_array that points to it, turn on leak_pending, and thus
cause prepare_revision_walk to leave it to us. And free it once
we're done.
Signed-off-by: Rene Scharfe <redacted>
---
bundle.c | 8 +++-----
1 files changed, 3 insertions(+), 5 deletions(-)
@@ -122,11 +122,8 @@ int verify_bundle(struct bundle_header *header, int verbose)req_nr=revs.pending.nr;setup_revisions(2,argv,&revs,NULL);-memset(&refs,0,sizeof(structobject_array));-for(i=0;i<revs.pending.nr;i++){-structobject_array_entry*e=revs.pending.objects+i;-add_object_array(e->item,e->name,&refs);-}+refs=revs.pending;+revs.leak_pending=1;if(prepare_revision_walk(&revs))die("revision walk setup failed");
@@ -146,6 +143,7 @@ int verify_bundle(struct bundle_header *header, int verbose)for(i=0;i<refs.nr;i++)clear_commit_marks((structcommit*)refs.objects[i].item,-1);+free(refs.objects);if(verbose){structref_list*r;
From: René Scharfe <hidden> Date: 2016-06-15 22:52:09
Instead of going through all the references again when we clear the
commit marks, do it like bisect and bundle and gain ownership of the
list of pending objects which we constructed from those references.
We simply copy the struct object_array that points to the list, set
the flag leak_pending and then prepare_revision_walk won't destroy
it and it's ours. We use it to clear the marks and free it at the
end.
Signed-off-by: Rene Scharfe <redacted>
---
builtin/checkout.c | 25 ++++++++++++-------------
1 files changed, 12 insertions(+), 13 deletions(-)
From: René Scharfe <hidden> Date: 2016-06-15 22:52:09
Factor out the code to clear the commit marks for a whole struct
object_array from builtin/checkout.c into its own exported function
clear_commit_marks_for_object_array and use it in bisect and bundle
as well. It handles tags and commits and ignores objects of any
other type.
Signed-off-by: Rene Scharfe <redacted>
---
bisect.c | 7 ++-----
builtin/checkout.c | 8 +-------
bundle.c | 3 +--
commit.c | 14 ++++++++++++++
commit.h | 1 +
5 files changed, 19 insertions(+), 14 deletions(-)
@@ -826,7 +826,7 @@ static int check_ancestors(const char *prefix){structrev_inforevs;structobject_arraypending_copy;-inti,res;+intres;bisect_rev_setup(&revs,prefix,"^%s","%s",0);
@@ -843,10 +843,7 @@ static int check_ancestors(const char *prefix)res=(revs.commits!=NULL);/* Clean up objects used, as they will be reused. */-for(i=0;i<pending_copy.nr;i++){-structobject*o=pending_copy.objects[i].item;-clear_commit_marks((structcommit*)o,ALL_REV_FLAGS);-}+clear_commit_marks_for_object_array(&pending_copy,ALL_REV_FLAGS);free(pending_copy.objects);returnres;
@@ -141,8 +141,7 @@ int verify_bundle(struct bundle_header *header, int verbose)refs.objects[i].name);}-for(i=0;i<refs.nr;i++)-clear_commit_marks((structcommit*)refs.objects[i].item,-1);+clear_commit_marks_for_object_array(&refs,ALL_REV_FLAGS);free(refs.objects);if(verbose){
Heya,
On Sat, Oct 1, 2011 at 17:38, René Scharfe [off-list ref] wrote:
If we leave a detached head, exactly one of two things happens: either
checkout warns about it being an orphan or describes it as a courtesy.
Test t2020 already checked that the warning is shown as needed. This
patch also checks for the description.
A cover letter would have been nice for such a long series :).
--
Cheers,
Sverre Rabbelier