From 83933c9832af91a71337e429a6251f1a3b6d6f60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scharfe?= Date: Sat, 1 Oct 2011 17:38:34 +0200 Subject: checkout: check for "Previous HEAD" notice in t2020 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 Signed-off-by: Junio C Hamano diff --git a/t/t2020-checkout-detach.sh b/t/t2020-checkout-detach.sh index 2366f0f..068fba4 100755 --- a/t/t2020-checkout-detach.sh +++ b/t/t2020-checkout-detach.sh @@ -12,11 +12,14 @@ check_not_detached () { } ORPHAN_WARNING='you are leaving .* commit.*behind' +PREV_HEAD_DESC='Previous HEAD position was' check_orphan_warning() { - test_i18ngrep "$ORPHAN_WARNING" "$1" + test_i18ngrep "$ORPHAN_WARNING" "$1" && + test_i18ngrep ! "$PREV_HEAD_DESC" "$1" } check_no_orphan_warning() { - test_i18ngrep ! "$ORPHAN_WARNING" "$1" + test_i18ngrep ! "$ORPHAN_WARNING" "$1" && + test_i18ngrep "$PREV_HEAD_DESC" "$1" } reset () { -- cgit v0.10.2-6-g49f6 From 26c3177ee41897af984fac9148763131562accf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scharfe?= Date: Sat, 1 Oct 2011 17:43:52 +0200 Subject: revision: factor out add_pending_sha1 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 Signed-off-by: Junio C Hamano diff --git a/revision.c b/revision.c index c46cfaa..2e8aa33 100644 --- a/revision.c +++ b/revision.c @@ -185,6 +185,13 @@ static struct object *get_reference(struct rev_info *revs, const char *name, con return object; } +void add_pending_sha1(struct rev_info *revs, const char *name, + const unsigned char *sha1, unsigned int flags) +{ + struct object *object = get_reference(revs, name, sha1, flags); + add_pending_object(revs, object, name); +} + static struct commit *handle_commit(struct rev_info *revs, struct object *object, const char *name) { unsigned long flags = object->flags; @@ -832,9 +839,7 @@ struct all_refs_cb { static int handle_one_ref(const char *path, const unsigned char *sha1, int flag, void *cb_data) { struct all_refs_cb *cb = cb_data; - struct object *object = get_reference(cb->all_revs, path, sha1, - cb->all_flags); - add_pending_object(cb->all_revs, object, path); + add_pending_sha1(cb->all_revs, path, sha1, cb->all_flags); return 0; } diff --git a/revision.h b/revision.h index 3d64ada..4541265 100644 --- a/revision.h +++ b/revision.h @@ -191,6 +191,7 @@ extern void add_object(struct object *obj, const char *name); extern void add_pending_object(struct rev_info *revs, struct object *obj, const char *name); +extern void add_pending_sha1(struct rev_info *revs, const char *name, const unsigned char *sha1, unsigned int flags); extern void add_head_to_pending(struct rev_info *); -- cgit v0.10.2-6-g49f6 From 468224e580aeb55bd85b37b86f32baada3d17f1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scharfe?= Date: Sat, 1 Oct 2011 17:51:39 +0200 Subject: checkout: use add_pending_{object,sha1} in orphan check 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 Signed-off-by: Junio C Hamano diff --git a/builtin/checkout.c b/builtin/checkout.c index 28cdc51..a76899d 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -588,24 +588,11 @@ static void update_refs_for_switch(struct checkout_opts *opts, report_tracking(new); } -struct rev_list_args { - int argc; - int alloc; - const char **argv; -}; - -static void add_one_rev_list_arg(struct rev_list_args *args, const char *s) -{ - ALLOC_GROW(args->argv, args->argc + 1, args->alloc); - args->argv[args->argc++] = s; -} - -static int add_one_ref_to_rev_list_arg(const char *refname, - const unsigned char *sha1, - int flags, - void *cb_data) +static int add_pending_uninteresting_ref(const char *refname, + const unsigned char *sha1, + int flags, void *cb_data) { - add_one_rev_list_arg(cb_data, refname); + add_pending_sha1(cb_data, refname, sha1, flags | UNINTERESTING); return 0; } @@ -684,19 +671,17 @@ static void suggest_reattach(struct commit *commit, struct rev_info *revs) */ static void orphaned_commit_warning(struct commit *commit) { - struct rev_list_args args = { 0, 0, NULL }; struct rev_info revs; - - 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); + struct object *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)) -- cgit v0.10.2-6-g49f6 From 4a43d374fcbdea26b3596592a497a1c16f90b9e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scharfe?= Date: Sat, 1 Oct 2011 17:56:08 +0200 Subject: revision: add leak_pending flag 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 Signed-off-by: Junio C Hamano diff --git a/revision.c b/revision.c index 2e8aa33..6d329b4 100644 --- a/revision.c +++ b/revision.c @@ -1974,7 +1974,8 @@ int prepare_revision_walk(struct rev_info *revs) } e++; } - free(list); + if (!revs->leak_pending) + free(list); if (revs->no_walk) return 0; diff --git a/revision.h b/revision.h index 4541265..366a9b4 100644 --- a/revision.h +++ b/revision.h @@ -97,6 +97,7 @@ struct rev_info { date_mode_explicit:1, preserve_subject:1; unsigned int disable_stdin:1; + unsigned int leak_pending:1; enum date_mode date_mode; -- cgit v0.10.2-6-g49f6 From 353f5657a8263bf4159d7e0450fb891df5e2b4c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scharfe?= Date: Sat, 1 Oct 2011 18:01:12 +0200 Subject: bisect: use leak_pending flag 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 Signed-off-by: Junio C Hamano diff --git a/bisect.c b/bisect.c index dd7e8ed..63cf166 100644 --- a/bisect.c +++ b/bisect.c @@ -823,12 +823,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_common calls prepare_revision_walk right away, which + * (together with .leak_pending = 1) makes us the sole owner of + * the list of pending objects. + */ bisect_common(&revs); res = (revs.commits != NULL); @@ -837,6 +839,7 @@ static int check_ancestors(const char *prefix) struct object *o = pending_copy.objects[i].item; clear_commit_marks((struct commit *)o, ALL_REV_FLAGS); } + free(pending_copy.objects); return res; } -- cgit v0.10.2-6-g49f6 From 5be7859962585589f374f8467f3252bfcfa10fd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scharfe?= Date: Sat, 1 Oct 2011 18:02:36 +0200 Subject: bundle: use leak_pending flag 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 Signed-off-by: Junio C Hamano diff --git a/bundle.c b/bundle.c index f48fd7d..26cc9ab 100644 --- a/bundle.c +++ b/bundle.c @@ -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(struct object_array)); - for (i = 0; i < revs.pending.nr; i++) { - struct object_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((struct commit *)refs.objects[i].item, -1); + free(refs.objects); if (verbose) { struct ref_list *r; -- cgit v0.10.2-6-g49f6 From 1062141928aaa1d272be8ce007d371168e8daef6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scharfe?= Date: Sat, 1 Oct 2011 18:09:36 +0200 Subject: checkout: use leak_pending flag 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 Signed-off-by: Junio C Hamano diff --git a/builtin/checkout.c b/builtin/checkout.c index a76899d..2e8402f 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -596,17 +596,6 @@ static int add_pending_uninteresting_ref(const char *refname, return 0; } -static int clear_commit_marks_from_one_ref(const char *refname, - const unsigned char *sha1, - int flags, - void *cb_data) -{ - struct commit *commit = lookup_commit_reference_gently(sha1, 1); - if (commit) - clear_commit_marks(commit, -1); - return 0; -} - static void describe_one_orphan(struct strbuf *sb, struct commit *commit) { parse_commit(commit); @@ -673,6 +662,8 @@ static void orphaned_commit_warning(struct commit *commit) { struct rev_info revs; struct object *object = &commit->object; + struct object_array refs; + unsigned int i; init_revisions(&revs, NULL); setup_revisions(0, NULL, &revs, NULL); @@ -682,6 +673,9 @@ static void orphaned_commit_warning(struct commit *commit) for_each_ref(add_pending_uninteresting_ref, &revs); + refs = revs.pending; + revs.leak_pending = 1; + if (prepare_revision_walk(&revs)) die(_("internal error in revision walk")); if (!(commit->object.flags & UNINTERESTING)) @@ -689,8 +683,13 @@ static void orphaned_commit_warning(struct commit *commit) else describe_detached_head(_("Previous HEAD position was"), commit); - clear_commit_marks(commit, -1); - for_each_ref(clear_commit_marks_from_one_ref, NULL); + for (i = 0; i < refs.nr; i++) { + struct object *o = refs.objects[i].item; + struct commit *c = lookup_commit_reference_gently(o->sha1, 1); + if (c) + clear_commit_marks(c, ALL_REV_FLAGS); + } + free(refs.objects); } static int switch_branches(struct checkout_opts *opts, struct branch_info *new) -- cgit v0.10.2-6-g49f6 From 86a0a408b900eecc9d0d4a1eb8ae223181e96679 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scharfe?= Date: Sat, 1 Oct 2011 18:16:08 +0200 Subject: commit: factor out clear_commit_marks_for_object_array 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 Signed-off-by: Junio C Hamano diff --git a/bisect.c b/bisect.c index 63cf166..54674fc 100644 --- a/bisect.c +++ b/bisect.c @@ -818,7 +818,7 @@ static int check_ancestors(const char *prefix) { struct rev_info revs; struct object_array pending_copy; - int i, res; + int res; bisect_rev_setup(&revs, prefix, "^%s", "%s", 0); @@ -835,10 +835,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++) { - struct object *o = pending_copy.objects[i].item; - clear_commit_marks((struct commit *)o, ALL_REV_FLAGS); - } + clear_commit_marks_for_object_array(&pending_copy, ALL_REV_FLAGS); free(pending_copy.objects); return res; diff --git a/builtin/checkout.c b/builtin/checkout.c index 2e8402f..cefa51d 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -663,7 +663,6 @@ static void orphaned_commit_warning(struct commit *commit) struct rev_info revs; struct object *object = &commit->object; struct object_array refs; - unsigned int i; init_revisions(&revs, NULL); setup_revisions(0, NULL, &revs, NULL); @@ -683,12 +682,7 @@ static void orphaned_commit_warning(struct commit *commit) else describe_detached_head(_("Previous HEAD position was"), commit); - for (i = 0; i < refs.nr; i++) { - struct object *o = refs.objects[i].item; - struct commit *c = lookup_commit_reference_gently(o->sha1, 1); - if (c) - clear_commit_marks(c, ALL_REV_FLAGS); - } + clear_commit_marks_for_object_array(&refs, ALL_REV_FLAGS); free(refs.objects); } diff --git a/bundle.c b/bundle.c index 26cc9ab..a8ea918 100644 --- a/bundle.c +++ b/bundle.c @@ -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((struct commit *)refs.objects[i].item, -1); + clear_commit_marks_for_object_array(&refs, ALL_REV_FLAGS); free(refs.objects); if (verbose) { diff --git a/commit.c b/commit.c index ac337c7..4d80f25 100644 --- a/commit.c +++ b/commit.c @@ -440,6 +440,20 @@ void clear_commit_marks(struct commit *commit, unsigned int mark) } } +void clear_commit_marks_for_object_array(struct object_array *a, unsigned mark) +{ + struct object *object; + struct commit *commit; + unsigned int i; + + for (i = 0; i < a->nr; i++) { + object = a->objects[i].item; + commit = lookup_commit_reference_gently(object->sha1, 1); + if (commit) + clear_commit_marks(commit, mark); + } +} + struct commit *pop_commit(struct commit_list **stack) { struct commit_list *top = *stack; diff --git a/commit.h b/commit.h index a2d571b..641f70f 100644 --- a/commit.h +++ b/commit.h @@ -126,6 +126,7 @@ struct commit *pop_most_recent_commit(struct commit_list **list, struct commit *pop_commit(struct commit_list **stack); void clear_commit_marks(struct commit *commit, unsigned int mark); +void clear_commit_marks_for_object_array(struct object_array *a, unsigned mark); /* * Performs an in-place topological sort of list supplied. -- cgit v0.10.2-6-g49f6