lf;
commit_msg ::= data;
- file_change ::= file_clr | file_del | file_obm | file_inm;
+ file_change ::= file_clr
+ | file_del
+ | file_rnm
+ | file_cpy
+ | file_obm
+ | file_inm;
file_clr ::= 'deleteall' lf;
file_del ::= 'D' sp path_str lf;
+ file_rnm ::= 'R' sp path_str sp path_str lf;
+ file_cpy ::= 'C' sp path_str sp path_str lf;
file_obm ::= 'M' sp mode sp (hexsha1 | idnum) sp path_str lf;
file_inm ::= 'M' sp mode sp 'inline' sp path_str lf
data;
avail_tree_entry = e;
}
+static struct tree_content *dup_tree_content(struct tree_content *s)
+{
+ struct tree_content *d;
+ struct tree_entry *a, *b;
+ unsigned int i;
+
+ if (!s)
+ return NULL;
+ d = new_tree_content(s->entry_count);
+ for (i = 0; i < s->entry_count; i++) {
+ a = s->entries[i];
+ b = new_tree_entry();
+ memcpy(b, a, sizeof(*a));
+ if (a->tree && is_null_sha1(b->versions[1].sha1))
+ b->tree = dup_tree_content(a->tree);
+ else
+ b->tree = NULL;
+ d->entries[i] = b;
+ }
+ d->entry_count = s->entry_count;
+ d->delta_depth = s->delta_depth;
+
+ return d;
+}
+
static void start_packfile(void)
{
static char tmpfile[PATH_MAX];
struct tree_entry *root,
const char *p,
const unsigned char *sha1,
- const uint16_t mode)
+ const uint16_t mode,
+ struct tree_content *subtree)
{
struct tree_content *t = root->tree;
const char *slash1;
n = strlen(p);
if (!n)
die("Empty path component found in input");
+ if (!slash1 && !S_ISDIR(mode) && subtree)
+ die("Non-directories cannot have subtrees");
for (i = 0; i < t->entry_count; i++) {
e = t->entries[i];
if (e->name->str_len == n && !strncmp(p, e->name->str_dat, n)) {
if (!slash1) {
- if (e->versions[1].mode == mode
+ if (!S_ISDIR(mode)
+ && e->versions[1].mode == mode
&& !hashcmp(e->versions[1].sha1, sha1))
return 0;
e->versions[1].mode = mode;
hashcpy(e->versions[1].sha1, sha1);
- if (e->tree) {
+ if (e->tree)
release_tree_content_recursive(e->tree);
- e->tree = NULL;
- }
+ e->tree = subtree;
hashclr(root->versions[1].sha1);
return 1;
}
}
if (!e->tree)
load_tree(e);
- if (tree_content_set(e, slash1 + 1, sha1, mode)) {
+ if (tree_content_set(e, slash1 + 1, sha1, mode, subtree)) {
hashclr(root->versions[1].sha1);
return 1;
}
if (slash1) {
e->tree = new_tree_content(8);
e->versions[1].mode = S_IFDIR;
- tree_content_set(e, slash1 + 1, sha1, mode);
+ tree_content_set(e, slash1 + 1, sha1, mode, subtree);
} else {
- e->tree = NULL;
+ e->tree = subtree;
e->versions[1].mode = mode;
hashcpy(e->versions[1].sha1, sha1);
}
return 1;
}
-static int tree_content_remove(struct tree_entry *root, const char *p)
+static int tree_content_remove(
+ struct tree_entry *root,
+ const char *p,
+ struct tree_entry *backup_leaf)
{
struct tree_content *t = root->tree;
const char *slash1;
goto del_entry;
if (!e->tree)
load_tree(e);
- if (tree_content_remove(e, slash1 + 1)) {
+ if (tree_content_remove(e, slash1 + 1, backup_leaf)) {
for (n = 0; n < e->tree->entry_count; n++) {
if (e->tree->entries[n]->versions[1].mode) {
hashclr(root->versions[1].sha1);
return 1;
}
}
+ backup_leaf = NULL;
goto del_entry;
}
return 0;
return 0;
del_entry:
- if (e->tree) {
+ if (backup_leaf)
+ memcpy(backup_leaf, e, sizeof(*backup_leaf));
+ else if (e->tree)
release_tree_content_recursive(e->tree);
- e->tree = NULL;
- }
+ e->tree = NULL;
e->versions[1].mode = 0;
hashclr(e->versions[1].sha1);
hashclr(root->versions[1].sha1);
return 1;
}
+static int tree_content_get(
+ struct tree_entry *root,
+ const char *p,
+ struct tree_entry *leaf)
+{
+ struct tree_content *t = root->tree;
+ const char *slash1;
+ unsigned int i, n;
+ struct tree_entry *e;
+
+ slash1 = strchr(p, '/');
+ if (slash1)
+ n = slash1 - p;
+ else
+ n = strlen(p);
+
+ for (i = 0; i < t->entry_count; i++) {
+ e = t->entries[i];
+ if (e->name->str_len == n && !strncmp(p, e->name->str_dat, n)) {
+ if (!slash1) {
+ memcpy(leaf, e, sizeof(*leaf));
+ if (e->tree && is_null_sha1(e->versions[1].sha1))
+ leaf->tree = dup_tree_content(e->tree);
+ else
+ leaf->tree = NULL;
+ return 1;
+ }
+ if (!S_ISDIR(e->versions[1].mode))
+ return 0;
+ if (!e->tree)
+ load_tree(e);
+ return tree_content_get(e, slash1 + 1, leaf);
+ }
+ }
+ return 0;
+}
+
static int update_branch(struct branch *b)
{
static const char *msg = "fast-import";
if (read_ref(b->name, old_sha1))
hashclr(old_sha1);
- lock = lock_any_ref_for_update(b->name, old_sha1);
+ lock = lock_any_ref_for_update(b->name, old_sha1, 0);
if (!lock)
return error("Unable to lock %s", b->name);
if (!force_update && !is_null_sha1(old_sha1)) {
typename(type), command_buf.buf);
}
- tree_content_set(&b->branch_tree, p, sha1, S_IFREG | mode);
+ tree_content_set(&b->branch_tree, p, sha1, S_IFREG | mode, NULL);
free(p_uq);
}
die("Garbage after path in: %s", command_buf.buf);
p = p_uq;
}
- tree_content_remove(&b->branch_tree, p);
+ tree_content_remove(&b->branch_tree, p, NULL);
free(p_uq);
}
+static void file_change_cr(struct branch *b, int rename)
+{
+ const char *s, *d;
+ char *s_uq, *d_uq;
+ const char *endp;
+ struct tree_entry leaf;
+
+ s = command_buf.buf + 2;
+ s_uq = unquote_c_style(s, &endp);
+ if (s_uq) {
+ if (*endp != ' ')
+ die("Missing space after source: %s", command_buf.buf);
+ }
+ else {
+ endp = strchr(s, ' ');
+ if (!endp)
+ die("Missing space after source: %s", command_buf.buf);
+ s_uq = xmalloc(endp - s + 1);
+ memcpy(s_uq, s, endp - s);
+ s_uq[endp - s] = 0;
+ }
+ s = s_uq;
+
+ endp++;
+ if (!*endp)
+ die("Missing dest: %s", command_buf.buf);
+
+ d = endp;
+ d_uq = unquote_c_style(d, &endp);
+ if (d_uq) {
+ if (*endp)
+ die("Garbage after dest in: %s", command_buf.buf);
+ d = d_uq;
+ }
+
+ memset(&leaf, 0, sizeof(leaf));
+ if (rename)
+ tree_content_remove(&b->branch_tree, s, &leaf);
+ else
+ tree_content_get(&b->branch_tree, s, &leaf);
+ if (!leaf.versions[1].mode)
+ die("Path %s not in branch", s);
+ tree_content_set(&b->branch_tree, d,
+ leaf.versions[1].sha1,
+ leaf.versions[1].mode,
+ leaf.tree);
+
+ free(s_uq);
+ free(d_uq);
+}
+
static void file_change_deleteall(struct branch *b)
{
release_tree_content_recursive(b->branch_tree.tree);
file_change_m(b);
else if (!prefixcmp(command_buf.buf, "D "))
file_change_d(b);
+ else if (!prefixcmp(command_buf.buf, "R "))
+ file_change_cr(b, 1);
+ else if (!prefixcmp(command_buf.buf, "C "))
+ file_change_cr(b, 0);
else if (!strcmp("deleteall", command_buf.buf))
file_change_deleteall(b);
else