PROG= update-cache show-diff init-db write-tree read-tree commit-tree \
cat-file fsck-cache checkout-cache diff-tree rev-tree show-files \
- check-files ls-tree merge-base
+ check-files ls-tree merge-base merge-cache
all: $(PROG)
cat-file: cat-file.o read-cache.o
$(CC) $(CFLAGS) -o cat-file cat-file.o read-cache.o $(LIBS)
- fsck-cache: fsck-cache.o read-cache.o
- $(CC) $(CFLAGS) -o fsck-cache fsck-cache.o read-cache.o $(LIBS)
+ fsck-cache: fsck-cache.o read-cache.o object.o commit.o tree.o blob.o
+ $(CC) $(CFLAGS) -o fsck-cache fsck-cache.o read-cache.o object.o commit.o tree.o blob.o $(LIBS)
checkout-cache: checkout-cache.o read-cache.o
$(CC) $(CFLAGS) -o checkout-cache checkout-cache.o read-cache.o $(LIBS)
diff-tree: diff-tree.o read-cache.o
$(CC) $(CFLAGS) -o diff-tree diff-tree.o read-cache.o $(LIBS)
- rev-tree: rev-tree.o read-cache.o
- $(CC) $(CFLAGS) -o rev-tree rev-tree.o read-cache.o $(LIBS)
+ rev-tree: rev-tree.o read-cache.o object.o commit.o tree.o blob.o
+ $(CC) $(CFLAGS) -o rev-tree rev-tree.o read-cache.o object.o commit.o tree.o blob.o $(LIBS)
show-files: show-files.o read-cache.o
$(CC) $(CFLAGS) -o show-files show-files.o read-cache.o $(LIBS)
ls-tree: ls-tree.o read-cache.o
$(CC) $(CFLAGS) -o ls-tree ls-tree.o read-cache.o $(LIBS)
- merge-base: merge-base.o read-cache.o
- $(CC) $(CFLAGS) -o merge-base merge-base.o read-cache.o $(LIBS)
+ merge-base: merge-base.o read-cache.o object.o commit.o tree.o blob.o
+ $(CC) $(CFLAGS) -o merge-base merge-base.o read-cache.o object.o commit.o tree.o blob.o $(LIBS)
+merge-cache: merge-cache.o read-cache.o
+ $(CC) $(CFLAGS) -o merge-cache merge-cache.o read-cache.o $(LIBS)
+
read-cache.o: cache.h
show-diff.o: cache.h
#include <sys/types.h>
#include <dirent.h>
- #include "revision.h"
+ #include "commit.h"
+ #include "tree.h"
+ #include "blob.h"
+
+ #define REACHABLE 0x0001
static int show_unreachable = 0;
static unsigned char head_sha1[20];
int i;
/* Look up all the requirements, warn about missing objects.. */
- for (i = 0; i < nr_revs; i++) {
- struct revision *rev = revs[i];
+ for (i = 0; i < nr_objs; i++) {
+ struct object *obj = objs[i];
- if (show_unreachable && !(rev->flags & REACHABLE)) {
- printf("unreachable %s %s\n", rev->tag, sha1_to_hex(rev->sha1));
+ if (show_unreachable && !(obj->flags & REACHABLE)) {
+ printf("unreachable %s\n", sha1_to_hex(obj->sha1));
continue;
}
- switch (rev->flags & (SEEN | USED)) {
- case 0:
- printf("bad %s %s\n", rev->tag, sha1_to_hex(rev->sha1));
- break;
- case USED:
- printf("missing %s, %s\n", rev->tag, sha1_to_hex(rev->sha1));
- break;
- case SEEN:
- printf("dangling %s %s\n", rev->tag, sha1_to_hex(rev->sha1));
- break;
+ if (!obj->parsed) {
+ printf("missing %s %s\n", obj->type,
+ sha1_to_hex(obj->sha1));
+ }
+ if (!obj->used) {
+ printf("dangling %s %s\n", obj->type,
+ sha1_to_hex(obj->sha1));
}
}
}
- static void mark_needs_sha1(unsigned char *parent, const char *ptag, unsigned char *child, const char *ctag)
- {
- struct revision * child_rev = add_relationship(lookup_rev(parent, ptag), child, ctag);
- child_rev->flags |= USED;
- }
-
- static int mark_sha1_seen(unsigned char *sha1, const char *tag)
- {
- struct revision *rev = lookup_rev(sha1, tag);
-
- rev->flags |= SEEN;
- return 0;
- }
-
static int fsck_tree(unsigned char *sha1, void *data, unsigned long size)
{
- int warn_old_tree = 1;
-
- while (size) {
- int len = 1+strlen(data);
- unsigned char *file_sha1 = data + len;
- char *path = strchr(data, ' ');
- unsigned int mode;
- if (size < len + 20 || !path || sscanf(data, "%o", &mode) != 1)
- return -1;
-
- /* Warn about trees that don't do the recursive thing.. */
- if (warn_old_tree && strchr(path, '/')) {
- fprintf(stderr, "warning: fsck-cache: tree %s has full pathnames in it\n", sha1_to_hex(sha1));
- warn_old_tree = 0;
- }
-
- data += len + 20;
- size -= len + 20;
- mark_needs_sha1(sha1, "tree", file_sha1, S_ISDIR(mode) ? "tree" : "blob");
+ struct tree *item = lookup_tree(sha1);
+ if (parse_tree(item))
+ return -1;
+ if (item->has_full_path) {
+ fprintf(stderr, "warning: fsck-cache: tree %s "
+ "has full pathnames in it\n", sha1_to_hex(sha1));
}
return 0;
}
static int fsck_commit(unsigned char *sha1, void *data, unsigned long size)
{
- int parents;
- unsigned char tree_sha1[20];
- unsigned char parent_sha1[20];
-
- if (memcmp(data, "tree ", 5))
+ struct commit *commit = lookup_commit(sha1);
+ if (parse_commit(commit))
return -1;
- if (get_sha1_hex(data + 5, tree_sha1) < 0)
+ if (!commit->tree)
return -1;
- mark_needs_sha1(sha1, "commit", tree_sha1, "tree");
- data += 5 + 40 + 1; /* "tree " + <hex sha1> + '\n' */
- parents = 0;
- while (!memcmp(data, "parent ", 7)) {
- if (get_sha1_hex(data + 7, parent_sha1) < 0)
- return -1;
- mark_needs_sha1(sha1, "commit", parent_sha1, "commit");
- data += 7 + 40 + 1; /* "parent " + <hex sha1> + '\n' */
- parents++;
- }
- if (!parents)
+ if (!commit->parents)
printf("root %s\n", sha1_to_hex(sha1));
return 0;
}
- static int fsck_entry(unsigned char *sha1, char *tag, void *data, unsigned long size)
+ static int fsck_entry(unsigned char *sha1, char *tag, void *data,
+ unsigned long size)
{
if (!strcmp(tag, "blob")) {
- /* Nothing to check */;
+ lookup_blob(sha1); /* Nothing to check; but notice it. */
} else if (!strcmp(tag, "tree")) {
if (fsck_tree(sha1, data, size) < 0)
return -1;
return -1;
} else
return -1;
- return mark_sha1_seen(sha1, tag);
+ return 0;
}
static int fsck_name(char *hex)
unsigned long size;
void *buffer = NULL;
if (!check_sha1_signature(sha1, map, mapsize))
- buffer = unpack_sha1_file(map, mapsize, type, &size);
+ buffer = unpack_sha1_file(map, mapsize, type,
+ &size);
munmap(map, mapsize);
if (buffer && !fsck_entry(sha1, type, buffer, size))
return 0;
continue;
}
if (!get_sha1_hex(argv[i], head_sha1)) {
- mark_reachable(lookup_rev(head_sha1, "commit"), REACHABLE);
- struct object *obj =
- &lookup_commit(head_sha1)->object;
++ struct object *obj = &lookup_commit(head_sha1)->object;
+ obj->used = 1;
+ mark_reachable(obj, REACHABLE);
heads++;
continue;
}
+ #include <stdlib.h>
#include "cache.h"
- #include "revision.h"
+ #include "commit.h"
- /*
- * This is stupid. We could have much better heurstics, I bet.
- */
- static int better(struct revision *new, struct revision *old)
+ static struct commit *process_list(struct commit_list **list_p, int this_mark,
+ int other_mark)
{
- return new->date > old->date;
+ struct commit_list *parent, *temp;
+ struct commit_list *posn = *list_p;
+ *list_p = NULL;
+ while (posn) {
+ parse_commit(posn->item);
+ if (posn->item->object.flags & this_mark) {
+ /*
+ printf("%d already seen %s %x\n",
+ this_mark
+ sha1_to_hex(posn->parent->sha1),
+ posn->parent->flags);
+ */
+ /* do nothing; this indicates that this side
+ * split and reformed, and we only need to
+ * mark it once.
+ */
+ } else if (posn->item->object.flags & other_mark) {
+ return posn->item;
+ } else {
+ /*
+ printf("%d based on %s\n",
+ this_mark,
+ sha1_to_hex(posn->parent->sha1));
+ */
+ posn->item->object.flags |= this_mark;
+
+ parent = posn->item->parents;
+ while (parent) {
+ temp = malloc(sizeof(struct commit_list));
+ temp->next = *list_p;
+ temp->item = parent->item;
+ *list_p = temp;
+ parent = parent->next;
+ }
+ }
+ posn = posn->next;
+ }
+ return NULL;
}
- static struct revision *common_parent(struct revision *rev1, struct revision *rev2)
+ struct commit *common_ancestor(struct commit *rev1, struct commit *rev2)
{
- int i;
- struct revision *best = NULL;
+ struct commit_list *rev1list = malloc(sizeof(struct commit_list));
+ struct commit_list *rev2list = malloc(sizeof(struct commit_list));
+
+ rev1list->item = rev1;
+ rev1list->next = NULL;
+
+ rev2list->item = rev2;
+ rev2list->next = NULL;
- mark_reachable(rev1, 1);
- mark_reachable(rev2, 2);
- for (i = 0; i < nr_revs ;i++) {
- struct revision *rev = revs[i];
- if ((rev->flags & 3) != 3)
- continue;
- if (!best) {
- best = rev;
- continue;
+ while (rev1list || rev2list) {
+ struct commit *ret;
+ ret = process_list(&rev1list, 0x1, 0x2);
+ if (ret) {
+ /* XXXX free lists */
+ return ret;
+ }
+ ret = process_list(&rev2list, 0x2, 0x1);
+ if (ret) {
+ /* XXXX free lists */
+ return ret;
}
- if (better(rev, best))
- best = rev;
}
- return best;
+ return NULL;
}
int main(int argc, char **argv)
{
- unsigned char rev1[20], rev2[20];
- struct revision *common;
-
- if (argc != 3 || get_sha1_hex(argv[1], rev1) || get_sha1_hex(argv[2], rev2))
- usage("merge-base <commit1> <commit2>");
+ struct commit *rev1, *rev2, *ret;
+ unsigned char rev1key[20], rev2key[20];
- /*
- * We will eventually want to include a revision cache file
- * that "rev-tree.c" has generated, since this is going to
- * otherwise be quite expensive for big trees..
- *
- * That's some time off, though, and in the meantime we know
- * that we have a solution to the eventual expense.
- */
- common = common_parent(parse_commit(rev1), parse_commit(rev2));
- if (!common)
- die("no common parent found");
- printf("%s\n", sha1_to_hex(common->sha1));
+ if (argc != 3 ||
+ get_sha1_hex(argv[1], rev1key) ||
+ get_sha1_hex(argv[2], rev2key)) {
+ usage("merge-base <commit-id> <commit-id>");
+ }
+ rev1 = lookup_commit(rev1key);
+ rev2 = lookup_commit(rev2key);
+ ret = common_ancestor(rev1, rev2);
- if (ret) {
- printf("%s\n", sha1_to_hex(ret->object.sha1));
- return 0;
- } else {
++ if (!ret)
+ return 1;
- }
-
++ printf("%s\n", sha1_to_hex(ret->object.sha1));
+ return 0;
}