Merge branch 'mv/merge-custom'
authorJunio C Hamano <gitster@pobox.com>
Thu, 28 Aug 2008 00:28:31 +0000 (17:28 -0700)
committerJunio C Hamano <gitster@pobox.com>
Thu, 28 Aug 2008 00:28:31 +0000 (17:28 -0700)
* mv/merge-custom:
t7606: fix custom merge test
Fix "git-merge -s bogo" help text
Update .gitignore to ignore git-help
Builtin git-help.
builtin-help: always load_command_list() in cmd_help()
Add a second testcase for handling invalid strategies in git-merge
Add a new test for using a custom merge strategy
builtin-merge: allow using a custom strategy
builtin-help: make some internal functions available to other builtins

Conflicts:
help.c

1  2 
Makefile
builtin-merge.c
t/t7600-merge.sh
diff --combined Makefile
index 4119fb30032b3f3d931e6f7b1beee25de85a10aa,3bb7c774b7615dc38592126cc0cef03a466ceb60..bf400e64f39e5967206c01d2266aca800d4db667
+++ b/Makefile
@@@ -124,9 -124,6 +124,9 @@@ all:
  # Define USE_STDEV below if you want git to care about the underlying device
  # change being considered an inode change from the update-index perspective.
  #
 +# Define NO_ST_BLOCKS_IN_STRUCT_STAT if your platform does not have st_blocks
 +# field that counts the on-disk footprint in 512-byte blocks.
 +#
  # Define ASCIIDOC8 if you want to format documentation with AsciiDoc 8
  #
  # Define DOCBOOK_XSL_172 if you want to format man pages with DocBook XSL v1.72.
@@@ -336,6 -333,7 +336,6 @@@ endi
  export PERL_PATH
  
  LIB_FILE=libgit.a
 -COMPAT_LIB = compat/lib.a
  XDIFF_LIB=xdiff/lib.a
  
  LIB_H += archive.h
@@@ -357,6 -355,7 +357,7 @@@ LIB_H += git-compat-util.
  LIB_H += graph.h
  LIB_H += grep.h
  LIB_H += hash.h
+ LIB_H += help.h
  LIB_H += list-objects.h
  LIB_H += ll-merge.h
  LIB_H += log-tree.h
@@@ -520,6 -519,7 +521,7 @@@ BUILTIN_OBJS += builtin-for-each-ref.
  BUILTIN_OBJS += builtin-fsck.o
  BUILTIN_OBJS += builtin-gc.o
  BUILTIN_OBJS += builtin-grep.o
+ BUILTIN_OBJS += builtin-help.o
  BUILTIN_OBJS += builtin-init-db.o
  BUILTIN_OBJS += builtin-log.o
  BUILTIN_OBJS += builtin-ls-files.o
@@@ -577,11 -577,9 +579,11 @@@ EXTLIBS 
  
  ifeq ($(uname_S),Linux)
        NO_STRLCPY = YesPlease
 +      THREADED_DELTA_SEARCH = YesPlease
  endif
  ifeq ($(uname_S),GNU/kFreeBSD)
        NO_STRLCPY = YesPlease
 +      THREADED_DELTA_SEARCH = YesPlease
  endif
  ifeq ($(uname_S),UnixWare)
        CC = cc
@@@ -679,7 -677,6 +681,7 @@@ ifeq ($(uname_S),FreeBSD
        BASIC_CFLAGS += -I/usr/local/include
        BASIC_LDFLAGS += -L/usr/local/lib
        DIR_HAS_BSD_GROUP_SEMANTICS = YesPlease
 +      THREADED_DELTA_SEARCH = YesPlease
  endif
  ifeq ($(uname_S),OpenBSD)
        NO_STRCASESTR = YesPlease
        NEEDS_LIBICONV = YesPlease
        BASIC_CFLAGS += -I/usr/local/include
        BASIC_LDFLAGS += -L/usr/local/lib
 +      THREADED_DELTA_SEARCH = YesPlease
  endif
  ifeq ($(uname_S),NetBSD)
        ifeq ($(shell expr "$(uname_R)" : '[01]\.'),2)
        BASIC_CFLAGS += -I/usr/pkg/include
        BASIC_LDFLAGS += -L/usr/pkg/lib
        ALL_LDFLAGS += -Wl,-rpath,/usr/pkg/lib
 +      THREADED_DELTA_SEARCH = YesPlease
  endif
  ifeq ($(uname_S),AIX)
        NO_STRCASESTR=YesPlease
@@@ -734,7 -729,6 +736,7 @@@ ifeq ($(uname_S),HP-UX
        NO_UNSETENV = YesPlease
        NO_HSTRERROR = YesPlease
        NO_SYS_SELECT_H = YesPlease
 +      SNPRINTF_RETURNS_BOGUS = YesPlease
  endif
  ifneq (,$(findstring MINGW,$(uname_S)))
        NO_MMAP = YesPlease
        NO_SVN_TESTS = YesPlease
        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 += -DSNPRINTF_SIZE_CORR=1
        COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
@@@ -872,9 -865,6 +874,9 @@@ endi
  ifdef NO_D_INO_IN_DIRENT
        BASIC_CFLAGS += -DNO_D_INO_IN_DIRENT
  endif
 +ifdef NO_ST_BLOCKS_IN_STRUCT_STAT
 +      BASIC_CFLAGS += -DNO_ST_BLOCKS_IN_STRUCT_STAT
 +endif
  ifdef NO_C99_FORMAT
        BASIC_CFLAGS += -DNO_C99_FORMAT
  endif
@@@ -1072,11 -1062,9 +1074,11 @@@ export TAR INSTALL DESTDIR SHELL_PAT
  
  ### Build rules
  
 -all:: $(ALL_PROGRAMS) $(BUILT_INS) $(OTHER_PROGRAMS) GIT-BUILD-OPTIONS
 +SHELL = $(SHELL_PATH)
 +
 +all:: shell_compatibility_test $(ALL_PROGRAMS) $(BUILT_INS) $(OTHER_PROGRAMS) GIT-BUILD-OPTIONS
  ifneq (,$X)
 -      $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) git$X)), $(RM) '$p';)
 +      $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) git$X)), test '$p' -ef '$p$X' || $(RM) '$p';)
  endif
  
  all::
@@@ -1087,11 -1075,6 +1089,11 @@@ endi
        $(QUIET_SUBDIR0)perl $(QUIET_SUBDIR1) PERL_PATH='$(PERL_PATH_SQ)' prefix='$(prefix_SQ)' all
        $(QUIET_SUBDIR0)templates $(QUIET_SUBDIR1)
  
 +please_set_SHELL_PATH_to_a_more_modern_shell:
 +      @$$(:)
 +
 +shell_compatibility_test: please_set_SHELL_PATH_to_a_more_modern_shell
 +
  strip: $(PROGRAMS) git$X
        $(STRIP) $(STRIP_OPTS) $(PROGRAMS) git$X
  
@@@ -1103,17 -1086,14 +1105,17 @@@ git$X: git.o $(BUILTIN_OBJS) $(GITLIBS
        $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ git.o \
                $(BUILTIN_OBJS) $(ALL_LDFLAGS) $(LIBS)
  
help.o: help.c common-cmds.h GIT-CFLAGS
builtin-help.o: builtin-help.c common-cmds.h GIT-CFLAGS
        $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) \
                '-DGIT_HTML_PATH="$(htmldir_SQ)"' \
                '-DGIT_MAN_PATH="$(mandir_SQ)"' \
                '-DGIT_INFO_PATH="$(infodir_SQ)"' $<
  
  $(BUILT_INS): git$X
 -      $(QUIET_BUILT_IN)$(RM) $@ && ln git$X $@
 +      $(QUIET_BUILT_IN)$(RM) $@ && \
 +      ln git$X $@ 2>/dev/null || \
 +      ln -s git$X $@ 2>/dev/null || \
 +      cp git$X $@
  
  common-cmds.h: ./generate-cmdlist.sh command-list.txt
  
@@@ -1230,9 -1210,7 +1232,9 @@@ endi
  git-%$X: %.o $(GITLIBS)
        $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
  
 -git-imap-send$X: imap-send.o $(LIB_FILE)
 +git-imap-send$X: imap-send.o $(GITLIBS)
 +      $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
 +              $(LIBS) $(OPENSSL_LINK) $(OPENSSL_LIBSSL)
  
  http.o http-walker.o http-push.o transport.o: http.h
  
@@@ -1240,6 -1218,12 +1242,6 @@@ git-http-push$X: revision.o http.o http
        $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
                $(LIBS) $(CURL_LIBCURL) $(EXPAT_LIBEXPAT)
  
 -$(COMPAT_LIB): $(COMPAT_OBJS)
 -      $(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(COMPAT_OBJS)
 -
 -git-shell$X: abspath.o ctype.o exec_cmd.o quote.o strbuf.o usage.o wrapper.o shell.o $(COMPAT_LIB)
 -      $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(COMPAT_LIB)
 -
  $(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H)
  $(patsubst git-%$X,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h)
  builtin-revert.o wt-status.o: wt-status.h
@@@ -1362,7 -1346,7 +1364,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 '$(DESTDIR_SQ)$(bindir_SQ)'
 +      $(INSTALL) git$X git-upload-pack$X git-receive-pack$X git-upload-archive$X git-shell$X '$(DESTDIR_SQ)$(bindir_SQ)'
        $(MAKE) -C templates DESTDIR='$(DESTDIR_SQ)' install
        $(MAKE) -C perl prefix='$(prefix_SQ)' DESTDIR='$(DESTDIR_SQ)' install
  ifndef NO_TCLTK
@@@ -1374,13 -1358,16 +1376,13 @@@ ifneq (,$X
  endif
        bindir=$$(cd '$(DESTDIR_SQ)$(bindir_SQ)' && pwd) && \
        execdir=$$(cd '$(DESTDIR_SQ)$(gitexec_instdir_SQ)' && pwd) && \
 -      if test "z$$bindir" != "z$$execdir"; \
 -      then \
 -              ln -f "$$bindir/git$X" "$$execdir/git$X" || \
 -              cp "$$bindir/git$X" "$$execdir/git$X"; \
 -      fi && \
 -      { $(foreach p,$(BUILT_INS), $(RM) "$$execdir/$p" && ln "$$execdir/git$X" "$$execdir/$p" ;) } && \
 -      if test "z$$bindir" != "z$$execdir"; \
 -      then \
 -              $(RM) "$$execdir/git$X"; \
 -      fi && \
 +      { $(RM) "$$execdir/git-add$X" && \
 +              ln git-add$X "$$execdir/git-add$X" 2>/dev/null || \
 +              cp git-add$X "$$execdir/git-add$X"; } && \
 +      { $(foreach p,$(filter-out git-add,$(BUILT_INS)), $(RM) "$$execdir/$p" && \
 +              ln "$$execdir/git-add$X" "$$execdir/$p" 2>/dev/null || \
 +              ln -s "git-add$X" "$$execdir/$p" 2>/dev/null || \
 +              cp "$$execdir/git-add$X" "$$execdir/$p" || exit;) } && \
        ./check_bindir "z$$bindir" "z$$execdir" "$$bindir/git-add$X"
  
  install-doc:
@@@ -1449,7 -1436,7 +1451,7 @@@ distclean: clea
  
  clean:
        $(RM) *.o mozilla-sha1/*.o arm/*.o ppc/*.o compat/*.o xdiff/*.o \
 -              $(LIB_FILE) $(XDIFF_LIB) $(COMPAT_LIB)
 +              $(LIB_FILE) $(XDIFF_LIB)
        $(RM) $(ALL_PROGRAMS) $(BUILT_INS) git$X
        $(RM) $(TEST_PROGRAMS)
        $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo common-cmds.h TAGS tags cscope*
@@@ -1470,7 -1457,6 +1472,7 @@@ endi
        $(RM) GIT-VERSION-FILE GIT-CFLAGS GIT-GUI-VARS GIT-BUILD-OPTIONS
  
  .PHONY: all install clean strip
 +.PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell
  .PHONY: .FORCE-GIT-VERSION-FILE TAGS tags cscope .FORCE-GIT-CFLAGS
  .PHONY: .FORCE-GIT-BUILD-OPTIONS
  
diff --combined builtin-merge.c
index 0bff26e8332f44bad12b391bb811442c9c93731e,3e8db0d383430eaa45fa4ffc4929609efd9932b4..d6bcbec705fe5a2d278cba9cafd56415127d5afc
@@@ -22,6 -22,7 +22,7 @@@
  #include "log-tree.h"
  #include "color.h"
  #include "rerere.h"
+ #include "help.h"
  
  #define DEFAULT_TWOHEAD (1<<0)
  #define DEFAULT_OCTOPUS (1<<1)
@@@ -77,7 -78,9 +78,9 @@@ static int option_parse_message(const s
  static struct strategy *get_strategy(const char *name)
  {
        int i;
-       struct strbuf err;
+       struct strategy *ret;
+       static struct cmdnames main_cmds, other_cmds;
+       static int longest;
  
        if (!name)
                return NULL;
                if (!strcmp(name, all_strategy[i].name))
                        return &all_strategy[i];
  
-       strbuf_init(&err, 0);
-       for (i = 0; i < ARRAY_SIZE(all_strategy); i++)
-               strbuf_addf(&err, " %s", all_strategy[i].name);
-       fprintf(stderr, "Could not find merge strategy '%s'.\n", name);
-       fprintf(stderr, "Available strategies are:%s.\n", err.buf);
-       exit(1);
+       if (!longest) {
+               struct cmdnames not_strategies;
+               memset(&main_cmds, 0, sizeof(struct cmdnames));
+               memset(&other_cmds, 0, sizeof(struct cmdnames));
+               memset(&not_strategies, 0, sizeof(struct cmdnames));
+               longest = load_command_list("git-merge-", &main_cmds,
+                               &other_cmds);
+               for (i = 0; i < main_cmds.cnt; i++) {
+                       int j, found = 0;
+                       struct cmdname *ent = main_cmds.names[i];
+                       for (j = 0; j < ARRAY_SIZE(all_strategy); j++)
+                               if (!strncmp(ent->name, all_strategy[j].name, ent->len)
+                                               && !all_strategy[j].name[ent->len])
+                                       found = 1;
+                       if (!found)
+                               add_cmdname(&not_strategies, ent->name, ent->len);
+                       exclude_cmds(&main_cmds, &not_strategies);
+               }
+       }
+       if (!is_in_cmdlist(&main_cmds, name) && !is_in_cmdlist(&other_cmds, name)) {
+               fprintf(stderr, "Could not find merge strategy '%s'.\n", name);
+               fprintf(stderr, "Available strategies are:");
+               for (i = 0; i < main_cmds.cnt; i++)
+                       fprintf(stderr, " %s", main_cmds.names[i]->name);
+               fprintf(stderr, ".\n");
+               if (other_cmds.cnt) {
+                       fprintf(stderr, "Available custom strategies are:");
+                       for (i = 0; i < other_cmds.cnt; i++)
+                               fprintf(stderr, " %s", other_cmds.names[i]->name);
+                       fprintf(stderr, ".\n");
+               }
+               exit(1);
+       }
+       ret = xmalloc(sizeof(struct strategy));
+       memset(ret, 0, sizeof(struct strategy));
+       ret->name = xstrdup(name);
+       return ret;
  }
  
  static void append_strategy(struct strategy *s)
@@@ -396,12 -432,12 +432,12 @@@ static void merge_name(const char *remo
                struct strbuf truname = STRBUF_INIT;
                strbuf_addstr(&truname, "refs/heads/");
                strbuf_addstr(&truname, remote);
 -              strbuf_setlen(&truname, len+11);
 +              strbuf_setlen(&truname, truname.len - len);
                if (resolve_ref(truname.buf, buf_sha, 0, 0)) {
                        strbuf_addf(msg,
                                    "%s\t\tbranch '%s'%s of .\n",
                                    sha1_to_hex(remote_head->sha1),
 -                                  truname.buf,
 +                                  truname.buf + 11,
                                    (early ? " (early part)" : ""));
                        return;
                }
@@@ -564,7 -600,8 +600,7 @@@ static int checkout_fast_forward(unsign
        struct dir_struct dir;
        struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));
  
 -      if (read_cache_unmerged())
 -              die("you need to resolve your current index first");
 +      refresh_cache(REFRESH_QUIET);
  
        fd = hold_locked_index(lock_file, 1);
  
@@@ -649,15 -686,13 +685,15 @@@ static void add_strategies(const char *
  static int merge_trivial(void)
  {
        unsigned char result_tree[20], result_commit[20];
 -      struct commit_list parent;
 +      struct commit_list *parent = xmalloc(sizeof(struct commit_list *));
  
        write_tree_trivial(result_tree);
        printf("Wonderful.\n");
 -      parent.item = remoteheads->item;
 -      parent.next = NULL;
 -      commit_tree(merge_msg.buf, result_tree, &parent, result_commit);
 +      parent->item = lookup_commit(head);
 +      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);
        finish(result_commit, "In-index merge");
        drop_save();
        return 0;
@@@ -743,7 -778,6 +779,7 @@@ static int evaluate_result(void
        int cnt = 0;
        struct rev_info rev;
  
 +      discard_cache();
        if (read_cache() < 0)
                die("failed to read the cache");
  
@@@ -777,7 -811,7 +813,7 @@@ int cmd_merge(int argc, const char **ar
        struct commit_list **remotes = &remoteheads;
  
        setup_work_tree();
 -      if (unmerged_cache())
 +      if (read_cache_unmerged())
                die("You are in the middle of a conflicted merge.");
  
        /*
                if (argc != 1)
                        die("Can merge only exactly one commit into "
                                "empty head");
 +              if (squash)
 +                      die("Squash commit into empty head not supported yet");
 +              if (!allow_fast_forward)
 +                      die("Non-fast-forward commit does not make sense into "
 +                          "an empty head");
                remote_head = peel_to_type(argv[0], 0, NULL, OBJ_COMMIT);
                if (!remote_head)
                        die("%s - not something we can merge", argv[0]);
                        hex,
                        find_unique_abbrev(remoteheads->item->object.sha1,
                        DEFAULT_ABBREV));
 -              refresh_cache(REFRESH_QUIET);
                strbuf_init(&msg, 0);
                strbuf_addstr(&msg, "Fast forward");
                if (have_message)
                }
  
                /* Automerge succeeded. */
 +              discard_cache();
                write_tree_trivial(result_tree);
                automerge_was_ok = 1;
                break;
diff --combined t/t7600-merge.sh
index dbc90bc41625fccb4119cd6c2fc49668fe784122,0329aee2cde2cbca720183213ff97e60b0e960ee..6a2b12558a85db2d522b3cc6047b1d5b1b7fb327
@@@ -230,6 -230,10 +230,10 @@@ test_expect_success 'test option parsin
        test_must_fail git merge
  '
  
+ test_expect_success 'reject non-strategy with a git-merge-foo name' '
+       test_must_fail git merge -s index c1
+ '
  test_expect_success 'merge c0 with c1' '
        git reset --hard c0 &&
        git merge c1 &&
@@@ -488,23 -492,4 +492,23 @@@ test_expect_success 'merge c1 with c1 a
  
  test_debug 'gitk --all'
  
 +test_expect_success 'merge fast-forward in a dirty tree' '
 +       git reset --hard c0 &&
 +       mv file file1 &&
 +       cat file1 >file &&
 +       rm -f file1 &&
 +       git merge c2
 +'
 +
 +test_debug 'gitk --all'
 +
 +test_expect_success 'in-index merge' '
 +      git reset --hard c0 &&
 +      git merge --no-ff -s resolve c1 > out &&
 +      grep "Wonderful." out &&
 +      verify_parents $c0 $c1
 +'
 +
 +test_debug 'gitk --all'
 +
  test_done