X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=merge-recursive.c;h=34e3167cafc3d09e1a2b32bc9a5c64b4de1e442d;hb=79f43f3de8d992f141e1b08ab8f7bce5e66947f9;hp=c8539ec0bafce5e238d97d6397a9d08c2c92a09c;hpb=fe5e7f332c8a95680a869eaca8033213676cbc7b;p=git.git diff --git a/merge-recursive.c b/merge-recursive.c index c8539ec0b..34e3167ca 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -85,63 +85,59 @@ struct stage_data unsigned processed:1; }; -struct output_buffer -{ - struct output_buffer *next; - char *str; -}; - static struct path_list current_file_set = {NULL, 0, 0, 1}; static struct path_list current_directory_set = {NULL, 0, 0, 1}; static int call_depth = 0; static int verbosity = 2; +static int rename_limit = -1; static int buffer_output = 1; -static struct output_buffer *output_list, *output_end; +static struct strbuf obuf = STRBUF_INIT; -static int show (int v) +static int show(int v) { return (!call_depth && verbosity >= v) || verbosity >= 5; } -static void output(int v, const char *fmt, ...) +static void flush_output(void) { - va_list args; - va_start(args, fmt); - if (buffer_output && show(v)) { - struct output_buffer *b = xmalloc(sizeof(*b)); - nfvasprintf(&b->str, fmt, args); - b->next = NULL; - if (output_end) - output_end->next = b; - else - output_list = b; - output_end = b; - } else if (show(v)) { - int i; - for (i = call_depth; i--;) - fputs(" ", stdout); - vfprintf(stdout, fmt, args); - fputc('\n', stdout); + if (obuf.len) { + fputs(obuf.buf, stdout); + strbuf_reset(&obuf); } - va_end(args); } -static void flush_output(void) +static void output(int v, const char *fmt, ...) { - struct output_buffer *b, *n; - for (b = output_list; b; b = n) { - int i; - for (i = call_depth; i--;) - fputs(" ", stdout); - fputs(b->str, stdout); - fputc('\n', stdout); - n = b->next; - free(b->str); - free(b); + int len; + va_list ap; + + if (!show(v)) + return; + + strbuf_grow(&obuf, call_depth * 2 + 2); + memset(obuf.buf + obuf.len, ' ', call_depth * 2); + strbuf_setlen(&obuf, obuf.len + call_depth * 2); + + va_start(ap, fmt); + len = vsnprintf(obuf.buf + obuf.len, strbuf_avail(&obuf), fmt, ap); + va_end(ap); + + if (len < 0) + len = 0; + if (len >= strbuf_avail(&obuf)) { + strbuf_grow(&obuf, len + 2); + va_start(ap, fmt); + len = vsnprintf(obuf.buf + obuf.len, strbuf_avail(&obuf), fmt, ap); + va_end(ap); + if (len >= strbuf_avail(&obuf)) { + die("this should not happen, your snprintf is broken"); + } } - output_list = NULL; - output_end = NULL; + strbuf_setlen(&obuf, obuf.len + len); + strbuf_add(&obuf, "\n", 1); + if (!buffer_output) + flush_output(); } static void output_commit_title(struct commit *commit) @@ -171,30 +167,6 @@ static void output_commit_title(struct commit *commit) } } -static struct cache_entry *make_cache_entry(unsigned int mode, - const unsigned char *sha1, const char *path, int stage, int refresh) -{ - int size, len; - struct cache_entry *ce; - - if (!verify_path(path)) - return NULL; - - len = strlen(path); - size = cache_entry_size(len); - ce = xcalloc(1, size); - - hashcpy(ce->sha1, sha1); - memcpy(ce->name, path, len); - ce->ce_flags = create_ce_flags(len, stage); - ce->ce_mode = create_ce_mode(mode); - - if (refresh) - return refresh_cache_entry(ce, 0); - - return ce; -} - static int add_cacheinfo(unsigned int mode, const unsigned char *sha1, const char *path, int stage, int refresh, int options) { @@ -216,13 +188,19 @@ static int add_cacheinfo(unsigned int mode, const unsigned char *sha1, */ static int index_only = 0; +static void init_tree_desc_from_tree(struct tree_desc *desc, struct tree *tree) +{ + parse_tree(tree); + init_tree_desc(desc, tree->buffer, tree->size); +} + static int git_merge_trees(int index_only, struct tree *common, struct tree *head, struct tree *merge) { int rc; - struct object_list *trees = NULL; + struct tree_desc t[3]; struct unpack_trees_options opts; memset(&opts, 0, sizeof(opts)); @@ -234,11 +212,11 @@ static int git_merge_trees(int index_only, opts.head_idx = 2; opts.fn = threeway_merge; - object_list_append(&common->object, &trees); - object_list_append(&head->object, &trees); - object_list_append(&merge->object, &trees); + init_tree_desc_from_tree(t+0, common); + init_tree_desc_from_tree(t+1, head); + init_tree_desc_from_tree(t+2, merge); - rc = unpack_trees(trees, &opts); + rc = unpack_trees(3, t, &opts); cache_tree_free(&active_cache_tree); return rc; } @@ -311,7 +289,7 @@ static int get_files_dirs(struct tree *tree) } /* - * Returns a index_entry instance which doesn't have to correspond to + * Returns an index_entry instance which doesn't have to correspond to * a real cache entry in Git's index. */ static struct stage_data *insert_stage_data(const char *path, @@ -388,8 +366,9 @@ static struct path_list *get_renames(struct tree *tree, renames = xcalloc(1, sizeof(struct path_list)); diff_setup(&opts); - opts.recursive = 1; + DIFF_OPT_SET(&opts, RECURSIVE); opts.detect_rename = DIFF_DETECT_RENAME; + opts.rename_limit = rename_limit; opts.output_format = DIFF_FORMAT_NO_OUTPUT; if (diff_setup_done(&opts) < 0) die("diff setup failed"); @@ -450,19 +429,15 @@ static int update_stages(const char *path, struct diff_filespec *o, static int remove_path(const char *name) { - int ret, len; + int ret; char *slash, *dirs; ret = unlink(name); if (ret) return ret; - len = strlen(name); - dirs = xmalloc(len+1); - memcpy(dirs, name, len); - dirs[len] = '\0'; + dirs = xstrdup(name); while ((slash = strrchr(name, '/'))) { *slash = '\0'; - len = slash - name; if (rmdir(name) != 0) break; } @@ -574,6 +549,10 @@ static void update_file_flags(const unsigned char *sha, void *buf; unsigned long size; + if (S_ISGITLINK(mode)) + die("cannot read object %s '%s': It is a submodule!", + sha1_to_hex(sha), path); + buf = read_sha1_file(sha, &type, &size); if (!buf) die("cannot read object %s '%s'", sha1_to_hex(sha), path); @@ -596,9 +575,7 @@ static void update_file_flags(const unsigned char *sha, flush_buffer(fd, buf, size); close(fd); } else if (S_ISLNK(mode)) { - char *lnk = xmalloc(size + 1); - memcpy(lnk, buf, size); - lnk[size] = '\0'; + char *lnk = xmemdupz(buf, size); mkdir_p(path, 0777); unlink(path); symlink(lnk, path); @@ -671,6 +648,26 @@ struct ll_merge_driver { /* * Built-in low-levels */ +static int ll_binary_merge(const struct ll_merge_driver *drv_unused, + const char *path_unused, + mmfile_t *orig, + mmfile_t *src1, const char *name1, + mmfile_t *src2, const char *name2, + mmbuffer_t *result) +{ + /* + * The tentative merge result is "ours" for the final round, + * or common ancestor for an internal merge. Still return + * "conflicted merge" status. + */ + mmfile_t *stolen = index_only ? orig : src1; + + result->ptr = stolen->ptr; + result->size = stolen->size; + stolen->ptr = NULL; + return 1; +} + static int ll_xdl_merge(const struct ll_merge_driver *drv_unused, const char *path_unused, mmfile_t *orig, @@ -681,10 +678,15 @@ static int ll_xdl_merge(const struct ll_merge_driver *drv_unused, xpparam_t xpp; if (buffer_is_binary(orig->ptr, orig->size) || - buffer_is_binary(src1->ptr, src1->size) || - buffer_is_binary(src2->ptr, src2->size)) - return error("Cannot merge binary files: %s vs. %s\n", + buffer_is_binary(src1->ptr, src1->size) || + buffer_is_binary(src2->ptr, src2->size)) { + warning("Cannot merge binary files: %s vs. %s\n", name1, name2); + return ll_binary_merge(drv_unused, path_unused, + orig, src1, name1, + src2, name2, + result); + } memset(&xpp, 0, sizeof(xpp)); return xdl_merge(orig, @@ -737,26 +739,6 @@ static int ll_union_merge(const struct ll_merge_driver *drv_unused, return 0; } -static int ll_binary_merge(const struct ll_merge_driver *drv_unused, - const char *path_unused, - mmfile_t *orig, - mmfile_t *src1, const char *name1, - mmfile_t *src2, const char *name2, - mmbuffer_t *result) -{ - /* - * The tentative merge result is "ours" for the final round, - * or common ancestor for an internal merge. Still return - * "conflicted merge" status. - */ - mmfile_t *stolen = index_only ? orig : src1; - - result->ptr = stolen->ptr; - result->size = stolen->size; - stolen->ptr = NULL; - return 1; -} - #define LL_BINARY_MERGE 0 #define LL_TEXT_MERGE 1 #define LL_UNION_MERGE 2 @@ -771,9 +753,7 @@ static void create_temp(mmfile_t *src, char *path) int fd; strcpy(path, ".merge_file_XXXXXX"); - fd = mkstemp(path); - if (fd < 0) - die("unable to create temp-file"); + fd = xmkstemp(path); if (write_in_full(fd, src->ptr, src->size) != src->size) die("unable to write temp-file"); close(fd); @@ -864,8 +844,9 @@ static int read_merge_config(const char *var, const char *value) int namelen; if (!strcmp(var, "merge.default")) { - if (value) - default_ll_merge = strdup(value); + if (!value) + return config_error_nonbool(var); + default_ll_merge = strdup(value); return 0; } @@ -887,14 +868,9 @@ static int read_merge_config(const char *var, const char *value) if (!strncmp(fn->name, name, namelen) && !fn->name[namelen]) break; if (!fn) { - char *namebuf; fn = xcalloc(1, sizeof(struct ll_merge_driver)); - namebuf = xmalloc(namelen + 1); - memcpy(namebuf, name, namelen); - namebuf[namelen] = 0; - fn->name = namebuf; + fn->name = xmemdupz(name, namelen); fn->fn = ll_ext_merge; - fn->next = NULL; *ll_user_merge_tail = fn; ll_user_merge_tail = &(fn->next); } @@ -903,14 +879,14 @@ static int read_merge_config(const char *var, const char *value) if (!strcmp("name", ep)) { if (!value) - return error("%s: lacks value", var); + return config_error_nonbool(var); fn->description = strdup(value); return 0; } if (!strcmp("driver", ep)) { if (!value) - return error("%s: lacks value", var); + return config_error_nonbool(var); /* * merge..driver specifies the command line: * @@ -933,7 +909,7 @@ static int read_merge_config(const char *var, const char *value) if (!strcmp("recursive", ep)) { if (!value) - return error("%s: lacks value", var); + return config_error_nonbool(var); fn->recursive = strdup(value); return 0; } @@ -1075,14 +1051,16 @@ static struct merge_file_info merge_file(struct diff_filespec *o, free(result_buf.ptr); result.clean = (merge_status == 0); - } else { - if (!(S_ISLNK(a->mode) || S_ISLNK(b->mode))) - die("cannot merge modes?"); - + } else if (S_ISGITLINK(a->mode)) { + result.clean = 0; + hashcpy(result.sha, a->sha1); + } else if (S_ISLNK(a->mode)) { hashcpy(result.sha, a->sha1); if (!sha_eq(a->sha1, b->sha1)) result.clean = 0; + } else { + die("unsupported object type in the tree"); } } @@ -1490,10 +1468,13 @@ static int process_entry(const char *path, struct stage_data *entry, mfi = merge_file(&o, &a, &b, branch1, branch2); + clean_merge = mfi.clean; if (mfi.clean) update_file(1, mfi.sha, mfi.mode, path); + else if (S_ISGITLINK(mfi.mode)) + output(1, "CONFLICT (submodule): Merge conflict in %s " + "- needs %s", path, sha1_to_hex(b.sha1)); else { - clean_merge = 0; output(1, "CONFLICT (%s): Merge conflict in %s", reason, path); @@ -1601,7 +1582,7 @@ static int merge(struct commit *h1, { struct commit_list *iter; struct commit *merged_common_ancestors; - struct tree *mrtree; + struct tree *mrtree = mrtree; int clean; if (show(4)) { @@ -1708,6 +1689,10 @@ static int merge_config(const char *var, const char *value) verbosity = git_config_int(var, value); return 0; } + if (!strcasecmp(var, "diff.renamelimit")) { + rename_limit = git_config_int(var, value); + return 0; + } return git_default_config(var, value); } @@ -1769,7 +1754,7 @@ int main(int argc, char *argv[]) if (active_cache_changed && (write_cache(index_fd, active_cache, active_nr) || - close(index_fd) || commit_locked_index(lock))) + commit_locked_index(lock))) die ("unable to write %s", get_index_file()); return clean ? 0: 1;