From f35a6d3bce79c2995bbf0a3bd9fcad29e54a8d3c Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 9 Apr 2007 21:20:29 -0700 Subject: Teach core object handling functions about gitlinks This teaches the really fundamental core SHA1 object handling routines about gitlinks. We can compare trees with gitlinks in them (although we can not actually generate patches for them yet - just raw git diffs), and they show up as commits in "git ls-tree". We also know to compare gitlinks as if they were directories (ie the normal "sort as trees" rules apply). [jc: amended a cut&paste error] Signed-off-by: Linus Torvalds Signed-off-by: Junio C Hamano --- cache-tree.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'cache-tree.c') diff --git a/cache-tree.c b/cache-tree.c index 9b73c8669a..6369cc7c53 100644 --- a/cache-tree.c +++ b/cache-tree.c @@ -326,7 +326,7 @@ static int update_one(struct cache_tree *it, mode = ntohl(ce->ce_mode); entlen = pathlen - baselen; } - if (!missing_ok && !has_sha1_file(sha1)) + if (mode != S_IFDIRLNK && !missing_ok && !has_sha1_file(sha1)) return error("invalid object %s", sha1_to_hex(sha1)); if (!ce->ce_mode) -- cgit v1.2.3 From 302b9282c9ddfcc704ca759bdc98c1d5f75eba2f Mon Sep 17 00:00:00 2001 From: Martin Waitz Date: Mon, 21 May 2007 22:08:28 +0200 Subject: rename dirlink to gitlink. Unify naming of plumbing dirlink/gitlink concept: git ls-files -z '*.[ch]' | xargs -0 perl -pi -e 's/dirlink/gitlink/g;' -e 's/DIRLNK/GITLINK/g;' Signed-off-by: Junio C Hamano --- cache-tree.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'cache-tree.c') diff --git a/cache-tree.c b/cache-tree.c index 6369cc7c53..350a79b768 100644 --- a/cache-tree.c +++ b/cache-tree.c @@ -326,7 +326,7 @@ static int update_one(struct cache_tree *it, mode = ntohl(ce->ce_mode); entlen = pathlen - baselen; } - if (mode != S_IFDIRLNK && !missing_ok && !has_sha1_file(sha1)) + if (mode != S_IFGITLINK && !missing_ok && !has_sha1_file(sha1)) return error("invalid object %s", sha1_to_hex(sha1)); if (!ce->ce_mode) -- cgit v1.2.3 From 63daae47e59b72ebec3595ca3e9917e6c595c814 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Fri, 22 Jun 2007 23:19:43 -0700 Subject: Two trivial -Wcast-qual fixes Luiz Fernando N. Capitulino noticed the one in tree-walk.h where we cast away constness while computing the legnth of a tree entry. Signed-off-by: Junio C Hamano --- cache-tree.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'cache-tree.c') diff --git a/cache-tree.c b/cache-tree.c index 350a79b768..077f034369 100644 --- a/cache-tree.c +++ b/cache-tree.c @@ -478,7 +478,7 @@ static struct cache_tree *read_one(const char **buffer, unsigned long *size_p) if (0 <= it->entry_count) { if (size < 20) goto free_return; - hashcpy(it->sha1, (unsigned char*)buf); + hashcpy(it->sha1, (const unsigned char*)buf); buf += 20; size -= 20; } -- cgit v1.2.3 From 5242bcbb638f031818e9ebd4467c8e55d5a06bfb Mon Sep 17 00:00:00 2001 From: Pierre Habouzit Date: Thu, 6 Sep 2007 13:20:11 +0200 Subject: Use strbuf API in cache-tree.c Should even be marginally faster. Signed-off-by: Pierre Habouzit Signed-off-by: Junio C Hamano --- cache-tree.c | 59 ++++++++++++++++++++++------------------------------------- 1 file changed, 22 insertions(+), 37 deletions(-) (limited to 'cache-tree.c') diff --git a/cache-tree.c b/cache-tree.c index 077f034369..76af6f5d99 100644 --- a/cache-tree.c +++ b/cache-tree.c @@ -1,4 +1,5 @@ #include "cache.h" +#include "strbuf.h" #include "tree.h" #include "cache-tree.h" @@ -235,8 +236,7 @@ static int update_one(struct cache_tree *it, int missing_ok, int dryrun) { - unsigned long size, offset; - char *buffer; + struct strbuf buffer; int i; if (0 <= it->entry_count && has_sha1_file(it->sha1)) @@ -293,9 +293,8 @@ static int update_one(struct cache_tree *it, /* * Then write out the tree object for this level. */ - size = 8192; - buffer = xmalloc(size); - offset = 0; + strbuf_init(&buffer); + strbuf_grow(&buffer, 8192); for (i = 0; i < entries; i++) { struct cache_entry *ce = cache[i]; @@ -332,15 +331,9 @@ static int update_one(struct cache_tree *it, if (!ce->ce_mode) continue; /* entry being removed */ - if (size < offset + entlen + 100) { - size = alloc_nr(offset + entlen + 100); - buffer = xrealloc(buffer, size); - } - offset += sprintf(buffer + offset, - "%o %.*s", mode, entlen, path + baselen); - buffer[offset++] = 0; - hashcpy((unsigned char*)buffer + offset, sha1); - offset += 20; + strbuf_grow(&buffer, entlen + 100); + strbuf_addf(&buffer, "%o %.*s%c", mode, entlen, path + baselen, '\0'); + strbuf_add(&buffer, sha1, 20); #if DEBUG fprintf(stderr, "cache-tree update-one %o %.*s\n", @@ -349,10 +342,10 @@ static int update_one(struct cache_tree *it, } if (dryrun) - hash_sha1_file(buffer, offset, tree_type, it->sha1); + hash_sha1_file(buffer.buf, buffer.len, tree_type, it->sha1); else - write_sha1_file(buffer, offset, tree_type, it->sha1); - free(buffer); + write_sha1_file(buffer.buf, buffer.len, tree_type, it->sha1); + strbuf_release(&buffer); it->entry_count = i; #if DEBUG fprintf(stderr, "cache-tree update-one (%d ent, %d subtree) %s\n", @@ -378,12 +371,10 @@ int cache_tree_update(struct cache_tree *it, return 0; } -static void *write_one(struct cache_tree *it, +static void write_one(struct cache_tree *it, char *path, int pathlen, - char *buffer, - unsigned long *size, - unsigned long *offset) + struct strbuf *buffer) { int i; @@ -393,13 +384,9 @@ static void *write_one(struct cache_tree *it, * tree-sha1 (missing if invalid) * subtree_nr "cache-tree" entries for subtrees. */ - if (*size < *offset + pathlen + 100) { - *size = alloc_nr(*offset + pathlen + 100); - buffer = xrealloc(buffer, *size); - } - *offset += sprintf(buffer + *offset, "%.*s%c%d %d\n", - pathlen, path, 0, - it->entry_count, it->subtree_nr); + strbuf_grow(buffer, pathlen + 100); + strbuf_add(buffer, path, pathlen); + strbuf_addf(buffer, "%c%d %d\n", 0, it->entry_count, it->subtree_nr); #if DEBUG if (0 <= it->entry_count) @@ -412,8 +399,7 @@ static void *write_one(struct cache_tree *it, #endif if (0 <= it->entry_count) { - hashcpy((unsigned char*)buffer + *offset, it->sha1); - *offset += 20; + strbuf_add(buffer, it->sha1, 20); } for (i = 0; i < it->subtree_nr; i++) { struct cache_tree_sub *down = it->down[i]; @@ -423,21 +409,20 @@ static void *write_one(struct cache_tree *it, prev->name, prev->namelen) <= 0) die("fatal - unsorted cache subtree"); } - buffer = write_one(down->cache_tree, down->name, down->namelen, - buffer, size, offset); + write_one(down->cache_tree, down->name, down->namelen, buffer); } - return buffer; } void *cache_tree_write(struct cache_tree *root, unsigned long *size_p) { char path[PATH_MAX]; - unsigned long size = 8192; - char *buffer = xmalloc(size); + struct strbuf buffer; - *size_p = 0; path[0] = 0; - return write_one(root, path, 0, buffer, &size, size_p); + strbuf_init(&buffer); + write_one(root, path, 0, &buffer); + *size_p = buffer.len; + return strbuf_detach(&buffer); } static struct cache_tree *read_one(const char **buffer, unsigned long *size_p) -- cgit v1.2.3 From f1696ee398e92bcea3cdc7b3da85d8e0f77f6c50 Mon Sep 17 00:00:00 2001 From: Pierre Habouzit Date: Mon, 10 Sep 2007 12:35:04 +0200 Subject: Strbuf API extensions and fixes. * Add strbuf_rtrim to remove trailing spaces. * Add strbuf_insert to insert data at a given position. * Off-by one fix in strbuf_addf: strbuf_avail() does not counts the final \0 so the overflow test for snprintf is the strict comparison. This is not critical as the growth mechanism chosen will always allocate _more_ memory than asked, so the second test will not fail. It's some kind of miracle though. * Add size extension hints for strbuf_init and strbuf_read. If 0, default applies, else: + initial buffer has the given size for strbuf_init. + first growth checks it has at least this size rather than the default 8192. Signed-off-by: Pierre Habouzit Signed-off-by: Junio C Hamano --- cache-tree.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'cache-tree.c') diff --git a/cache-tree.c b/cache-tree.c index 76af6f5d99..8f53c99f15 100644 --- a/cache-tree.c +++ b/cache-tree.c @@ -293,8 +293,7 @@ static int update_one(struct cache_tree *it, /* * Then write out the tree object for this level. */ - strbuf_init(&buffer); - strbuf_grow(&buffer, 8192); + strbuf_init(&buffer, 8192); for (i = 0; i < entries; i++) { struct cache_entry *ce = cache[i]; @@ -419,7 +418,7 @@ void *cache_tree_write(struct cache_tree *root, unsigned long *size_p) struct strbuf buffer; path[0] = 0; - strbuf_init(&buffer); + strbuf_init(&buffer, 0); write_one(root, path, 0, &buffer); *size_p = buffer.len; return strbuf_detach(&buffer); -- cgit v1.2.3 From ba3ed09728cb25e004d3b732de14fca8aeb602f6 Mon Sep 17 00:00:00 2001 From: Pierre Habouzit Date: Sat, 15 Sep 2007 15:56:50 +0200 Subject: Now that cache.h needs strbuf.h, remove useless includes. Signed-off-by: Pierre Habouzit Acked-by: Linus Torvalds Signed-off-by: Junio C Hamano --- cache-tree.c | 1 - 1 file changed, 1 deletion(-) (limited to 'cache-tree.c') diff --git a/cache-tree.c b/cache-tree.c index 8f53c99f15..5471844af6 100644 --- a/cache-tree.c +++ b/cache-tree.c @@ -1,5 +1,4 @@ #include "cache.h" -#include "strbuf.h" #include "tree.h" #include "cache-tree.h" -- cgit v1.2.3 From 1dffb8fa8056860e769f3a0c6e232d436f5a5c17 Mon Sep 17 00:00:00 2001 From: Pierre Habouzit Date: Tue, 25 Sep 2007 10:22:44 +0200 Subject: Small cache_tree_write refactor. This function cannot fail, make it void. Also make write_one act on a const char* instead of a char*. Signed-off-by: Pierre Habouzit Signed-off-by: Junio C Hamano --- cache-tree.c | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) (limited to 'cache-tree.c') diff --git a/cache-tree.c b/cache-tree.c index 5471844af6..50b35264fd 100644 --- a/cache-tree.c +++ b/cache-tree.c @@ -369,10 +369,8 @@ int cache_tree_update(struct cache_tree *it, return 0; } -static void write_one(struct cache_tree *it, - char *path, - int pathlen, - struct strbuf *buffer) +static void write_one(struct strbuf *buffer, struct cache_tree *it, + const char *path, int pathlen) { int i; @@ -407,20 +405,13 @@ static void write_one(struct cache_tree *it, prev->name, prev->namelen) <= 0) die("fatal - unsorted cache subtree"); } - write_one(down->cache_tree, down->name, down->namelen, buffer); + write_one(buffer, down->cache_tree, down->name, down->namelen); } } -void *cache_tree_write(struct cache_tree *root, unsigned long *size_p) +void cache_tree_write(struct strbuf *sb, struct cache_tree *root) { - char path[PATH_MAX]; - struct strbuf buffer; - - path[0] = 0; - strbuf_init(&buffer, 0); - write_one(root, path, 0, &buffer); - *size_p = buffer.len; - return strbuf_detach(&buffer); + write_one(sb, root, "", 0); } static struct cache_tree *read_one(const char **buffer, unsigned long *size_p) -- cgit v1.2.3 From 7a51ed66f653c248993b3c4a61932e47933d835e Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 14 Jan 2008 16:03:17 -0800 Subject: Make on-disk index representation separate from in-core one This converts the index explicitly on read and write to its on-disk format, allowing the in-core format to contain more flags, and be simpler. In particular, the in-core format is now host-endian (as opposed to the on-disk one that is network endian in order to be able to be shared across machines) and as a result we can dispense with all the htonl/ntohl on accesses to the cache_entry fields. This will make it easier to make use of various temporary flags that do not exist in the on-disk format. Signed-off-by: Linus Torvalds --- cache-tree.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'cache-tree.c') diff --git a/cache-tree.c b/cache-tree.c index 50b35264fd..bfc95d2dc9 100644 --- a/cache-tree.c +++ b/cache-tree.c @@ -320,13 +320,13 @@ static int update_one(struct cache_tree *it, } else { sha1 = ce->sha1; - mode = ntohl(ce->ce_mode); + mode = ce->ce_mode; entlen = pathlen - baselen; } if (mode != S_IFGITLINK && !missing_ok && !has_sha1_file(sha1)) return error("invalid object %s", sha1_to_hex(sha1)); - if (!ce->ce_mode) + if (ce->ce_flags & CE_REMOVE) continue; /* entry being removed */ strbuf_grow(&buffer, entlen + 100); -- cgit v1.2.3 From 45525bd022dda75ec935c9c579e452577dcfd31f Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Thu, 10 Jan 2008 22:49:35 -0800 Subject: Make error messages from cherry-pick/revert more sensible MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The original "rewrite in C" did somewhat a sloppy job while stealing code from git-write-tree. The caller pretends as if the write_tree() function would return an error code and being able to issue a sensible error message itself, but write_tree() function just calls die() and never returns an error. Worse yet, the function claims that it was running git-write-tree (which is no longer true after cherry-pick stole it). Tested-by: Björn Steinbrink Signed-off-by: Junio C Hamano --- cache-tree.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) (limited to 'cache-tree.c') diff --git a/cache-tree.c b/cache-tree.c index 50b35264fd..4e1e7b25cf 100644 --- a/cache-tree.c +++ b/cache-tree.c @@ -529,3 +529,58 @@ struct cache_tree *cache_tree_find(struct cache_tree *it, const char *path) } return it; } + +int write_cache_as_tree(unsigned char *sha1, int missing_ok, const char *prefix) +{ + int entries, was_valid, newfd; + + /* + * We can't free this memory, it becomes part of a linked list + * parsed atexit() + */ + struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file)); + + newfd = hold_locked_index(lock_file, 1); + + entries = read_cache(); + if (entries < 0) + return WRITE_TREE_UNREADABLE_INDEX; + + if (!active_cache_tree) + active_cache_tree = cache_tree(); + + was_valid = cache_tree_fully_valid(active_cache_tree); + + if (!was_valid) { + if (cache_tree_update(active_cache_tree, + active_cache, active_nr, + missing_ok, 0) < 0) + return WRITE_TREE_UNMERGED_INDEX; + if (0 <= newfd) { + if (!write_cache(newfd, active_cache, active_nr) && + !commit_lock_file(lock_file)) + newfd = -1; + } + /* Not being able to write is fine -- we are only interested + * in updating the cache-tree part, and if the next caller + * ends up using the old index with unupdated cache-tree part + * it misses the work we did here, but that is just a + * performance penalty and not a big deal. + */ + } + + if (prefix) { + struct cache_tree *subtree = + cache_tree_find(active_cache_tree, prefix); + if (!subtree) + return WRITE_TREE_PREFIX_ERROR; + hashcpy(sha1, subtree->sha1); + } + else + hashcpy(sha1, active_cache_tree->sha1); + + if (0 <= newfd) + rollback_lock_file(lock_file); + + return 0; +} -- cgit v1.2.3 From edae5f0c20b7e71a717b59873ddb8eeddfa49b86 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 23 Apr 2008 09:47:17 -0700 Subject: write-tree: properly detect failure to write tree objects Tomasz Fortuna reported that "git commit" does not error out properly when it cannot write tree objects out. "git write-tree" shares the same issue, as the failure to notice the error is deep in the logic to write tree objects out recursively. Signed-off-by: Junio C Hamano --- cache-tree.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'cache-tree.c') diff --git a/cache-tree.c b/cache-tree.c index 50b35264fd..cfe937b0f1 100644 --- a/cache-tree.c +++ b/cache-tree.c @@ -341,8 +341,11 @@ static int update_one(struct cache_tree *it, if (dryrun) hash_sha1_file(buffer.buf, buffer.len, tree_type, it->sha1); - else - write_sha1_file(buffer.buf, buffer.len, tree_type, it->sha1); + else if (write_sha1_file(buffer.buf, buffer.len, tree_type, it->sha1)) { + strbuf_release(&buffer); + return -1; + } + strbuf_release(&buffer); it->entry_count = i; #if DEBUG -- cgit v1.2.3 From 7ba04d9f3741abd5788ff713b6a16351cbf3773a Mon Sep 17 00:00:00 2001 From: Nanako Shiraishi Date: Wed, 16 Jul 2008 19:42:10 +0900 Subject: cache-tree.c: make cache_tree_find() static This function is not used by any other file. Signed-off-by: Nanako Shiraishi Signed-off-by: Junio C Hamano --- cache-tree.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'cache-tree.c') diff --git a/cache-tree.c b/cache-tree.c index 73cb340707..5f8ee87bb1 100644 --- a/cache-tree.c +++ b/cache-tree.c @@ -507,7 +507,7 @@ struct cache_tree *cache_tree_read(const char *buffer, unsigned long size) return read_one(&buffer, &size); } -struct cache_tree *cache_tree_find(struct cache_tree *it, const char *path) +static struct cache_tree *cache_tree_find(struct cache_tree *it, const char *path) { while (*path) { const char *slash; -- cgit v1.2.3 From 331fcb598ec0127fd89c992361bc573dcd3a4a63 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Fri, 28 Nov 2008 19:56:34 -0800 Subject: git add --intent-to-add: do not let an empty blob be committed by accident Writing a tree out of an index with an "intent to add" entry is blocked. This implies that you cannot "git commit" from such a state; however you can still do "git commit -a" or "git commit $that_path". Signed-off-by: Junio C Hamano --- cache-tree.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'cache-tree.c') diff --git a/cache-tree.c b/cache-tree.c index 5f8ee87bb1..3d8f218a5f 100644 --- a/cache-tree.c +++ b/cache-tree.c @@ -155,13 +155,17 @@ static int verify_cache(struct cache_entry **cache, funny = 0; for (i = 0; i < entries; i++) { struct cache_entry *ce = cache[i]; - if (ce_stage(ce)) { + if (ce_stage(ce) || (ce->ce_flags & CE_INTENT_TO_ADD)) { if (10 < ++funny) { fprintf(stderr, "...\n"); break; } - fprintf(stderr, "%s: unmerged (%s)\n", - ce->name, sha1_to_hex(ce->sha1)); + if (ce_stage(ce)) + fprintf(stderr, "%s: unmerged (%s)\n", + ce->name, sha1_to_hex(ce->sha1)); + else + fprintf(stderr, "%s: not added yet\n", + ce->name); } } if (funny) -- cgit v1.2.3 From b9d37a5420446d0db2dc0dc5458a5e50656a4852 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Mon, 20 Apr 2009 03:58:18 -0700 Subject: Move prime_cache_tree() to cache-tree.c The interface to build cache-tree belongs there. Signed-off-by: Junio C Hamano --- cache-tree.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) (limited to 'cache-tree.c') diff --git a/cache-tree.c b/cache-tree.c index 3d8f218a5f..37bf35e636 100644 --- a/cache-tree.c +++ b/cache-tree.c @@ -1,5 +1,6 @@ #include "cache.h" #include "tree.h" +#include "tree-walk.h" #include "cache-tree.h" #ifndef DEBUG @@ -591,3 +592,36 @@ int write_cache_as_tree(unsigned char *sha1, int missing_ok, const char *prefix) return 0; } + +static void prime_cache_tree_rec(struct cache_tree *it, struct tree *tree) +{ + struct tree_desc desc; + struct name_entry entry; + int cnt; + + hashcpy(it->sha1, tree->object.sha1); + init_tree_desc(&desc, tree->buffer, tree->size); + cnt = 0; + while (tree_entry(&desc, &entry)) { + if (!S_ISDIR(entry.mode)) + cnt++; + else { + struct cache_tree_sub *sub; + struct tree *subtree = lookup_tree(entry.sha1); + if (!subtree->object.parsed) + parse_tree(subtree); + sub = cache_tree_sub(it, entry.path); + sub->cache_tree = cache_tree(); + prime_cache_tree_rec(sub->cache_tree, subtree); + cnt += sub->cache_tree->entry_count; + } + } + it->entry_count = cnt; +} + +void prime_cache_tree(struct cache_tree **it, struct tree *tree) +{ + cache_tree_free(it); + *it = cache_tree(); + prime_cache_tree_rec(*it, tree); +} -- cgit v1.2.3 From d11b8d342529a8fe2164ceb563ad9213902d3533 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 20 May 2009 11:04:35 -0700 Subject: write-tree --ignore-cache-tree This allows you to discard the cache-tree information before writing the tree out of the index (i.e. it always recomputes the tree object names for all the subtrees). This is only useful as a debug option, so I did not bother documenting it. Signed-off-by: Junio C Hamano --- cache-tree.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'cache-tree.c') diff --git a/cache-tree.c b/cache-tree.c index 37bf35e636..6dd8411945 100644 --- a/cache-tree.c +++ b/cache-tree.c @@ -538,28 +538,32 @@ static struct cache_tree *cache_tree_find(struct cache_tree *it, const char *pat return it; } -int write_cache_as_tree(unsigned char *sha1, int missing_ok, const char *prefix) +int write_cache_as_tree(unsigned char *sha1, int flags, const char *prefix) { int entries, was_valid, newfd; + struct lock_file *lock_file; /* * We can't free this memory, it becomes part of a linked list * parsed atexit() */ - struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file)); + lock_file = xcalloc(1, sizeof(struct lock_file)); newfd = hold_locked_index(lock_file, 1); entries = read_cache(); if (entries < 0) return WRITE_TREE_UNREADABLE_INDEX; + if (flags & WRITE_TREE_IGNORE_CACHE_TREE) + cache_tree_free(&(active_cache_tree)); if (!active_cache_tree) active_cache_tree = cache_tree(); was_valid = cache_tree_fully_valid(active_cache_tree); - if (!was_valid) { + int missing_ok = flags & WRITE_TREE_MISSING_OK; + if (cache_tree_update(active_cache_tree, active_cache, active_nr, missing_ok, 0) < 0) -- cgit v1.2.3 From b87fc96476c4218de044cf77b4c6d10d49aee78a Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 20 May 2009 15:53:57 -0700 Subject: cache-tree.c::cache_tree_find(): simplify internal API Earlier cache_tree_find() needs to be called with a valid cache_tree, but repeated look-up may find an invalid or missing cache_tree in between. Help simplify the callers by returning NULL to mean "nothing appropriate found" when the input is NULL. Signed-off-by: Junio C Hamano --- cache-tree.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'cache-tree.c') diff --git a/cache-tree.c b/cache-tree.c index 6dd8411945..5481e43340 100644 --- a/cache-tree.c +++ b/cache-tree.c @@ -514,6 +514,8 @@ struct cache_tree *cache_tree_read(const char *buffer, unsigned long size) static struct cache_tree *cache_tree_find(struct cache_tree *it, const char *path) { + if (!it) + return NULL; while (*path) { const char *slash; struct cache_tree_sub *sub; -- cgit v1.2.3 From b65982b60876c8f5f4d3b2898d5174f4812552b1 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 20 May 2009 15:57:22 -0700 Subject: Optimize "diff-index --cached" using cache-tree When running "diff-index --cached" after making a change to only a small portion of the index, there is no point unpacking unchanged subtrees into the index recursively, only to find that all entries match anyway. Tweak unpack_trees() logic that is used to read in the tree object to catch the case where the tree entry we are looking at matches the index as a whole by looking at the cache-tree. As an exercise, after modifying a few paths in the kernel tree, here are a few numbers on my Athlon 64X2 3800+: (without patch, hot cache) $ /usr/bin/time git diff --cached --raw :100644 100644 b57e1f5... e69de29... M Makefile :100644 000000 8c86b72... 0000000... D arch/x86/Makefile :000000 100644 0000000... e69de29... A arche 0.07user 0.02system 0:00.09elapsed 102%CPU (0avgtext+0avgdata 0maxresident)k 0inputs+0outputs (0major+9407minor)pagefaults 0swaps (with patch, hot cache) $ /usr/bin/time ../git.git/git-diff --cached --raw :100644 100644 b57e1f5... e69de29... M Makefile :100644 000000 8c86b72... 0000000... D arch/x86/Makefile :000000 100644 0000000... e69de29... A arche 0.02user 0.00system 0:00.02elapsed 103%CPU (0avgtext+0avgdata 0maxresident)k 0inputs+0outputs (0major+2446minor)pagefaults 0swaps Cold cache numbers are very impressive, but it does not matter very much in practice: (without patch, cold cache) $ su root sh -c 'echo 3 >/proc/sys/vm/drop_caches' $ /usr/bin/time git diff --cached --raw :100644 100644 b57e1f5... e69de29... M Makefile :100644 000000 8c86b72... 0000000... D arch/x86/Makefile :000000 100644 0000000... e69de29... A arche 0.06user 0.17system 0:10.26elapsed 2%CPU (0avgtext+0avgdata 0maxresident)k 247032inputs+0outputs (1172major+8237minor)pagefaults 0swaps (with patch, cold cache) $ su root sh -c 'echo 3 >/proc/sys/vm/drop_caches' $ /usr/bin/time ../git.git/git-diff --cached --raw :100644 100644 b57e1f5... e69de29... M Makefile :100644 000000 8c86b72... 0000000... D arch/x86/Makefile :000000 100644 0000000... e69de29... A arche 0.02user 0.01system 0:01.01elapsed 3%CPU (0avgtext+0avgdata 0maxresident)k 18440inputs+0outputs (79major+2369minor)pagefaults 0swaps This of course helps "git status" as well. (without patch, hot cache) $ /usr/bin/time ../git.git/git-status >/dev/null 0.17user 0.18system 0:00.35elapsed 100%CPU (0avgtext+0avgdata 0maxresident)k 0inputs+5336outputs (0major+10970minor)pagefaults 0swaps (with patch, hot cache) $ /usr/bin/time ../git.git/git-status >/dev/null 0.10user 0.16system 0:00.27elapsed 99%CPU (0avgtext+0avgdata 0maxresident)k 0inputs+5336outputs (0major+3921minor)pagefaults 0swaps Signed-off-by: Junio C Hamano --- cache-tree.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'cache-tree.c') diff --git a/cache-tree.c b/cache-tree.c index 5481e43340..16a65dfac1 100644 --- a/cache-tree.c +++ b/cache-tree.c @@ -631,3 +631,35 @@ void prime_cache_tree(struct cache_tree **it, struct tree *tree) *it = cache_tree(); prime_cache_tree_rec(*it, tree); } + +/* + * find the cache_tree that corresponds to the current level without + * exploding the full path into textual form. The root of the + * cache tree is given as "root", and our current level is "info". + * (1) When at root level, info->prev is NULL, so it is "root" itself. + * (2) Otherwise, find the cache_tree that corresponds to one level + * above us, and find ourselves in there. + */ +static struct cache_tree *find_cache_tree_from_traversal(struct cache_tree *root, + struct traverse_info *info) +{ + struct cache_tree *our_parent; + + if (!info->prev) + return root; + our_parent = find_cache_tree_from_traversal(root, info->prev); + return cache_tree_find(our_parent, info->name.path); +} + +int cache_tree_matches_traversal(struct cache_tree *root, + struct name_entry *ent, + struct traverse_info *info) +{ + struct cache_tree *it; + + it = find_cache_tree_from_traversal(root, info); + it = cache_tree_find(it, ent->path); + if (it && it->entry_count > 0 && !hashcmp(ent->sha1, it->sha1)) + return it->entry_count; + return 0; +} -- cgit v1.2.3 From a38837341c995773f2adc29ff5971196187b07fb Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Tue, 14 Jul 2009 11:25:17 -0700 Subject: Improve on the 'invalid object' error message at commit time Not that anybody should ever get it, but somebody did (probably because of a flaky filesystem, but whatever). And each time I see an error message that I haven't seen before, I decide that next time it will look better. So this makes us write more relevant information about exactly which file ended up having issues with a missing object. Which will tell whether it was a tree object, for example, or just a regular file in the index (and which one). Signed-off-by: Linus Torvalds Signed-off-by: Junio C Hamano --- cache-tree.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'cache-tree.c') diff --git a/cache-tree.c b/cache-tree.c index 16a65dfac1..d91743775d 100644 --- a/cache-tree.c +++ b/cache-tree.c @@ -329,7 +329,8 @@ static int update_one(struct cache_tree *it, entlen = pathlen - baselen; } if (mode != S_IFGITLINK && !missing_ok && !has_sha1_file(sha1)) - return error("invalid object %s", sha1_to_hex(sha1)); + return error("invalid object %06o %s for '%.*s'", + mode, sha1_to_hex(sha1), entlen+baselen, path); if (ce->ce_flags & CE_REMOVE) continue; /* entry being removed */ -- cgit v1.2.3