Code

Merge branch 'jc/alternate-push'
authorShawn O. Pearce <spearce@spearce.org>
Thu, 25 Sep 2008 16:39:24 +0000 (09:39 -0700)
committerShawn O. Pearce <spearce@spearce.org>
Thu, 25 Sep 2008 16:39:24 +0000 (09:39 -0700)
* jc/alternate-push:
  push: receiver end advertises refs from alternate repositories
  push: prepare sender to receive extended ref information from the receiver
  receive-pack: make it a builtin
  is_directory(): a generic helper function

1  2 
Makefile
builtin-clone.c
builtin-fetch-pack.c
builtin-send-pack.c
builtin.h
daemon.c
git.c
sha1_file.c

diff --combined Makefile
index 3c0664a0734a156859ea204ae4b9b5979620c28c,f9c54ffd2f1de5698ce1bafcd42fb9260e252e00..48547a21139e7c22ebc96fc19ee7cd1f6b3116bb
+++ b/Makefile
@@@ -294,7 -294,6 +294,6 @@@ 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
@@@ -546,6 -545,7 +545,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 -636,6 +636,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 -686,6 +688,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
@@@ -716,8 -712,6 +716,8 @@@ ifeq ($(uname_S),AIX
        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 -763,10 +769,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
@@@ -1271,12 -1265,6 +1271,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 -1368,7 +1380,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 -1401,6 +1413,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-clone.c
index 5b40e07ba7f13950078d36a48c2cb3f6e6c3c2c4,a4b87904fc7ad387cf5748327186ec23e2164829..49d2eb9c2ba574f2c1484717f0755208e7ed8147
@@@ -58,7 -58,7 +58,7 @@@ static struct option builtin_clone_opti
        OPT_STRING(0, "reference", &option_reference, "repo",
                   "reference repository"),
        OPT_STRING('o', "origin", &option_origin, "branch",
 -                 "use <branch> instead or 'origin' to track upstream"),
 +                 "use <branch> instead of 'origin' to track upstream"),
        OPT_STRING('u', "upload-pack", &option_upload_pack, "path",
                   "path to git-upload-pack on the remote"),
        OPT_STRING(0, "depth", &option_depth, "depth",
@@@ -77,7 -77,7 +77,7 @@@ static char *get_repo_path(const char *
        for (i = 0; i < ARRAY_SIZE(suffix); i++) {
                const char *path;
                path = mkpath("%s%s", repo, suffix[i]);
-               if (!stat(path, &st) && S_ISDIR(st.st_mode)) {
+               if (is_directory(path)) {
                        *is_bundle = 0;
                        return xstrdup(make_nonrelative_path(path));
                }
@@@ -140,13 -140,6 +140,6 @@@ static char *guess_dir_name(const char 
        return xstrndup(start, end - start);
  }
  
- static int is_directory(const char *path)
- {
-       struct stat buf;
-       return !stat(path, &buf) && S_ISDIR(buf.st_mode);
- }
  static void strip_trailing_slashes(char *dir)
  {
        char *end = dir + strlen(dir);
diff --combined builtin-fetch-pack.c
index 4dfef29bcd23a174593203e521247a3d4209cf89,e0c25615ef3078790da461156674815493b98879..fa3c936493cc0b139edf3e4e8154569f453afc02
@@@ -735,7 -735,7 +735,7 @@@ int cmd_fetch_pack(int argc, const cha
        conn = git_connect(fd, (char *)dest, args.uploadpack,
                           args.verbose ? CONNECT_VERBOSE : 0);
        if (conn) {
-               get_remote_heads(fd[0], &ref, 0, NULL, 0);
+               get_remote_heads(fd[0], &ref, 0, NULL, 0, NULL);
  
                ref = fetch_pack(&args, fd, conn, ref, dest, nr_heads, heads, NULL);
                close(fd[0]);
        if (!ret && nr_heads) {
                /* If the heads to pull were given, we should have
                 * consumed all of them by matching the remote.
 -               * Otherwise, 'git-fetch remote no-such-ref' would
 +               * Otherwise, 'git fetch remote no-such-ref' would
                 * silently succeed without issuing an error.
                 */
                for (i = 0; i < nr_heads; i++)
diff --combined builtin-send-pack.c
index 2af9f2934142f55858f4b5c76deb6397ac74b9f8,b3c22f6a4a19313e0455356091cb86f10baf2623..910db92b62eb6dd91a4002b2643fef4a76ec8f83
@@@ -18,7 -18,7 +18,7 @@@ static struct send_pack_args args = 
  /*
   * Make a pack stream and spit it out into file descriptor fd
   */
- static int pack_objects(int fd, struct ref *refs)
+ static int pack_objects(int fd, struct ref *refs, struct extra_have_objects *extra)
  {
        /*
         * The child becomes pack-objects --revs; we feed
@@@ -34,6 -34,8 +34,8 @@@
                NULL,
        };
        struct child_process po;
+       int i;
+       char buf[42];
  
        if (args.use_thin_pack)
                argv[4] = "--thin";
        po.out = fd;
        po.git_cmd = 1;
        if (start_command(&po))
 -              die("git-pack-objects failed (%s)", strerror(errno));
 +              die("git pack-objects failed (%s)", strerror(errno));
  
        /*
         * We feed the pack-objects we just spawned with revision
         * parameters by writing to the pipe.
         */
-       while (refs) {
-               char buf[42];
+       for (i = 0; i < extra->nr; i++) {
+               memcpy(buf + 1, sha1_to_hex(&extra->array[i][0]), 40);
+               buf[0] = '^';
+               buf[41] = '\n';
+               if (!write_or_whine(po.in, buf, 42, "send-pack: send refs"))
+                       break;
+       }
  
+       while (refs) {
                if (!is_null_sha1(refs->old_sha1) &&
                    has_sha1_file(refs->old_sha1)) {
                        memcpy(buf + 1, sha1_to_hex(refs->old_sha1), 40);
@@@ -381,14 -389,17 +389,17 @@@ static int do_send_pack(int in, int out
        int expect_status_report = 0;
        int flags = MATCH_REFS_NONE;
        int ret;
+       struct extra_have_objects extra_have;
  
+       memset(&extra_have, 0, sizeof(extra_have));
        if (args.send_all)
                flags |= MATCH_REFS_ALL;
        if (args.send_mirror)
                flags |= MATCH_REFS_MIRROR;
  
        /* No funny business with the matcher */
-       remote_tail = get_remote_heads(in, &remote_refs, 0, NULL, REF_NORMAL);
+       remote_tail = get_remote_heads(in, &remote_refs, 0, NULL, REF_NORMAL,
+                                      &extra_have);
        get_local_heads();
  
        /* Does the other end support the reporting? */
  
        packet_flush(out);
        if (new_refs && !args.dry_run) {
-               if (pack_objects(out, remote_refs) < 0)
+               if (pack_objects(out, remote_refs, &extra_have) < 0)
                        return -1;
        }
        else
diff --combined builtin.h
index 8893b3ca59e650f88384ddc19389cfe96088e654,5d7cdca70c011b817b824ef77c5da71b2b80c64a..1495cf6a20128ccffb981c3ac4d1da5469da1940
+++ b/builtin.h
@@@ -17,8 -17,7 +17,8 @@@ extern int read_line_with_nul(char *buf
  extern int fmt_merge_msg(int merge_summary, struct strbuf *in,
        struct strbuf *out);
  extern int commit_tree(const char *msg, unsigned char *tree,
 -              struct commit_list *parents, unsigned char *ret);
 +              struct commit_list *parents, unsigned char *ret,
 +              const char *author);
  extern int check_pager_config(const char *cmd);
  
  extern int cmd_add(int argc, const char **argv, const char *prefix);
@@@ -79,6 -78,7 +79,7 @@@ extern int cmd_prune(int argc, const ch
  extern int cmd_prune_packed(int argc, const char **argv, const char *prefix);
  extern int cmd_push(int argc, const char **argv, const char *prefix);
  extern int cmd_read_tree(int argc, const char **argv, const char *prefix);
+ extern int cmd_receive_pack(int argc, const char **argv, const char *prefix);
  extern int cmd_reflog(int argc, const char **argv, const char *prefix);
  extern int cmd_remote(int argc, const char **argv, const char *prefix);
  extern int cmd_config(int argc, const char **argv, const char *prefix);
diff --combined daemon.c
index 0e026f65ecc089c869979069b33aabc1008d3f68,ab7a273859b66f5f2ae09deb0e2203121fb0c12e..3e5582d28921af22357f2d6068ef55f847bd016a
+++ b/daemon.c
@@@ -1083,8 -1083,7 +1083,8 @@@ int main(int argc, char **argv
                openlog("git-daemon", LOG_PID, LOG_DAEMON);
                set_die_routine(daemon_die);
        } else
 -              setlinebuf(stderr); /* avoid splitting a message in the middle */
 +              /* avoid splitting a message in the middle */
 +              setvbuf(stderr, NULL, _IOLBF, 0);
  
        if (inetd_mode && (group_name || user_name))
                die("--user and --group are incompatible with --inetd");
        if (strict_paths && (!ok_paths || !*ok_paths))
                die("option --strict-paths requires a whitelist");
  
-       if (base_path) {
-               struct stat st;
-               if (stat(base_path, &st) || !S_ISDIR(st.st_mode))
-                       die("base-path '%s' does not exist or "
-                           "is not a directory", base_path);
-       }
+       if (base_path && !is_directory(base_path))
+               die("base-path '%s' does not exist or is not a directory",
+                   base_path);
  
        if (inetd_mode) {
                struct sockaddr_storage ss;
diff --combined git.c
index 00f5dd1d4994ff44c5d718ee8f9ea9d21777245f,2f5b4d72ee249821f88617a4d5a8bbf3a0204340..f4b0cf611b8a281d51970fa088c7271f0aacf21c
--- 1/git.c
--- 2/git.c
+++ b/git.c
@@@ -162,8 -162,6 +162,8 @@@ static int handle_alias(int *argcp, con
                            alias_string + 1, alias_command);
                }
                count = split_cmdline(alias_string, &new_argv);
 +              if (count < 0)
 +                      die("Bad alias.%s string", alias_command);
                option_count = handle_options(&new_argv, &count, &envchanged);
                if (envchanged)
                        die("alias '%s' changes environment variables\n"
@@@ -330,6 -328,7 +330,7 @@@ static void handle_internal_command(in
                { "prune-packed", cmd_prune_packed, RUN_SETUP },
                { "push", cmd_push, RUN_SETUP },
                { "read-tree", cmd_read_tree, RUN_SETUP },
+               { "receive-pack", cmd_receive_pack },
                { "reflog", cmd_reflog, RUN_SETUP },
                { "remote", cmd_remote, RUN_SETUP },
                { "repo-config", cmd_config },
        if (sizeof(ext) > 1) {
                i = strlen(argv[0]) - strlen(ext);
                if (i > 0 && !strcmp(argv[0] + i, ext)) {
 -                      char *argv0 = strdup(argv[0]);
 +                      char *argv0 = xstrdup(argv[0]);
                        argv[0] = cmd = argv0;
                        argv0[i] = '\0';
                }
diff --combined sha1_file.c
index 7d4f24d56446570f71f99bfa974879a937873c57,12be17b5dace07a2ca71613e4e9093cdb77492ac..70ff904717c2ffed12a70b988b1aa4dea3a896e2
@@@ -99,11 -99,7 +99,11 @@@ int safe_create_leading_directories(cha
                pos = strchr(pos, '/');
                if (!pos)
                        break;
 -              *pos = 0;
 +              while (*++pos == '/')
 +                      ;
 +              if (!*pos)
 +                      break;
 +              *--pos = '\0';
                if (!stat(path, &st)) {
                        /* path exists */
                        if (!S_ISDIR(st.st_mode)) {
@@@ -254,7 -250,6 +254,6 @@@ static void read_info_alternates(const 
   */
  static int link_alt_odb_entry(const char * entry, int len, const char * relative_base, int depth)
  {
-       struct stat st;
        const char *objdir = get_object_directory();
        struct alternate_object_database *ent;
        struct alternate_object_database *alt;
        ent->base[pfxlen] = ent->base[entlen-1] = 0;
  
        /* Detect cases where alternate disappeared */
-       if (stat(ent->base, &st) || !S_ISDIR(st.st_mode)) {
+       if (!is_directory(ent->base)) {
                error("object directory %s does not exist; "
                      "check .git/objects/info/alternates.",
                      ent->base);
@@@ -398,6 -393,16 +397,16 @@@ void add_to_alternates_file(const char 
                link_alt_odb_entries(alt, alt + strlen(alt), '\n', NULL, 0);
  }
  
+ void foreach_alt_odb(alt_odb_fn fn, void *cb)
+ {
+       struct alternate_object_database *ent;
+       prepare_alt_odb();
+       for (ent = alt_odb_list; ent; ent = ent->next)
+               if (fn(ent, cb))
+                       return;
+ }
  void prepare_alt_odb(void)
  {
        const char *alt;
@@@ -2140,9 -2145,7 +2149,9 @@@ static void write_sha1_file_prepare(con
   */
  int move_temp_to_file(const char *tmpfile, const char *filename)
  {
 -      int ret = link(tmpfile, filename);
 +      int ret = 0;
 +      if (link(tmpfile, filename))
 +              ret = errno;
  
        /*
         * Coda hack - coda doesn't like cross-directory links,