+static struct branch* lookup_branch(const char *name)
+{
+ struct branch *b;
+ for (b = branches; b; b = b->next_branch) {
+ if (!strcmp(name, b->name))
+ return b;
+ }
+ die("No branch named '%s' has been declared", name);
+}
+
+static struct tree* deep_copy_tree (struct tree *t)
+{
+ struct tree *r = xmalloc(sizeof(struct tree));
+ unsigned long i;
+
+ if (t->last_tree.data) {
+ r->last_tree.data = xmalloc(t->last_tree.len);
+ r->last_tree.len = t->last_tree.len;
+ r->last_tree.depth = t->last_tree.depth;
+ memcpy(r->last_tree.data, t->last_tree.data, t->last_tree.len);
+ memcpy(r->last_tree.sha1, t->last_tree.sha1, sizeof(t->last_tree.sha1));
+ }
+
+ r->entry_count = t->entry_count;
+ r->entries = xmalloc(t->entry_count * sizeof(struct tree_entry*));
+ for (i = 0; i < t->entry_count; i++) {
+ struct tree_entry *a = t->entries[i];
+ struct tree_entry *b;
+
+ b = xmalloc(sizeof(struct tree_entry) + strlen(a->name) + 1);
+ b->tree = a->tree ? deep_copy_tree(a->tree) : 0;
+ b->mode = a->mode;
+ memcpy(b->sha1, a->sha1, sizeof(a->sha1));
+ strcpy(b->name, a->name);
+ r->entries[i] = b;
+ }
+
+ return r;
+}
+
+static void store_tree (struct tree_entry *e)
+{
+ struct tree *t = e->tree;
+ unsigned long maxlen, i;
+ char *buf, *c;
+
+ if (memcmp(null_sha1, e->sha1, sizeof(e->sha1)))
+ return;
+
+ maxlen = t->entry_count * 32;
+ for (i = 0; i < t->entry_count; i++)
+ maxlen += strlen(t->entries[i]->name);
+
+ buf = c = xmalloc(maxlen);
+ for (i = 0; i < t->entry_count; i++) {
+ struct tree_entry *e = t->entries[i];
+ c += sprintf(c, "%o %s", e->mode, e->name) + 1;
+ if (e->tree)
+ store_tree(e);
+ memcpy(c, e->sha1, sizeof(e->sha1));
+ c += sizeof(e->sha1);
+ }
+
+ if (!store_object(OBJ_TREE, buf, c - buf, &t->last_tree, e->sha1))
+ free(buf);
+}
+
+static void new_branch()
+{
+ struct branch *nb = xcalloc(1, sizeof(struct branch));
+ const char *source_name;
+
+ nb->name = strdup(read_required_string());
+ source_name = read_string();
+ if (source_name) {
+ struct branch *sb = lookup_branch(source_name);
+ nb->tree.tree = deep_copy_tree(sb->tree.tree);
+ memcpy(nb->tree.sha1, sb->tree.sha1, sizeof(sb->tree.sha1));
+ memcpy(nb->sha1, sb->sha1, sizeof(sb->sha1));
+ } else {
+ nb->tree.tree = xcalloc(1, sizeof(struct tree));
+ nb->tree.tree->entries = xmalloc(8*sizeof(struct tree_entry*));
+ }
+ nb->next_branch = branches;
+ branches = nb;
+ branch_count++;
+}
+
+static void set_branch()
+{
+ current_branch = lookup_branch(read_required_string());
+}
+
+static void commit()
+{
+ store_tree(¤t_branch->tree);
+}
+