Merge branch 'jc/receive-verify'
authorJunio C Hamano <gitster@pobox.com>
Wed, 5 Oct 2011 19:36:21 +0000 (12:36 -0700)
committerJunio C Hamano <gitster@pobox.com>
Wed, 5 Oct 2011 19:36:21 +0000 (12:36 -0700)
* jc/receive-verify:
receive-pack: check connectivity before concluding "git push"
check_everything_connected(): libify
check_everything_connected(): refactor to use an iterator
fetch: verify we have everything we need before updating our ref

Conflicts:
builtin/fetch.c

1  2 
Makefile
builtin/fetch.c
builtin/receive-pack.c
diff --combined Makefile
index 68201dea7838bd12b8be7432f9fe4366033bda1a,23d765892470d0f65c3e55cef556b0d95b00c6f8..741aac424f11877e1fea39647ef39ba73de46639
+++ b/Makefile
@@@ -30,15 -30,15 +30,15 @@@ all:
  # Define LIBPCREDIR=/foo/bar if your libpcre header and library files are in
  # /foo/bar/include and /foo/bar/lib directories.
  #
 -# Define NO_CURL if you do not have libcurl installed.  git-http-pull and
 +# Define NO_CURL if you do not have libcurl installed.  git-http-fetch and
  # git-http-push are not built, and you cannot use http:// and https://
 -# transports.
 +# transports (neither smart nor dumb).
  #
  # Define CURLDIR=/foo/bar if your curl header and library files are in
  # /foo/bar/include and /foo/bar/lib directories.
  #
  # Define NO_EXPAT if you do not have expat installed.  git-http-push is
 -# not built, and you cannot push using http:// and https:// transports.
 +# not built, and you cannot push using http:// and https:// transports (dumb).
  #
  # Define EXPATDIR=/foo/bar if your expat header and library files are in
  # /foo/bar/include and /foo/bar/lib directories.
  #
  # Define NEEDS_SSL_WITH_CRYPTO if you need -lssl when using -lcrypto (Darwin).
  #
 +# Define NEEDS_SSL_WITH_CURL if you need -lssl with -lcurl (Minix).
 +#
 +# Define NEEDS_IDN_WITH_CURL if you need -lidn when using -lcurl (Minix).
 +#
  # Define NEEDS_LIBICONV if linking with libc is not enough (Darwin).
  #
  # Define NEEDS_SOCKET if linking with libc is not enough (SunOS,
  # that tells runtime paths to dynamic libraries;
  # "-Wl,-rpath=/path/lib" is used instead.
  #
 +# Define NO_NORETURN if using buggy versions of gcc 4.6+ and profile feedback,
 +# as the compiler can crash (http://gcc.gnu.org/bugzilla/show_bug.cgi?id=49299)
 +#
  # Define USE_NSEC below if you want git to care about sub-second file mtimes
  # and ctimes. Note that you need recent glibc (at least 2.2.4) for this, and
  # it will BREAK YOUR LOCAL DIFFS! show-diff and anything using it will likely
  #   DEFAULT_EDITOR='$GIT_FALLBACK_EDITOR',
  #   DEFAULT_EDITOR='"C:\Program Files\Vim\gvim.exe" --nofork'
  #
 -# Define COMPUTE_HEADER_DEPENDENCIES if your compiler supports the -MMD option
 -# and you want to avoid rebuilding objects when an unrelated header file
 -# changes.
 -#
  # Define CHECK_HEADER_DEPENDENCIES to check for problems in the hard-coded
  # dependency rules.
  #
@@@ -298,7 -295,6 +298,7 @@@ bindir = $(prefix)/$(bindir_relative
  mandir = share/man
  infodir = share/info
  gitexecdir = libexec/git-core
 +mergetoolsdir = $(gitexecdir)/mergetools
  sharedir = $(prefix)/share
  gitwebdir = $(sharedir)/gitweb
  template_dir = share/git-core/templates
@@@ -511,11 -507,11 +511,12 @@@ LIB_H += commit.
  LIB_H += compat/bswap.h
  LIB_H += compat/cygwin.h
  LIB_H += compat/mingw.h
 +LIB_H += compat/obstack.h
  LIB_H += compat/win32/pthread.h
  LIB_H += compat/win32/syslog.h
  LIB_H += compat/win32/sys/poll.h
  LIB_H += compat/win32/dirent.h
+ LIB_H += connected.h
  LIB_H += csum-file.h
  LIB_H += decorate.h
  LIB_H += delta.h
@@@ -530,7 -526,6 +531,7 @@@ LIB_H += graph.
  LIB_H += grep.h
  LIB_H += hash.h
  LIB_H += help.h
 +LIB_H += kwset.h
  LIB_H += levenshtein.h
  LIB_H += list-objects.h
  LIB_H += ll-merge.h
@@@ -557,13 -552,11 +558,13 @@@ LIB_H += rerere.
  LIB_H += resolve-undo.h
  LIB_H += revision.h
  LIB_H += run-command.h
 +LIB_H += sequencer.h
  LIB_H += sha1-array.h
  LIB_H += sha1-lookup.h
  LIB_H += sideband.h
  LIB_H += sigchain.h
  LIB_H += strbuf.h
 +LIB_H += streaming.h
  LIB_H += string-list.h
  LIB_H += submodule.h
  LIB_H += tag.h
@@@ -593,9 -586,9 +594,10 @@@ LIB_OBJS += cache-tree.
  LIB_OBJS += color.o
  LIB_OBJS += combine-diff.o
  LIB_OBJS += commit.o
 +LIB_OBJS += compat/obstack.o
  LIB_OBJS += config.o
  LIB_OBJS += connect.o
+ LIB_OBJS += connected.o
  LIB_OBJS += convert.o
  LIB_OBJS += copy.o
  LIB_OBJS += csum-file.o
@@@ -623,7 -616,6 +625,7 @@@ LIB_OBJS += hash.
  LIB_OBJS += help.o
  LIB_OBJS += hex.o
  LIB_OBJS += ident.o
 +LIB_OBJS += kwset.o
  LIB_OBJS += levenshtein.o
  LIB_OBJS += list-objects.o
  LIB_OBJS += ll-merge.o
@@@ -644,7 -636,6 +646,7 @@@ LIB_OBJS += pack-revindex.
  LIB_OBJS += pack-write.o
  LIB_OBJS += pager.o
  LIB_OBJS += parse-options.o
 +LIB_OBJS += parse-options-cb.o
  LIB_OBJS += patch-delta.o
  LIB_OBJS += patch-ids.o
  LIB_OBJS += path.o
@@@ -665,7 -656,6 +667,7 @@@ LIB_OBJS += revision.
  LIB_OBJS += run-command.o
  LIB_OBJS += server-info.o
  LIB_OBJS += setup.o
 +LIB_OBJS += sequencer.o
  LIB_OBJS += sha1-array.o
  LIB_OBJS += sha1-lookup.o
  LIB_OBJS += sha1_file.o
@@@ -674,7 -664,6 +676,7 @@@ LIB_OBJS += shallow.
  LIB_OBJS += sideband.o
  LIB_OBJS += sigchain.o
  LIB_OBJS += strbuf.o
 +LIB_OBJS += streaming.o
  LIB_OBJS += string-list.o
  LIB_OBJS += submodule.o
  LIB_OBJS += symlinks.o
@@@ -1137,6 -1126,8 +1139,6 @@@ endi
        X = .exe
  endif
  ifeq ($(uname_S),Interix)
 -      NO_SYS_POLL_H = YesPlease
 -      NO_INTTYPES_H = YesPlease
        NO_INITGROUPS = YesPlease
        NO_IPV6 = YesPlease
        NO_MEMMEM = YesPlease
        ifeq ($(uname_R),3.5)
                NO_INET_NTOP = YesPlease
                NO_INET_PTON = YesPlease
 +              NO_SOCKADDR_STORAGE = YesPlease
 +              NO_FNMATCH_CASEFOLD = YesPlease
        endif
        ifeq ($(uname_R),5.2)
                NO_INET_NTOP = YesPlease
                NO_INET_PTON = YesPlease
 +              NO_SOCKADDR_STORAGE = YesPlease
 +              NO_FNMATCH_CASEFOLD = YesPlease
        endif
  endif
 +ifeq ($(uname_S),Minix)
 +      NO_IPV6 = YesPlease
 +      NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease
 +      NO_NSEC = YesPlease
 +      NEEDS_LIBGEN =
 +      NEEDS_CRYPTO_WITH_SSL = YesPlease
 +      NEEDS_IDN_WITH_CURL = YesPlease
 +      NEEDS_SSL_WITH_CURL = YesPlease
 +      NEEDS_RESOLV =
 +      NO_HSTRERROR = YesPlease
 +      NO_MMAP = YesPlease
 +      NO_CURL =
 +      NO_EXPAT =
 +endif
  ifneq (,$(findstring MINGW,$(uname_S)))
        pathsep = ;
        NO_PREAD = YesPlease
@@@ -1240,15 -1213,6 +1242,15 @@@ endi
  ifdef CHECK_HEADER_DEPENDENCIES
  COMPUTE_HEADER_DEPENDENCIES =
  USE_COMPUTED_HEADER_DEPENDENCIES =
 +else
 +ifndef COMPUTE_HEADER_DEPENDENCIES
 +dep_check = $(shell $(CC) $(ALL_CFLAGS) \
 +      -c -MF /dev/null -MMD -MP -x c /dev/null -o /dev/null 2>&1; \
 +      echo $$?)
 +ifeq ($(dep_check),0)
 +COMPUTE_HEADER_DEPENDENCIES=YesPlease
 +endif
 +endif
  endif
  
  ifdef COMPUTE_HEADER_DEPENDENCIES
        else
                CURL_LIBCURL = -lcurl
        endif
 +      ifdef NEEDS_SSL_WITH_CURL
 +              CURL_LIBCURL += -lssl
 +              ifdef NEEDS_CRYPTO_WITH_SSL
 +                      CURL_LIBCURL += -lcrypto
 +              endif
 +      endif
 +      ifdef NEEDS_IDN_WITH_CURL
 +              CURL_LIBCURL += -lidn
 +      endif
 +
        REMOTE_CURL_PRIMARY = git-remote-http$X
        REMOTE_CURL_ALIASES = git-remote-https$X git-remote-ftp$X git-remote-ftps$X
        REMOTE_CURL_NAMES = $(REMOTE_CURL_PRIMARY) $(REMOTE_CURL_ALIASES)
@@@ -1370,7 -1324,7 +1372,7 @@@ ifndef NO_OPENSS
                OPENSSL_LINK =
        endif
        ifdef NEEDS_CRYPTO_WITH_SSL
 -              OPENSSL_LINK += -lcrypto
 +              OPENSSL_LIBSSL += -lcrypto
        endif
  else
        BASIC_CFLAGS += -DNO_OPENSSL
@@@ -1422,9 -1376,6 +1424,9 @@@ endi
  ifdef USE_ST_TIMESPEC
        BASIC_CFLAGS += -DUSE_ST_TIMESPEC
  endif
 +ifdef NO_NORETURN
 +      BASIC_CFLAGS += -DNO_NORETURN
 +endif
  ifdef NO_NSEC
        BASIC_CFLAGS += -DNO_NSEC
  endif
@@@ -1757,7 -1708,7 +1759,7 @@@ git.sp git.s git.o: EXTRA_CPPFLAGS = -D
        '-DGIT_MAN_PATH="$(mandir_SQ)"' \
        '-DGIT_INFO_PATH="$(infodir_SQ)"'
  
 -git$X: git.o $(BUILTIN_OBJS) $(GITLIBS)
 +git$X: git.o GIT-LDFLAGS $(BUILTIN_OBJS) $(GITLIBS)
        $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ git.o \
                $(BUILTIN_OBJS) $(ALL_LDFLAGS) $(LIBS)
  
@@@ -1889,7 -1840,7 +1891,7 @@@ ifndef NO_CUR
        GIT_OBJS += http.o http-walker.o remote-curl.o
  endif
  XDIFF_OBJS = xdiff/xdiffi.o xdiff/xprepare.o xdiff/xutils.o xdiff/xemit.o \
 -      xdiff/xmerge.o xdiff/xpatience.o
 +      xdiff/xmerge.o xdiff/xpatience.o xdiff/xhistogram.o
  VCSSVN_OBJS = vcs-svn/string_pool.o vcs-svn/line_buffer.o \
        vcs-svn/repo_tree.o vcs-svn/fast_export.o vcs-svn/svndump.o
  VCSSVN_TEST_OBJS = test-obj-pool.o test-string-pool.o \
@@@ -2055,17 -2006,17 +2057,17 @@@ compat/nedmalloc/nedmalloc.sp compat/ne
        -DNDEBUG -DOVERRIDE_STRDUP -DREPLACE_SYSTEM_ALLOCATOR
  endif
  
 -git-%$X: %.o $(GITLIBS)
 +git-%$X: %.o GIT-LDFLAGS $(GITLIBS)
        $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
  
 -git-imap-send$X: imap-send.o $(GITLIBS)
 +git-imap-send$X: imap-send.o GIT-LDFLAGS $(GITLIBS)
        $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
                $(LIBS) $(OPENSSL_LINK) $(OPENSSL_LIBSSL) $(LIB_4_CRYPTO)
  
 -git-http-fetch$X: revision.o http.o http-walker.o http-fetch.o $(GITLIBS)
 +git-http-fetch$X: revision.o http.o http-walker.o http-fetch.o GIT-LDFLAGS $(GITLIBS)
        $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
                $(LIBS) $(CURL_LIBCURL)
 -git-http-push$X: revision.o http.o http-push.o $(GITLIBS)
 +git-http-push$X: revision.o http.o http-push.o GIT-LDFLAGS $(GITLIBS)
        $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
                $(LIBS) $(CURL_LIBCURL) $(EXPAT_LIBEXPAT)
  
@@@ -2075,7 -2026,7 +2077,7 @@@ $(REMOTE_CURL_ALIASES): $(REMOTE_CURL_P
        ln -s $< $@ 2>/dev/null || \
        cp $< $@
  
 -$(REMOTE_CURL_PRIMARY): remote-curl.o http.o http-walker.o $(GITLIBS)
 +$(REMOTE_CURL_PRIMARY): remote-curl.o http.o http-walker.o GIT-LDFLAGS $(GITLIBS)
        $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
                $(LIBS) $(CURL_LIBCURL) $(EXPAT_LIBEXPAT)
  
@@@ -2145,15 -2096,6 +2147,15 @@@ GIT-CFLAGS: FORC
                echo "$$FLAGS" >GIT-CFLAGS; \
              fi
  
 +TRACK_LDFLAGS = $(subst ','\'',$(ALL_LDFLAGS))
 +
 +GIT-LDFLAGS: FORCE
 +      @FLAGS='$(TRACK_LDFLAGS)'; \
 +          if test x"$$FLAGS" != x"`cat GIT-LDFLAGS 2>/dev/null`" ; then \
 +              echo 1>&2 "    * new link flags"; \
 +              echo "$$FLAGS" >GIT-LDFLAGS; \
 +            fi
 +
  # We need to apply sq twice, once to protect from the shell
  # that runs GIT-BUILD-OPTIONS, and then again to protect it
  # and the first level quoting from the shell that runs "echo".
@@@ -2217,7 -2159,7 +2219,7 @@@ test-delta$X: diff-delta.o patch-delta.
  
  test-line-buffer$X: vcs-svn/lib.a
  
 -test-parse-options$X: parse-options.o
 +test-parse-options$X: parse-options.o parse-options-cb.o
  
  test-string-pool$X: vcs-svn/lib.a
  
@@@ -2225,7 -2167,7 +2227,7 @@@ test-svn-fe$X: vcs-svn/lib.
  
  .PRECIOUS: $(TEST_OBJS)
  
 -test-%$X: test-%.o $(GITLIBS)
 +test-%$X: test-%.o GIT-LDFLAGS $(GITLIBS)
        $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(filter %.a,$^) $(LIBS)
  
  check-sha1:: test-sha1$X
@@@ -2270,13 -2212,6 +2272,13 @@@ endi
  gitexec_instdir_SQ = $(subst ','\'',$(gitexec_instdir))
  export gitexec_instdir
  
 +ifneq ($(filter /%,$(firstword $(mergetoolsdir))),)
 +mergetools_instdir = $(mergetoolsdir)
 +else
 +mergetools_instdir = $(prefix)/$(mergetoolsdir)
 +endif
 +mergetools_instdir_SQ = $(subst ','\'',$(mergetools_instdir))
 +
  install_bindir_programs := $(patsubst %,%$X,$(BINDIR_PROGRAMS_NEED_X)) $(BINDIR_PROGRAMS_NO_X)
  
  install: all
        $(INSTALL) -m 644 $(SCRIPT_LIB) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
        $(INSTALL) $(install_bindir_programs) '$(DESTDIR_SQ)$(bindir_SQ)'
        $(MAKE) -C templates DESTDIR='$(DESTDIR_SQ)' install
 +      $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(mergetools_instdir_SQ)'
 +      (cd mergetools && $(TAR) cf - .) | \
 +      (cd '$(DESTDIR_SQ)$(mergetools_instdir_SQ)' && umask 022 && $(TAR) xof -)
  ifndef NO_PERL
        $(MAKE) -C perl prefix='$(prefix_SQ)' DESTDIR='$(DESTDIR_SQ)' install
        $(MAKE) -C gitweb install
@@@ -2445,7 -2377,7 +2447,7 @@@ ifndef NO_TCLT
        $(MAKE) -C gitk-git clean
        $(MAKE) -C git-gui clean
  endif
 -      $(RM) GIT-VERSION-FILE GIT-CFLAGS GIT-GUI-VARS GIT-BUILD-OPTIONS
 +      $(RM) GIT-VERSION-FILE GIT-CFLAGS GIT-LDFLAGS GIT-GUI-VARS GIT-BUILD-OPTIONS
  
  .PHONY: all install clean strip
  .PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell
@@@ -2556,19 -2488,3 +2558,19 @@@ cover_db: coverage-repor
  
  cover_db_html: cover_db
        cover -report html -outputdir cover_db_html cover_db
 +
 +### profile feedback build
 +#
 +.PHONY: profile-all profile-clean
 +
 +PROFILE_GEN_CFLAGS := $(CFLAGS) -fprofile-generate -DNO_NORETURN=1
 +PROFILE_USE_CFLAGS := $(CFLAGS) -fprofile-use -fprofile-correction -DNO_NORETURN=1
 +
 +profile-clean:
 +      $(RM) $(addsuffix *.gcda,$(object_dirs))
 +      $(RM) $(addsuffix *.gcno,$(object_dirs))
 +
 +profile-all: profile-clean
 +      $(MAKE) CFLAGS="$(PROFILE_GEN_CFLAGS)" all
 +      $(MAKE) CFLAGS="$(PROFILE_GEN_CFLAGS)" -j1 test
 +      $(MAKE) CFLAGS="$(PROFILE_USE_CFLAGS)" all
diff --combined builtin/fetch.c
index ead8c9d5c37411da0fefd7a4f2272cb94652ffdb,ffda063d91cd19c2a4e74e53520dbf464233fe0b..7a4e41cca75b87d3e5a7c4690658d9879777e965
@@@ -13,6 -13,7 +13,7 @@@
  #include "sigchain.h"
  #include "transport.h"
  #include "submodule.h"
+ #include "connected.h"
  
  static const char * const builtin_fetch_usage[] = {
        "git fetch [<options>] [<repository> [<refspec>...]]",
@@@ -345,62 -346,16 +346,16 @@@ static int update_local_ref(struct ref 
        }
  }
  
- /*
-  * The ref_map records the tips of the refs we are fetching. If
-  *
-  *  $ git rev-list --verify-objects --stdin --not --all
-  *
-  * (feeding all the refs in ref_map on its standard input) does not
-  * error out, that means everything reachable from these updated refs
-  * locally exists and is connected to some of our existing refs.
-  *
-  * Returns 0 if everything is connected, non-zero otherwise.
-  */
- static int check_everything_connected(struct ref *ref_map, int quiet)
+ static int iterate_ref_map(void *cb_data, unsigned char sha1[20])
  {
-       struct child_process rev_list;
-       const char *argv[] = {"rev-list", "--verify-objects",
-                             "--stdin", "--not", "--all", NULL, NULL};
-       char commit[41];
-       struct ref *ref;
-       int err = 0;
-       if (!ref_map)
-               return 0;
-       if (quiet)
-               argv[5] = "--quiet";
-       memset(&rev_list, 0, sizeof(rev_list));
-       rev_list.argv = argv;
-       rev_list.git_cmd = 1;
-       rev_list.in = -1;
-       rev_list.no_stdout = 1;
-       rev_list.no_stderr = quiet;
-       if (start_command(&rev_list))
-               return error(_("Could not run 'git rev-list'"));
-       sigchain_push(SIGPIPE, SIG_IGN);
-       memcpy(commit + 40, "\n", 2);
-       for (ref = ref_map; ref; ref = ref->next) {
-               memcpy(commit, sha1_to_hex(ref->old_sha1), 40);
-               if (write_in_full(rev_list.in, commit, 41) < 0) {
-                       if (errno != EPIPE && errno != EINVAL)
-                               error(_("failed write to rev-list: %s"),
-                                     strerror(errno));
-                       err = -1;
-                       break;
-               }
-       }
-       if (close(rev_list.in)) {
-               error(_("failed to close rev-list's stdin: %s"), strerror(errno));
-               err = -1;
-       }
-       sigchain_pop(SIGPIPE);
+       struct ref **rm = cb_data;
+       struct ref *ref = *rm;
  
-       return finish_command(&rev_list) || err;
+       if (!ref)
+               return -1; /* end of the list */
+       *rm = ref->next;
+       hashcpy(sha1, ref->old_sha1);
+       return 0;
  }
  
  static int store_updated_refs(const char *raw_url, const char *remote_name,
        else
                url = xstrdup("foreign");
  
-       if (check_everything_connected(ref_map, 0))
+       rm = ref_map;
+       if (check_everything_connected(iterate_ref_map, 0, &rm))
                return error(_("%s did not send all necessary objects\n"), url);
  
        for (rm = ref_map; rm; rm = rm->next) {
   */
  static int quickfetch(struct ref *ref_map)
  {
+       struct ref *rm = ref_map;
        /*
         * If we are deepening a shallow clone we already have these
         * objects reachable.  Running rev-list here will return with
         */
        if (depth)
                return -1;
-       return check_everything_connected(ref_map, 1);
+       return check_everything_connected(iterate_ref_map, 1, &rm);
  }
  
  static int fetch_refs(struct transport *transport, struct ref *ref_map)
@@@ -882,7 -840,6 +840,7 @@@ static int fetch_one(struct remote *rem
  {
        int i;
        static const char **refs = NULL;
 +      struct refspec *refspec;
        int ref_nr = 0;
        int exit_code;
  
  
        sigchain_push_common(unlock_pack_on_signal);
        atexit(unlock_pack);
 -      exit_code = do_fetch(transport,
 -                      parse_fetch_refspec(ref_nr, refs), ref_nr);
 +      refspec = parse_fetch_refspec(ref_nr, refs);
 +      exit_code = do_fetch(transport, refspec, ref_nr);
 +      free(refspec);
        transport_disconnect(transport);
        transport = NULL;
        return exit_code;
@@@ -948,15 -904,6 +906,15 @@@ int cmd_fetch(int argc, const char **ar
        argc = parse_options(argc, argv, prefix,
                             builtin_fetch_options, builtin_fetch_usage, 0);
  
 +      if (recurse_submodules != RECURSE_SUBMODULES_OFF) {
 +              if (recurse_submodules_default) {
 +                      int arg = parse_fetch_recurse_submodules_arg("--recurse-submodules-default", recurse_submodules_default);
 +                      set_config_fetch_recurse_submodules(arg);
 +              }
 +              gitmodules_config();
 +              git_config(submodule_config, NULL);
 +      }
 +
        if (all) {
                if (argc == 1)
                        die(_("fetch --all does not take a repository argument"));
        if (!result && (recurse_submodules != RECURSE_SUBMODULES_OFF)) {
                const char *options[10];
                int num_options = 0;
 -              if (recurse_submodules_default) {
 -                      int arg = parse_fetch_recurse_submodules_arg("--recurse-submodules-default", recurse_submodules_default);
 -                      set_config_fetch_recurse_submodules(arg);
 -              }
 -              gitmodules_config();
 -              git_config(submodule_config, NULL);
                add_options_to_argv(&num_options, options);
                result = fetch_populated_submodules(num_options, options,
                                                    submodule_prefix,
diff --combined builtin/receive-pack.c
index 4cc03065bf04ad389333bde8c510251540bbe3a2,42f712318faf994efb0038c1036d934b5d279e9e..9b56be3cc690d4a5e4eb65ccd8e364f3245cde39
@@@ -11,6 -11,7 +11,7 @@@
  #include "transport.h"
  #include "string-list.h"
  #include "sha1-array.h"
+ #include "connected.h"
  
  static const char receive_pack_usage[] = "git receive-pack <git-dir>";
  
@@@ -25,8 -26,7 +26,8 @@@ static int deny_deletes
  static int deny_non_fast_forwards;
  static enum deny_action deny_current_branch = DENY_UNCONFIGURED;
  static enum deny_action deny_delete_current = DENY_UNCONFIGURED;
 -static int receive_fsck_objects;
 +static int receive_fsck_objects = -1;
 +static int transfer_fsck_objects = -1;
  static int receive_unpack_limit = -1;
  static int transfer_unpack_limit = -1;
  static int unpack_limit = 100;
@@@ -80,11 -80,6 +81,11 @@@ static int receive_pack_config(const ch
                return 0;
        }
  
 +      if (strcmp(var, "transfer.fsckobjects") == 0) {
 +              transfer_fsck_objects = git_config_bool(var, value);
 +              return 0;
 +      }
 +
        if (!strcmp(var, "receive.denycurrentbranch")) {
                deny_current_branch = parse_deny_action(var, value);
                return 0;
@@@ -126,25 -121,9 +127,25 @@@ static int show_ref(const char *path, c
        return 0;
  }
  
 +static int show_ref_cb(const char *path, const unsigned char *sha1, int flag, void *cb_data)
 +{
 +      path = strip_namespace(path);
 +      /*
 +       * Advertise refs outside our current namespace as ".have"
 +       * refs, so that the client can use them to minimize data
 +       * transfer but will otherwise ignore them. This happens to
 +       * cover ".have" that are thrown in by add_one_alternate_ref()
 +       * to mark histories that are complete in our alternates as
 +       * well.
 +       */
 +      if (!path)
 +              path = ".have";
 +      return show_ref(path, sha1, flag, cb_data);
 +}
 +
  static void write_head_info(void)
  {
 -      for_each_ref(show_ref, NULL);
 +      for_each_ref(show_ref_cb, NULL);
        if (!sent_capabilities)
                show_ref("capabilities^{}", null_sha1, 0, NULL);
  
@@@ -355,8 -334,6 +356,8 @@@ static void refuse_unconfigured_deny_de
  static const char *update(struct command *cmd)
  {
        const char *name = cmd->ref_name;
 +      struct strbuf namespaced_name_buf = STRBUF_INIT;
 +      const char *namespaced_name;
        unsigned char *old_sha1 = cmd->old_sha1;
        unsigned char *new_sha1 = cmd->new_sha1;
        struct ref_lock *lock;
                return "funny refname";
        }
  
 -      if (is_ref_checked_out(name)) {
 +      strbuf_addf(&namespaced_name_buf, "%s%s", get_git_namespace(), name);
 +      namespaced_name = strbuf_detach(&namespaced_name_buf, NULL);
 +
 +      if (is_ref_checked_out(namespaced_name)) {
                switch (deny_current_branch) {
                case DENY_IGNORE:
                        break;
                        return "deletion prohibited";
                }
  
 -              if (!strcmp(name, head_name)) {
 +              if (!strcmp(namespaced_name, head_name)) {
                        switch (deny_delete_current) {
                        case DENY_IGNORE:
                                break;
                        rp_warning("Allowing deletion of corrupt ref.");
                        old_sha1 = NULL;
                }
 -              if (delete_ref(name, old_sha1, 0)) {
 +              if (delete_ref(namespaced_name, old_sha1, 0)) {
                        rp_error("failed to delete %s", name);
                        return "failed to delete";
                }
                return NULL; /* good */
        }
        else {
 -              lock = lock_any_ref_for_update(name, old_sha1, 0);
 +              lock = lock_any_ref_for_update(namespaced_name, old_sha1, 0);
                if (!lock) {
                        rp_error("failed to lock %s", name);
                        return "failed to lock";
@@@ -518,29 -492,17 +519,29 @@@ static void run_update_post_hook(struc
  
  static void check_aliased_update(struct command *cmd, struct string_list *list)
  {
 +      struct strbuf buf = STRBUF_INIT;
 +      const char *dst_name;
        struct string_list_item *item;
        struct command *dst_cmd;
        unsigned char sha1[20];
        char cmd_oldh[41], cmd_newh[41], dst_oldh[41], dst_newh[41];
        int flag;
  
 -      const char *dst_name = resolve_ref(cmd->ref_name, sha1, 0, &flag);
 +      strbuf_addf(&buf, "%s%s", get_git_namespace(), cmd->ref_name);
 +      dst_name = resolve_ref(buf.buf, sha1, 0, &flag);
 +      strbuf_release(&buf);
  
        if (!(flag & REF_ISSYMREF))
                return;
  
 +      dst_name = strip_namespace(dst_name);
 +      if (!dst_name) {
 +              rp_error("refusing update to broken symref '%s'", cmd->ref_name);
 +              cmd->skip_update = 1;
 +              cmd->error_string = "broken symref";
 +              return;
 +      }
 +
        if ((item = string_list_lookup(list, dst_name)) == NULL)
                return;
  
@@@ -585,6 -547,43 +586,43 @@@ static void check_aliased_updates(struc
        string_list_clear(&ref_list, 0);
  }
  
+ static int command_singleton_iterator(void *cb_data, unsigned char sha1[20])
+ {
+       struct command **cmd_list = cb_data;
+       struct command *cmd = *cmd_list;
+       if (!cmd)
+               return -1; /* end of list */
+       *cmd_list = NULL; /* this returns only one */
+       hashcpy(sha1, cmd->new_sha1);
+       return 0;
+ }
+ static void set_connectivity_errors(struct command *commands)
+ {
+       struct command *cmd;
+       for (cmd = commands; cmd; cmd = cmd->next) {
+               struct command *singleton = cmd;
+               if (!check_everything_connected(command_singleton_iterator,
+                                               0, &singleton))
+                       continue;
+               cmd->error_string = "missing necessary objects";
+       }
+ }
+ static int iterate_receive_command_list(void *cb_data, unsigned char sha1[20])
+ {
+       struct command **cmd_list = cb_data;
+       struct command *cmd = *cmd_list;
+       if (!cmd)
+               return -1; /* end of list */
+       *cmd_list = cmd->next;
+       hashcpy(sha1, cmd->new_sha1);
+       return 0;
+ }
  static void execute_commands(struct command *commands, const char *unpacker_error)
  {
        struct command *cmd;
                return;
        }
  
+       cmd = commands;
+       if (check_everything_connected(iterate_receive_command_list,
+                                      0, &cmd))
+               set_connectivity_errors(commands);
        if (run_receive_hook(commands, pre_receive_hook)) {
                for (cmd = commands; cmd; cmd = cmd->next)
                        cmd->error_string = "pre-receive hook declined";
@@@ -680,11 -684,6 +723,11 @@@ static const char *unpack(void
        struct pack_header hdr;
        const char *hdr_err;
        char hdr_arg[38];
 +      int fsck_objects = (receive_fsck_objects >= 0
 +                          ? receive_fsck_objects
 +                          : transfer_fsck_objects >= 0
 +                          ? transfer_fsck_objects
 +                          : 0);
  
        hdr_err = parse_pack_header(&hdr);
        if (hdr_err)
                int code, i = 0;
                const char *unpacker[4];
                unpacker[i++] = "unpack-objects";
 -              if (receive_fsck_objects)
 +              if (fsck_objects)
                        unpacker[i++] = "--strict";
                unpacker[i++] = hdr_arg;
                unpacker[i++] = NULL;
  
                keeper[i++] = "index-pack";
                keeper[i++] = "--stdin";
 -              if (receive_fsck_objects)
 +              if (fsck_objects)
                        keeper[i++] = "--strict";
                keeper[i++] = "--fix-thin";
                keeper[i++] = hdr_arg;