From eafb45265bb9fcbee3cc03b451da7e17db9e6be7 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 22 Jul 2009 23:07:05 -0700 Subject: do_one_ref(): null_sha1 check is not about broken ref f8948e2 (remote prune: warn dangling symrefs, 2009-02-08) introduced a more dangerous variant of for_each_ref() family that skips the check for dangling refs, but it also made another unrelated check optional by mistake. The check to see if a ref points at 0{40} is not about brokenness, but is about a possible future plan to represent a deleted ref by writing 40 "0" in a loose ref when there is a stale version of the same ref already in .git/packed-refs, so that we can implement deletion of a ref without having to rewrite the packed refs file excluding the ref being deleted. This check has to live outside of the conditional. Signed-off-by: Junio C Hamano --- refs.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/refs.c b/refs.c index bb0762ee2..3da3c8cef 100644 --- a/refs.c +++ b/refs.c @@ -531,9 +531,10 @@ static int do_one_ref(const char *base, each_ref_fn fn, int trim, { if (strncmp(base, entry->name, trim)) return 0; + /* Is this a "negative ref" that represents a deleted ref? */ + if (is_null_sha1(entry->sha1)) + return 0; if (!(flags & DO_FOR_EACH_INCLUDE_BROKEN)) { - if (is_null_sha1(entry->sha1)) - return 0; if (!has_sha1_file(entry->sha1)) { error("%s does not point to a valid object!", entry->name); return 0; -- cgit v1.2.1 From e6e4a47ba12bd19ed956251f191b1ea9915f61f8 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Thu, 23 Jul 2009 10:17:04 -0700 Subject: git branch: fix performance problem 'git branch' looks at _all_ the refs, and verifies them. Which means that during cold-cache situations with a slow disk (and lots of tags, for example) it can take several very annoying seconds (7.5s according to a report by Carlos R. Mafra). This avoids most of it by simply doing the filtering before looking up the commits, by using the "raw" version of for_each_ref. Reported-by: Carlos R. Mafra Signed-off-by: Linus Torvalds Signed-off-by: Junio C Hamano --- builtin-branch.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/builtin-branch.c b/builtin-branch.c index 91098ca9b..3784dda09 100644 --- a/builtin-branch.c +++ b/builtin-branch.c @@ -240,6 +240,10 @@ static int append_ref(const char *refname, const unsigned char *sha1, int flags, if (ARRAY_SIZE(ref_kind) <= i) return 0; + /* Don't add types the caller doesn't want */ + if ((kind & ref_list->kinds) == 0) + return 0; + commit = lookup_commit_reference_gently(sha1, 1); if (!commit) return error("branch '%s' does not point at a commit", refname); @@ -248,10 +252,6 @@ static int append_ref(const char *refname, const unsigned char *sha1, int flags, if (!is_descendant_of(commit, ref_list->with_commit)) return 0; - /* Don't add types the caller doesn't want */ - if ((kind & ref_list->kinds) == 0) - return 0; - if (merge_filter != NO_FILTER) add_pending_object(&ref_list->revs, (struct object *)commit, refname); @@ -426,7 +426,7 @@ static void print_ref_list(int kinds, int detached, int verbose, int abbrev, str ref_list.with_commit = with_commit; if (merge_filter != NO_FILTER) init_revisions(&ref_list.revs, NULL); - for_each_ref(append_ref, &ref_list); + for_each_rawref(append_ref, &ref_list); if (merge_filter != NO_FILTER) { struct commit *filter; filter = lookup_commit_reference_gently(merge_filter_ref, 0); -- cgit v1.2.1 From 191d1ac435c01e2a7acfb93fb9da8378da90214c Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Thu, 23 Jul 2009 12:05:34 -0700 Subject: git branch: avoid unnecessary object lookups They can be expensive in the cold-cache case, so don't bother looking up the commits for all branches unless we really need them for some reason. Signed-off-by: Linus Torvalds Signed-off-by: Junio C Hamano --- builtin-branch.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/builtin-branch.c b/builtin-branch.c index 3784dda09..0e30756b1 100644 --- a/builtin-branch.c +++ b/builtin-branch.c @@ -191,7 +191,7 @@ struct ref_item { struct ref_list { struct rev_info revs; - int index, alloc, maxwidth; + int index, alloc, maxwidth, verbose; struct ref_item *list; struct commit_list *with_commit; int kinds; @@ -244,17 +244,20 @@ static int append_ref(const char *refname, const unsigned char *sha1, int flags, if ((kind & ref_list->kinds) == 0) return 0; - commit = lookup_commit_reference_gently(sha1, 1); - if (!commit) - return error("branch '%s' does not point at a commit", refname); + commit = NULL; + if (ref_list->verbose || ref_list->with_commit || merge_filter != NO_FILTER) { + commit = lookup_commit_reference_gently(sha1, 1); + if (!commit) + return error("branch '%s' does not point at a commit", refname); - /* Filter with with_commit if specified */ - if (!is_descendant_of(commit, ref_list->with_commit)) - return 0; + /* Filter with with_commit if specified */ + if (!is_descendant_of(commit, ref_list->with_commit)) + return 0; - if (merge_filter != NO_FILTER) - add_pending_object(&ref_list->revs, - (struct object *)commit, refname); + if (merge_filter != NO_FILTER) + add_pending_object(&ref_list->revs, + (struct object *)commit, refname); + } /* Resize buffer */ if (ref_list->index >= ref_list->alloc) { @@ -423,6 +426,7 @@ static void print_ref_list(int kinds, int detached, int verbose, int abbrev, str memset(&ref_list, 0, sizeof(ref_list)); ref_list.kinds = kinds; + ref_list.verbose = verbose; ref_list.with_commit = with_commit; if (merge_filter != NO_FILTER) init_revisions(&ref_list.revs, NULL); -- cgit v1.2.1 From 7e9ff00bbe1f437ff492a714758a4f7360feb22b Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Thu, 23 Jul 2009 12:13:48 -0700 Subject: git branch: clean up detached branch handling Make the 'show detached branch info' a routine of its own. And in the process, avoid the object lookup that is unnecessary if the current branch isn't detached. Signed-off-by: Linus Torvalds Signed-off-by: Junio C Hamano --- builtin-branch.c | 38 +++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/builtin-branch.c b/builtin-branch.c index 0e30756b1..887fa60fa 100644 --- a/builtin-branch.c +++ b/builtin-branch.c @@ -191,7 +191,7 @@ struct ref_item { struct ref_list { struct rev_info revs; - int index, alloc, maxwidth, verbose; + int index, alloc, maxwidth, verbose, abbrev; struct ref_item *list; struct commit_list *with_commit; int kinds; @@ -418,15 +418,34 @@ static int calc_maxwidth(struct ref_list *refs) return w; } + +static void show_detached(struct ref_list *ref_list) +{ + struct commit *head_commit = lookup_commit_reference_gently(head_sha1, 1); + + if (head_commit && is_descendant_of(head_commit, ref_list->with_commit)) { + struct ref_item item; + item.name = xstrdup("(no branch)"); + item.len = strlen(item.name); + item.kind = REF_LOCAL_BRANCH; + item.dest = NULL; + item.commit = head_commit; + if (item.len > ref_list->maxwidth) + ref_list->maxwidth = item.len; + print_ref_item(&item, ref_list->maxwidth, ref_list->verbose, ref_list->abbrev, 1, ""); + free(item.name); + } +} + static void print_ref_list(int kinds, int detached, int verbose, int abbrev, struct commit_list *with_commit) { int i; struct ref_list ref_list; - struct commit *head_commit = lookup_commit_reference_gently(head_sha1, 1); memset(&ref_list, 0, sizeof(ref_list)); ref_list.kinds = kinds; ref_list.verbose = verbose; + ref_list.abbrev = abbrev; ref_list.with_commit = with_commit; if (merge_filter != NO_FILTER) init_revisions(&ref_list.revs, NULL); @@ -446,19 +465,8 @@ static void print_ref_list(int kinds, int detached, int verbose, int abbrev, str qsort(ref_list.list, ref_list.index, sizeof(struct ref_item), ref_cmp); detached = (detached && (kinds & REF_LOCAL_BRANCH)); - if (detached && head_commit && - is_descendant_of(head_commit, with_commit)) { - struct ref_item item; - item.name = xstrdup("(no branch)"); - item.len = strlen(item.name); - item.kind = REF_LOCAL_BRANCH; - item.dest = NULL; - item.commit = head_commit; - if (item.len > ref_list.maxwidth) - ref_list.maxwidth = item.len; - print_ref_item(&item, ref_list.maxwidth, verbose, abbrev, 1, ""); - free(item.name); - } + if (detached) + show_detached(&ref_list); for (i = 0; i < ref_list.index; i++) { int current = !detached && -- cgit v1.2.1 From 96d69b554325b6caa323428e64fba62ca033310d Mon Sep 17 00:00:00 2001 From: Matthias Andree Date: Fri, 24 Jul 2009 10:17:13 +0200 Subject: Fix export_marks() error handling. - Don't leak one FILE * on error per export_marks() call. Found with cppcheck and reported by Martin Ettl. - Abort the potentially long for(;idnums.size;) loop on write errors. - Record error if fprintf() fails for reasons not required to set the stream error indicator, such as ENOMEM. - Add a trailing full-stop to error message when fopen() fails. Signed-off-by: Matthias Andree Signed-off-by: Junio C Hamano --- builtin-fast-export.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/builtin-fast-export.c b/builtin-fast-export.c index 673171322..9091481fd 100644 --- a/builtin-fast-export.c +++ b/builtin-fast-export.c @@ -428,21 +428,27 @@ static void export_marks(char *file) uint32_t mark; struct object_decoration *deco = idnums.hash; FILE *f; + int e = 0; f = fopen(file, "w"); if (!f) - error("Unable to open marks file %s for writing", file); + error("Unable to open marks file %s for writing.", file); for (i = 0; i < idnums.size; i++) { if (deco->base && deco->base->type == 1) { mark = ptr_to_mark(deco->decoration); - fprintf(f, ":%"PRIu32" %s\n", mark, - sha1_to_hex(deco->base->sha1)); + if (fprintf(f, ":%"PRIu32" %s\n", mark, + sha1_to_hex(deco->base->sha1)) < 0) { + e = 1; + break; + } } deco++; } - if (ferror(f) || fclose(f)) + e |= ferror(f); + e |= fclose(f); + if (e) error("Unable to write marks file %s.", file); } -- cgit v1.2.1 From 01ae841ccf3aa5d5331a4e6aed6122fee6617740 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Thu, 23 Jul 2009 22:30:07 -0700 Subject: SunOS grep does not understand -C nor -e The first "grep -C1" test in t7002 does not pass on my SunOS-5.11-i86pc, and that is not because our way to spawn external grep is broken, but because the native grep does not understand -C. It turns out that Peff was also using this option himself because our Makefile doesn't do that automatically. Brandon Casey uses SUNWspro compiler without having to set this, and it turns out that the compiler does not define preprocessor macro __unix__ which made him always use the built-in grep, never an external one. Let's be more explicit and say that we do not use external grep on Suns. Signed-off-by: Junio C Hamano --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index c6b81d012..f88ed3e14 100644 --- a/Makefile +++ b/Makefile @@ -702,6 +702,7 @@ ifeq ($(uname_S),SunOS) NO_HSTRERROR = YesPlease NO_MKDTEMP = YesPlease OLD_ICONV = UnfortunatelyYes + NO_EXTERNAL_GREP = YesPlease ifeq ($(uname_R),5.8) NO_UNSETENV = YesPlease NO_SETENV = YesPlease -- cgit v1.2.1