Merge branch 'fix'
authorJunio C Hamano <junkio@cox.net>
Mon, 15 May 2006 20:48:22 +0000 (13:48 -0700)
committerJunio C Hamano <junkio@cox.net>
Mon, 15 May 2006 20:48:22 +0000 (13:48 -0700)
* fix:
  Fix pack-index issue on 64-bit platforms a bit more portably.
  Install git-send-email by default
  Fix compilation on newer NetBSD systems
  git config syntax updates
  Another config file parsing fix.
  checkout: use --aggressive when running a 3-way merge (-m).

1  2 
Makefile
pack-objects.c
repo-config.c
sha1_file.c
t/t1300-repo-config.sh

diff --combined Makefile
+++ b/Makefile
@@@ -115,13 -115,13 +115,13 @@@ SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__pow
  SCRIPT_SH = \
        git-add.sh git-bisect.sh git-branch.sh git-checkout.sh \
        git-cherry.sh git-clean.sh git-clone.sh git-commit.sh \
 -      git-count-objects.sh git-diff.sh git-fetch.sh \
 +      git-fetch.sh \
        git-format-patch.sh git-ls-remote.sh \
        git-merge-one-file.sh git-parse-remote.sh \
 -      git-prune.sh git-pull.sh git-push.sh git-rebase.sh \
 +      git-prune.sh git-pull.sh git-rebase.sh \
        git-repack.sh git-request-pull.sh git-reset.sh \
        git-resolve.sh git-revert.sh git-rm.sh git-sh-setup.sh \
 -      git-tag.sh git-verify-tag.sh git-whatchanged.sh \
 +      git-tag.sh git-verify-tag.sh \
        git-applymbox.sh git-applypatch.sh git-am.sh \
        git-merge.sh git-merge-stupid.sh git-merge-octopus.sh \
        git-merge-resolve.sh git-merge-ours.sh git-grep.sh \
@@@ -140,7 -140,7 +140,7 @@@ SCRIPT_PYTHON = 
  SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) \
          $(patsubst %.perl,%,$(SCRIPT_PERL)) \
          $(patsubst %.py,%,$(SCRIPT_PYTHON)) \
 -        git-cherry-pick git-show git-status
 +        git-cherry-pick git-status
  
  # The ones that do not have to link with lcrypto, lz nor xdiff.
  SIMPLE_PROGRAMS = \
@@@ -168,8 -168,7 +168,8 @@@ PROGRAMS = 
        git-name-rev$X git-pack-redundant$X git-repo-config$X git-var$X \
        git-describe$X git-merge-tree$X git-blame$X git-imap-send$X
  
 -BUILT_INS = git-log$X
 +BUILT_INS = git-log$X git-whatchanged$X git-show$X \
 +      git-count-objects$X git-diff$X git-push$X
  
  # what 'all' will build and 'install' will install, in gitexecdir
  ALL_PROGRAMS = $(PROGRAMS) $(SIMPLE_PROGRAMS) $(SCRIPTS)
@@@ -201,12 -200,12 +201,12 @@@ LIB_H = 
        tree-walk.h log-tree.h
  
  DIFF_OBJS = \
 -      diff.o diffcore-break.o diffcore-order.o \
 +      diff.o diff-lib.o diffcore-break.o diffcore-order.o \
        diffcore-pickaxe.o diffcore-rename.o tree-diff.o combine-diff.o \
        diffcore-delta.o log-tree.o
  
  LIB_OBJS = \
 -      blob.o commit.o connect.o csum-file.o \
 +      blob.o commit.o connect.o csum-file.o base85.o \
        date.o diff-delta.o entry.o exec_cmd.o ident.o index.o \
        object.o pack-check.o patch-delta.o path.o pkt-line.o \
        quote.o read-cache.o refs.o run-command.o \
        fetch-clone.o revision.o pager.o tree-walk.o xdiff-interface.o \
        $(DIFF_OBJS)
  
 +BUILTIN_OBJS = \
 +      builtin-log.o builtin-help.o builtin-count.o builtin-diff.o builtin-push.o
 +
  GITLIBS = $(LIB_FILE) $(XDIFF_LIB)
  LIBS = $(GITLIBS) -lz
  
@@@ -286,7 -282,9 +286,9 @@@ ifeq ($(uname_S),OpenBSD
        ALL_LDFLAGS += -L/usr/local/lib
  endif
  ifeq ($(uname_S),NetBSD)
-       NEEDS_LIBICONV = YesPlease
+       ifeq ($(shell expr "$(uname_R)" : '[01]\.'),2)
+               NEEDS_LIBICONV = YesPlease
+       endif
        ALL_CFLAGS += -I/usr/pkg/include
        ALL_LDFLAGS += -L/usr/pkg/lib -Wl,-rpath,/usr/pkg/lib
  endif
@@@ -467,12 -465,10 +469,12 @@@ all
  strip: $(PROGRAMS) git$X
        $(STRIP) $(STRIP_OPTS) $(PROGRAMS) git$X
  
 -git$X: git.c common-cmds.h $(GITLIBS)
 +git$X: git.c common-cmds.h $(BUILTIN_OBJS) $(GITLIBS)
        $(CC) -DGIT_VERSION='"$(GIT_VERSION)"' \
                $(ALL_CFLAGS) -o $@ $(filter %.c,$^) \
 -              $(ALL_LDFLAGS) $(LIBS)
 +              $(BUILTIN_OBJS) $(ALL_LDFLAGS) $(LIBS)
 +
 +builtin-help.o: common-cmds.h
  
  $(BUILT_INS): git$X
        rm -f $@ && ln git$X $@
@@@ -507,6 -503,9 +509,6 @@@ $(patsubst %.py,%,$(SCRIPT_PYTHON)) : 
  git-cherry-pick: git-revert
        cp $< $@
  
 -git-show: git-whatchanged
 -      cp $< $@
 -
  git-status: git-commit
        cp $< $@
  
@@@ -561,21 -560,25 +563,21 @@@ git-http-push$X: revision.o http.o http
        $(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
                $(LIBS) $(CURL_LIBCURL) $(EXPAT_LIBEXPAT)
  
 -git-rev-list$X: rev-list.o $(LIB_FILE)
 -      $(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
 -              $(LIBS) $(OPENSSL_LIBSSL)
 -
  init-db.o: init-db.c
        $(CC) -c $(ALL_CFLAGS) \
                -DDEFAULT_GIT_TEMPLATE_DIR='"$(template_dir_SQ)"' $*.c
  
 -$(LIB_OBJS): $(LIB_H)
 +$(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H)
  $(patsubst git-%$X,%.o,$(PROGRAMS)): $(GITLIBS)
  $(DIFF_OBJS): diffcore.h
  
  $(LIB_FILE): $(LIB_OBJS)
 -      $(AR) rcs $@ $(LIB_OBJS)
 +      rm -f $@ && $(AR) rcs $@ $(LIB_OBJS)
  
  XDIFF_OBJS=xdiff/xdiffi.o xdiff/xprepare.o xdiff/xutils.o xdiff/xemit.o
  
  $(XDIFF_LIB): $(XDIFF_OBJS)
 -      $(AR) rcs $@ $(XDIFF_OBJS)
 +      rm -f $@ && $(AR) rcs $@ $(XDIFF_OBJS)
  
  
  doc:
@@@ -604,7 -607,7 +606,7 @@@ test-date$X: test-date.c date.o ctype.
        $(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) test-date.c date.o ctype.o
  
  test-delta$X: test-delta.c diff-delta.o patch-delta.o
 -      $(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $^ -lz
 +      $(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $^
  
  check:
        for i in *.c; do sparse $(ALL_CFLAGS) $(SPARSE_FLAGS) $$i || exit; done
diff --combined pack-objects.c
@@@ -10,7 -10,6 +10,6 @@@
  #include "tree-walk.h"
  #include <sys/time.h>
  #include <signal.h>
- #include <stdint.h>
  
  static const char pack_usage[] = "git-pack-objects [-q] [--no-reuse-delta] [--non-empty] [--local] [--incremental] [--window=N] [--depth=N] {--stdout | base-name} < object-list";
  
@@@ -157,7 -156,7 +156,7 @@@ static void prepare_pack_revindex(struc
  
        rix->revindex = xmalloc(sizeof(unsigned long) * (num_ent + 1));
        for (i = 0; i < num_ent; i++) {
-               uint32_t hl = *((uint32_t *)(index + 24 * i));
+               unsigned int hl = *((unsigned int *)(index + 24 * i));
                rix->revindex[i] = ntohl(hl);
        }
        /* This knows the pack format -- the 20-byte trailer
@@@ -995,7 -994,6 +994,7 @@@ static int type_size_sort(const struct 
  struct unpacked {
        struct object_entry *entry;
        void *data;
 +      struct delta_index *index;
  };
  
  /*
   * more importantly, the bigger file is likely the more recent
   * one.
   */
 -static int try_delta(struct unpacked *cur, struct unpacked *old, unsigned max_depth)
 +static int try_delta(struct unpacked *trg, struct unpacked *src,
 +                   struct delta_index *src_index, unsigned max_depth)
  {
 -      struct object_entry *cur_entry = cur->entry;
 -      struct object_entry *old_entry = old->entry;
 -      unsigned long size, oldsize, delta_size, sizediff;
 -      long max_size;
 +      struct object_entry *trg_entry = trg->entry;
 +      struct object_entry *src_entry = src->entry;
 +      unsigned long size, src_size, delta_size, sizediff, max_size;
        void *delta_buf;
  
        /* Don't bother doing diffs between different types */
 -      if (cur_entry->type != old_entry->type)
 +      if (trg_entry->type != src_entry->type)
                return -1;
  
        /* We do not compute delta to *create* objects we are not
         * going to pack.
         */
 -      if (cur_entry->preferred_base)
 +      if (trg_entry->preferred_base)
                return -1;
  
 -      /* If the current object is at pack edge, take the depth the
 +      /*
 +       * If the current object is at pack edge, take the depth the
         * objects that depend on the current object into account --
         * otherwise they would become too deep.
         */
 -      if (cur_entry->delta_child) {
 -              if (max_depth <= cur_entry->delta_limit)
 +      if (trg_entry->delta_child) {
 +              if (max_depth <= trg_entry->delta_limit)
                        return 0;
 -              max_depth -= cur_entry->delta_limit;
 +              max_depth -= trg_entry->delta_limit;
        }
 -
 -      size = cur_entry->size;
 -      oldsize = old_entry->size;
 -      sizediff = oldsize > size ? oldsize - size : size - oldsize;
 -
 -      if (size < 50)
 -              return -1;
 -      if (old_entry->depth >= max_depth)
 +      if (src_entry->depth >= max_depth)
                return 0;
  
 -      /*
 -       * NOTE!
 -       *
 -       * We always delta from the bigger to the smaller, since that's
 -       * more space-efficient (deletes don't have to say _what_ they
 -       * delete).
 -       */
 +      /* Now some size filtering euristics. */
 +      size = trg_entry->size;
        max_size = size / 2 - 20;
 -      if (cur_entry->delta)
 -              max_size = cur_entry->delta_size-1;
 +      if (trg_entry->delta)
 +              max_size = trg_entry->delta_size-1;
 +      src_size = src_entry->size;
 +      sizediff = src_size < size ? size - src_size : 0;
        if (sizediff >= max_size)
                return 0;
 -      delta_buf = diff_delta(old->data, oldsize,
 -                             cur->data, size, &delta_size, max_size);
 +
 +      delta_buf = create_delta(src_index, trg->data, size, &delta_size, max_size);
        if (!delta_buf)
                return 0;
 -      cur_entry->delta = old_entry;
 -      cur_entry->delta_size = delta_size;
 -      cur_entry->depth = old_entry->depth + 1;
 +
 +      trg_entry->delta = src_entry;
 +      trg_entry->delta_size = delta_size;
 +      trg_entry->depth = src_entry->depth + 1;
        free(delta_buf);
 -      return 0;
 +      return 1;
  }
  
  static void progress_interval(int signum)
@@@ -1103,19 -1109,11 +1102,19 @@@ static void find_deltas(struct object_e
                         */
                        continue;
  
 +              if (entry->size < 50)
 +                      continue;
 +              if (n->index)
 +                      free_delta_index(n->index);
                free(n->data);
                n->entry = entry;
                n->data = read_sha1_file(entry->sha1, type, &size);
                if (size != entry->size)
 -                      die("object %s inconsistent object length (%lu vs %lu)", sha1_to_hex(entry->sha1), size, entry->size);
 +                      die("object %s inconsistent object length (%lu vs %lu)",
 +                          sha1_to_hex(entry->sha1), size, entry->size);
 +              n->index = create_delta_index(n->data, size);
 +              if (!n->index)
 +                      die("out of memory");
  
                j = window;
                while (--j > 0) {
                        m = array + other_idx;
                        if (!m->entry)
                                break;
 -                      if (try_delta(n, m, depth) < 0)
 +                      if (try_delta(n, m, m->index, depth) < 0)
                                break;
                }
  #if 0
        if (progress)
                fputc('\n', stderr);
  
 -      for (i = 0; i < window; ++i)
 +      for (i = 0; i < window; ++i) {
 +              if (array[i].index)
 +                      free_delta_index(array[i].index);
                free(array[i].data);
 +      }
        free(array);
  }
  
@@@ -1244,7 -1239,6 +1243,7 @@@ int main(int argc, char **argv
  
        setup_git_directory();
  
 +      progress = isatty(2);
        for (i = 1; i < argc; i++) {
                const char *arg = argv[i];
  
                                        usage(pack_usage);
                                continue;
                        }
 +                      if (!strcmp("--progress", arg)) {
 +                              progress = 1;
 +                              continue;
 +                      }
                        if (!strcmp("-q", arg)) {
                                progress = 0;
                                continue;
diff --combined repo-config.c
@@@ -2,83 -2,60 +2,85 @@@
  #include <regex.h>
  
  static const char git_config_set_usage[] =
 -"git-repo-config [ --bool | --int ] [--get | --get-all | --replace-all | --unset | --unset-all] name [value [value_regex]]";
 +"git-repo-config [ --bool | --int ] [--get | --get-all | --get-regexp | --replace-all | --unset | --unset-all] name [value [value_regex]] | --list";
  
  static char* key = NULL;
 -static char* value = NULL;
 +static regex_t* key_regexp = NULL;
  static regex_t* regexp = NULL;
 +static int show_keys = 0;
 +static int use_key_regexp = 0;
  static int do_all = 0;
  static int do_not_match = 0;
  static int seen = 0;
  static enum { T_RAW, T_INT, T_BOOL } type = T_RAW;
  
 +static int show_all_config(const char *key_, const char *value_)
 +{
 +      if (value_)
 +              printf("%s=%s\n", key_, value_);
 +      else
 +              printf("%s\n", key_);
 +      return 0;
 +}
 +
  static int show_config(const char* key_, const char* value_)
  {
 +      char value[256];
 +      const char *vptr = value;
 +      int dup_error = 0;
 +
        if (value_ == NULL)
                value_ = "";
  
 -      if (!strcmp(key_, key) &&
 -                      (regexp == NULL ||
 +      if (!use_key_regexp && strcmp(key_, key))
 +              return 0;
 +      if (use_key_regexp && regexec(key_regexp, key_, 0, NULL, 0))
 +              return 0;
 +      if (regexp != NULL &&
                         (do_not_match ^
 -                        !regexec(regexp, value_, 0, NULL, 0)))) {
 -              if (do_all) {
 -                      printf("%s\n", value_);
 -                      return 0;
 -              }
 -              if (seen > 0) {
 -                      fprintf(stderr, "More than one value: %s\n", value);
 -                      free(value);
 -              }
 +                        regexec(regexp, value_, 0, NULL, 0)))
 +              return 0;
  
 -              if (type == T_INT) {
 -                      value = malloc(256);
 -                      sprintf(value, "%d", git_config_int(key_, value_));
 -              } else if (type == T_BOOL) {
 -                      value = malloc(256);
 -                      sprintf(value, "%s", git_config_bool(key_, value_)
 -                                           ? "true" : "false");
 -              } else {
 -                      value = strdup(value_);
 -              }
 -              seen++;
 +      if (show_keys)
 +              printf("%s ", key_);
 +      if (seen && !do_all)
 +              dup_error = 1;
 +      if (type == T_INT)
 +              sprintf(value, "%d", git_config_int(key_, value_));
 +      else if (type == T_BOOL)
 +              vptr = git_config_bool(key_, value_) ? "true" : "false";
 +      else
 +              vptr = value_;
 +      seen++;
 +      if (dup_error) {
 +              error("More than one value for the key %s: %s",
 +                              key_, vptr);
        }
 +      else
 +              printf("%s\n", vptr);
 +
        return 0;
  }
  
  static int get_value(const char* key_, const char* regex_)
  {
        int i;
+       char *tl;
  
-       key = malloc(strlen(key_)+1);
-       for (i = 0; key_[i]; i++)
-               key[i] = tolower(key_[i]);
-       key[i] = 0;
+       key = strdup(key_);
+       for (tl=key+strlen(key)-1; tl >= key && *tl != '.'; --tl)
+               *tl = tolower(*tl);
+       for (tl=key; *tl && *tl != '.'; ++tl)
+               *tl = tolower(*tl);
  
 +      if (use_key_regexp) {
 +              key_regexp = (regex_t*)malloc(sizeof(regex_t));
 +              if (regcomp(key_regexp, key, REG_EXTENDED)) {
 +                      fprintf(stderr, "Invalid key pattern: %s\n", key_);
 +                      return -1;
 +              }
 +      }
 +
        if (regex_) {
                if (regex_[0] == '!') {
                        do_not_match = 1;
                }
        }
  
 -      i = git_config(show_config);
 -      if (value) {
 -              printf("%s\n", value);
 -              free(value);
 -      }
 +      git_config(show_config);
        free(key);
        if (regexp) {
                regfree(regexp);
        }
  
        if (do_all)
 -              return 0;
 +              return !seen;
  
 -      return seen == 1 ? 0 : 1;
 +      return (seen == 1) ? 0 : 1;
  }
  
  int main(int argc, const char **argv)
                        type = T_INT;
                else if (!strcmp(argv[1], "--bool"))
                        type = T_BOOL;
 +              else if (!strcmp(argv[1], "--list") || !strcmp(argv[1], "-l"))
 +                      return git_config(show_all_config);
                else
                        break;
                argc--;
                else if (!strcmp(argv[1], "--get-all")) {
                        do_all = 1;
                        return get_value(argv[2], NULL);
 +              } else if (!strcmp(argv[1], "--get-regexp")) {
 +                      show_keys = 1;
 +                      use_key_regexp = 1;
 +                      do_all = 1;
 +                      return get_value(argv[2], NULL);
                } else
  
                        return git_config_set(argv[1], argv[2]);
                else if (!strcmp(argv[1], "--get-all")) {
                        do_all = 1;
                        return get_value(argv[2], argv[3]);
 +              } else if (!strcmp(argv[1], "--get-regexp")) {
 +                      show_keys = 1;
 +                      use_key_regexp = 1;
 +                      do_all = 1;
 +                      return get_value(argv[2], argv[3]);
                } else if (!strcmp(argv[1], "--replace-all"))
  
                        return git_config_set_multivar(argv[2], argv[3], NULL, 1);
diff --combined sha1_file.c
@@@ -13,7 -13,6 +13,6 @@@
  #include "commit.h"
  #include "tag.h"
  #include "tree.h"
- #include <stdint.h>
  
  #ifndef O_NOATIME
  #if defined(__linux__) && (defined(__i386__) || defined(__PPC__))
@@@ -109,10 -108,9 +108,10 @@@ int safe_create_leading_directories(cha
  
  char * sha1_to_hex(const unsigned char *sha1)
  {
 -      static char buffer[50];
 +      static int bufno;
 +      static char hexbuffer[4][50];
        static const char hex[] = "0123456789abcdef";
 -      char *buf = buffer;
 +      char *buffer = hexbuffer[3 & ++bufno], *buf = buffer;
        int i;
  
        for (i = 0; i < 20; i++) {
@@@ -218,8 -216,6 +217,8 @@@ char *sha1_pack_index_name(const unsign
  struct alternate_object_database *alt_odb_list;
  static struct alternate_object_database **alt_odb_tail;
  
 +static void read_info_alternates(const char * alternates, int depth);
 +
  /*
   * Prepare alternate object database registry.
   *
   * SHA1, an extra slash for the first level indirection, and the
   * terminating NUL.
   */
 -static void link_alt_odb_entries(const char *alt, const char *ep, int sep,
 -                               const char *relative_base)
 +static int link_alt_odb_entry(const char * entry, int len, const char * relative_base, int depth)
  {
 -      const char *cp, *last;
 -      struct alternate_object_database *ent;
 +      struct stat st;
        const char *objdir = get_object_directory();
 +      struct alternate_object_database *ent;
 +      struct alternate_object_database *alt;
 +      /* 43 = 40-byte + 2 '/' + terminating NUL */
 +      int pfxlen = len;
 +      int entlen = pfxlen + 43;
        int base_len = -1;
  
 +      if (*entry != '/' && relative_base) {
 +              /* Relative alt-odb */
 +              if (base_len < 0)
 +                      base_len = strlen(relative_base) + 1;
 +              entlen += base_len;
 +              pfxlen += base_len;
 +      }
 +      ent = xmalloc(sizeof(*ent) + entlen);
 +
 +      if (*entry != '/' && relative_base) {
 +              memcpy(ent->base, relative_base, base_len - 1);
 +              ent->base[base_len - 1] = '/';
 +              memcpy(ent->base + base_len, entry, len);
 +      }
 +      else
 +              memcpy(ent->base, entry, pfxlen);
 +
 +      ent->name = ent->base + pfxlen + 1;
 +      ent->base[pfxlen + 3] = '/';
 +      ent->base[pfxlen] = ent->base[entlen-1] = 0;
 +
 +      /* Detect cases where alternate disappeared */
 +      if (stat(ent->base, &st) || !S_ISDIR(st.st_mode)) {
 +              error("object directory %s does not exist; "
 +                    "check .git/objects/info/alternates.",
 +                    ent->base);
 +              free(ent);
 +              return -1;
 +      }
 +
 +      /* Prevent the common mistake of listing the same
 +       * thing twice, or object directory itself.
 +       */
 +      for (alt = alt_odb_list; alt; alt = alt->next) {
 +              if (!memcmp(ent->base, alt->base, pfxlen)) {
 +                      free(ent);
 +                      return -1;
 +              }
 +      }
 +      if (!memcmp(ent->base, objdir, pfxlen)) {
 +              free(ent);
 +              return -1;
 +      }
 +
 +      /* add the alternate entry */
 +      *alt_odb_tail = ent;
 +      alt_odb_tail = &(ent->next);
 +      ent->next = NULL;
 +
 +      /* recursively add alternates */
 +      read_info_alternates(ent->base, depth + 1);
 +
 +      ent->base[pfxlen] = '/';
 +
 +      return 0;
 +}
 +
 +static void link_alt_odb_entries(const char *alt, const char *ep, int sep,
 +                               const char *relative_base, int depth)
 +{
 +      const char *cp, *last;
 +
 +      if (depth > 5) {
 +              error("%s: ignoring alternate object stores, nesting too deep.",
 +                              relative_base);
 +              return;
 +      }
 +
        last = alt;
        while (last < ep) {
                cp = last;
                        last = cp + 1;
                        continue;
                }
 -              for ( ; cp < ep && *cp != sep; cp++)
 -                      ;
 +              while (cp < ep && *cp != sep)
 +                      cp++;
                if (last != cp) {
 -                      struct stat st;
 -                      struct alternate_object_database *alt;
 -                      /* 43 = 40-byte + 2 '/' + terminating NUL */
 -                      int pfxlen = cp - last;
 -                      int entlen = pfxlen + 43;
 -
 -                      if (*last != '/' && relative_base) {
 -                              /* Relative alt-odb */
 -                              if (base_len < 0)
 -                                      base_len = strlen(relative_base) + 1;
 -                              entlen += base_len;
 -                              pfxlen += base_len;
 -                      }
 -                      ent = xmalloc(sizeof(*ent) + entlen);
 -
 -                      if (*last != '/' && relative_base) {
 -                              memcpy(ent->base, relative_base, base_len - 1);
 -                              ent->base[base_len - 1] = '/';
 -                              memcpy(ent->base + base_len,
 -                                     last, cp - last);
 -                      }
 -                      else
 -                              memcpy(ent->base, last, pfxlen);
 -
 -                      ent->name = ent->base + pfxlen + 1;
 -                      ent->base[pfxlen + 3] = '/';
 -                      ent->base[pfxlen] = ent->base[entlen-1] = 0;
 -
 -                      /* Detect cases where alternate disappeared */
 -                      if (stat(ent->base, &st) || !S_ISDIR(st.st_mode)) {
 -                              error("object directory %s does not exist; "
 -                                    "check .git/objects/info/alternates.",
 -                                    ent->base);
 -                              goto bad;
 -                      }
 -                      ent->base[pfxlen] = '/';
 -
 -                      /* Prevent the common mistake of listing the same
 -                       * thing twice, or object directory itself.
 -                       */
 -                      for (alt = alt_odb_list; alt; alt = alt->next)
 -                              if (!memcmp(ent->base, alt->base, pfxlen))
 -                                      goto bad;
 -                      if (!memcmp(ent->base, objdir, pfxlen)) {
 -                      bad:
 -                              free(ent);
 -                      }
 -                      else {
 -                              *alt_odb_tail = ent;
 -                              alt_odb_tail = &(ent->next);
 -                              ent->next = NULL;
 +                      if ((*last != '/') && depth) {
 +                              error("%s: ignoring relative alternate object store %s",
 +                                              relative_base, last);
 +                      } else {
 +                              link_alt_odb_entry(last, cp - last,
 +                                              relative_base, depth);
                        }
                }
                while (cp < ep && *cp == sep)
        }
  }
  
 -void prepare_alt_odb(void)
 +static void read_info_alternates(const char * relative_base, int depth)
  {
 -      char path[PATH_MAX];
        char *map;
 -      int fd;
        struct stat st;
 -      char *alt;
 -
 -      alt = getenv(ALTERNATE_DB_ENVIRONMENT);
 -      if (!alt) alt = "";
 -
 -      if (alt_odb_tail)
 -              return;
 -      alt_odb_tail = &alt_odb_list;
 -      link_alt_odb_entries(alt, alt + strlen(alt), ':', NULL);
 +      char path[PATH_MAX];
 +      int fd;
  
 -      sprintf(path, "%s/info/alternates", get_object_directory());
 +      sprintf(path, "%s/info/alternates", relative_base);
        fd = open(path, O_RDONLY);
        if (fd < 0)
                return;
        if (map == MAP_FAILED)
                return;
  
 -      link_alt_odb_entries(map, map + st.st_size, '\n',
 -                           get_object_directory());
 +      link_alt_odb_entries(map, map + st.st_size, '\n', relative_base, depth);
 +
        munmap(map, st.st_size);
  }
  
 +void prepare_alt_odb(void)
 +{
 +      char *alt;
 +
 +      alt = getenv(ALTERNATE_DB_ENVIRONMENT);
 +      if (!alt) alt = "";
 +
 +      if (alt_odb_tail)
 +              return;
 +      alt_odb_tail = &alt_odb_list;
 +      link_alt_odb_entries(alt, alt + strlen(alt), ':', NULL, 0);
 +
 +      read_info_alternates(get_object_directory(), 0);
 +}
 +
  static char *find_sha1_file(const unsigned char *sha1, struct stat *st)
  {
        char *name = sha1_file_name(sha1);
@@@ -1162,7 -1126,7 +1161,7 @@@ int find_pack_entry_one(const unsigned 
                int mi = (lo + hi) / 2;
                int cmp = memcmp(index + 24 * mi + 4, sha1, 20);
                if (!cmp) {
-                       e->offset = ntohl(*((uint32_t *)(index + 24 * mi)));
+                       e->offset = ntohl(*((unsigned int *)(index + 24 * mi)));
                        memcpy(e->sha1, sha1, 20);
                        e->p = p;
                        return 1;
diff --combined t/t1300-repo-config.sh
@@@ -229,7 -229,7 +229,7 @@@ test_expect_failure 'invalid key' 'git-
  test_expect_success 'correct key' 'git-repo-config 123456.a123 987'
  
  test_expect_success 'hierarchical section' \
-       'git-repo-config 1.2.3.alpha beta'
+       'git-repo-config Version.1.2.3eX.Alpha beta'
  
  cat > expect << EOF
  [beta] ; silly comment # another comment
@@@ -241,30 -241,12 +241,30 @@@ noIndent= sillyValue ; 'nother silly co
        NoNewLine = wow2 for me
  [123456]
        a123 = 987
- [1.2.3]
-       alpha = beta
+ [Version "1.2.3eX"]
+       Alpha = beta
  EOF
  
  test_expect_success 'hierarchical section value' 'cmp .git/config expect'
  
- 1.2.3.alpha=beta
 +cat > expect << EOF
 +beta.noindent=sillyValue
 +nextsection.nonewline=wow2 for me
 +123456.a123=987
++version.1.2.3eX.alpha=beta
 +EOF
 +
 +test_expect_success 'working --list' \
 +      'git-repo-config --list > output && cmp output expect'
 +
 +cat > expect << EOF
 +beta.noindent sillyValue
 +nextsection.nonewline wow2 for me
 +EOF
 +
 +test_expect_success '--get-regexp' \
 +      'git-repo-config --get-regexp in > output && cmp output expect'
 +
  cat > .git/config << EOF
  [novalue]
        variable
@@@ -273,41 -255,5 +273,41 @@@ EO
  test_expect_success 'get variable with no value' \
        'git-repo-config --get novalue.variable ^$'
  
 +git-repo-config > output 2>&1
 +
 +test_expect_success 'no arguments, but no crash' \
 +      "test $? = 129 && grep usage output"
 +
 +cat > .git/config << EOF
 +[a.b]
 +      c = d
 +EOF
 +
 +git-repo-config a.x y
 +
 +cat > expect << EOF
 +[a.b]
 +      c = d
 +[a]
 +      x = y
 +EOF
 +
 +test_expect_success 'new section is partial match of another' 'cmp .git/config expect'
 +
 +git-repo-config b.x y
 +git-repo-config a.b c
 +
 +cat > expect << EOF
 +[a.b]
 +      c = d
 +[a]
 +      x = y
 +      b = c
 +[b]
 +      x = y
 +EOF
 +
 +test_expect_success 'new variable inserts into proper section' 'cmp .git/config expect'
 +
  test_done