From 518120e3487a00148f8001454f1e76e484442a22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santi=20B=C3=A9jar?= Date: Mon, 25 Feb 2008 10:43:33 +0100 Subject: [PATCH 01/53] git-describe: --long shows the object name even for a tagged commit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is useful when you want to see parts of the commit object name in "describe" output, even when the commit in question happens to be a tagged version. Instead of just emitting the tag name, it will describe such a commit as v1.2-0-deadbeef (0th commit since tag v1.2 that points at object deadbeef....). Signed-off-by: Santi Béjar Signed-off-by: Junio C Hamano --- Documentation/git-describe.txt | 9 +++++++++ builtin-describe.c | 11 ++++++++++- t/t6120-describe.sh | 2 ++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/Documentation/git-describe.txt b/Documentation/git-describe.txt index 1c3dfb40c6..270b808755 100644 --- a/Documentation/git-describe.txt +++ b/Documentation/git-describe.txt @@ -51,6 +51,15 @@ OPTIONS being employed to standard error. The tag name will still be printed to standard out. +--long:: + Always output the long format (the tag, the number of commits + and the abbreviated commit name) even when it matches a tag. + This is useful when you want to see parts of the commit object name + in "describe" output, even when the commit in question happens to be + a tagged version. Instead of just emitting the tag name, it will + describe such a commit as v1.2-0-deadbeef (0th commit since tag v1.2 + that points at object deadbeef....). + --match :: Only consider tags matching the given pattern (can be used to avoid leaking private tags made from the repository). diff --git a/builtin-describe.c b/builtin-describe.c index 3428483134..3fd2e7371f 100644 --- a/builtin-describe.c +++ b/builtin-describe.c @@ -17,6 +17,7 @@ static const char * const describe_usage[] = { static int debug; /* Display lots of verbose info */ static int all; /* Default to annotated tags only */ static int tags; /* But allow any tags if --tags is specified */ +static int longformat; static int abbrev = DEFAULT_ABBREV; static int max_candidates = 10; const char *pattern = NULL; @@ -155,7 +156,11 @@ static void describe(const char *arg, int last_one) n = cmit->util; if (n) { - printf("%s\n", n->path); + if (!longformat) + printf("%s\n", n->path); + else + printf("%s-0-g%s\n", n->path, + find_unique_abbrev(cmit->object.sha1, abbrev)); return; } @@ -254,6 +259,7 @@ int cmd_describe(int argc, const char **argv, const char *prefix) OPT_BOOLEAN(0, "debug", &debug, "debug search strategy on stderr"), OPT_BOOLEAN(0, "all", &all, "use any ref in .git/refs"), OPT_BOOLEAN(0, "tags", &tags, "use any tag in .git/refs/tags"), + OPT_BOOLEAN(0, "long", &longformat, "always use long format"), OPT__ABBREV(&abbrev), OPT_INTEGER(0, "candidates", &max_candidates, "consider most recent tags (default: 10)"), @@ -270,6 +276,9 @@ int cmd_describe(int argc, const char **argv, const char *prefix) save_commit_buffer = 0; + if (longformat && abbrev == 0) + die("--long is incompatible with --abbrev=0"); + if (contains) { const char **args = xmalloc((6 + argc) * sizeof(char*)); int i = 0; diff --git a/t/t6120-describe.sh b/t/t6120-describe.sh index ae8ee11183..a7557bdc79 100755 --- a/t/t6120-describe.sh +++ b/t/t6120-describe.sh @@ -94,4 +94,6 @@ check_describe D-* --tags HEAD^^ check_describe A-* --tags HEAD^^2 check_describe B --tags HEAD^^2^ +check_describe B-0-* --long HEAD^^2^ + test_done From 355885d531568e144ce5c9a2f65792a3aa8b5528 Mon Sep 17 00:00:00 2001 From: Martin Koegler Date: Mon, 25 Feb 2008 22:46:04 +0100 Subject: [PATCH 02/53] add generic, type aware object chain walker The requirements are: * it may not crash on NULL pointers * a callback function is needed, as index-pack/unpack-objects need to do different things * the type information is needed to check the expected <-> real type and print better error messages Signed-off-by: Martin Koegler Signed-off-by: Junio C Hamano --- Makefile | 4 +-- cache.h | 1 + fsck.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ fsck.h | 23 ++++++++++++++ 4 files changed, 117 insertions(+), 2 deletions(-) create mode 100644 fsck.c create mode 100644 fsck.h diff --git a/Makefile b/Makefile index 92341c4bbe..33c367dfb1 100644 --- a/Makefile +++ b/Makefile @@ -297,7 +297,7 @@ LIB_H = \ run-command.h strbuf.h tag.h tree.h git-compat-util.h revision.h \ tree-walk.h log-tree.h dir.h path-list.h unpack-trees.h builtin.h \ utf8.h reflog-walk.h patch-ids.h attr.h decorate.h progress.h \ - mailmap.h remote.h parse-options.h transport.h diffcore.h hash.h + mailmap.h remote.h parse-options.h transport.h diffcore.h hash.h fsck.h DIFF_OBJS = \ diff.o diff-lib.o diffcore-break.o diffcore-order.o \ @@ -320,7 +320,7 @@ LIB_OBJS = \ alloc.o merge-file.o path-list.o help.o unpack-trees.o $(DIFF_OBJS) \ color.o wt-status.o archive-zip.o archive-tar.o shallow.o utf8.o \ convert.o attr.o decorate.o progress.o mailmap.o symlinks.o remote.o \ - transport.o bundle.o walker.o parse-options.o ws.o archive.o + transport.o bundle.o walker.o parse-options.o ws.o archive.o fsck.o BUILTIN_OBJS = \ builtin-add.o \ diff --git a/cache.h b/cache.h index 43ba6a3ba5..d3b898708b 100644 --- a/cache.h +++ b/cache.h @@ -189,6 +189,7 @@ enum object_type { /* 5 for future expansion */ OBJ_OFS_DELTA = 6, OBJ_REF_DELTA = 7, + OBJ_ANY, OBJ_MAX, }; diff --git a/fsck.c b/fsck.c new file mode 100644 index 0000000000..98fb41af68 --- /dev/null +++ b/fsck.c @@ -0,0 +1,91 @@ +#include "cache.h" +#include "object.h" +#include "blob.h" +#include "tree.h" +#include "tree-walk.h" +#include "commit.h" +#include "tag.h" +#include "fsck.h" + +static int fsck_walk_tree(struct tree *tree, fsck_walk_func walk, void *data) +{ + struct tree_desc desc; + struct name_entry entry; + int res = 0; + + if (parse_tree(tree)) + return -1; + + init_tree_desc(&desc, tree->buffer, tree->size); + while (tree_entry(&desc, &entry)) { + int result; + + if (S_ISGITLINK(entry.mode)) + continue; + if (S_ISDIR(entry.mode)) + result = walk(&lookup_tree(entry.sha1)->object, OBJ_TREE, data); + else if (S_ISREG(entry.mode) || S_ISLNK(entry.mode)) + result = walk(&lookup_blob(entry.sha1)->object, OBJ_BLOB, data); + else { + result = error("in tree %s: entry %s has bad mode %.6o\n", + sha1_to_hex(tree->object.sha1), entry.path, entry.mode); + } + if (result < 0) + return result; + if (!res) + res = result; + } + return res; +} + +static int fsck_walk_commit(struct commit *commit, fsck_walk_func walk, void *data) +{ + struct commit_list *parents; + int res; + int result; + + if (parse_commit(commit)) + return -1; + + result = walk((struct object *)commit->tree, OBJ_TREE, data); + if (result < 0) + return result; + res = result; + + parents = commit->parents; + while (parents) { + result = walk((struct object *)parents->item, OBJ_COMMIT, data); + if (result < 0) + return result; + if (!res) + res = result; + parents = parents->next; + } + return res; +} + +static int fsck_walk_tag(struct tag *tag, fsck_walk_func walk, void *data) +{ + if (parse_tag(tag)) + return -1; + return walk(tag->tagged, OBJ_ANY, data); +} + +int fsck_walk(struct object *obj, fsck_walk_func walk, void *data) +{ + if (!obj) + return -1; + switch (obj->type) { + case OBJ_BLOB: + return 0; + case OBJ_TREE: + return fsck_walk_tree((struct tree *)obj, walk, data); + case OBJ_COMMIT: + return fsck_walk_commit((struct commit *)obj, walk, data); + case OBJ_TAG: + return fsck_walk_tag((struct tag *)obj, walk, data); + default: + error("Unknown object type for %s", sha1_to_hex(obj->sha1)); + return -1; + } +} diff --git a/fsck.h b/fsck.h new file mode 100644 index 0000000000..ba5514a818 --- /dev/null +++ b/fsck.h @@ -0,0 +1,23 @@ +#ifndef GIT_FSCK_H +#define GIT_FSCK_H + +/* + * callback function for fsck_walk + * type is the expected type of the object or OBJ_ANY + * the return value is: + * 0 everything OK + * <0 error signaled and abort + * >0 error signaled and do not abort + */ +typedef int (*fsck_walk_func)(struct object *obj, int type, void *data); + +/* descend in all linked child objects + * the return value is: + * -1 error in processing the object + * <0 return value of the callback, which lead to an abort + * >0 return value of the first sigaled error >0 (in the case of no other errors) + * 0 everything OK + */ +int fsck_walk(struct object *obj, fsck_walk_func walk, void *data); + +#endif From 271b8d25b25e49b367087440e093e755e5f35aa9 Mon Sep 17 00:00:00 2001 From: Martin Koegler Date: Mon, 25 Feb 2008 22:46:05 +0100 Subject: [PATCH 03/53] builtin-fsck: move away from object-refs to fsck_walk Signed-off-by: Martin Koegler Signed-off-by: Junio C Hamano --- builtin-fsck.c | 99 ++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 71 insertions(+), 28 deletions(-) diff --git a/builtin-fsck.c b/builtin-fsck.c index 2a6e94deaf..7321ab236b 100644 --- a/builtin-fsck.c +++ b/builtin-fsck.c @@ -8,6 +8,7 @@ #include "pack.h" #include "cache-tree.h" #include "tree-walk.h" +#include "fsck.h" #include "parse-options.h" #define REACHABLE 0x0001 @@ -63,13 +64,73 @@ static int objwarning(struct object *obj, const char *err, ...) return -1; } +static int mark_object(struct object *obj, int type, void *data) +{ + struct tree *tree = NULL; + struct object *parent = data; + int result; + + if (!obj) { + printf("broken link from %7s %s\n", + typename(parent->type), sha1_to_hex(parent->sha1)); + printf("broken link from %7s %s\n", + (type == OBJ_ANY ? "unknown" : typename(type)), "unknown"); + errors_found |= ERROR_REACHABLE; + return 1; + } + + if (type != OBJ_ANY && obj->type != type) + objerror(parent, "wrong object type in link"); + + if (obj->flags & REACHABLE) + return 0; + obj->flags |= REACHABLE; + if (!obj->parsed) { + if (parent && !has_sha1_file(obj->sha1)) { + printf("broken link from %7s %s\n", + typename(parent->type), sha1_to_hex(parent->sha1)); + printf(" to %7s %s\n", + typename(obj->type), sha1_to_hex(obj->sha1)); + errors_found |= ERROR_REACHABLE; + } + return 1; + } + + if (obj->type == OBJ_TREE) { + obj->parsed = 0; + tree = (struct tree *)obj; + if (parse_tree(tree) < 0) + return 1; /* error already displayed */ + } + result = fsck_walk(obj, mark_object, obj); + if (tree) { + free(tree->buffer); + tree->buffer = NULL; + } + if (result < 0) + result = 1; + + return result; +} + +static void mark_object_reachable(struct object *obj) +{ + mark_object(obj, OBJ_ANY, 0); +} + +static int mark_used(struct object *obj, int type, void *data) +{ + if (!obj) + return 1; + obj->used = 1; + return 0; +} + /* * Check a single reachable object */ static void check_reachable_object(struct object *obj) { - const struct object_refs *refs; - /* * We obviously want the object to be parsed, * except if it was in a pack-file and we didn't @@ -82,25 +143,6 @@ static void check_reachable_object(struct object *obj) errors_found |= ERROR_REACHABLE; return; } - - /* - * Check that everything that we try to reference is also good. - */ - refs = lookup_object_refs(obj); - if (refs) { - unsigned j; - for (j = 0; j < refs->count; j++) { - struct object *ref = refs->ref[j]; - if (ref->parsed || - (has_sha1_file(ref->sha1))) - continue; - printf("broken link from %7s %s\n", - typename(obj->type), sha1_to_hex(obj->sha1)); - printf(" to %7s %s\n", - typename(ref->type), sha1_to_hex(ref->sha1)); - errors_found |= ERROR_REACHABLE; - } - } } /* @@ -414,6 +456,8 @@ static int fsck_sha1(const unsigned char *sha1) if (obj->flags & SEEN) return 0; obj->flags |= SEEN; + if (fsck_walk(obj, mark_used, 0)) + objerror(obj, "broken links"); if (obj->type == OBJ_BLOB) return 0; if (obj->type == OBJ_TREE) @@ -538,13 +582,13 @@ static int fsck_handle_reflog_ent(unsigned char *osha1, unsigned char *nsha1, obj = lookup_object(osha1); if (obj) { obj->used = 1; - mark_reachable(obj, REACHABLE); + mark_object_reachable(obj); } } obj = lookup_object(nsha1); if (obj) { obj->used = 1; - mark_reachable(obj, REACHABLE); + mark_object_reachable(obj); } return 0; } @@ -574,7 +618,7 @@ static int fsck_handle_ref(const char *refname, const unsigned char *sha1, int f error("%s: not a commit", refname); default_refs++; obj->used = 1; - mark_reachable(obj, REACHABLE); + mark_object_reachable(obj); return 0; } @@ -660,7 +704,7 @@ static int fsck_cache_tree(struct cache_tree *it) sha1_to_hex(it->sha1)); return 1; } - mark_reachable(obj, REACHABLE); + mark_object_reachable(obj); obj->used = 1; if (obj->type != OBJ_TREE) err |= objerror(obj, "non-tree in cache-tree"); @@ -693,7 +737,6 @@ int cmd_fsck(int argc, const char **argv, const char *prefix) { int i, heads; - track_object_refs = 1; errors_found = 0; argc = parse_options(argc, argv, fsck_opts, fsck_usage, 0); @@ -741,7 +784,7 @@ int cmd_fsck(int argc, const char **argv, const char *prefix) continue; obj->used = 1; - mark_reachable(obj, REACHABLE); + mark_object_reachable(obj); heads++; continue; } @@ -773,7 +816,7 @@ int cmd_fsck(int argc, const char **argv, const char *prefix) continue; obj = &blob->object; obj->used = 1; - mark_reachable(obj, REACHABLE); + mark_object_reachable(obj); } if (active_cache_tree) fsck_cache_tree(active_cache_tree); From 7914053ba9901be1f1530f46e8e2e6ee6f4ae5b1 Mon Sep 17 00:00:00 2001 From: Martin Koegler Date: Mon, 25 Feb 2008 22:46:06 +0100 Subject: [PATCH 04/53] Remove unused object-ref code Signed-off-by: Martin Koegler Signed-off-by: Junio C Hamano --- Makefile | 2 +- builtin-fetch-pack.c | 1 - builtin-pack-objects.c | 1 - builtin-rev-list.c | 1 - commit.c | 11 ------ object-refs.c | 87 ------------------------------------------ object.h | 8 ---- tag.c | 6 --- tree.c | 48 ----------------------- upload-pack.c | 1 - walker.c | 1 - 11 files changed, 1 insertion(+), 166 deletions(-) delete mode 100644 object-refs.c diff --git a/Makefile b/Makefile index 33c367dfb1..8ff0c772f1 100644 --- a/Makefile +++ b/Makefile @@ -312,7 +312,7 @@ LIB_OBJS = \ patch-ids.o \ object.o pack-check.o pack-write.o patch-delta.o path.o pkt-line.o \ sideband.o reachable.o reflog-walk.o \ - quote.o read-cache.o refs.o run-command.o dir.o object-refs.o \ + quote.o read-cache.o refs.o run-command.o dir.o \ server-info.o setup.o sha1_file.o sha1_name.o strbuf.o \ tag.o tree.o usage.o config.o environment.o ctype.o copy.o \ revision.o pager.o tree-walk.o xdiff-interface.o \ diff --git a/builtin-fetch-pack.c b/builtin-fetch-pack.c index e68e01592d..410414d91f 100644 --- a/builtin-fetch-pack.c +++ b/builtin-fetch-pack.c @@ -385,7 +385,6 @@ static int everything_local(struct ref **refs, int nr_match, char **match) int retval; unsigned long cutoff = 0; - track_object_refs = 0; save_commit_buffer = 0; for (ref = *refs; ref; ref = ref->next) { diff --git a/builtin-pack-objects.c b/builtin-pack-objects.c index d3efeff03f..6f8f388bdf 100644 --- a/builtin-pack-objects.c +++ b/builtin-pack-objects.c @@ -2009,7 +2009,6 @@ static void get_object_list(int ac, const char **av) init_revisions(&revs, NULL); save_commit_buffer = 0; - track_object_refs = 0; setup_revisions(ac, av, &revs, NULL); while (fgets(line, sizeof(line), stdin) != NULL) { diff --git a/builtin-rev-list.c b/builtin-rev-list.c index de80158fd4..14e86ceabc 100644 --- a/builtin-rev-list.c +++ b/builtin-rev-list.c @@ -605,7 +605,6 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix) usage(rev_list_usage); save_commit_buffer = revs.verbose_header || revs.grep_filter; - track_object_refs = 0; if (bisect_list) revs.limited = 1; diff --git a/commit.c b/commit.c index 22ce776863..6684c4e731 100644 --- a/commit.c +++ b/commit.c @@ -290,17 +290,6 @@ int parse_commit_buffer(struct commit *item, void *buffer, unsigned long size) } item->date = parse_commit_date(bufptr, tail); - if (track_object_refs) { - unsigned i = 0; - struct commit_list *p; - struct object_refs *refs = alloc_object_refs(n_refs); - if (item->tree) - refs->ref[i++] = &item->tree->object; - for (p = item->parents; p; p = p->next) - refs->ref[i++] = &p->item->object; - set_object_refs(&item->object, refs); - } - return 0; } diff --git a/object-refs.c b/object-refs.c deleted file mode 100644 index 5345671569..0000000000 --- a/object-refs.c +++ /dev/null @@ -1,87 +0,0 @@ -#include "cache.h" -#include "object.h" -#include "decorate.h" - -int track_object_refs = 0; - -static struct decoration ref_decorate; - -struct object_refs *lookup_object_refs(struct object *base) -{ - return lookup_decoration(&ref_decorate, base); -} - -static void add_object_refs(struct object *obj, struct object_refs *refs) -{ - if (add_decoration(&ref_decorate, obj, refs)) - die("object %s tried to add refs twice!", sha1_to_hex(obj->sha1)); -} - -struct object_refs *alloc_object_refs(unsigned count) -{ - struct object_refs *refs; - size_t size = sizeof(*refs) + count*sizeof(struct object *); - - refs = xcalloc(1, size); - refs->count = count; - return refs; -} - -static int compare_object_pointers(const void *a, const void *b) -{ - const struct object * const *pa = a; - const struct object * const *pb = b; - if (*pa == *pb) - return 0; - else if (*pa < *pb) - return -1; - else - return 1; -} - -void set_object_refs(struct object *obj, struct object_refs *refs) -{ - unsigned int i, j; - - /* Do not install empty list of references */ - if (refs->count < 1) { - free(refs); - return; - } - - /* Sort the list and filter out duplicates */ - qsort(refs->ref, refs->count, sizeof(refs->ref[0]), - compare_object_pointers); - for (i = j = 1; i < refs->count; i++) { - if (refs->ref[i] != refs->ref[i - 1]) - refs->ref[j++] = refs->ref[i]; - } - if (j < refs->count) { - /* Duplicates were found - reallocate list */ - size_t size = sizeof(*refs) + j*sizeof(struct object *); - refs->count = j; - refs = xrealloc(refs, size); - } - - for (i = 0; i < refs->count; i++) - refs->ref[i]->used = 1; - add_object_refs(obj, refs); -} - -void mark_reachable(struct object *obj, unsigned int mask) -{ - const struct object_refs *refs; - - if (!track_object_refs) - die("cannot do reachability with object refs turned off"); - /* If we've been here already, don't bother */ - if (obj->flags & mask) - return; - obj->flags |= mask; - refs = lookup_object_refs(obj); - if (refs) { - unsigned i; - for (i = 0; i < refs->count; i++) - mark_reachable(refs->ref[i], mask); - } -} diff --git a/object.h b/object.h index 397bbfa090..036bd66fe9 100644 --- a/object.h +++ b/object.h @@ -35,14 +35,11 @@ struct object { unsigned char sha1[20]; }; -extern int track_object_refs; - extern const char *typename(unsigned int type); extern int type_from_string(const char *str); extern unsigned int get_max_object_index(void); extern struct object *get_indexed_object(unsigned int); -extern struct object_refs *lookup_object_refs(struct object *); /** Internal only **/ struct object *lookup_object(const unsigned char *sha1); @@ -61,11 +58,6 @@ struct object *parse_object_buffer(const unsigned char *sha1, enum object_type t /** Returns the object, with potentially excess memory allocated. **/ struct object *lookup_unknown_object(const unsigned char *sha1); -struct object_refs *alloc_object_refs(unsigned count); -void set_object_refs(struct object *obj, struct object_refs *refs); - -void mark_reachable(struct object *obj, unsigned int mask); - struct object_list *object_list_insert(struct object *item, struct object_list **list_p); diff --git a/tag.c b/tag.c index 38bf9134f9..d19f56d60c 100644 --- a/tag.c +++ b/tag.c @@ -84,12 +84,6 @@ int parse_tag_buffer(struct tag *item, void *data, unsigned long size) item->tagged = NULL; } - if (item->tagged && track_object_refs) { - struct object_refs *refs = alloc_object_refs(1); - refs->ref[0] = item->tagged; - set_object_refs(&item->object, refs); - } - return 0; } diff --git a/tree.c b/tree.c index 8c0819fa72..113e1bb0a4 100644 --- a/tree.c +++ b/tree.c @@ -202,52 +202,6 @@ struct tree *lookup_tree(const unsigned char *sha1) return (struct tree *) obj; } -/* - * NOTE! Tree refs to external git repositories - * (ie gitlinks) do not count as real references. - * - * You don't have to have those repositories - * available at all, much less have the objects - * accessible from the current repository. - */ -static void track_tree_refs(struct tree *item) -{ - int n_refs = 0, i; - struct object_refs *refs; - struct tree_desc desc; - struct name_entry entry; - - /* Count how many entries there are.. */ - init_tree_desc(&desc, item->buffer, item->size); - while (tree_entry(&desc, &entry)) { - if (S_ISGITLINK(entry.mode)) - continue; - n_refs++; - } - - /* Allocate object refs and walk it again.. */ - i = 0; - refs = alloc_object_refs(n_refs); - init_tree_desc(&desc, item->buffer, item->size); - while (tree_entry(&desc, &entry)) { - struct object *obj; - - if (S_ISGITLINK(entry.mode)) - continue; - if (S_ISDIR(entry.mode)) - obj = &lookup_tree(entry.sha1)->object; - else if (S_ISREG(entry.mode) || S_ISLNK(entry.mode)) - obj = &lookup_blob(entry.sha1)->object; - else { - warning("in tree %s: entry %s has bad mode %.6o\n", - sha1_to_hex(item->object.sha1), entry.path, entry.mode); - obj = lookup_unknown_object(entry.sha1); - } - refs->ref[i++] = obj; - } - set_object_refs(&item->object, refs); -} - int parse_tree_buffer(struct tree *item, void *buffer, unsigned long size) { if (item->object.parsed) @@ -256,8 +210,6 @@ int parse_tree_buffer(struct tree *item, void *buffer, unsigned long size) item->buffer = buffer; item->size = size; - if (track_object_refs) - track_tree_refs(item); return 0; } diff --git a/upload-pack.c b/upload-pack.c index d1d2c2a1f7..ba9ba59976 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -392,7 +392,6 @@ static int get_common_commits(void) char hex[41], last_hex[41]; int len; - track_object_refs = 0; save_commit_buffer = 0; for(;;) { diff --git a/walker.c b/walker.c index adc3e80ce1..c10eca8826 100644 --- a/walker.c +++ b/walker.c @@ -256,7 +256,6 @@ int walker_fetch(struct walker *walker, int targets, char **target, int i; save_commit_buffer = 0; - track_object_refs = 0; for (i = 0; i < targets; i++) { if (!write_ref || !write_ref[i]) From 45163382437c3862d3beb88134b7a975a3a26443 Mon Sep 17 00:00:00 2001 From: Martin Koegler Date: Mon, 25 Feb 2008 22:46:07 +0100 Subject: [PATCH 05/53] builtin-fsck: reports missing parent commits parse_commit ignores parent commits with certain errors (eg. a non commit object is already loaded under the sha1 of the parent). To make fsck reports such errors, it has to compare the nummer of parent commits returned by parse commit with the number of parent commits in the object or in the graft/shallow file. Signed-off-by: Martin Koegler Signed-off-by: Junio C Hamano --- builtin-fsck.c | 24 ++++++++++++++++++++++++ commit.c | 2 +- commit.h | 1 + 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/builtin-fsck.c b/builtin-fsck.c index 7321ab236b..727310afc2 100644 --- a/builtin-fsck.c +++ b/builtin-fsck.c @@ -397,6 +397,8 @@ static int fsck_commit(struct commit *commit) { char *buffer = commit->buffer; unsigned char tree_sha1[20], sha1[20]; + struct commit_graft *graft; + int parents = 0; if (verbose) fprintf(stderr, "Checking commit %s\n", @@ -411,6 +413,28 @@ static int fsck_commit(struct commit *commit) if (get_sha1_hex(buffer+7, sha1) || buffer[47] != '\n') return objerror(&commit->object, "invalid 'parent' line format - bad sha1"); buffer += 48; + parents++; + } + graft = lookup_commit_graft(commit->object.sha1); + if (graft) { + struct commit_list *p = commit->parents; + parents = 0; + while (p) { + p = p->next; + parents++; + } + if (graft->nr_parent == -1 && !parents) + ; /* shallow commit */ + else if (graft->nr_parent != parents) + return objerror(&commit->object, "graft objects missing"); + } else { + struct commit_list *p = commit->parents; + while (p && parents) { + p = p->next; + parents--; + } + if (p || parents) + return objerror(&commit->object, "parent objects missing"); } if (memcmp(buffer, "author ", 7)) return objerror(&commit->object, "invalid format - expected 'author' line"); diff --git a/commit.c b/commit.c index 6684c4e731..94d5b3d261 100644 --- a/commit.c +++ b/commit.c @@ -193,7 +193,7 @@ static void prepare_commit_graft(void) commit_graft_prepared = 1; } -static struct commit_graft *lookup_commit_graft(const unsigned char *sha1) +struct commit_graft *lookup_commit_graft(const unsigned char *sha1) { int pos; prepare_commit_graft(); diff --git a/commit.h b/commit.h index 10e2b5d4cf..3ad3dd9af1 100644 --- a/commit.h +++ b/commit.h @@ -101,6 +101,7 @@ struct commit_graft { struct commit_graft *read_graft_line(char *buf, int len); int register_commit_graft(struct commit_graft *, int); int read_graft_file(const char *graft_file); +struct commit_graft *lookup_commit_graft(const unsigned char *sha1); extern struct commit_list *get_merge_bases(struct commit *rev1, struct commit *rev2, int cleanup); From ba002f3b28ab9febea432d4c415dbe581836d9a0 Mon Sep 17 00:00:00 2001 From: Martin Koegler Date: Mon, 25 Feb 2008 22:46:08 +0100 Subject: [PATCH 06/53] builtin-fsck: move common object checking code to fsck.c Signed-off-by: Martin Koegler Signed-off-by: Junio C Hamano --- builtin-fsck.c | 274 +++++++------------------------------------------ fsck.c | 215 ++++++++++++++++++++++++++++++++++++++ fsck.h | 7 ++ 3 files changed, 259 insertions(+), 237 deletions(-) diff --git a/builtin-fsck.c b/builtin-fsck.c index 727310afc2..d545650c8c 100644 --- a/builtin-fsck.c +++ b/builtin-fsck.c @@ -55,13 +55,13 @@ static int objerror(struct object *obj, const char *err, ...) return -1; } -static int objwarning(struct object *obj, const char *err, ...) +static int fsck_error_func(struct object *obj, int type, const char *err, ...) { va_list params; va_start(params, err); - objreport(obj, "warning", err, params); + objreport(obj, (type == FSCK_WARN) ? "warning" : "error", err, params); va_end(params); - return -1; + return (type == FSCK_WARN) ? 0 : 1; } static int mark_object(struct object *obj, int type, void *data) @@ -246,229 +246,6 @@ static void check_connectivity(void) } } -/* - * The entries in a tree are ordered in the _path_ order, - * which means that a directory entry is ordered by adding - * a slash to the end of it. - * - * So a directory called "a" is ordered _after_ a file - * called "a.c", because "a/" sorts after "a.c". - */ -#define TREE_UNORDERED (-1) -#define TREE_HAS_DUPS (-2) - -static int verify_ordered(unsigned mode1, const char *name1, unsigned mode2, const char *name2) -{ - int len1 = strlen(name1); - int len2 = strlen(name2); - int len = len1 < len2 ? len1 : len2; - unsigned char c1, c2; - int cmp; - - cmp = memcmp(name1, name2, len); - if (cmp < 0) - return 0; - if (cmp > 0) - return TREE_UNORDERED; - - /* - * Ok, the first characters are the same. - * Now we need to order the next one, but turn - * a '\0' into a '/' for a directory entry. - */ - c1 = name1[len]; - c2 = name2[len]; - if (!c1 && !c2) - /* - * git-write-tree used to write out a nonsense tree that has - * entries with the same name, one blob and one tree. Make - * sure we do not have duplicate entries. - */ - return TREE_HAS_DUPS; - if (!c1 && S_ISDIR(mode1)) - c1 = '/'; - if (!c2 && S_ISDIR(mode2)) - c2 = '/'; - return c1 < c2 ? 0 : TREE_UNORDERED; -} - -static int fsck_tree(struct tree *item) -{ - int retval; - int has_full_path = 0; - int has_empty_name = 0; - int has_zero_pad = 0; - int has_bad_modes = 0; - int has_dup_entries = 0; - int not_properly_sorted = 0; - struct tree_desc desc; - unsigned o_mode; - const char *o_name; - const unsigned char *o_sha1; - - if (verbose) - fprintf(stderr, "Checking tree %s\n", - sha1_to_hex(item->object.sha1)); - - init_tree_desc(&desc, item->buffer, item->size); - - o_mode = 0; - o_name = NULL; - o_sha1 = NULL; - while (desc.size) { - unsigned mode; - const char *name; - const unsigned char *sha1; - - sha1 = tree_entry_extract(&desc, &name, &mode); - - if (strchr(name, '/')) - has_full_path = 1; - if (!*name) - has_empty_name = 1; - has_zero_pad |= *(char *)desc.buffer == '0'; - update_tree_entry(&desc); - - switch (mode) { - /* - * Standard modes.. - */ - case S_IFREG | 0755: - case S_IFREG | 0644: - case S_IFLNK: - case S_IFDIR: - case S_IFGITLINK: - break; - /* - * This is nonstandard, but we had a few of these - * early on when we honored the full set of mode - * bits.. - */ - case S_IFREG | 0664: - if (!check_strict) - break; - default: - has_bad_modes = 1; - } - - if (o_name) { - switch (verify_ordered(o_mode, o_name, mode, name)) { - case TREE_UNORDERED: - not_properly_sorted = 1; - break; - case TREE_HAS_DUPS: - has_dup_entries = 1; - break; - default: - break; - } - } - - o_mode = mode; - o_name = name; - o_sha1 = sha1; - } - free(item->buffer); - item->buffer = NULL; - - retval = 0; - if (has_full_path) { - objwarning(&item->object, "contains full pathnames"); - } - if (has_empty_name) { - objwarning(&item->object, "contains empty pathname"); - } - if (has_zero_pad) { - objwarning(&item->object, "contains zero-padded file modes"); - } - if (has_bad_modes) { - objwarning(&item->object, "contains bad file modes"); - } - if (has_dup_entries) { - retval = objerror(&item->object, "contains duplicate file entries"); - } - if (not_properly_sorted) { - retval = objerror(&item->object, "not properly sorted"); - } - return retval; -} - -static int fsck_commit(struct commit *commit) -{ - char *buffer = commit->buffer; - unsigned char tree_sha1[20], sha1[20]; - struct commit_graft *graft; - int parents = 0; - - if (verbose) - fprintf(stderr, "Checking commit %s\n", - sha1_to_hex(commit->object.sha1)); - - if (memcmp(buffer, "tree ", 5)) - return objerror(&commit->object, "invalid format - expected 'tree' line"); - if (get_sha1_hex(buffer+5, tree_sha1) || buffer[45] != '\n') - return objerror(&commit->object, "invalid 'tree' line format - bad sha1"); - buffer += 46; - while (!memcmp(buffer, "parent ", 7)) { - if (get_sha1_hex(buffer+7, sha1) || buffer[47] != '\n') - return objerror(&commit->object, "invalid 'parent' line format - bad sha1"); - buffer += 48; - parents++; - } - graft = lookup_commit_graft(commit->object.sha1); - if (graft) { - struct commit_list *p = commit->parents; - parents = 0; - while (p) { - p = p->next; - parents++; - } - if (graft->nr_parent == -1 && !parents) - ; /* shallow commit */ - else if (graft->nr_parent != parents) - return objerror(&commit->object, "graft objects missing"); - } else { - struct commit_list *p = commit->parents; - while (p && parents) { - p = p->next; - parents--; - } - if (p || parents) - return objerror(&commit->object, "parent objects missing"); - } - if (memcmp(buffer, "author ", 7)) - return objerror(&commit->object, "invalid format - expected 'author' line"); - free(commit->buffer); - commit->buffer = NULL; - if (!commit->tree) - return objerror(&commit->object, "could not load commit's tree %s", tree_sha1); - if (!commit->parents && show_root) - printf("root %s\n", sha1_to_hex(commit->object.sha1)); - if (!commit->date) - printf("bad commit date in %s\n", - sha1_to_hex(commit->object.sha1)); - return 0; -} - -static int fsck_tag(struct tag *tag) -{ - struct object *tagged = tag->tagged; - - if (verbose) - fprintf(stderr, "Checking tag %s\n", - sha1_to_hex(tag->object.sha1)); - - if (!tagged) { - return objerror(&tag->object, "could not load tagged object"); - } - if (!show_tags) - return 0; - - printf("tagged %s %s", typename(tagged->type), sha1_to_hex(tagged->sha1)); - printf(" (%s) in %s\n", tag->tag, sha1_to_hex(tag->object.sha1)); - return 0; -} - static int fsck_sha1(const unsigned char *sha1) { struct object *obj = parse_object(sha1); @@ -480,20 +257,43 @@ static int fsck_sha1(const unsigned char *sha1) if (obj->flags & SEEN) return 0; obj->flags |= SEEN; + + if (verbose) + fprintf(stderr, "Checking %s %s\n", + typename(obj->type), sha1_to_hex(obj->sha1)); + if (fsck_walk(obj, mark_used, 0)) objerror(obj, "broken links"); - if (obj->type == OBJ_BLOB) - return 0; - if (obj->type == OBJ_TREE) - return fsck_tree((struct tree *) obj); - if (obj->type == OBJ_COMMIT) - return fsck_commit((struct commit *) obj); - if (obj->type == OBJ_TAG) - return fsck_tag((struct tag *) obj); + if (fsck_object(obj, check_strict, fsck_error_func)) + return -1; - /* By now, parse_object() would've returned NULL instead. */ - return objerror(obj, "unknown type '%d' (internal fsck error)", - obj->type); + if (obj->type == OBJ_TREE) { + struct tree *item = (struct tree *) obj; + + free(item->buffer); + item->buffer = NULL; + } + + if (obj->type == OBJ_COMMIT) { + struct commit *commit = (struct commit *) obj; + + free(commit->buffer); + commit->buffer = NULL; + + if (!commit->parents && show_root) + printf("root %s\n", sha1_to_hex(commit->object.sha1)); + } + + if (obj->type == OBJ_TAG) { + struct tag *tag = (struct tag *) obj; + + if (show_tags && tag->tagged) { + printf("tagged %s %s", typename(tag->tagged->type), sha1_to_hex(tag->tagged->sha1)); + printf(" (%s) in %s\n", tag->tag, sha1_to_hex(tag->object.sha1)); + } + } + + return 0; } /* diff --git a/fsck.c b/fsck.c index 98fb41af68..0680862151 100644 --- a/fsck.c +++ b/fsck.c @@ -89,3 +89,218 @@ int fsck_walk(struct object *obj, fsck_walk_func walk, void *data) return -1; } } + +/* + * The entries in a tree are ordered in the _path_ order, + * which means that a directory entry is ordered by adding + * a slash to the end of it. + * + * So a directory called "a" is ordered _after_ a file + * called "a.c", because "a/" sorts after "a.c". + */ +#define TREE_UNORDERED (-1) +#define TREE_HAS_DUPS (-2) + +static int verify_ordered(unsigned mode1, const char *name1, unsigned mode2, const char *name2) +{ + int len1 = strlen(name1); + int len2 = strlen(name2); + int len = len1 < len2 ? len1 : len2; + unsigned char c1, c2; + int cmp; + + cmp = memcmp(name1, name2, len); + if (cmp < 0) + return 0; + if (cmp > 0) + return TREE_UNORDERED; + + /* + * Ok, the first characters are the same. + * Now we need to order the next one, but turn + * a '\0' into a '/' for a directory entry. + */ + c1 = name1[len]; + c2 = name2[len]; + if (!c1 && !c2) + /* + * git-write-tree used to write out a nonsense tree that has + * entries with the same name, one blob and one tree. Make + * sure we do not have duplicate entries. + */ + return TREE_HAS_DUPS; + if (!c1 && S_ISDIR(mode1)) + c1 = '/'; + if (!c2 && S_ISDIR(mode2)) + c2 = '/'; + return c1 < c2 ? 0 : TREE_UNORDERED; +} + +static int fsck_tree(struct tree *item, int strict, fsck_error error_func) +{ + int retval; + int has_full_path = 0; + int has_empty_name = 0; + int has_zero_pad = 0; + int has_bad_modes = 0; + int has_dup_entries = 0; + int not_properly_sorted = 0; + struct tree_desc desc; + unsigned o_mode; + const char *o_name; + const unsigned char *o_sha1; + + init_tree_desc(&desc, item->buffer, item->size); + + o_mode = 0; + o_name = NULL; + o_sha1 = NULL; + if (!desc.size) + return error_func(&item->object, FSCK_ERROR, "empty tree"); + + while (desc.size) { + unsigned mode; + const char *name; + const unsigned char *sha1; + + sha1 = tree_entry_extract(&desc, &name, &mode); + + if (strchr(name, '/')) + has_full_path = 1; + if (!*name) + has_empty_name = 1; + has_zero_pad |= *(char *)desc.buffer == '0'; + update_tree_entry(&desc); + + switch (mode) { + /* + * Standard modes.. + */ + case S_IFREG | 0755: + case S_IFREG | 0644: + case S_IFLNK: + case S_IFDIR: + case S_IFGITLINK: + break; + /* + * This is nonstandard, but we had a few of these + * early on when we honored the full set of mode + * bits.. + */ + case S_IFREG | 0664: + if (!strict) + break; + default: + has_bad_modes = 1; + } + + if (o_name) { + switch (verify_ordered(o_mode, o_name, mode, name)) { + case TREE_UNORDERED: + not_properly_sorted = 1; + break; + case TREE_HAS_DUPS: + has_dup_entries = 1; + break; + default: + break; + } + } + + o_mode = mode; + o_name = name; + o_sha1 = sha1; + } + + retval = 0; + if (has_full_path) + retval += error_func(&item->object, FSCK_WARN, "contains full pathnames"); + if (has_empty_name) + retval += error_func(&item->object, FSCK_WARN, "contains empty pathname"); + if (has_zero_pad) + retval += error_func(&item->object, FSCK_WARN, "contains zero-padded file modes"); + if (has_bad_modes) + retval += error_func(&item->object, FSCK_WARN, "contains bad file modes"); + if (has_dup_entries) + retval += error_func(&item->object, FSCK_ERROR, "contains duplicate file entries"); + if (not_properly_sorted) + retval += error_func(&item->object, FSCK_ERROR, "not properly sorted"); + return retval; +} + +static int fsck_commit(struct commit *commit, fsck_error error_func) +{ + char *buffer = commit->buffer; + unsigned char tree_sha1[20], sha1[20]; + struct commit_graft *graft; + int parents = 0; + + if (!commit->date) + return error_func(&commit->object, FSCK_ERROR, "invalid author/committer line"); + + if (memcmp(buffer, "tree ", 5)) + return error_func(&commit->object, FSCK_ERROR, "invalid format - expected 'tree' line"); + if (get_sha1_hex(buffer+5, tree_sha1) || buffer[45] != '\n') + return error_func(&commit->object, FSCK_ERROR, "invalid 'tree' line format - bad sha1"); + buffer += 46; + while (!memcmp(buffer, "parent ", 7)) { + if (get_sha1_hex(buffer+7, sha1) || buffer[47] != '\n') + return error_func(&commit->object, FSCK_ERROR, "invalid 'parent' line format - bad sha1"); + buffer += 48; + parents++; + } + graft = lookup_commit_graft(commit->object.sha1); + if (graft) { + struct commit_list *p = commit->parents; + parents = 0; + while (p) { + p = p->next; + parents++; + } + if (graft->nr_parent == -1 && !parents) + ; /* shallow commit */ + else if (graft->nr_parent != parents) + return error_func(&commit->object, FSCK_ERROR, "graft objects missing"); + } else { + struct commit_list *p = commit->parents; + while (p && parents) { + p = p->next; + parents--; + } + if (p || parents) + return error_func(&commit->object, FSCK_ERROR, "parent objects missing"); + } + if (memcmp(buffer, "author ", 7)) + return error_func(&commit->object, FSCK_ERROR, "invalid format - expected 'author' line"); + if (!commit->tree) + return error_func(&commit->object, FSCK_ERROR, "could not load commit's tree %s", sha1_to_hex(tree_sha1)); + + return 0; +} + +static int fsck_tag(struct tag *tag, fsck_error error_func) +{ + struct object *tagged = tag->tagged; + + if (!tagged) + return error_func(&tag->object, FSCK_ERROR, "could not load tagged object"); + return 0; +} + +int fsck_object(struct object *obj, int strict, fsck_error error_func) +{ + if (!obj) + return error_func(obj, FSCK_ERROR, "no valid object to fsck"); + + if (obj->type == OBJ_BLOB) + return 0; + if (obj->type == OBJ_TREE) + return fsck_tree((struct tree *) obj, strict, error_func); + if (obj->type == OBJ_COMMIT) + return fsck_commit((struct commit *) obj, error_func); + if (obj->type == OBJ_TAG) + return fsck_tag((struct tag *) obj, error_func); + + return error_func(obj, FSCK_ERROR, "unknown type '%d' (internal fsck error)", + obj->type); +} diff --git a/fsck.h b/fsck.h index ba5514a818..9bd37c9f1c 100644 --- a/fsck.h +++ b/fsck.h @@ -1,6 +1,9 @@ #ifndef GIT_FSCK_H #define GIT_FSCK_H +#define FSCK_ERROR 1 +#define FSCK_WARN 2 + /* * callback function for fsck_walk * type is the expected type of the object or OBJ_ANY @@ -11,6 +14,9 @@ */ typedef int (*fsck_walk_func)(struct object *obj, int type, void *data); +/* callback for fsck_object, type is FSCK_ERROR or FSCK_WARN */ +typedef int (*fsck_error)(struct object *obj, int type, const char *err, ...); + /* descend in all linked child objects * the return value is: * -1 error in processing the object @@ -19,5 +25,6 @@ typedef int (*fsck_walk_func)(struct object *obj, int type, void *data); * 0 everything OK */ int fsck_walk(struct object *obj, fsck_walk_func walk, void *data); +int fsck_object(struct object *obj, int strict, fsck_error error_func); #endif From d6ffc8d784d41977397a49ce5333cfe7db1e9c2c Mon Sep 17 00:00:00 2001 From: Martin Koegler Date: Mon, 25 Feb 2008 22:46:09 +0100 Subject: [PATCH 07/53] add common fsck error printing function Signed-off-by: Martin Koegler Signed-off-by: Junio C Hamano --- fsck.c | 29 +++++++++++++++++++++++++++++ fsck.h | 2 ++ 2 files changed, 31 insertions(+) diff --git a/fsck.c b/fsck.c index 0680862151..6883d1bd68 100644 --- a/fsck.c +++ b/fsck.c @@ -304,3 +304,32 @@ int fsck_object(struct object *obj, int strict, fsck_error error_func) return error_func(obj, FSCK_ERROR, "unknown type '%d' (internal fsck error)", obj->type); } + +int fsck_error_function(struct object *obj, int type, const char *fmt, ...) +{ + va_list ap; + int len; + struct strbuf sb; + + strbuf_init(&sb, 0); + strbuf_addf(&sb, "object %s:", obj->sha1?sha1_to_hex(obj->sha1):"(null)"); + + va_start(ap, fmt); + len = vsnprintf(sb.buf + sb.len, strbuf_avail(&sb), fmt, ap); + va_end(ap); + + if (len < 0) + len = 0; + if (len >= strbuf_avail(&sb)) { + strbuf_grow(&sb, len + 2); + va_start(ap, fmt); + len = vsnprintf(sb.buf + sb.len, strbuf_avail(&sb), fmt, ap); + va_end(ap); + if (len >= strbuf_avail(&sb)) + die("this should not happen, your snprintf is broken"); + } + + error(sb.buf); + strbuf_release(&sb); + return 1; +} diff --git a/fsck.h b/fsck.h index 9bd37c9f1c..990ee02335 100644 --- a/fsck.h +++ b/fsck.h @@ -17,6 +17,8 @@ typedef int (*fsck_walk_func)(struct object *obj, int type, void *data); /* callback for fsck_object, type is FSCK_ERROR or FSCK_WARN */ typedef int (*fsck_error)(struct object *obj, int type, const char *err, ...); +int fsck_error_function(struct object *obj, int type, const char *fmt, ...); + /* descend in all linked child objects * the return value is: * -1 error in processing the object From 47e83e3cc0b5b5e2402afb34b7617515f905b7a7 Mon Sep 17 00:00:00 2001 From: Sebastian Noack Date: Mon, 25 Feb 2008 15:56:28 +0100 Subject: [PATCH 08/53] git-svn: Don't prompt for client cert password everytime. Acked-by: Eric Wong Signed-off-by: Junio C Hamano --- git-svn.perl | 1 + 1 file changed, 1 insertion(+) diff --git a/git-svn.perl b/git-svn.perl index 75e97cc72f..a4ab05155d 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -3632,6 +3632,7 @@ sub _auth_providers () { SVN::Client::get_ssl_client_cert_file_provider(), SVN::Client::get_ssl_client_cert_prompt_provider( \&Git::SVN::Prompt::ssl_client_cert, 2), + SVN::Client::get_ssl_client_cert_pw_file_provider(), SVN::Client::get_ssl_client_cert_pw_prompt_provider( \&Git::SVN::Prompt::ssl_client_cert_pw, 2), SVN::Client::get_username_provider(), From 311e552e7674be620bd930ddada307c15140c6ac Mon Sep 17 00:00:00 2001 From: Jakub Narebski Date: Tue, 26 Feb 2008 13:22:06 +0100 Subject: [PATCH 09/53] gitweb: Change parse_commits signature to allow for multiple options Change order of parameters in parse_commits() to have $filename before @args (extra options), to allow for multiple extra options, for example both '--grep=' and '--fixed-strings'. Change all callers to follow new calling convention. Originally by Petr Baudis, in http://repo.or.cz/git/gitweb.git: b98f0a7c gitweb: Clearly distinguish regexp / exact match searches Signed-off-by: Petr Baudis Signed-off-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index fc95e2ca85..3b4b15a5f0 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -2079,7 +2079,7 @@ sub parse_commit { } sub parse_commits { - my ($commit_id, $maxcount, $skip, $arg, $filename) = @_; + my ($commit_id, $maxcount, $skip, $filename, @args) = @_; my @cos; $maxcount ||= 1; @@ -2089,7 +2089,7 @@ sub parse_commits { open my $fd, "-|", git_cmd(), "rev-list", "--header", - ($arg ? ($arg) : ()), + @args, ("--max-count=" . $maxcount), ("--skip=" . $skip), @extra_options, @@ -5172,7 +5172,7 @@ sub git_history { $ftype = git_get_type($hash); } - my @commitlist = parse_commits($hash_base, 101, (100 * $page), "--full-history", $file_name); + my @commitlist = parse_commits($hash_base, 101, (100 * $page), $file_name, "--full-history"); my $paging_nav = ''; if ($page > 0) { @@ -5255,7 +5255,7 @@ sub git_search { $greptype = "--committer="; } $greptype .= $search_regexp; - my @commitlist = parse_commits($hash, 101, (100 * $page), $greptype); + my @commitlist = parse_commits($hash, 101, (100 * $page), undef, $greptype); my $paging_nav = ''; if ($page > 0) { @@ -5507,7 +5507,7 @@ sub git_feed { # log/feed of current (HEAD) branch, log of given branch, history of file/directory my $head = $hash || 'HEAD'; - my @commitlist = parse_commits($head, 150, 0, undef, $file_name); + my @commitlist = parse_commits($head, 150, 0, $file_name); my %latest_commit; my %latest_date; From 0270cd0eeaff06f6bee1b52d5cdffb1a6e69c15a Mon Sep 17 00:00:00 2001 From: Jakub Narebski Date: Tue, 26 Feb 2008 13:22:07 +0100 Subject: [PATCH 10/53] gitweb: Simplify fixed string search Use '--fixed-strings' option to git-rev-list to simplify and improve searching commit messages (commit search). It allows to search for example for "don't" successfully from gitweb. Signed-off-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 3b4b15a5f0..90cf78e436 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -5254,14 +5254,16 @@ sub git_search { } elsif ($searchtype eq 'committer') { $greptype = "--committer="; } - $greptype .= $search_regexp; - my @commitlist = parse_commits($hash, 101, (100 * $page), undef, $greptype); + $greptype .= $searchtext; + my @commitlist = parse_commits($hash, 101, (100 * $page), undef, + $greptype, '--fixed-strings'); my $paging_nav = ''; if ($page > 0) { $paging_nav .= $cgi->a({-href => href(action=>"search", hash=>$hash, - searchtext=>$searchtext, searchtype=>$searchtype)}, + searchtext=>$searchtext, + searchtype=>$searchtype)}, "first"); $paging_nav .= " ⋅ " . $cgi->a({-href => href(-replay=>1, page=>$page-1), From 0e55991987e490a69bc549f6f789b34489c953a7 Mon Sep 17 00:00:00 2001 From: Petr Baudis Date: Tue, 26 Feb 2008 13:22:08 +0100 Subject: [PATCH 11/53] gitweb: Clearly distinguish regexp / exact match searches This patch does a couple of things: * Makes commit/author/committer search case insensitive To be consistent with the grep search; I see no convincing reason for the search to be case sensitive, and you might get in trouble especially with contributors e.g. from Japan or France where they sometimes like to uppercase their last name. * Makes grep search by default search for fixed strings. * Introduces 're' checkbox that enables POSIX extended regexp searches This works for all the search types. The idea comes from Jakub. It does not make much sense (and is not easy at all) to untangle most of these changes from each other, thus they all go in a single patch. [jn: Cherry-picked from Pasky's http://repo.or.cz/git/gitweb.git] Signed-off-by: Petr Baudis Signed-off-by: Jakub Narebski Signed-off-by: Junio C Hamano --- gitweb/gitweb.perl | 44 ++++++++++++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 90cf78e436..20dc5d59c2 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -472,13 +472,15 @@ if (defined $searchtype) { } } +our $search_use_regexp = $cgi->param('sr'); + our $searchtext = $cgi->param('s'); our $search_regexp; if (defined $searchtext) { if (length($searchtext) < 2) { die_error(undef, "At least two characters are required for search parameter"); } - $search_regexp = quotemeta $searchtext; + $search_regexp = $search_use_regexp ? $searchtext : quotemeta $searchtext; } # now read PATH_INFO and use it as alternative to parameters @@ -608,6 +610,7 @@ sub href(%) { searchtype => "st", snapshot_format => "sf", extra_options => "opt", + search_use_regexp => "sr", ); my %mapping = @mapping; @@ -2584,6 +2587,10 @@ EOF $cgi->sup($cgi->a({-href => href(action=>"search_help")}, "?")) . " search:\n", $cgi->textfield(-name => "s", -value => $searchtext) . "\n" . + "" . + $cgi->checkbox(-name => 'sr', -value => 1, -label => 're', + -checked => $search_use_regexp) . + "" . "" . $cgi->end_form() . "\n"; } @@ -5256,7 +5263,8 @@ sub git_search { } $greptype .= $searchtext; my @commitlist = parse_commits($hash, 101, (100 * $page), undef, - $greptype, '--fixed-strings'); + $greptype, '--regexp-ignore-case', + $search_use_regexp ? '--extended-regexp' : '--fixed-strings'); my $paging_nav = ''; if ($page > 0) { @@ -5300,8 +5308,9 @@ sub git_search { my $git_command = git_cmd_str(); my $searchqtext = $searchtext; $searchqtext =~ s/'/'\\''/; + my $pickaxe_flags = $search_use_regexp ? '--pickaxe-regex' : ''; open my $fd, "-|", "$git_command rev-list $hash | " . - "$git_command diff-tree -r --stdin -S\'$searchqtext\'"; + "$git_command diff-tree -r --stdin -S\'$searchqtext\' $pickaxe_flags"; undef %co; my @files; while (my $line = <$fd>) { @@ -5365,7 +5374,9 @@ sub git_search { my $alternate = 1; my $matches = 0; $/ = "\n"; - open my $fd, "-|", git_cmd(), 'grep', '-n', '-i', '-E', $searchtext, $co{'tree'}; + open my $fd, "-|", git_cmd(), 'grep', '-n', + $search_use_regexp ? ('-E', '-i') : '-F', + $searchtext, $co{'tree'}; my $lastfile = ''; while (my $line = <$fd>) { chomp $line; @@ -5395,7 +5406,7 @@ sub git_search { print "
Binary file
\n"; } else { $ltext = untabify($ltext); - if ($ltext =~ m/^(.*)($searchtext)(.*)$/i) { + if ($ltext =~ m/^(.*)($search_regexp)(.*)$/i) { $ltext = esc_html($1, -nbsp=>1); $ltext .= ''; $ltext .= esc_html($2, -nbsp=>1); @@ -5430,27 +5441,31 @@ sub git_search_help { git_header_html(); git_print_page_nav('','', $hash,$hash,$hash); print <Pattern is by default a normal string that is matched precisely (but without +regard to case, except in the case of pickaxe). However, when you check the re checkbox, +the pattern entered is recognized as the POSIX extended +regular expression (also case +insensitive).

commit
-
The commit messages and authorship information will be scanned for the given string.
+
The commit messages and authorship information will be scanned for the given pattern.
EOT my ($have_grep) = gitweb_check_feature('grep'); if ($have_grep) { print <grep
All files in the currently selected tree (HEAD unless you are explicitly browsing - a different one) are searched for the given -regular expression -(POSIX extended) and the matches are listed. On large -trees, this search can take a while and put some strain on the server, so please use it with -some consideration.
+ a different one) are searched for the given pattern. On large trees, this search can take +a while and put some strain on the server, so please use it with some consideration. Note that +due to git-grep peculiarity, currently if regexp mode is turned off, the matches are +case-sensitive. EOT } print <author -
Name and e-mail of the change author and date of birth of the patch will be scanned for the given string.
+
Name and e-mail of the change author and date of birth of the patch will be scanned for the given pattern.
committer
-
Name and e-mail of the committer and date of commit will be scanned for the given string.
+
Name and e-mail of the committer and date of commit will be scanned for the given pattern.
EOT my ($have_pickaxe) = gitweb_check_feature('pickaxe'); if ($have_pickaxe) { @@ -5458,7 +5473,8 @@ EOT
pickaxe
All commits that caused the string to appear or disappear from any file (changes that added, removed or "modified" the string) will be listed. This search can take a while and -takes a lot of strain on the server, so please use it wisely.
+takes a lot of strain on the server, so please use it wisely. Note that since you may be +interested even in changes just changing the case as well, this search is case sensitive. EOT } print "
\n"; From 95775e5377960409a1b3ac4082dded7d17e14a46 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 27 Feb 2008 13:50:44 -0800 Subject: [PATCH 12/53] git-remote: do not complain on multiple URLs for a remote Having more than one URL for a remote is perfectly normal when the remote is defined to push to multiple places. Get rid of the annoying "Warning" message. Signed-off-by: Junio C Hamano --- git-remote.perl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/git-remote.perl b/git-remote.perl index 5cd69513cf..b30ed734e7 100755 --- a/git-remote.perl +++ b/git-remote.perl @@ -7,10 +7,10 @@ my $git = Git->repository(); sub add_remote_config { my ($hash, $name, $what, $value) = @_; if ($what eq 'url') { - if (exists $hash->{$name}{'URL'}) { - print STDERR "Warning: more than one remote.$name.url\n"; + # Having more than one is Ok -- it is used for push. + if (! exists $hash->{'URL'}) { + $hash->{$name}{'URL'} = $value; } - $hash->{$name}{'URL'} = $value; } elsif ($what eq 'fetch') { $hash->{$name}{'FETCH'} ||= []; From 22665bbaab799b1f20a23039a5c759cd35d36939 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 25 Feb 2008 14:25:20 +0100 Subject: [PATCH 13/53] daemon: send more error messages to the syslog There were a number of die() calls before the syslog was opened; hence, these error messages would have been sent to /dev/null in detached mode. Now we install the daemon-specific die routine before any error message is generated so that these messages go to the syslog. Signed-off-by: Johannes Sixt Signed-off-by: Junio C Hamano --- daemon.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/daemon.c b/daemon.c index 41a60af624..dd0177f48d 100644 --- a/daemon.c +++ b/daemon.c @@ -1149,6 +1149,11 @@ int main(int argc, char **argv) usage(daemon_usage); } + if (log_syslog) { + openlog("git-daemon", 0, LOG_DAEMON); + set_die_routine(daemon_die); + } + if (inetd_mode && (group_name || user_name)) die("--user and --group are incompatible with --inetd"); @@ -1176,11 +1181,6 @@ int main(int argc, char **argv) } } - if (log_syslog) { - openlog("git-daemon", 0, LOG_DAEMON); - set_die_routine(daemon_die); - } - if (strict_paths && (!ok_paths || !*ok_paths)) die("option --strict-paths requires a whitelist"); From 20632071560ad4915f4e620d3c053e5ee3af80f3 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 26 Feb 2008 13:00:55 +0100 Subject: [PATCH 14/53] daemon: ensure that base-path is an existing directory Any request to the daemon would fail if base-path (if specified) is not a directory. We now check for this condition early. Signed-off-by: Johannes Sixt Signed-off-by: Junio C Hamano --- daemon.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/daemon.c b/daemon.c index dd0177f48d..2b4a6f145c 100644 --- a/daemon.c +++ b/daemon.c @@ -1184,6 +1184,14 @@ int main(int argc, char **argv) if (strict_paths && (!ok_paths || !*ok_paths)) die("option --strict-paths requires a whitelist"); + if (base_path) { + struct stat st; + + if (stat(base_path, &st) || !S_ISDIR(st.st_mode)) + die("base-path '%s' does not exist or " + "is not a directory", base_path); + } + if (inetd_mode) { struct sockaddr_storage ss; struct sockaddr *peer = (struct sockaddr *)&ss; From 9fc6440d783ca773353880aa97c23ed9c640d3c0 Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Wed, 27 Feb 2008 21:35:50 +0100 Subject: [PATCH 15/53] Set proxy override with http_init() In transport.c, proxy setting (the one from the remote conf) was set through curl_easy_setopt() call, while http.c already does the same with the http.proxy setting. We now just use this infrastructure instead, and make http_init() now take the struct remote as argument so that it can take the http_proxy setting from there, and any other property that would be added later. At the same time, we make get_http_walker() take a struct remote argument too, and pass it to http_init(), which makes remote defined proxy be used for more than get_refs_via_curl(). We leave out http-fetch and http-push, which don't use remotes for the moment, purposefully. Signed-off-by: Mike Hommey Acked-by: Daniel Barkalow Signed-off-by: Junio C Hamano --- builtin-http-fetch.c | 2 +- http-push.c | 2 +- http-walker.c | 4 ++-- http.c | 10 +++++++++- http.h | 3 ++- transport.c | 9 ++++----- walker.h | 4 +++- 7 files changed, 22 insertions(+), 12 deletions(-) diff --git a/builtin-http-fetch.c b/builtin-http-fetch.c index 7f450c61d9..48128c610e 100644 --- a/builtin-http-fetch.c +++ b/builtin-http-fetch.c @@ -59,7 +59,7 @@ int cmd_http_fetch(int argc, const char **argv, const char *prefix) url = rewritten_url; } - walker = get_http_walker(url); + walker = get_http_walker(url, NULL); walker->get_tree = get_tree; walker->get_history = get_history; walker->get_all = get_all; diff --git a/http-push.c b/http-push.c index b2b410df90..869c01c75b 100644 --- a/http-push.c +++ b/http-push.c @@ -2233,7 +2233,7 @@ int main(int argc, char **argv) memset(remote_dir_exists, -1, 256); - http_init(); + http_init(NULL); no_pragma_header = curl_slist_append(no_pragma_header, "Pragma:"); diff --git a/http-walker.c b/http-walker.c index 2c3786870e..7bda34d914 100644 --- a/http-walker.c +++ b/http-walker.c @@ -902,13 +902,13 @@ static void cleanup(struct walker *walker) curl_slist_free_all(data->no_pragma_header); } -struct walker *get_http_walker(const char *url) +struct walker *get_http_walker(const char *url, struct remote *remote) { char *s; struct walker_data *data = xmalloc(sizeof(struct walker_data)); struct walker *walker = xmalloc(sizeof(struct walker)); - http_init(); + http_init(remote); data->no_pragma_header = curl_slist_append(NULL, "Pragma:"); diff --git a/http.c b/http.c index 5925d07478..8e554c0969 100644 --- a/http.c +++ b/http.c @@ -218,13 +218,16 @@ static CURL* get_curl_handle(void) return result; } -void http_init(void) +void http_init(struct remote *remote) { char *low_speed_limit; char *low_speed_time; curl_global_init(CURL_GLOBAL_ALL); + if (remote && remote->http_proxy) + curl_http_proxy = xstrdup(remote->http_proxy); + pragma_header = curl_slist_append(pragma_header, "Pragma: no-cache"); #ifdef USE_CURL_MULTI @@ -314,6 +317,11 @@ void http_cleanup(void) curl_slist_free_all(pragma_header); pragma_header = NULL; + + if (curl_http_proxy) { + free(curl_http_proxy); + curl_http_proxy = NULL; + } } struct active_request_slot *get_active_slot(void) diff --git a/http.h b/http.h index 9bab2c8821..04169d5f9c 100644 --- a/http.h +++ b/http.h @@ -7,6 +7,7 @@ #include #include "strbuf.h" +#include "remote.h" /* * We detect based on the cURL version if multi-transfer is @@ -83,7 +84,7 @@ extern void add_fill_function(void *data, int (*fill)(void *)); extern void step_active_slots(void); #endif -extern void http_init(void); +extern void http_init(struct remote *remote); extern void http_cleanup(void); extern int data_received; diff --git a/transport.c b/transport.c index 497f853721..97c59dce60 100644 --- a/transport.c +++ b/transport.c @@ -442,7 +442,8 @@ static struct ref *get_refs_via_curl(struct transport *transport) struct ref *last_ref = NULL; if (!transport->data) - transport->data = get_http_walker(transport->url); + transport->data = get_http_walker(transport->url, + transport->remote); refs_url = xmalloc(strlen(transport->url) + 11); sprintf(refs_url, "%s/info/refs", transport->url); @@ -453,9 +454,6 @@ static struct ref *get_refs_via_curl(struct transport *transport) curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer); curl_easy_setopt(slot->curl, CURLOPT_URL, refs_url); curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, NULL); - if (transport->remote->http_proxy) - curl_easy_setopt(slot->curl, CURLOPT_PROXY, - transport->remote->http_proxy); if (start_active_slot(slot)) { run_active_slot(slot); @@ -509,7 +507,8 @@ static int fetch_objs_via_curl(struct transport *transport, int nr_objs, struct ref **to_fetch) { if (!transport->data) - transport->data = get_http_walker(transport->url); + transport->data = get_http_walker(transport->url, + transport->remote); return fetch_objs_via_walker(transport, nr_objs, to_fetch); } diff --git a/walker.h b/walker.h index ea2c363f4e..e1d40deaff 100644 --- a/walker.h +++ b/walker.h @@ -1,6 +1,8 @@ #ifndef WALKER_H #define WALKER_H +#include "remote.h" + struct walker { void *data; int (*fetch_ref)(struct walker *, char *ref, unsigned char *sha1); @@ -32,6 +34,6 @@ int walker_fetch(struct walker *impl, int targets, char **target, void walker_free(struct walker *walker); -struct walker *get_http_walker(const char *url); +struct walker *get_http_walker(const char *url, struct remote *remote); #endif /* WALKER_H */ From 6eaf40608dfe0c23aa990a8c7d4a135df1af3cab Mon Sep 17 00:00:00 2001 From: Clemens Buchacher Date: Wed, 27 Feb 2008 20:27:53 +0100 Subject: [PATCH 16/53] http-push: push : deletes remote branch This mirrors current ssh/git push syntax. Signed-off-by: Clemens Buchacher Signed-off-by: Junio C Hamano --- http-push.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/http-push.c b/http-push.c index 0beb7406c3..4b31070eb9 100644 --- a/http-push.c +++ b/http-push.c @@ -2138,6 +2138,8 @@ static int delete_remote_branch(char *pattern, int force) /* Send delete request */ fprintf(stderr, "Removing remote branch '%s'\n", remote_ref->name); + if (dry_run) + return 0; url = xmalloc(strlen(remote->url) + strlen(remote_ref->name) + 1); sprintf(url, "%s%s", remote->url, remote_ref->name); slot = get_active_slot(); @@ -2311,6 +2313,16 @@ int main(int argc, char **argv) if (!ref->peer_ref) continue; + + if (is_zero_sha1(ref->peer_ref->new_sha1)) { + if (delete_remote_branch(ref->name, 1) == -1) { + error("Could not remove %s", ref->name); + rc = -4; + } + new_refs++; + continue; + } + if (!hashcmp(ref->old_sha1, ref->peer_ref->new_sha1)) { if (push_verbosely || 1) fprintf(stderr, "'%s': up-to-date\n", ref->name); @@ -2342,11 +2354,6 @@ int main(int argc, char **argv) } } hashcpy(ref->new_sha1, ref->peer_ref->new_sha1); - if (is_zero_sha1(ref->new_sha1)) { - error("cannot happen anymore"); - rc = -3; - continue; - } new_refs++; strcpy(old_hex, sha1_to_hex(ref->old_sha1)); new_hex = sha1_to_hex(ref->new_sha1); From faa4bc35a05ddb1822f3770cd8c51859e3b929ee Mon Sep 17 00:00:00 2001 From: Clemens Buchacher Date: Wed, 27 Feb 2008 20:28:45 +0100 Subject: [PATCH 17/53] http-push: add regression tests http-push tests require a web server with WebDAV support. This commit introduces a HTTPD test library, which can be configured using the following environment variables. GIT_TEST_HTTPD enable HTTPD tests LIB_HTTPD_PATH web server path LIB_HTTPD_MODULE_PATH web server modules path LIB_HTTPD_PORT listening port LIB_HTTPD_DAV enable DAV LIB_HTTPD_SVN enable SVN LIB_HTTPD_SSL enable SSL Signed-off-by: Clemens Buchacher Signed-off-by: Junio C Hamano --- t/lib-httpd.sh | 96 +++++++++++++++++++++++++++++++++++++++++ t/lib-httpd/apache.conf | 34 +++++++++++++++ t/lib-httpd/ssl.cnf | 8 ++++ t/t5540-http-push.sh | 73 +++++++++++++++++++++++++++++++ t/test-lib.sh | 9 +++- 5 files changed, 218 insertions(+), 2 deletions(-) create mode 100644 t/lib-httpd.sh create mode 100644 t/lib-httpd/apache.conf create mode 100644 t/lib-httpd/ssl.cnf create mode 100755 t/t5540-http-push.sh diff --git a/t/lib-httpd.sh b/t/lib-httpd.sh new file mode 100644 index 0000000000..7f206c56cf --- /dev/null +++ b/t/lib-httpd.sh @@ -0,0 +1,96 @@ +#!/bin/sh +# +# Copyright (c) 2008 Clemens Buchacher +# + +if test -z "$GIT_TEST_HTTPD" +then + say "skipping test, network testing disabled by default" + say "(define GIT_TEST_HTTPD to enable)" + test_done + exit +fi + +LIB_HTTPD_PATH=${LIB_HTTPD_PATH-'/usr/sbin/apache2'} +LIB_HTTPD_PORT=${LIB_HTTPD_PORT-'8111'} + +TEST_PATH="$PWD"/../lib-httpd +HTTPD_ROOT_PATH="$PWD"/httpd +HTTPD_DOCUMENT_ROOT_PATH=$HTTPD_ROOT_PATH/www + +if ! test -x "$LIB_HTTPD_PATH" +then + say "skipping test, no web server found at '$LIB_HTTPD_PATH'" + test_done + exit +fi + +HTTPD_VERSION=`$LIB_HTTPD_PATH -v | \ + sed -n 's/^Server version: Apache\/\([0-9]*\)\..*$/\1/p; q'` + +if test -n "$HTTPD_VERSION" +then + if test -z "$LIB_HTTPD_MODULE_PATH" + then + if ! test $HTTPD_VERSION -ge 2 + then + say "skipping test, at least Apache version 2 is required" + test_done + exit + fi + + LIB_HTTPD_MODULE_PATH='/usr/lib/apache2/modules' + fi +else + error "Could not identify web server at '$LIB_HTTPD_PATH'" +fi + +HTTPD_PARA="-d $HTTPD_ROOT_PATH -f $TEST_PATH/apache.conf" + +prepare_httpd() { + mkdir -p $HTTPD_DOCUMENT_ROOT_PATH + + ln -s $LIB_HTTPD_MODULE_PATH $HTTPD_ROOT_PATH/modules + + if test -n "$LIB_HTTPD_SSL" + then + HTTPD_URL=https://127.0.0.1:$LIB_HTTPD_PORT + + RANDFILE_PATH="$HTTPD_ROOT_PATH"/.rnd openssl req \ + -config $TEST_PATH/ssl.cnf \ + -new -x509 -nodes \ + -out $HTTPD_ROOT_PATH/httpd.pem \ + -keyout $HTTPD_ROOT_PATH/httpd.pem + export GIT_SSL_NO_VERIFY=t + HTTPD_PARA="$HTTPD_PARA -DSSL" + else + HTTPD_URL=http://127.0.0.1:$LIB_HTTPD_PORT + fi + + if test -n "$LIB_HTTPD_DAV" -o -n "$LIB_HTTPD_SVN" + then + HTTPD_PARA="$HTTPD_PARA -DDAV" + + if test -n "$LIB_HTTPD_SVN" + then + HTTPD_PARA="$HTTPD_PARA -DSVN" + rawsvnrepo="$HTTPD_ROOT_PATH/svnrepo" + svnrepo="http://127.0.0.1:$LIB_HTTPD_PORT/svn" + fi + fi +} + +start_httpd() { + prepare_httpd + + trap 'stop_httpd; die' exit + + "$LIB_HTTPD_PATH" $HTTPD_PARA \ + -c "Listen 127.0.0.1:$LIB_HTTPD_PORT" -k start +} + +stop_httpd() { + trap 'die' exit + + "$LIB_HTTPD_PATH" $HTTPD_PARA -k stop +} diff --git a/t/lib-httpd/apache.conf b/t/lib-httpd/apache.conf new file mode 100644 index 0000000000..a4473462d1 --- /dev/null +++ b/t/lib-httpd/apache.conf @@ -0,0 +1,34 @@ +PidFile httpd.pid +DocumentRoot www +ErrorLog error.log + + +LoadModule ssl_module modules/mod_ssl.so + +SSLCertificateFile httpd.pem +SSLCertificateKeyFile httpd.pem +SSLRandomSeed startup file:/dev/urandom 512 +SSLRandomSeed connect file:/dev/urandom 512 +SSLSessionCache none +SSLMutex file:ssl_mutex +SSLEngine On + + + + LoadModule dav_module modules/mod_dav.so + LoadModule dav_fs_module modules/mod_dav_fs.so + + DAVLockDB DAVLock + + Dav on + + + + + LoadModule dav_svn_module modules/mod_dav_svn.so + + + DAV svn + SVNPath svnrepo + + diff --git a/t/lib-httpd/ssl.cnf b/t/lib-httpd/ssl.cnf new file mode 100644 index 0000000000..6dab2579cb --- /dev/null +++ b/t/lib-httpd/ssl.cnf @@ -0,0 +1,8 @@ +RANDFILE = $ENV::RANDFILE_PATH + +[ req ] +default_bits = 1024 +distinguished_name = req_distinguished_name +prompt = no +[ req_distinguished_name ] +commonName = 127.0.0.1 diff --git a/t/t5540-http-push.sh b/t/t5540-http-push.sh new file mode 100755 index 0000000000..7372439164 --- /dev/null +++ b/t/t5540-http-push.sh @@ -0,0 +1,73 @@ +#!/bin/sh +# +# Copyright (c) 2008 Clemens Buchacher +# + +test_description='test http-push + +This test runs various sanity checks on http-push.' + +. ./test-lib.sh + +ROOT_PATH="$PWD" +LIB_HTTPD_DAV=t + +. ../lib-httpd.sh + +if ! start_httpd >&3 2>&4 +then + say "skipping test, web server setup failed" + test_done + exit +fi + +test_expect_success 'setup remote repository' ' + cd "$ROOT_PATH" && + mkdir test_repo && + cd test_repo && + git init && + : >path1 && + git add path1 && + test_tick && + git commit -m initial && + cd - && + git clone --bare test_repo test_repo.git && + cd test_repo.git && + git --bare update-server-info && + chmod +x hooks/post-update && + cd - && + mv test_repo.git $HTTPD_DOCUMENT_ROOT_PATH +' + +test_expect_success 'clone remote repository' ' + cd "$ROOT_PATH" && + git clone $HTTPD_URL/test_repo.git test_repo_clone +' + +test_expect_success 'push to remote repository' ' + cd "$ROOT_PATH"/test_repo_clone && + : >path2 && + git add path2 && + test_tick && + git commit -m path2 && + git push +' + +test_expect_success 'create and delete remote branch' ' + cd "$ROOT_PATH"/test_repo_clone && + git checkout -b dev && + : >path3 && + git add path3 && + test_tick && + git commit -m dev && + git push origin dev && + git fetch && + git push origin :dev && + git branch -d -r origin/dev && + git fetch && + ! git show-ref --verify refs/remotes/origin/dev +' + +stop_httpd + +test_done diff --git a/t/test-lib.sh b/t/test-lib.sh index 83889c4f46..9d9cb8d5a1 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -80,7 +80,7 @@ do -q|--q|--qu|--qui|--quie|--quiet) quiet=t; shift ;; --no-color) - color=; shift ;; + color=; shift ;; --no-python) # noop now... shift ;; @@ -142,7 +142,12 @@ test_count=0 test_fixed=0 test_broken=0 -trap 'echo >&5 "FATAL: Unexpected exit with code $?"; exit 1' exit +die () { + echo >&5 "FATAL: Unexpected exit with code $?" + exit 1 +} + +trap 'die' exit test_tick () { if test -z "${test_tick+set}" From e82447b1dfbda6ecfc101381c1295c444c73c903 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Tue, 26 Feb 2008 23:18:38 -0800 Subject: [PATCH 18/53] Fix "git log --merge --left-right" The command did not reject the combination of these options, but did not show left/right markers. Signed-off-by: Junio C Hamano --- revision.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/revision.c b/revision.c index 6e85aaa3fb..a399f27144 100644 --- a/revision.c +++ b/revision.c @@ -749,14 +749,9 @@ static void prepare_show_merge(struct rev_info *revs) add_pending_object(revs, &head->object, "HEAD"); add_pending_object(revs, &other->object, "MERGE_HEAD"); bases = get_merge_bases(head, other, 1); - while (bases) { - struct commit *it = bases->item; - struct commit_list *n = bases->next; - free(bases); - bases = n; - it->object.flags |= UNINTERESTING; - add_pending_object(revs, &it->object, "(merge-base)"); - } + add_pending_commit_list(revs, bases, UNINTERESTING); + free_commit_list(bases); + head->object.flags |= SYMMETRIC_LEFT; if (!active_nr) read_cache(); @@ -775,6 +770,7 @@ static void prepare_show_merge(struct rev_info *revs) i++; } revs->prune_data = prune; + revs->limited = 1; } int handle_revision_arg(const char *arg, struct rev_info *revs, From 212945d4a85dfa172ea55ec73b1d830ef2d8582f Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Thu, 28 Feb 2008 01:22:36 -0500 Subject: [PATCH 19/53] Teach git-describe to verify annotated tag names before output If an annotated tag describes a commit we want to favor the name listed in the body of the tag, rather than whatever name it has been stored under locally. By doing so it is easier to converse about tags with others, even if the tags happen to be fetched to a different name than it was given by its creator. To avoid confusion when a tag is stored under a different name (and thus is not readable via git-rev-parse --verify, etc.) we show a warning message if the name of the tag does not match the ref we found it under and if that tag was also selected for output. For example: $ git tag -a -m "i am a test" testtag $ mv .git/refs/tags/testtag .git/refs/tags/bobbytag $ ./git-describe HEAD warning: tag 'testtag' is really 'bobbytag' here testtag $ git tag -d testtag error: tag 'testtag' not found. $ git tag -d bobbytag Deleted tag 'bobbytag' Signed-off-by: Shawn O. Pearce Signed-off-by: Junio C Hamano --- builtin-describe.c | 38 ++++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/builtin-describe.c b/builtin-describe.c index 05e309f5ad..08d18507ac 100644 --- a/builtin-describe.c +++ b/builtin-describe.c @@ -22,7 +22,9 @@ static int max_candidates = 10; const char *pattern = NULL; struct commit_name { + struct tag *tag; int prio; /* annotated tag = 2, tag = 1, head = 0 */ + unsigned char sha1[20]; char path[FLEX_ARRAY]; /* more */ }; static const char *prio_names[] = { @@ -31,14 +33,17 @@ static const char *prio_names[] = { static void add_to_known_names(const char *path, struct commit *commit, - int prio) + int prio, + const unsigned char *sha1) { struct commit_name *e = commit->util; if (!e || e->prio < prio) { size_t len = strlen(path)+1; free(e); e = xmalloc(sizeof(struct commit_name) + len); + e->tag = NULL; e->prio = prio; + hashcpy(e->sha1, sha1); memcpy(e->path, path, len); commit->util = e; } @@ -89,7 +94,7 @@ static int get_name(const char *path, const unsigned char *sha1, int flag, void if (!tags && prio < 2) return 0; } - add_to_known_names(all ? path + 5 : path + 10, commit, prio); + add_to_known_names(all ? path + 5 : path + 10, commit, prio, sha1); return 0; } @@ -146,6 +151,22 @@ static unsigned long finish_depth_computation( return seen_commits; } +static void display_name(struct commit_name *n) +{ + if (n->prio == 2 && !n->tag) { + n->tag = lookup_tag(n->sha1); + if (!n->tag || !n->tag->tag) + die("annotated tag %s not available", n->path); + if (strcmp(n->tag->tag, n->path)) + warning("tag '%s' is really '%s' here", n->tag->tag, n->path); + } + + if (n->tag) + printf("%s", n->tag->tag); + else + printf("%s", n->path); +} + static void describe(const char *arg, int last_one) { unsigned char sha1[20]; @@ -170,7 +191,8 @@ static void describe(const char *arg, int last_one) n = cmit->util; if (n) { - printf("%s\n", n->path); + display_name(n); + printf("\n"); return; } @@ -252,12 +274,12 @@ static void describe(const char *arg, int last_one) sha1_to_hex(gave_up_on->object.sha1)); } } - if (abbrev == 0) - printf("%s\n", all_matches[0].name->path ); - else - printf("%s-%d-g%s\n", all_matches[0].name->path, - all_matches[0].depth, + + display_name(all_matches[0].name); + if (abbrev) + printf("-%d-g%s", all_matches[0].depth, find_unique_abbrev(cmit->object.sha1, abbrev)); + printf("\n"); if (!last_one) clear_commit_marks(cmit, -1); From 2add1e6db44c81e19cd4263317b53f3c1339e61b Mon Sep 17 00:00:00 2001 From: Martin Koegler Date: Mon, 25 Feb 2008 22:46:10 +0100 Subject: [PATCH 20/53] unpack-object: cache for non written objects Preventing objects with broken links entering the repository means, that write of some objects must be delayed. This patch adds a cache to keep the object data in memory. The delta resolving code must also search in the cache. Signed-off-by: Martin Koegler Signed-off-by: Junio C Hamano --- builtin-unpack-objects.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/builtin-unpack-objects.c b/builtin-unpack-objects.c index 1e51865c52..50e07faa12 100644 --- a/builtin-unpack-objects.c +++ b/builtin-unpack-objects.c @@ -8,6 +8,7 @@ #include "tag.h" #include "tree.h" #include "progress.h" +#include "decorate.h" static int dry_run, quiet, recover, has_errors; static const char unpack_usage[] = "git-unpack-objects [-n] [-q] [-r] < pack-file"; @@ -18,6 +19,18 @@ static unsigned int offset, len; static off_t consumed_bytes; static SHA_CTX ctx; +struct obj_buffer { + char *buffer; + unsigned long size; +}; + +static struct decoration obj_decorate; + +static struct obj_buffer *lookup_object_buffer(struct object *base) +{ + return lookup_decoration(&obj_decorate, base); +} + /* * Make sure at least "min" bytes are available in the buffer, and * return the pointer to the buffer. @@ -189,6 +202,7 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size, void *delta_data, *base; unsigned long base_size; unsigned char base_sha1[20]; + struct object *obj; if (type == OBJ_REF_DELTA) { hashcpy(base_sha1, fill(20)); @@ -252,6 +266,15 @@ static void unpack_delta_entry(enum object_type type, unsigned long delta_size, } } + obj = lookup_object(base_sha1); + if (obj) { + struct obj_buffer *obj_buf = lookup_object_buffer(obj); + if (obj_buf) { + resolve_delta(nr, obj->type, obj_buf->buffer, obj_buf->size, delta_data, delta_size); + return; + } + } + base = read_sha1_file(base_sha1, &type, &base_size); if (!base) { error("failed to read delta-pack base object %s", From d5ef408b9afb5b4417f4e7e1593a96302d666650 Mon Sep 17 00:00:00 2001 From: Martin Koegler Date: Mon, 25 Feb 2008 22:46:11 +0100 Subject: [PATCH 21/53] unpack-objects: prevent writing of inconsistent objects This patch introduces a strict mode, which ensures that: - no malformed object will be written - no object with broken links will be written The patch ensures this by delaying the write of all non blob object. These object are written, after all objects they link to are written. An error can only result in unreferenced objects. Signed-off-by: Martin Koegler Signed-off-by: Junio C Hamano --- Documentation/git-unpack-objects.txt | 3 + builtin-unpack-objects.c | 110 +++++++++++++++++++++++++-- 2 files changed, 106 insertions(+), 7 deletions(-) diff --git a/Documentation/git-unpack-objects.txt b/Documentation/git-unpack-objects.txt index b79be3fd4c..3697896a06 100644 --- a/Documentation/git-unpack-objects.txt +++ b/Documentation/git-unpack-objects.txt @@ -40,6 +40,9 @@ OPTIONS and make the best effort to recover as many objects as possible. +--strict:: + Don't write objects with broken content or links. + Author ------ diff --git a/builtin-unpack-objects.c b/builtin-unpack-objects.c index 50e07faa12..9d2a854950 100644 --- a/builtin-unpack-objects.c +++ b/builtin-unpack-objects.c @@ -7,11 +7,13 @@ #include "commit.h" #include "tag.h" #include "tree.h" +#include "tree-walk.h" #include "progress.h" #include "decorate.h" +#include "fsck.h" -static int dry_run, quiet, recover, has_errors; -static const char unpack_usage[] = "git-unpack-objects [-n] [-q] [-r] < pack-file"; +static int dry_run, quiet, recover, has_errors, strict; +static const char unpack_usage[] = "git-unpack-objects [-n] [-q] [-r] [--strict] < pack-file"; /* We always read in 4kB chunks. */ static unsigned char buffer[4096]; @@ -31,6 +33,16 @@ static struct obj_buffer *lookup_object_buffer(struct object *base) return lookup_decoration(&obj_decorate, base); } +static void add_object_buffer(struct object *object, char *buffer, unsigned long size) +{ + struct obj_buffer *obj; + obj = xcalloc(1, sizeof(struct obj_buffer)); + obj->buffer = buffer; + obj->size = size; + if (add_decoration(&obj_decorate, object, obj)) + die("object %s tried to add buffer twice!", sha1_to_hex(object->sha1)); +} + /* * Make sure at least "min" bytes are available in the buffer, and * return the pointer to the buffer. @@ -134,9 +146,58 @@ static void add_delta_to_list(unsigned nr, unsigned const char *base_sha1, struct obj_info { off_t offset; unsigned char sha1[20]; + struct object *obj; }; +#define FLAG_OPEN (1u<<20) +#define FLAG_WRITTEN (1u<<21) + static struct obj_info *obj_list; +unsigned nr_objects; + +static void write_cached_object(struct object *obj) +{ + unsigned char sha1[20]; + struct obj_buffer *obj_buf = lookup_object_buffer(obj); + if (write_sha1_file(obj_buf->buffer, obj_buf->size, typename(obj->type), sha1) < 0) + die("failed to write object %s", sha1_to_hex(obj->sha1)); + obj->flags |= FLAG_WRITTEN; +} + +static int check_object(struct object *obj, int type, void *data) +{ + if (!obj) + return 0; + + if (obj->flags & FLAG_WRITTEN) + return 1; + + if (type != OBJ_ANY && obj->type != type) + die("object type mismatch"); + + if (!(obj->flags & FLAG_OPEN)) { + unsigned long size; + int type = sha1_object_info(obj->sha1, &size); + if (type != obj->type || type <= 0) + die("object of unexpected type"); + obj->flags |= FLAG_WRITTEN; + return 1; + } + + if (fsck_object(obj, 1, fsck_error_function)) + die("Error in object"); + if (!fsck_walk(obj, check_object, 0)) + die("Error on reachable objects of %s", sha1_to_hex(obj->sha1)); + write_cached_object(obj); + return 1; +} + +static void write_rest(void) +{ + unsigned i; + for (i = 0; i < nr_objects; i++) + check_object(obj_list[i].obj, OBJ_ANY, 0); +} static void added_object(unsigned nr, enum object_type type, void *data, unsigned long size); @@ -144,9 +205,36 @@ static void added_object(unsigned nr, enum object_type type, static void write_object(unsigned nr, enum object_type type, void *buf, unsigned long size) { - if (write_sha1_file(buf, size, typename(type), obj_list[nr].sha1) < 0) - die("failed to write object"); added_object(nr, type, buf, size); + if (!strict) { + if (write_sha1_file(buf, size, typename(type), obj_list[nr].sha1) < 0) + die("failed to write object"); + free(buf); + obj_list[nr].obj = 0; + } else if (type == OBJ_BLOB) { + struct blob *blob; + if (write_sha1_file(buf, size, typename(type), obj_list[nr].sha1) < 0) + die("failed to write object"); + free(buf); + + blob = lookup_blob(obj_list[nr].sha1); + if (blob) + blob->object.flags |= FLAG_WRITTEN; + else + die("invalid blob object"); + obj_list[nr].obj = 0; + } else { + struct object *obj; + int eaten; + hash_sha1_file(buf, size, typename(type), obj_list[nr].sha1); + obj = parse_object_buffer(obj_list[nr].sha1, type, size, buf, &eaten); + if (!obj) + die("invalid %s", typename(type)); + /* buf is stored via add_object_buffer and in obj, if its a tree or commit */ + add_object_buffer(obj, buf, size); + obj->flags |= FLAG_OPEN; + obj_list[nr].obj = obj; + } } static void resolve_delta(unsigned nr, enum object_type type, @@ -163,7 +251,6 @@ static void resolve_delta(unsigned nr, enum object_type type, die("failed to apply delta"); free(delta); write_object(nr, type, result, result_size); - free(result); } static void added_object(unsigned nr, enum object_type type, @@ -193,7 +280,8 @@ static void unpack_non_delta_entry(enum object_type type, unsigned long size, if (!dry_run && buf) write_object(nr, type, buf, size); - free(buf); + else + free(buf); } static void unpack_delta_entry(enum object_type type, unsigned long delta_size, @@ -336,7 +424,8 @@ static void unpack_all(void) int i; struct progress *progress = NULL; struct pack_header *hdr = fill(sizeof(struct pack_header)); - unsigned nr_objects = ntohl(hdr->hdr_entries); + + nr_objects = ntohl(hdr->hdr_entries); if (ntohl(hdr->hdr_signature) != PACK_SIGNATURE) die("bad pack file"); @@ -347,6 +436,7 @@ static void unpack_all(void) if (!quiet) progress = start_progress("Unpacking objects", nr_objects); obj_list = xmalloc(nr_objects * sizeof(*obj_list)); + memset(obj_list, 0, nr_objects * sizeof(*obj_list)); for (i = 0; i < nr_objects; i++) { unpack_one(i); display_progress(progress, i + 1); @@ -382,6 +472,10 @@ int cmd_unpack_objects(int argc, const char **argv, const char *prefix) recover = 1; continue; } + if (!strcmp(arg, "--strict")) { + strict = 1; + continue; + } if (!prefixcmp(arg, "--pack_header=")) { struct pack_header *hdr; char *c; @@ -407,6 +501,8 @@ int cmd_unpack_objects(int argc, const char **argv, const char *prefix) unpack_all(); SHA1_Update(&ctx, buffer, offset); SHA1_Final(sha1, &ctx); + if (strict) + write_rest(); if (hashcmp(fill(20), sha1)) die("final sha1 did not match"); use(20); From 0153be05ae332b8df9bb21d8d249881323e30725 Mon Sep 17 00:00:00 2001 From: Martin Koegler Date: Mon, 25 Feb 2008 22:46:12 +0100 Subject: [PATCH 22/53] index-pack: introduce checking mode Adds strict option, which bails out if the pack would introduces broken object or links in the repository. Signed-off-by: Martin Koegler Signed-off-by: Junio C Hamano --- Documentation/git-index-pack.txt | 3 ++ index-pack.c | 88 +++++++++++++++++++++++++++++++- 2 files changed, 90 insertions(+), 1 deletion(-) diff --git a/Documentation/git-index-pack.txt b/Documentation/git-index-pack.txt index 72b5d00116..a7825b6144 100644 --- a/Documentation/git-index-pack.txt +++ b/Documentation/git-index-pack.txt @@ -75,6 +75,9 @@ OPTIONS to force the version for the generated pack index, and to force 64-bit index entries on objects located above the given offset. +--strict:: + Die, if the pack contains broken objects or links. + Note ---- diff --git a/index-pack.c b/index-pack.c index 9fd6982a97..9c0c27813f 100644 --- a/index-pack.c +++ b/index-pack.c @@ -7,9 +7,10 @@ #include "tag.h" #include "tree.h" #include "progress.h" +#include "fsck.h" static const char index_pack_usage[] = -"git-index-pack [-v] [-o ] [{ ---keep | --keep= }] { | --stdin [--fix-thin] [] }"; +"git-index-pack [-v] [-o ] [{ ---keep | --keep= }] [--strict] { | --stdin [--fix-thin] [] }"; struct object_entry { @@ -31,6 +32,9 @@ union delta_base { */ #define UNION_BASE_SZ 20 +#define FLAG_LINK (1u<<20) +#define FLAG_CHECKED (1u<<21) + struct delta_entry { union delta_base base; @@ -44,6 +48,7 @@ static int nr_deltas; static int nr_resolved_deltas; static int from_stdin; +static int strict; static int verbose; static struct progress *progress; @@ -56,6 +61,48 @@ static SHA_CTX input_ctx; static uint32_t input_crc32; static int input_fd, output_fd, pack_fd; +static int mark_link(struct object *obj, int type, void *data) +{ + if (!obj) + return -1; + + if (type != OBJ_ANY && obj->type != type) + die("object type mismatch at %s", sha1_to_hex(obj->sha1)); + + obj->flags |= FLAG_LINK; + return 0; +} + +/* The content of each linked object must have been checked + or it must be already present in the object database */ +static void check_object(struct object *obj) +{ + if (!obj) + return; + + if (!(obj->flags & FLAG_LINK)) + return; + + if (!(obj->flags & FLAG_CHECKED)) { + unsigned long size; + int type = sha1_object_info(obj->sha1, &size); + if (type != obj->type || type <= 0) + die("object of unexpected type"); + obj->flags |= FLAG_CHECKED; + return; + } +} + +static void check_objects(void) +{ + unsigned i, max; + + max = get_max_object_index(); + for (i = 0; i < max; i++) + check_object(get_indexed_object(i)); +} + + /* Discard current buffer used content. */ static void flush(void) { @@ -341,6 +388,41 @@ static void sha1_object(const void *data, unsigned long size, die("SHA1 COLLISION FOUND WITH %s !", sha1_to_hex(sha1)); free(has_data); } + if (strict) { + if (type == OBJ_BLOB) { + struct blob *blob = lookup_blob(sha1); + if (blob) + blob->object.flags |= FLAG_CHECKED; + else + die("invalid blob object %s", sha1_to_hex(sha1)); + } else { + struct object *obj; + int eaten; + void *buf = (void *) data; + + /* + * we do not need to free the memory here, as the + * buf is deleted by the caller. + */ + obj = parse_object_buffer(sha1, type, size, buf, &eaten); + if (!obj) + die("invalid %s", typename(type)); + if (fsck_object(obj, 1, fsck_error_function)) + die("Error in object"); + if (fsck_walk(obj, mark_link, 0)) + die("Not all child objects of %s are reachable", sha1_to_hex(obj->sha1)); + + if (obj->type == OBJ_TREE) { + struct tree *item = (struct tree *) obj; + item->buffer = NULL; + } + if (obj->type == OBJ_COMMIT) { + struct commit *commit = (struct commit *) obj; + commit->buffer = NULL; + } + obj->flags |= FLAG_CHECKED; + } + } } static void resolve_delta(struct object_entry *delta_obj, void *base_data, @@ -714,6 +796,8 @@ int main(int argc, char **argv) from_stdin = 1; } else if (!strcmp(arg, "--fix-thin")) { fix_thin_pack = 1; + } else if (!strcmp(arg, "--strict")) { + strict = 1; } else if (!strcmp(arg, "--keep")) { keep_msg = ""; } else if (!prefixcmp(arg, "--keep=")) { @@ -812,6 +896,8 @@ int main(int argc, char **argv) nr_deltas - nr_resolved_deltas); } free(deltas); + if (strict) + check_objects(); idx_objects = xmalloc((nr_objects) * sizeof(struct pack_idx_entry *)); for (i = 0; i < nr_objects; i++) From 28f72a0f232dfc71b3be726e7e71d0a6d5f9ebba Mon Sep 17 00:00:00 2001 From: Martin Koegler Date: Mon, 25 Feb 2008 22:46:13 +0100 Subject: [PATCH 23/53] receive-pack: use strict mode for unpacking objects Signed-off-by: Martin Koegler Signed-off-by: Junio C Hamano --- Documentation/config.txt | 6 ++++++ receive-pack.c | 36 +++++++++++++++++++++++------------- 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 6d8cca46ab..72d3a345ec 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -860,6 +860,12 @@ imap:: The configuration variables in the 'imap' section are described in linkgit:git-imap-send[1]. +receive.fsckObjects:: + If it is set to true, git-receive-pack will check all received + objects. It will abort in the case of a malformed object or a + broken link. The result of an abort are only dangling objects. + The default value is true. + receive.unpackLimit:: If the number of objects received in a push is below this limit then the objects will be unpacked into loose object diff --git a/receive-pack.c b/receive-pack.c index 3267495832..f5440ff4d4 100644 --- a/receive-pack.c +++ b/receive-pack.c @@ -10,6 +10,7 @@ static const char receive_pack_usage[] = "git-receive-pack "; static int deny_non_fast_forwards = 0; +static int receive_fsck_objects = 1; static int receive_unpack_limit = -1; static int transfer_unpack_limit = -1; static int unpack_limit = 100; @@ -35,6 +36,11 @@ static int receive_pack_config(const char *var, const char *value) return 0; } + if (strcmp(var, "receive.fsckobjects") == 0) { + receive_fsck_objects = git_config_bool(var, value); + return 0; + } + return git_default_config(var, value); } @@ -367,11 +373,13 @@ static const char *unpack(void) ntohl(hdr.hdr_version), ntohl(hdr.hdr_entries)); if (ntohl(hdr.hdr_entries) < unpack_limit) { - int code; - const char *unpacker[3]; - unpacker[0] = "unpack-objects"; - unpacker[1] = hdr_arg; - unpacker[2] = NULL; + int code, i = 0; + const char *unpacker[4]; + unpacker[i++] = "unpack-objects"; + if (receive_fsck_objects) + unpacker[i++] = "--strict"; + unpacker[i++] = hdr_arg; + unpacker[i++] = NULL; code = run_command_v_opt(unpacker, RUN_GIT_CMD); switch (code) { case 0: @@ -392,8 +400,8 @@ static const char *unpack(void) return "unpacker exited with error code"; } } else { - const char *keeper[6]; - int s, status; + const char *keeper[7]; + int s, status, i = 0; char keep_arg[256]; struct child_process ip; @@ -401,12 +409,14 @@ static const char *unpack(void) if (gethostname(keep_arg + s, sizeof(keep_arg) - s)) strcpy(keep_arg + s, "localhost"); - keeper[0] = "index-pack"; - keeper[1] = "--stdin"; - keeper[2] = "--fix-thin"; - keeper[3] = hdr_arg; - keeper[4] = keep_arg; - keeper[5] = NULL; + keeper[i++] = "index-pack"; + keeper[i++] = "--stdin"; + if (receive_fsck_objects) + keeper[i++] = "--strict"; + keeper[i++] = "--fix-thin"; + keeper[i++] = hdr_arg; + keeper[i++] = keep_arg; + keeper[i++] = NULL; memset(&ip, 0, sizeof(ip)); ip.argv = keeper; ip.out = -1; From fbbbc362ab9d3a8d76eb4273e65fb1fb26849d75 Mon Sep 17 00:00:00 2001 From: "Philippe Bruhat (BooK" Date: Thu, 28 Feb 2008 11:18:21 +0100 Subject: [PATCH 24/53] cvsimport: have default merge regex allow for dashes in the branch name The default value of @mergerx uses \w, which matches word character; a branch name like policy-20050608-br will not be matched. Signed-off-by: Philippe Bruhat (BooK) Signed-off-by: Junio C Hamano --- git-cvsimport.perl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-cvsimport.perl b/git-cvsimport.perl index 9516242338..3d013a7d62 100755 --- a/git-cvsimport.perl +++ b/git-cvsimport.perl @@ -164,7 +164,7 @@ if ($#ARGV == 0) { our @mergerx = (); if ($opt_m) { - @mergerx = ( qr/\b(?:from|of|merge|merging|merged) (\w+)/i ); + @mergerx = ( qr/\b(?:from|of|merge|merging|merged) ([-\w]+)/i ); } if ($opt_M) { push (@mergerx, qr/$opt_M/); From bc434e829c6f1757d2761c50e06a28278dc2f2c7 Mon Sep 17 00:00:00 2001 From: "Philippe Bruhat (BooK" Date: Thu, 28 Feb 2008 11:18:22 +0100 Subject: [PATCH 25/53] cvsimport: allow for multiple -M options Use Getopt::Long instead of Getopt::Std to handle multiple -M options, for all the cases when having a single custom regex is not enough. Signed-off-by: Philippe Bruhat (BooK) Signed-off-by: Junio C Hamano --- git-cvsimport.perl | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/git-cvsimport.perl b/git-cvsimport.perl index 3d013a7d62..47f116f37e 100755 --- a/git-cvsimport.perl +++ b/git-cvsimport.perl @@ -15,7 +15,7 @@ use strict; use warnings; -use Getopt::Std; +use Getopt::Long; use File::Spec; use File::Temp qw(tempfile tmpnam); use File::Path qw(mkpath); @@ -29,7 +29,7 @@ use IPC::Open2; $SIG{'PIPE'}="IGNORE"; $ENV{'TZ'}="UTC"; -our ($opt_h,$opt_o,$opt_v,$opt_k,$opt_u,$opt_d,$opt_p,$opt_C,$opt_z,$opt_i,$opt_P, $opt_s,$opt_m,$opt_M,$opt_A,$opt_S,$opt_L, $opt_a, $opt_r); +our ($opt_h,$opt_o,$opt_v,$opt_k,$opt_u,$opt_d,$opt_p,$opt_C,$opt_z,$opt_i,$opt_P, $opt_s,$opt_m,@opt_M,$opt_A,$opt_S,$opt_L, $opt_a, $opt_r); my (%conv_author_name, %conv_author_email); sub usage(;$) { @@ -112,7 +112,12 @@ sub read_repo_config { my $opts = "haivmkuo:d:p:r:C:z:s:M:P:A:S:L:"; read_repo_config($opts); -getopts($opts) or usage(); +Getopt::Long::Configure( 'no_ignore_case', 'bundling' ); + +# turn the Getopt::Std specification in a Getopt::Long one, +# with support for multiple -M options +GetOptions( map { s/:/=s/; /M/ ? "$_\@" : $_ } split( /(?!:)/, $opts ) ) + or usage(); usage if $opt_h; if (@ARGV == 0) { @@ -166,8 +171,8 @@ our @mergerx = (); if ($opt_m) { @mergerx = ( qr/\b(?:from|of|merge|merging|merged) ([-\w]+)/i ); } -if ($opt_M) { - push (@mergerx, qr/$opt_M/); +if (@opt_M) { + push (@mergerx, map { qr/$_/ } @opt_M); } # Remember UTC of our starting time From 3c832a78b15f8ffcb4e6f1f6f6d8b7a607ba5d06 Mon Sep 17 00:00:00 2001 From: "Philippe Bruhat (BooK" Date: Thu, 28 Feb 2008 11:18:23 +0100 Subject: [PATCH 26/53] cvsimport: document that -M can be used multiple times Also document the capture behaviour (source branch name in $1) Signed-off-by: Philippe Bruhat (BooK) Signed-off-by: Junio C Hamano --- Documentation/git-cvsimport.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Documentation/git-cvsimport.txt b/Documentation/git-cvsimport.txt index 6f91b9ea2a..58eefd42e5 100644 --- a/Documentation/git-cvsimport.txt +++ b/Documentation/git-cvsimport.txt @@ -102,13 +102,17 @@ If you need to pass multiple options, separate them with a comma. -m:: Attempt to detect merges based on the commit message. This option - will enable default regexes that try to capture the name source + will enable default regexes that try to capture the source branch name from the commit message. -M :: Attempt to detect merges based on the commit message with a custom regex. It can be used with '-m' to enable the default regexes as well. You must escape forward slashes. ++ +The regex must capture the source branch name in $1. ++ +This option can be used several times to provide several detection regexes. -S :: Skip paths matching the regex. From 3449f8c4cb93a0ec445db22ee7549d0b051446d6 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Thu, 28 Feb 2008 00:25:17 -0500 Subject: [PATCH 27/53] factorize revindex code out of builtin-pack-objects.c No functional change. This is needed to fix verify-pack in a later patch. Signed-off-by: Nicolas Pitre Signed-off-by: Junio C Hamano --- Makefile | 5 +- builtin-pack-objects.c | 160 +++-------------------------------------- pack-revindex.c | 142 ++++++++++++++++++++++++++++++++++++ pack-revindex.h | 12 ++++ 4 files changed, 167 insertions(+), 152 deletions(-) create mode 100644 pack-revindex.c create mode 100644 pack-revindex.h diff --git a/Makefile b/Makefile index a5b6eebf1a..1acac02766 100644 --- a/Makefile +++ b/Makefile @@ -304,7 +304,8 @@ LIB_H = \ run-command.h strbuf.h tag.h tree.h git-compat-util.h revision.h \ tree-walk.h log-tree.h dir.h path-list.h unpack-trees.h builtin.h \ utf8.h reflog-walk.h patch-ids.h attr.h decorate.h progress.h \ - mailmap.h remote.h parse-options.h transport.h diffcore.h hash.h + mailmap.h remote.h parse-options.h transport.h diffcore.h hash.h \ + pack-revindex.h DIFF_OBJS = \ diff.o diff-lib.o diffcore-break.o diffcore-order.o \ @@ -328,7 +329,7 @@ LIB_OBJS = \ color.o wt-status.o archive-zip.o archive-tar.o shallow.o utf8.o \ convert.o attr.o decorate.o progress.o mailmap.o symlinks.o remote.o \ transport.o bundle.o walker.o parse-options.o ws.o archive.o branch.o \ - alias.o + alias.o pack-revindex.o BUILTIN_OBJS = \ builtin-add.o \ diff --git a/builtin-pack-objects.c b/builtin-pack-objects.c index 1bba6e6a64..c7834bb368 100644 --- a/builtin-pack-objects.c +++ b/builtin-pack-objects.c @@ -8,6 +8,7 @@ #include "tree.h" #include "delta.h" #include "pack.h" +#include "pack-revindex.h" #include "csum-file.h" #include "tree-walk.h" #include "diff.h" @@ -92,158 +93,12 @@ static unsigned long window_memory_limit = 0; static int *object_ix; static int object_ix_hashsz; -/* - * Pack index for existing packs give us easy access to the offsets into - * corresponding pack file where each object's data starts, but the entries - * do not store the size of the compressed representation (uncompressed - * size is easily available by examining the pack entry header). It is - * also rather expensive to find the sha1 for an object given its offset. - * - * We build a hashtable of existing packs (pack_revindex), and keep reverse - * index here -- pack index file is sorted by object name mapping to offset; - * this pack_revindex[].revindex array is a list of offset/index_nr pairs - * ordered by offset, so if you know the offset of an object, next offset - * is where its packed representation ends and the index_nr can be used to - * get the object sha1 from the main index. - */ -struct revindex_entry { - off_t offset; - unsigned int nr; -}; -struct pack_revindex { - struct packed_git *p; - struct revindex_entry *revindex; -}; -static struct pack_revindex *pack_revindex; -static int pack_revindex_hashsz; - /* * stats */ static uint32_t written, written_delta; static uint32_t reused, reused_delta; -static int pack_revindex_ix(struct packed_git *p) -{ - unsigned long ui = (unsigned long)p; - int i; - - ui = ui ^ (ui >> 16); /* defeat structure alignment */ - i = (int)(ui % pack_revindex_hashsz); - while (pack_revindex[i].p) { - if (pack_revindex[i].p == p) - return i; - if (++i == pack_revindex_hashsz) - i = 0; - } - return -1 - i; -} - -static void prepare_pack_ix(void) -{ - int num; - struct packed_git *p; - for (num = 0, p = packed_git; p; p = p->next) - num++; - if (!num) - return; - pack_revindex_hashsz = num * 11; - pack_revindex = xcalloc(sizeof(*pack_revindex), pack_revindex_hashsz); - for (p = packed_git; p; p = p->next) { - num = pack_revindex_ix(p); - num = - 1 - num; - pack_revindex[num].p = p; - } - /* revindex elements are lazily initialized */ -} - -static int cmp_offset(const void *a_, const void *b_) -{ - const struct revindex_entry *a = a_; - const struct revindex_entry *b = b_; - return (a->offset < b->offset) ? -1 : (a->offset > b->offset) ? 1 : 0; -} - -/* - * Ordered list of offsets of objects in the pack. - */ -static void prepare_pack_revindex(struct pack_revindex *rix) -{ - struct packed_git *p = rix->p; - int num_ent = p->num_objects; - int i; - const char *index = p->index_data; - - rix->revindex = xmalloc(sizeof(*rix->revindex) * (num_ent + 1)); - index += 4 * 256; - - if (p->index_version > 1) { - const uint32_t *off_32 = - (uint32_t *)(index + 8 + p->num_objects * (20 + 4)); - const uint32_t *off_64 = off_32 + p->num_objects; - for (i = 0; i < num_ent; i++) { - uint32_t off = ntohl(*off_32++); - if (!(off & 0x80000000)) { - rix->revindex[i].offset = off; - } else { - rix->revindex[i].offset = - ((uint64_t)ntohl(*off_64++)) << 32; - rix->revindex[i].offset |= - ntohl(*off_64++); - } - rix->revindex[i].nr = i; - } - } else { - for (i = 0; i < num_ent; i++) { - uint32_t hl = *((uint32_t *)(index + 24 * i)); - rix->revindex[i].offset = ntohl(hl); - rix->revindex[i].nr = i; - } - } - - /* This knows the pack format -- the 20-byte trailer - * follows immediately after the last object data. - */ - rix->revindex[num_ent].offset = p->pack_size - 20; - rix->revindex[num_ent].nr = -1; - qsort(rix->revindex, num_ent, sizeof(*rix->revindex), cmp_offset); -} - -static struct revindex_entry * find_packed_object(struct packed_git *p, - off_t ofs) -{ - int num; - int lo, hi; - struct pack_revindex *rix; - struct revindex_entry *revindex; - num = pack_revindex_ix(p); - if (num < 0) - die("internal error: pack revindex uninitialized"); - rix = &pack_revindex[num]; - if (!rix->revindex) - prepare_pack_revindex(rix); - revindex = rix->revindex; - lo = 0; - hi = p->num_objects + 1; - do { - int mi = (lo + hi) / 2; - if (revindex[mi].offset == ofs) { - return revindex + mi; - } - else if (ofs < revindex[mi].offset) - hi = mi; - else - lo = mi + 1; - } while (lo < hi); - die("internal error: pack revindex corrupt"); -} - -static const unsigned char *find_packed_object_name(struct packed_git *p, - off_t ofs) -{ - struct revindex_entry *entry = find_packed_object(p, ofs); - return nth_packed_object_sha1(p, entry->nr); -} static void *delta_against(void *buf, unsigned long size, struct object_entry *entry) { @@ -510,7 +365,7 @@ static unsigned long write_object(struct sha1file *f, } hdrlen = encode_header(obj_type, entry->size, header); offset = entry->in_pack_offset; - revidx = find_packed_object(p, offset); + revidx = find_pack_revindex(p, offset); datalen = revidx[1].offset - offset; if (!pack_to_stdout && p->index_version > 1 && check_pack_crc(p, &w_curs, offset, datalen, revidx->nr)) @@ -1162,8 +1017,11 @@ static void check_object(struct object_entry *entry) die("delta base offset out of bound for %s", sha1_to_hex(entry->idx.sha1)); ofs = entry->in_pack_offset - ofs; - if (!no_reuse_delta && !entry->preferred_base) - base_ref = find_packed_object_name(p, ofs); + if (!no_reuse_delta && !entry->preferred_base) { + struct revindex_entry *revidx; + revidx = find_pack_revindex(p, ofs); + base_ref = nth_packed_object_sha1(p, revidx->nr); + } entry->in_pack_header_size = used + used_0; break; } @@ -1240,9 +1098,11 @@ static void get_object_details(void) sorted_by_offset[i] = objects + i; qsort(sorted_by_offset, nr_objects, sizeof(*sorted_by_offset), pack_offset_sort); - prepare_pack_ix(); + init_pack_revindex(); + for (i = 0; i < nr_objects; i++) check_object(sorted_by_offset[i]); + free(sorted_by_offset); } diff --git a/pack-revindex.c b/pack-revindex.c new file mode 100644 index 0000000000..a8aa2cd6ca --- /dev/null +++ b/pack-revindex.c @@ -0,0 +1,142 @@ +#include "cache.h" +#include "pack-revindex.h" + +/* + * Pack index for existing packs give us easy access to the offsets into + * corresponding pack file where each object's data starts, but the entries + * do not store the size of the compressed representation (uncompressed + * size is easily available by examining the pack entry header). It is + * also rather expensive to find the sha1 for an object given its offset. + * + * We build a hashtable of existing packs (pack_revindex), and keep reverse + * index here -- pack index file is sorted by object name mapping to offset; + * this pack_revindex[].revindex array is a list of offset/index_nr pairs + * ordered by offset, so if you know the offset of an object, next offset + * is where its packed representation ends and the index_nr can be used to + * get the object sha1 from the main index. + */ + +struct pack_revindex { + struct packed_git *p; + struct revindex_entry *revindex; +}; + +static struct pack_revindex *pack_revindex; +static int pack_revindex_hashsz; + +static int pack_revindex_ix(struct packed_git *p) +{ + unsigned long ui = (unsigned long)p; + int i; + + ui = ui ^ (ui >> 16); /* defeat structure alignment */ + i = (int)(ui % pack_revindex_hashsz); + while (pack_revindex[i].p) { + if (pack_revindex[i].p == p) + return i; + if (++i == pack_revindex_hashsz) + i = 0; + } + return -1 - i; +} + +void init_pack_revindex(void) +{ + int num; + struct packed_git *p; + + for (num = 0, p = packed_git; p; p = p->next) + num++; + if (!num) + return; + pack_revindex_hashsz = num * 11; + pack_revindex = xcalloc(sizeof(*pack_revindex), pack_revindex_hashsz); + for (p = packed_git; p; p = p->next) { + num = pack_revindex_ix(p); + num = - 1 - num; + pack_revindex[num].p = p; + } + /* revindex elements are lazily initialized */ +} + +static int cmp_offset(const void *a_, const void *b_) +{ + const struct revindex_entry *a = a_; + const struct revindex_entry *b = b_; + return (a->offset < b->offset) ? -1 : (a->offset > b->offset) ? 1 : 0; +} + +/* + * Ordered list of offsets of objects in the pack. + */ +static void create_pack_revindex(struct pack_revindex *rix) +{ + struct packed_git *p = rix->p; + int num_ent = p->num_objects; + int i; + const char *index = p->index_data; + + rix->revindex = xmalloc(sizeof(*rix->revindex) * (num_ent + 1)); + index += 4 * 256; + + if (p->index_version > 1) { + const uint32_t *off_32 = + (uint32_t *)(index + 8 + p->num_objects * (20 + 4)); + const uint32_t *off_64 = off_32 + p->num_objects; + for (i = 0; i < num_ent; i++) { + uint32_t off = ntohl(*off_32++); + if (!(off & 0x80000000)) { + rix->revindex[i].offset = off; + } else { + rix->revindex[i].offset = + ((uint64_t)ntohl(*off_64++)) << 32; + rix->revindex[i].offset |= + ntohl(*off_64++); + } + rix->revindex[i].nr = i; + } + } else { + for (i = 0; i < num_ent; i++) { + uint32_t hl = *((uint32_t *)(index + 24 * i)); + rix->revindex[i].offset = ntohl(hl); + rix->revindex[i].nr = i; + } + } + + /* This knows the pack format -- the 20-byte trailer + * follows immediately after the last object data. + */ + rix->revindex[num_ent].offset = p->pack_size - 20; + rix->revindex[num_ent].nr = -1; + qsort(rix->revindex, num_ent, sizeof(*rix->revindex), cmp_offset); +} + +struct revindex_entry *find_pack_revindex(struct packed_git *p, off_t ofs) +{ + int num; + int lo, hi; + struct pack_revindex *rix; + struct revindex_entry *revindex; + + num = pack_revindex_ix(p); + if (num < 0) + die("internal error: pack revindex uninitialized"); + + rix = &pack_revindex[num]; + if (!rix->revindex) + create_pack_revindex(rix); + revindex = rix->revindex; + + lo = 0; + hi = p->num_objects + 1; + do { + int mi = (lo + hi) / 2; + if (revindex[mi].offset == ofs) { + return revindex + mi; + } else if (ofs < revindex[mi].offset) + hi = mi; + else + lo = mi + 1; + } while (lo < hi); + die("internal error: pack revindex corrupt"); +} diff --git a/pack-revindex.h b/pack-revindex.h new file mode 100644 index 0000000000..c3527a7565 --- /dev/null +++ b/pack-revindex.h @@ -0,0 +1,12 @@ +#ifndef PACK_REVINDEX_H +#define PACK_REVINDEX_H + +struct revindex_entry { + off_t offset; + unsigned int nr; +}; + +void init_pack_revindex(void); +struct revindex_entry *find_pack_revindex(struct packed_git *p, off_t ofs); + +#endif From 340814636dde3cbd2e461b12f9ae832d2100766a Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Thu, 28 Feb 2008 00:25:18 -0500 Subject: [PATCH 28/53] make verify_one_pack() a bit less wrong wrt packed_git structure Simply freeing it is wrong. There are many things attached to this structure that are not cleaned up. In practice this doesn't matter much since this happens just before the program exits, but it is still a bit more "correct" to leak it implicitly rather than explicitly. And therefore it is also a good idea to register it with install_packed_git(). Not only might it have better chance of being properly cleaned up if such functionality is implemented for the general case, but some functions like init_revindex() expect all packed_git instances to be globally accessible. Signed-off-by: Nicolas Pitre Signed-off-by: Junio C Hamano --- builtin-verify-pack.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin-verify-pack.c b/builtin-verify-pack.c index 4e31c273f4..4958bbbf11 100644 --- a/builtin-verify-pack.c +++ b/builtin-verify-pack.c @@ -40,8 +40,8 @@ static int verify_one_pack(const char *path, int verbose) if (!pack) return error("packfile %s not found.", arg); + install_packed_git(pack); err = verify_pack(pack, verbose); - free(pack); return err; } From 70f5d5d31cbf0ba273083805124ad67135142527 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Thu, 28 Feb 2008 00:25:19 -0500 Subject: [PATCH 29/53] fix unimplemented packed_object_info_detail() features Since commit eb32d236df0c16b936b04f0c5402addb61cdb311, there was a TODO comment in packed_object_info_detail() about the SHA1 of base object to OBJ_OFS_DELTA objects. So here it is at last. While at it, providing the actual storage size information as well is now trivial. Signed-off-by: Nicolas Pitre Signed-off-by: Junio C Hamano --- pack-check.c | 3 +++ sha1_file.c | 10 +++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/pack-check.c b/pack-check.c index d7dd62bb83..ae25685036 100644 --- a/pack-check.c +++ b/pack-check.c @@ -1,5 +1,6 @@ #include "cache.h" #include "pack.h" +#include "pack-revindex.h" struct idx_entry { @@ -101,8 +102,10 @@ static int verify_packfile(struct packed_git *p, static void show_pack_info(struct packed_git *p) { uint32_t nr_objects, i, chain_histogram[MAX_CHAIN+1]; + nr_objects = p->num_objects; memset(chain_histogram, 0, sizeof(chain_histogram)); + init_pack_revindex(); for (i = 0; i < nr_objects; i++) { const unsigned char *sha1; diff --git a/sha1_file.c b/sha1_file.c index 1ddb96bb82..445a871db3 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -14,6 +14,7 @@ #include "tag.h" #include "tree.h" #include "refs.h" +#include "pack-revindex.h" #ifndef O_NOATIME #if defined(__linux__) && (defined(__i386__) || defined(__PPC__)) @@ -1367,11 +1368,15 @@ const char *packed_object_info_detail(struct packed_git *p, unsigned long dummy; unsigned char *next_sha1; enum object_type type; + struct revindex_entry *revidx; *delta_chain_length = 0; curpos = obj_offset; type = unpack_object_header(p, &w_curs, &curpos, size); + revidx = find_pack_revindex(p, obj_offset); + *store_size = revidx[1].offset - obj_offset; + for (;;) { switch (type) { default: @@ -1381,14 +1386,13 @@ const char *packed_object_info_detail(struct packed_git *p, case OBJ_TREE: case OBJ_BLOB: case OBJ_TAG: - *store_size = 0; /* notyet */ unuse_pack(&w_curs); return typename(type); case OBJ_OFS_DELTA: obj_offset = get_delta_base(p, &w_curs, &curpos, type, obj_offset); if (*delta_chain_length == 0) { - /* TODO: find base_sha1 as pointed by curpos */ - hashclr(base_sha1); + revidx = find_pack_revindex(p, obj_offset); + hashcpy(base_sha1, nth_packed_object_sha1(p, revidx->nr)); } break; case OBJ_REF_DELTA: From 5f4347bba39ddb147b06913ac263fc46954d2d0b Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Thu, 28 Feb 2008 00:25:20 -0500 Subject: [PATCH 30/53] add storage size output to 'git verify-pack -v' This can possibly break external scripts that depend on the previous output, but those script can't possibly be critical to Git usage, and fixing them should be trivial. Signed-off-by: Nicolas Pitre Signed-off-by: Junio C Hamano --- Documentation/git-verify-pack.txt | 4 ++-- contrib/stats/packinfo.pl | 2 +- pack-check.c | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Documentation/git-verify-pack.txt b/Documentation/git-verify-pack.txt index db019a2b8d..ba2a157299 100644 --- a/Documentation/git-verify-pack.txt +++ b/Documentation/git-verify-pack.txt @@ -32,11 +32,11 @@ OUTPUT FORMAT ------------- When specifying the -v option the format used is: - SHA1 type size offset-in-packfile + SHA1 type size size-in-pack-file offset-in-packfile for objects that are not deltified in the pack, and - SHA1 type size offset-in-packfile depth base-SHA1 + SHA1 type size size-in-packfile offset-in-packfile depth base-SHA1 for objects that are deltified. diff --git a/contrib/stats/packinfo.pl b/contrib/stats/packinfo.pl index aab501ea08..f4a7b62cd9 100755 --- a/contrib/stats/packinfo.pl +++ b/contrib/stats/packinfo.pl @@ -93,7 +93,7 @@ my %depths; my @depths; while () { - my ($sha1, $type, $size, $offset, $depth, $parent) = split(/\s+/, $_); + my ($sha1, $type, $size, $space, $offset, $depth, $parent) = split(/\s+/, $_); next unless ($sha1 =~ /^[0-9a-f]{40}$/); $depths{$sha1} = $depth || 0; push(@depths, $depth || 0); diff --git a/pack-check.c b/pack-check.c index ae25685036..0f8ad2c00f 100644 --- a/pack-check.c +++ b/pack-check.c @@ -128,11 +128,11 @@ static void show_pack_info(struct packed_git *p) base_sha1); printf("%s ", sha1_to_hex(sha1)); if (!delta_chain_length) - printf("%-6s %lu %"PRIuMAX"\n", - type, size, (uintmax_t)offset); + printf("%-6s %lu %lu %"PRIuMAX"\n", + type, size, store_size, (uintmax_t)offset); else { - printf("%-6s %lu %"PRIuMAX" %u %s\n", - type, size, (uintmax_t)offset, + printf("%-6s %lu %lu %"PRIuMAX" %u %s\n", + type, size, store_size, (uintmax_t)offset, delta_chain_length, sha1_to_hex(base_sha1)); if (delta_chain_length <= MAX_CHAIN) chain_histogram[delta_chain_length]++; From 009c98ee170b36598548cc67c54826544cced108 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sat, 1 Mar 2008 18:18:16 -0800 Subject: [PATCH 31/53] CodingGuidelines: spell out how we use grep in our scripts Our scripts try to stick to fairly limited subset of POSIX BRE for portability. It is unclear from manual page from GNU grep which is GNU extension and which is portable, so let's spell it out to help new people to keep their contributions from hurting porters. Signed-off-by: Junio C Hamano --- Documentation/CodingGuidelines | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Documentation/CodingGuidelines b/Documentation/CodingGuidelines index 3b042db624..994eb9159a 100644 --- a/Documentation/CodingGuidelines +++ b/Documentation/CodingGuidelines @@ -53,6 +53,18 @@ For shell scripts specifically (not exhaustive): - We do not write the noiseword "function" in front of shell functions. + - As to use of grep, stick to a subset of BRE (namely, no \{m,n\}, + [::], [==], nor [..]) for portability. + + - We do not use \{m,n\}; + + - We do not use -E; + + - We do not use ? nor + (which are \{0,1\} and \{1,\} + respectively in BRE) but that goes without saying as these + are ERE elements not BRE (note that \? and \+ are not even part + of BRE -- making them accessible from BRE is a GNU extension). + For C programs: - We use tabs to indent, and interpret tabs as taking up to From f32086becc2b46bda0680ef178935546a64ad693 Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Sat, 1 Mar 2008 12:39:52 +0100 Subject: [PATCH 32/53] Documentation/git-rebase.txt: Add --strategy to synopsys Signed-off-by: Mike Hommey Signed-off-by: Junio C Hamano --- Documentation/git-rebase.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt index c11c6453ea..4b10304740 100644 --- a/Documentation/git-rebase.txt +++ b/Documentation/git-rebase.txt @@ -9,6 +9,7 @@ SYNOPSIS -------- [verse] 'git-rebase' [-i | --interactive] [-v | --verbose] [-m | --merge] + [-s | --strategy=] [-C] [ --whitespace=