From: Shawn O. Pearce Date: Thu, 25 Sep 2008 16:49:19 +0000 (-0700) Subject: Merge branch 'mv/merge-recursive' X-Git-Tag: v1.6.1-rc1~202 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/ed520a8f270253f4a779aece1352b10fb9a689de?ds=inline;hp=-c Merge branch 'mv/merge-recursive' * mv/merge-recursive: builtin-merge: release the lockfile in try_merge_strategy() merge-recursive: get rid of virtual_id merge-recursive: move current_{file,directory}_set to struct merge_options merge-recursive: move the global obuf to struct merge_options merge-recursive: get rid of the index_only global variable merge-recursive: move call_depth to struct merge_options cherry-pick/revert: make direct internal call to merge_tree() builtin-merge: avoid run_command_v_opt() for recursive and subtree merge-recursive: introduce merge_options merge-recursive.c: Add more generic merge_recursive_generic() Split out merge_recursive() to merge-recursive.c --- ed520a8f270253f4a779aece1352b10fb9a689de diff --combined Makefile index 48547a2113,f697618384..e0c03c3eec --- a/Makefile +++ b/Makefile @@@ -294,8 -294,8 +294,8 @@@ PROGRAMS += git-mktag$ PROGRAMS += git-mktree$X PROGRAMS += git-pack-redundant$X PROGRAMS += git-patch-id$X -PROGRAMS += git-receive-pack$X PROGRAMS += git-send-pack$X +PROGRAMS += git-shell$X PROGRAMS += git-show-index$X PROGRAMS += git-unpack-file$X PROGRAMS += git-update-server-info$X @@@ -358,12 -358,10 +358,12 @@@ LIB_H += graph. LIB_H += grep.h LIB_H += hash.h LIB_H += help.h +LIB_H += levenshtein.h LIB_H += list-objects.h LIB_H += ll-merge.h LIB_H += log-tree.h LIB_H += mailmap.h +LIB_H += merge-recursive.h LIB_H += object.h LIB_H += pack.h LIB_H += pack-refs.h @@@ -435,7 -433,6 +435,7 @@@ LIB_OBJS += hash. LIB_OBJS += help.o LIB_OBJS += ident.o LIB_OBJS += interpolate.o +LIB_OBJS += levenshtein.o LIB_OBJS += list-objects.o LIB_OBJS += ll-merge.o LIB_OBJS += lockfile.o @@@ -443,6 -440,7 +443,7 @@@ LIB_OBJS += log-tree. LIB_OBJS += mailmap.o LIB_OBJS += match-trees.o LIB_OBJS += merge-file.o + LIB_OBJS += merge-recursive.o LIB_OBJS += name-hash.o LIB_OBJS += object.o LIB_OBJS += pack-check.o @@@ -545,7 -543,6 +546,7 @@@ BUILTIN_OBJS += builtin-prune-packed. BUILTIN_OBJS += builtin-prune.o BUILTIN_OBJS += builtin-push.o BUILTIN_OBJS += builtin-read-tree.o +BUILTIN_OBJS += builtin-receive-pack.o BUILTIN_OBJS += builtin-reflog.o BUILTIN_OBJS += builtin-remote.o BUILTIN_OBJS += builtin-rerere.o @@@ -636,8 -633,6 +637,8 @@@ ifeq ($(uname_S),Darwin endif NO_STRLCPY = YesPlease NO_MEMMEM = YesPlease + COMPAT_CFLAGS += -Icompat/regex + COMPAT_OBJS += compat/regex/regex.o endif ifeq ($(uname_S),SunOS) NEEDS_SOCKET = YesPlease @@@ -688,8 -683,6 +689,8 @@@ ifeq ($(uname_S),FreeBSD BASIC_LDFLAGS += -L/usr/local/lib DIR_HAS_BSD_GROUP_SEMANTICS = YesPlease THREADED_DELTA_SEARCH = YesPlease + COMPAT_CFLAGS += -Icompat/regex + COMPAT_OBJS += compat/regex/regex.o endif ifeq ($(uname_S),OpenBSD) NO_STRCASESTR = YesPlease @@@ -704,7 -697,8 +705,7 @@@ ifeq ($(uname_S),NetBSD NEEDS_LIBICONV = YesPlease endif BASIC_CFLAGS += -I/usr/pkg/include - BASIC_LDFLAGS += -L/usr/pkg/lib - ALL_LDFLAGS += -Wl,-rpath,/usr/pkg/lib + BASIC_LDFLAGS += -L/usr/pkg/lib $(CC_LD_DYNPATH)/usr/pkg/lib THREADED_DELTA_SEARCH = YesPlease endif ifeq ($(uname_S),AIX) @@@ -716,8 -710,6 +717,8 @@@ INTERNAL_QSORT = UnfortunatelyYes NEEDS_LIBICONV=YesPlease BASIC_CFLAGS += -D_LARGE_FILES + COMPAT_CFLAGS += -Icompat/regex + COMPAT_OBJS += compat/regex/regex.o endif ifeq ($(uname_S),GNU) # GNU/Hurd @@@ -769,10 -761,10 +770,10 @@@ ifneq (,$(findstring MINGW,$(uname_S)) NO_PERL_MAKEMAKER = YesPlease NO_POSIX_ONLY_PROGRAMS = YesPlease NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease - COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat + COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/regex -Icompat/fnmatch COMPAT_CFLAGS += -DSNPRINTF_SIZE_CORR=1 COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\" - COMPAT_OBJS += compat/mingw.o compat/fnmatch.o compat/regex.o compat/winansi.o + COMPAT_OBJS += compat/mingw.o compat/fnmatch/fnmatch.o compat/regex/regex.o compat/winansi.o EXTLIBS += -lws2_32 X = .exe gitexecdir = ../libexec/git-core @@@ -801,14 -793,12 +802,14 @@@ ifeq ($(uname_S),Darwin endif endif -ifdef NO_R_TO_GCC_LINKER - # Some gcc does not accept and pass -R to the linker to specify - # the runtime dynamic library path. - CC_LD_DYNPATH = -Wl,-rpath= -else - CC_LD_DYNPATH = -R +ifndef CC_LD_DYNPATH + ifdef NO_R_TO_GCC_LINKER + # Some gcc does not accept and pass -R to the linker to specify + # the runtime dynamic library path. + CC_LD_DYNPATH = -Wl,-rpath, + else + CC_LD_DYNPATH = -R + endif endif ifdef NO_CURL @@@ -844,6 -834,7 +845,6 @@@ EXTLIBS += -l ifndef NO_POSIX_ONLY_PROGRAMS PROGRAMS += git-daemon$X PROGRAMS += git-imap-send$X - PROGRAMS += git-shell$X endif ifndef NO_OPENSSL OPENSSL_LIBSSL = -lssl @@@ -1271,12 -1262,6 +1272,12 @@@ $(XDIFF_LIB): $(XDIFF_OBJS doc: $(MAKE) -C Documentation all +man: + $(MAKE) -C Documentation man + +html: + $(MAKE) -C Documentation html + info: $(MAKE) -C Documentation info @@@ -1380,7 -1365,7 +1381,7 @@@ install: al $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)' $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(gitexec_instdir_SQ)' $(INSTALL) $(ALL_PROGRAMS) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)' - $(INSTALL) git$X git-upload-pack$X git-receive-pack$X git-upload-archive$X git-shell$X '$(DESTDIR_SQ)$(bindir_SQ)' + $(INSTALL) git$X git-upload-pack$X git-receive-pack$X git-upload-archive$X git-shell$X git-cvsserver '$(DESTDIR_SQ)$(bindir_SQ)' $(MAKE) -C templates DESTDIR='$(DESTDIR_SQ)' install $(MAKE) -C perl prefix='$(prefix_SQ)' DESTDIR='$(DESTDIR_SQ)' install ifndef NO_TCLTK @@@ -1413,9 -1398,6 +1414,9 @@@ install-info quick-install-doc: $(MAKE) -C Documentation quick-install +quick-install-html: + $(MAKE) -C Documentation quick-install-html + ### Maintainer's dist rules diff --combined builtin-checkout.c index 9a0c173c14,f3c6b0fad2..075667c9cc --- a/builtin-checkout.c +++ b/builtin-checkout.c @@@ -76,15 -76,6 +76,15 @@@ static int read_tree_some(struct tree * return 0; } +static int skip_same_name(struct cache_entry *ce, int pos) +{ + while (++pos < active_nr && + !strcmp(active_cache[pos]->name, ce->name)) + ; /* skip */ + return pos; +} + + static int checkout_paths(struct tree *source_tree, const char **pathspec) { int pos; @@@ -116,20 -107,6 +116,20 @@@ if (report_path_error(ps_matched, pathspec, 0)) return 1; + /* Any unmerged paths? */ + for (pos = 0; pos < active_nr; pos++) { + struct cache_entry *ce = active_cache[pos]; + if (pathspec_match(pathspec, NULL, ce->name, 0)) { + if (!ce_stage(ce)) + continue; + errs = 1; + error("path '%s' is unmerged", ce->name); + pos = skip_same_name(ce, pos) - 1; + } + } + if (errs) + return 1; + /* Now we are committed to check them out */ memset(&state, 0, sizeof(state)); state.force = 1; @@@ -137,11 -114,7 +137,11 @@@ for (pos = 0; pos < active_nr; pos++) { struct cache_entry *ce = active_cache[pos]; if (pathspec_match(pathspec, NULL, ce->name, 0)) { - errs |= checkout_entry(ce, &state, NULL); + if (!ce_stage(ce)) { + errs |= checkout_entry(ce, &state, NULL); + continue; + } + pos = skip_same_name(ce, pos) - 1; } } @@@ -269,8 -242,6 +269,8 @@@ static int merge_working_tree(struct ch } /* 2-way merge to the new branch */ + topts.initial_checkout = (!active_nr && + (old->commit == new->commit)); topts.update = 1; topts.merge = 1; topts.gently = opts->merge; @@@ -293,6 -264,7 +293,7 @@@ */ struct tree *result; struct tree *work; + struct merge_options o; if (!opts->merge) return 1; parse_commit(old->commit); @@@ -311,13 -283,17 +312,17 @@@ */ add_files_to_cache(NULL, NULL, 0); - work = write_tree_from_memory(); + init_merge_options(&o); + o.verbosity = 0; + work = write_tree_from_memory(&o); ret = reset_tree(new->commit->tree, opts, 1); if (ret) return ret; - merge_trees(new->commit->tree, work, old->commit->tree, - new->name, "local", &result); + o.branch1 = new->name; + o.branch2 = "local"; + merge_trees(&o, new->commit->tree, work, + old->commit->tree, &result); ret = reset_tree(new->commit->tree, opts, 0); if (ret) return ret; @@@ -328,7 -304,7 +333,7 @@@ commit_locked_index(lock_file)) die("unable to write new index file"); - if (!opts->force) + if (!opts->force && !opts->quiet) show_local_changes(&new->commit->object); return 0; @@@ -415,11 -391,13 +420,11 @@@ static int switch_branches(struct check } /* - * If the new thing isn't a branch and isn't HEAD and we're - * not starting a new branch, and we want messages, and we - * weren't on a branch, and we're moving to a new commit, - * describe the old commit. + * If we were on a detached HEAD, but we are now moving to + * a new commit, we want to mention the old commit once more + * to remind the user that it might be lost. */ - if (!new->path && strcmp(new->name, "HEAD") && !opts->new_branch && - !opts->quiet && !old.path && new->commit != old.commit) + if (!opts->quiet && !old.path && new->commit != old.commit) describe_detached_head("Previous HEAD position was", old.commit); if (!old.commit) { @@@ -580,18 -558,6 +585,18 @@@ no_reference return checkout_paths(source_tree, pathspec); } + if (opts.new_branch) { + struct strbuf buf; + strbuf_init(&buf, 0); + strbuf_addstr(&buf, "refs/heads/"); + strbuf_addstr(&buf, opts.new_branch); + if (!get_sha1(buf.buf, rev)) + die("git checkout: branch %s already exists", opts.new_branch); + if (check_ref_format(buf.buf)) + die("git checkout: we do not like '%s' as a branch name.", opts.new_branch); + strbuf_release(&buf); + } + if (new.name && !new.commit) { die("Cannot switch branch to a non-commit."); } diff --combined builtin-merge.c index 1942e72aaf,bb09e6fb34..5c65a58699 --- a/builtin-merge.c +++ b/builtin-merge.c @@@ -23,6 -23,7 +23,7 @@@ #include "color.h" #include "rerere.h" #include "help.h" + #include "merge-recursive.h" #define DEFAULT_TWOHEAD (1<<0) #define DEFAULT_OCTOPUS (1<<1) @@@ -476,8 -477,6 +477,8 @@@ static int git_merge_config(const char buf = xstrdup(v); argc = split_cmdline(buf, &argv); + if (argc < 0) + die("Bad branch.%s.mergeoptions string", branch); argv = xrealloc(argv, sizeof(*argv) * (argc + 2)); memmove(argv + 1, argv, sizeof(*argv) * (argc + 1)); argc++; @@@ -547,28 -546,65 +548,65 @@@ static int try_merge_strategy(const cha struct commit_list *j; struct strbuf buf; - args = xmalloc((4 + commit_list_count(common) + - commit_list_count(remoteheads)) * sizeof(char *)); - strbuf_init(&buf, 0); - strbuf_addf(&buf, "merge-%s", strategy); - args[i++] = buf.buf; - for (j = common; j; j = j->next) - args[i++] = xstrdup(sha1_to_hex(j->item->object.sha1)); - args[i++] = "--"; - args[i++] = head_arg; - for (j = remoteheads; j; j = j->next) - args[i++] = xstrdup(sha1_to_hex(j->item->object.sha1)); - args[i] = NULL; - ret = run_command_v_opt(args, RUN_GIT_CMD); - strbuf_release(&buf); - i = 1; - for (j = common; j; j = j->next) - free((void *)args[i++]); - i += 2; - for (j = remoteheads; j; j = j->next) - free((void *)args[i++]); - free(args); - return -ret; + if (!strcmp(strategy, "recursive") || !strcmp(strategy, "subtree")) { + int clean; + struct commit *result; + struct lock_file *lock = xcalloc(1, sizeof(struct lock_file)); + int index_fd; + struct commit_list *reversed = NULL; + struct merge_options o; + + if (remoteheads->next) { + error("Not handling anything other than two heads merge."); + return 2; + } + + init_merge_options(&o); + if (!strcmp(strategy, "subtree")) + o.subtree_merge = 1; + + o.branch1 = head_arg; + o.branch2 = remoteheads->item->util; + + for (j = common; j; j = j->next) + commit_list_insert(j->item, &reversed); + + index_fd = hold_locked_index(lock, 1); + clean = merge_recursive(&o, lookup_commit(head), + remoteheads->item, reversed, &result); + if (active_cache_changed && + (write_cache(index_fd, active_cache, active_nr) || + commit_locked_index(lock))) + die ("unable to write %s", get_index_file()); + rollback_lock_file(lock); + return clean ? 0 : 1; + } else { + args = xmalloc((4 + commit_list_count(common) + + commit_list_count(remoteheads)) * sizeof(char *)); + strbuf_init(&buf, 0); + strbuf_addf(&buf, "merge-%s", strategy); + args[i++] = buf.buf; + for (j = common; j; j = j->next) + args[i++] = xstrdup(sha1_to_hex(j->item->object.sha1)); + args[i++] = "--"; + args[i++] = head_arg; + for (j = remoteheads; j; j = j->next) + args[i++] = xstrdup(sha1_to_hex(j->item->object.sha1)); + args[i] = NULL; + ret = run_command_v_opt(args, RUN_GIT_CMD); + strbuf_release(&buf); + i = 1; + for (j = common; j; j = j->next) + free((void *)args[i++]); + i += 2; + for (j = remoteheads; j; j = j->next) + free((void *)args[i++]); + free(args); + discard_cache(); + if (read_cache() < 0) + die("failed to read the cache"); + return -ret; + } } static void count_diff_files(struct diff_queue_struct *q, @@@ -693,7 -729,7 +731,7 @@@ static int merge_trivial(void parent->next = xmalloc(sizeof(struct commit_list *)); parent->next->item = remoteheads->item; parent->next->next = NULL; - commit_tree(merge_msg.buf, result_tree, parent, result_commit); + commit_tree(merge_msg.buf, result_tree, parent, result_commit, NULL); finish(result_commit, "In-index merge"); drop_save(); return 0; @@@ -722,7 -758,7 +760,7 @@@ static int finish_automerge(struct comm } free_commit_list(remoteheads); strbuf_addch(&merge_msg, '\n'); - commit_tree(merge_msg.buf, result_tree, parents, result_commit); + commit_tree(merge_msg.buf, result_tree, parents, result_commit, NULL); strbuf_addf(&buf, "Merge made by %s.", wt_strategy); finish(result_commit, buf.buf); strbuf_release(&buf); @@@ -779,10 -815,6 +817,6 @@@ static int evaluate_result(void int cnt = 0; struct rev_info rev; - discard_cache(); - if (read_cache() < 0) - die("failed to read the cache"); - /* Check how many files differ. */ init_revisions(&rev, ""); setup_revisions(0, NULL, &rev, NULL); @@@ -916,12 -948,14 +950,14 @@@ int cmd_merge(int argc, const char **ar for (i = 0; i < argc; i++) { struct object *o; + struct commit *commit; o = peel_to_type(argv[i], 0, NULL, OBJ_COMMIT); if (!o) die("%s - not something we can merge", argv[i]); - remotes = &commit_list_insert(lookup_commit(o->sha1), - remotes)->next; + commit = lookup_commit(o->sha1); + commit->util = (void *)argv[i]; + remotes = &commit_list_insert(commit, remotes)->next; strbuf_addf(&buf, "GITHEAD_%s", sha1_to_hex(o->sha1)); setenv(buf.buf, argv[i], 1); @@@ -1115,7 -1149,6 +1151,6 @@@ } /* Automerge succeeded. */ - discard_cache(); write_tree_trivial(result_tree); automerge_was_ok = 1; break; diff --combined t/t6026-merge-attr.sh index 4b423e937d,86f47ca595..1ba0a25223 --- a/t/t6026-merge-attr.sh +++ b/t/t6026-merge-attr.sh @@@ -106,9 -106,9 +106,9 @@@ test_expect_success 'custom merge backe cmp binary union && sed -e 1,3d text >check-1 && - o=$(git-unpack-file master^:text) && - a=$(git-unpack-file side^:text) && - b=$(git-unpack-file master:text) && + o=$(git unpack-file master^:text) && + a=$(git unpack-file side^:text) && + b=$(git unpack-file master:text) && sh -c "./custom-merge $o $a $b 0" && sed -e 1,3d $a >check-2 && cmp check-1 check-2 && @@@ -133,13 -133,35 +133,35 @@@ test_expect_success 'custom merge backe cmp binary union && sed -e 1,3d text >check-1 && - o=$(git-unpack-file master^:text) && - a=$(git-unpack-file anchor:text) && - b=$(git-unpack-file master:text) && + o=$(git unpack-file master^:text) && + a=$(git unpack-file anchor:text) && + b=$(git unpack-file master:text) && sh -c "./custom-merge $o $a $b 0" && sed -e 1,3d $a >check-2 && cmp check-1 check-2 && rm -f $o $a $b ' + test_expect_success 'up-to-date merge without common ancestor' ' + test_create_repo repo1 && + test_create_repo repo2 && + test_tick && + ( + cd repo1 && + >a && + git add a && + git commit -m initial + ) && + test_tick && + ( + cd repo2 && + git commit --allow-empty -m initial + ) && + test_tick && + ( + cd repo1 && + git pull ../repo2 master + ) + ' + test_done