diff options
author | Junio C Hamano <junkio@cox.net> | 2007-01-06 22:32:41 -0800 |
---|---|---|
committer | Junio C Hamano <junkio@cox.net> | 2007-01-06 22:57:34 -0800 |
commit | cd1f9c36beeafd3dea4672494a98e1ed39ae63f1 (patch) | |
tree | 7b37e6126bbc0904a17141d2fc2b7314c13b40d6 | |
parent | 1389d9ddaa68a4cbf5018d88f971b9bbb7aaa3c9 (diff) | |
download | git-cd1f9c36beeafd3dea4672494a98e1ed39ae63f1.tar.gz git-cd1f9c36beeafd3dea4672494a98e1ed39ae63f1.tar.xz |
reflog --fix-stale: do not check the same trees and commits repeatedly.
Since we use the reachability tracking machinery now, we should
keep the already checked trees and commits whose completeness is
known, to avoid checking the same thing over and over again.
Signed-off-by: Junio C Hamano <junkio@cox.net>
-rw-r--r-- | builtin-reflog.c | 77 |
1 files changed, 54 insertions, 23 deletions
diff --git a/builtin-reflog.c b/builtin-reflog.c index 1da7da091..a96711766 100644 --- a/builtin-reflog.c +++ b/builtin-reflog.c @@ -34,35 +34,51 @@ struct expire_reflog_cb { struct cmd_reflog_expire_cb *cmd; }; +#define INCOMPLETE (1u<<10) +#define STUDYING (1u<<11) + static int tree_is_complete(const unsigned char *sha1) { struct tree_desc desc; - void *buf; - char type[20]; + struct name_entry entry; + int complete; + struct tree *tree; - buf = read_sha1_file(sha1, type, &desc.size); - if (!buf) + tree = lookup_tree(sha1); + if (!tree) + return 0; + if (tree->object.flags & SEEN) + return 1; + if (tree->object.flags & INCOMPLETE) return 0; - desc.buf = buf; - while (desc.size) { - const unsigned char *elem; - const char *name; - unsigned mode; - - elem = tree_entry_extract(&desc, &name, &mode); - if (!has_sha1_file(elem) || - (S_ISDIR(mode) && !tree_is_complete(elem))) { - free(buf); + + desc.buf = tree->buffer; + desc.size = tree->size; + if (!desc.buf) { + char type[20]; + void *data = read_sha1_file(sha1, type, &desc.size); + if (!data) { + tree->object.flags |= INCOMPLETE; return 0; } - update_tree_entry(&desc); + desc.buf = data; + tree->buffer = data; } - free(buf); - return 1; -} + complete = 1; + while (tree_entry(&desc, &entry)) { + if (!has_sha1_file(entry.sha1) || + (S_ISDIR(entry.mode) && !tree_is_complete(entry.sha1))) { + tree->object.flags |= INCOMPLETE; + complete = 0; + } + } + free(tree->buffer); + tree->buffer = NULL; -#define INCOMPLETE (1u<<10) -#define STUDYING (1u<<11) + if (complete) + tree->object.flags |= SEEN; + return complete; +} static int commit_is_complete(struct commit *commit) { @@ -112,14 +128,17 @@ static int commit_is_complete(struct commit *commit) } } if (!is_incomplete) { - /* make sure all commits in found have all the + /* + * make sure all commits in "found" array have all the * necessary objects. */ - for (i = 0; !is_incomplete && i < found.nr; i++) { + for (i = 0; i < found.nr; i++) { struct commit *c = (struct commit *)found.objects[i].item; - if (!tree_is_complete(c->tree->object.sha1)) + if (!tree_is_complete(c->tree->object.sha1)) { is_incomplete = 1; + c->object.flags |= INCOMPLETE; + } } if (!is_incomplete) { /* mark all found commits as complete, iow SEEN */ @@ -132,6 +151,18 @@ static int commit_is_complete(struct commit *commit) found.objects[i].item->flags &= ~STUDYING; if (is_incomplete) commit->object.flags |= INCOMPLETE; + else { + /* + * If we come here, we have (1) traversed the ancestry chain + * from the "commit" until we reach SEEN commits (which are + * known to be complete), and (2) made sure that the commits + * encountered during the above traversal refer to trees that + * are complete. Which means that we know *all* the commits + * we have seen during this process are complete. + */ + for (i = 0; i < found.nr; i++) + found.objects[i].item->flags |= SEEN; + } /* free object arrays */ free(study.objects); free(found.objects); |