commit_narrow_tree() works with a single narrow base. Unfortunately a merge may have more than one parent. If all parents have the same trees outside $GIT_DIR/narrow tree, then it's actually "a single narrow base". Other than that, refuse to merge. A merge in such case will need server support because narrow repos do not have enough trees to perform merge locally. Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@xxxxxxxxx> --- builtin/merge.c | 18 ++++++++++++++++++ narrow-tree.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ narrow-tree.h | 1 + 3 files changed, 74 insertions(+), 0 deletions(-) diff --git a/builtin/merge.c b/builtin/merge.c index 37ce4f5..c70d39d 100644 --- a/builtin/merge.c +++ b/builtin/merge.c @@ -25,6 +25,7 @@ #include "help.h" #include "merge-recursive.h" #include "resolve-undo.h" +#include "narrow-tree.h" #define DEFAULT_TWOHEAD (1<<0) #define DEFAULT_OCTOPUS (1<<1) @@ -1048,6 +1049,23 @@ int cmd_merge(int argc, const char **argv, const char *prefix) allow_trivial = 0; } + if (get_narrow_prefix()) { + struct commit_list *item = remoteheads; + struct commit *head_commit = lookup_commit(head); + + parse_commit(head_commit); + while (item) { + parse_commit(item->item); + if (!same_narrow_base(head_commit->tree->object.sha1, + item->item->tree->object.sha1, + get_narrow_prefix())) + break; + item = item->next; + } + if (item) + die("Different narrow base, couldn't do merge (yet)"); + } + if (!remoteheads->next) common = get_merge_bases(lookup_commit(head), remoteheads->item, 1); diff --git a/narrow-tree.c b/narrow-tree.c index 73d4f22..4a16647 100644 --- a/narrow-tree.c +++ b/narrow-tree.c @@ -95,3 +95,58 @@ int join_narrow_tree(const unsigned char *base, strbuf_release(&buffer); return 0; } + +int same_narrow_base(const unsigned char *t1, const unsigned char *t2, const char *prefix) +{ + struct tree_desc desc1, desc2; + struct name_entry entry1, entry2; + char *buf1, *buf2; + enum object_type type; + unsigned long size; + const char *slash; + int prefix_len; + + slash = strchr(prefix, '/'); + prefix_len = slash ? slash - prefix : strlen(prefix); + + buf1 = read_sha1_file(t1, &type, &size); + if (type != OBJ_TREE) + die("Bad tree %s", sha1_to_hex(t1)); + init_tree_desc(&desc1, buf1, size); + + buf2 = read_sha1_file(t2, &type, &size); + if (type != OBJ_TREE) + die("Bad tree %s", sha1_to_hex(t2)); + init_tree_desc(&desc2, buf2, size); + + while (tree_entry(&desc1, &entry1) && tree_entry(&desc2, &entry2)) { + if (strcmp(entry1.path, entry2.path) || + entry1.mode != entry2.mode) { + free(buf1); + free(buf2); + return 0; + } + + if (!hashcmp(entry1.sha1, entry2.sha1)) + continue; + + if (S_ISDIR(entry1.mode) && + !strncmp(entry1.path, prefix, prefix_len) && + entry1.path[prefix_len] == '\0') { + + /* This is subtree, SHA-1 does not matter */ + if (!slash) + continue; + + if (same_narrow_base(entry1.sha1, entry2.sha1, slash+1)) + continue; + } + + free(buf1); + free(buf2); + return 0; + } + free(buf1); + free(buf2); + return !desc1.size && !desc2.size; +} diff --git a/narrow-tree.h b/narrow-tree.h index ecb3ded..8756094 100644 --- a/narrow-tree.h +++ b/narrow-tree.h @@ -1,3 +1,4 @@ extern int check_narrow_prefix(); extern int join_narrow_tree(const unsigned char *base, unsigned char *newsha1, const unsigned char *subtree_sha1, const char *prefix); +int same_narrow_base(const unsigned char *t1, const unsigned char *t2, const char *prefix); -- 1.7.1.rc1.69.g24c2f7 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html