aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJunio C Hamano <junkio@cox.net>2007-01-06 22:32:41 -0800
committerJunio C Hamano <junkio@cox.net>2007-01-06 22:57:34 -0800
commitcd1f9c36beeafd3dea4672494a98e1ed39ae63f1 (patch)
tree7b37e6126bbc0904a17141d2fc2b7314c13b40d6
parent1389d9ddaa68a4cbf5018d88f971b9bbb7aaa3c9 (diff)
downloadgit-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.c77
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);