Merge branch 'nd/tag-version-sort'
authorJunio C Hamano <gitster@pobox.com>
Fri, 21 Mar 2014 19:47:38 +0000 (12:47 -0700)
committerJunio C Hamano <gitster@pobox.com>
Fri, 21 Mar 2014 19:47:39 +0000 (12:47 -0700)
Allow v1.9.0 sorted before v1.10.0 in "git tag --list" output.

* nd/tag-version-sort:
tag: support --sort=<spec>

1  2 
Makefile
builtin/tag.c
cache.h
diff --combined Makefile
index f818eecaf380c109be248f424d5c8f3a537359e0,16b00a5be29fcbf8070a8d0f9076913b3891fc89..36463919afd6ee40c3a0487e481ebbaadce7b6d8
+++ b/Makefile
@@@ -101,6 -101,14 +101,6 @@@ all:
  #
  # Define NO_MKSTEMPS if you don't have mkstemps in the C library.
  #
 -# Define NO_FNMATCH if you don't have fnmatch in the C library.
 -#
 -# Define NO_FNMATCH_CASEFOLD if your fnmatch function doesn't have the
 -# FNM_CASEFOLD GNU extension.
 -#
 -# Define NO_WILDMATCH if you do not want to use Git's wildmatch
 -# implementation as fnmatch
 -#
  # Define NO_GECOS_IN_PWENT if you don't have pw_gecos in struct passwd
  # in the C library.
  #
  # Define DEFAULT_HELP_FORMAT to "man", "info" or "html"
  # (defaults to "man") if you want to have a different default when
  # "git help" is called without a parameter specifying the format.
 +#
 +# Define TEST_GIT_INDEX_VERSION to 2, 3 or 4 to run the test suite
 +# with a different indexfile format version.  If it isn't set the index
 +# file format used is index-v[23].
  
  GIT-VERSION-FILE: FORCE
        @$(SHELL_PATH) ./GIT-VERSION-GEN
@@@ -551,7 -555,6 +551,7 @@@ TEST_PROGRAMS_NEED_X += test-dat
  TEST_PROGRAMS_NEED_X += test-delta
  TEST_PROGRAMS_NEED_X += test-dump-cache-tree
  TEST_PROGRAMS_NEED_X += test-genrandom
 +TEST_PROGRAMS_NEED_X += test-hashmap
  TEST_PROGRAMS_NEED_X += test-index-version
  TEST_PROGRAMS_NEED_X += test-line-buffer
  TEST_PROGRAMS_NEED_X += test-match-trees
@@@ -660,8 -663,6 +660,8 @@@ LIB_H += diff.
  LIB_H += diffcore.h
  LIB_H += dir.h
  LIB_H += exec_cmd.h
 +LIB_H += ewah/ewok.h
 +LIB_H += ewah/ewok_rlw.h
  LIB_H += fetch-pack.h
  LIB_H += fmt-merge-msg.h
  LIB_H += fsck.h
@@@ -670,7 -671,7 +670,7 @@@ LIB_H += git-compat-util.
  LIB_H += gpg-interface.h
  LIB_H += graph.h
  LIB_H += grep.h
 -LIB_H += hash.h
 +LIB_H += hashmap.h
  LIB_H += help.h
  LIB_H += http.h
  LIB_H += kwset.h
@@@ -689,10 -690,8 +689,10 @@@ LIB_H += notes-merge.
  LIB_H += notes-utils.h
  LIB_H += notes.h
  LIB_H += object.h
 +LIB_H += pack-objects.h
  LIB_H += pack-revindex.h
  LIB_H += pack.h
 +LIB_H += pack-bitmap.h
  LIB_H += parse-options.h
  LIB_H += patch-ids.h
  LIB_H += pathspec.h
@@@ -796,10 -795,6 +796,10 @@@ LIB_OBJS += dir.
  LIB_OBJS += editor.o
  LIB_OBJS += entry.o
  LIB_OBJS += environment.o
 +LIB_OBJS += ewah/bitmap.o
 +LIB_OBJS += ewah/ewah_bitmap.o
 +LIB_OBJS += ewah/ewah_io.o
 +LIB_OBJS += ewah/ewah_rlw.o
  LIB_OBJS += exec_cmd.o
  LIB_OBJS += fetch-pack.o
  LIB_OBJS += fsck.o
@@@ -807,7 -802,7 +807,7 @@@ LIB_OBJS += gettext.
  LIB_OBJS += gpg-interface.o
  LIB_OBJS += graph.o
  LIB_OBJS += grep.o
 -LIB_OBJS += hash.o
 +LIB_OBJS += hashmap.o
  LIB_OBJS += help.o
  LIB_OBJS += hex.o
  LIB_OBJS += ident.o
@@@ -831,10 -826,7 +831,10 @@@ LIB_OBJS += notes-cache.
  LIB_OBJS += notes-merge.o
  LIB_OBJS += notes-utils.o
  LIB_OBJS += object.o
 +LIB_OBJS += pack-bitmap.o
 +LIB_OBJS += pack-bitmap-write.o
  LIB_OBJS += pack-check.o
 +LIB_OBJS += pack-objects.o
  LIB_OBJS += pack-revindex.o
  LIB_OBJS += pack-write.o
  LIB_OBJS += pager.o
@@@ -892,6 -884,7 +892,7 @@@ LIB_OBJS += userdiff.
  LIB_OBJS += utf8.o
  LIB_OBJS += varint.o
  LIB_OBJS += version.o
+ LIB_OBJS += versioncmp.o
  LIB_OBJS += walker.o
  LIB_OBJS += wildmatch.o
  LIB_OBJS += wrapper.o
@@@ -1279,6 -1272,20 +1280,6 @@@ endi
  ifdef NO_STRTOULL
        COMPAT_CFLAGS += -DNO_STRTOULL
  endif
 -ifdef NO_FNMATCH
 -      COMPAT_CFLAGS += -Icompat/fnmatch
 -      COMPAT_CFLAGS += -DNO_FNMATCH
 -      COMPAT_OBJS += compat/fnmatch/fnmatch.o
 -else
 -ifdef NO_FNMATCH_CASEFOLD
 -      COMPAT_CFLAGS += -Icompat/fnmatch
 -      COMPAT_CFLAGS += -DNO_FNMATCH_CASEFOLD
 -      COMPAT_OBJS += compat/fnmatch/fnmatch.o
 -endif
 -endif
 -ifndef NO_WILDMATCH
 -      COMPAT_CFLAGS += -DUSE_WILDMATCH
 -endif
  ifdef NO_SETENV
        COMPAT_CFLAGS += -DNO_SETENV
        COMPAT_OBJS += compat/setenv.o
@@@ -2216,9 -2223,6 +2217,9 @@@ endi
  ifdef GIT_PERF_MAKE_OPTS
        @echo GIT_PERF_MAKE_OPTS=\''$(subst ','\'',$(subst ','\'',$(GIT_PERF_MAKE_OPTS)))'\' >>$@
  endif
 +ifdef TEST_GIT_INDEX_VERSION
 +      @echo TEST_GIT_INDEX_VERSION=\''$(subst ','\'',$(subst ','\'',$(TEST_GIT_INDEX_VERSION)))'\' >>$@
 +endif
  
  ### Detect Python interpreter path changes
  ifndef NO_PYTHON
@@@ -2476,9 -2480,8 +2477,9 @@@ profile-clean
        $(RM) $(addsuffix *.gcno,$(addprefix $(PROFILE_DIR)/, $(object_dirs)))
  
  clean: profile-clean coverage-clean
 -      $(RM) *.o *.res block-sha1/*.o ppc/*.o compat/*.o compat/*/*.o xdiff/*.o vcs-svn/*.o \
 -              builtin/*.o $(LIB_FILE) $(XDIFF_LIB) $(VCSSVN_LIB)
 +      $(RM) *.o *.res block-sha1/*.o ppc/*.o compat/*.o compat/*/*.o
 +      $(RM) xdiff/*.o vcs-svn/*.o ewah/*.o builtin/*.o
 +      $(RM) $(LIB_FILE) $(XDIFF_LIB) $(VCSSVN_LIB)
        $(RM) $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS) git$X
        $(RM) $(TEST_PROGRAMS) $(NO_INSTALL)
        $(RM) -r bin-wrappers $(dep_dirs)
diff --combined builtin/tag.c
index b7d9632867c06984a41ed14f4e13a58da4f457a4,0439c489f2f254dcf11b584ace7744d8b893261e..40356e3e41b44f87b565ebbed8ad0f7a5000b31d
@@@ -27,9 -27,16 +27,16 @@@ static const char * const git_tag_usage
        NULL
  };
  
+ #define STRCMP_SORT     0     /* must be zero */
+ #define VERCMP_SORT     1
+ #define SORT_MASK       0x7fff
+ #define REVERSE_SORT    0x8000
  struct tag_filter {
        const char **patterns;
        int lines;
+       int sort;
+       struct string_list tags;
        struct commit_list *with_commit;
  };
  
@@@ -42,7 -49,7 +49,7 @@@ static int match_pattern(const char **p
        if (!*patterns)
                return 1;
        for (; *patterns; patterns++)
 -              if (!fnmatch(*patterns, ref, 0))
 +              if (!wildmatch(*patterns, ref, 0, NULL))
                        return 1;
        return 0;
  }
@@@ -166,7 -173,10 +173,10 @@@ static int show_reference(const char *r
                        return 0;
  
                if (!filter->lines) {
-                       printf("%s\n", refname);
+                       if (filter->sort)
+                               string_list_append(&filter->tags, refname);
+                       else
+                               printf("%s\n", refname);
                        return 0;
                }
                printf("%-15s ", refname);
        return 0;
  }
  
+ static int sort_by_version(const void *a_, const void *b_)
+ {
+       const struct string_list_item *a = a_;
+       const struct string_list_item *b = b_;
+       return versioncmp(a->string, b->string);
+ }
  static int list_tags(const char **patterns, int lines,
-                       struct commit_list *with_commit)
+                    struct commit_list *with_commit, int sort)
  {
        struct tag_filter filter;
  
        filter.patterns = patterns;
        filter.lines = lines;
+       filter.sort = sort;
        filter.with_commit = with_commit;
+       memset(&filter.tags, 0, sizeof(filter.tags));
+       filter.tags.strdup_strings = 1;
  
        for_each_tag_ref(show_reference, (void *) &filter);
+       if (sort) {
+               int i;
+               if ((sort & SORT_MASK) == VERCMP_SORT)
+                       qsort(filter.tags.items, filter.tags.nr,
+                             sizeof(struct string_list_item), sort_by_version);
+               if (sort & REVERSE_SORT)
+                       for (i = filter.tags.nr - 1; i >= 0; i--)
+                               printf("%s\n", filter.tags.items[i].string);
+               else
+                       for (i = 0; i < filter.tags.nr; i++)
+                               printf("%s\n", filter.tags.items[i].string);
+               string_list_clear(&filter.tags, 0);
+       }
        return 0;
  }
  
@@@ -427,6 -459,29 +459,29 @@@ static int parse_opt_points_at(const st
        return 0;
  }
  
+ static int parse_opt_sort(const struct option *opt, const char *arg, int unset)
+ {
+       int *sort = opt->value;
+       int flags = 0;
+       if (*arg == '-') {
+               flags |= REVERSE_SORT;
+               arg++;
+       }
+       if (starts_with(arg, "version:")) {
+               *sort = VERCMP_SORT;
+               arg += 8;
+       } else if (starts_with(arg, "v:")) {
+               *sort = VERCMP_SORT;
+               arg += 2;
+       } else
+               *sort = STRCMP_SORT;
+       if (strcmp(arg, "refname"))
+               die(_("unsupported sort specification %s"), arg);
+       *sort |= flags;
+       return 0;
+ }
  int cmd_tag(int argc, const char **argv, const char *prefix)
  {
        struct strbuf buf = STRBUF_INIT;
        struct create_tag_options opt;
        char *cleanup_arg = NULL;
        int annotate = 0, force = 0, lines = -1;
-       int cmdmode = 0;
+       int cmdmode = 0, sort = 0;
        const char *msgfile = NULL, *keyid = NULL;
        struct msg_arg msg = { 0, STRBUF_INIT };
        struct commit_list *with_commit = NULL;
                                        N_("use another key to sign the tag")),
                OPT__FORCE(&force, N_("replace the tag if exists")),
                OPT_COLUMN(0, "column", &colopts, N_("show tag list in columns")),
+               {
+                       OPTION_CALLBACK, 0, "sort", &sort, N_("type"), N_("sort tags"),
+                       PARSE_OPT_NONEG, parse_opt_sort
+               },
  
                OPT_GROUP(N_("Tag listing options")),
                {
                        PARSE_OPT_LASTARG_DEFAULT,
                        parse_opt_with_commit, (intptr_t)"HEAD",
                },
 +              {
 +                      OPTION_CALLBACK, 0, "with", &with_commit, N_("commit"),
 +                      N_("print only tags that contain the commit"),
 +                      PARSE_OPT_HIDDEN | PARSE_OPT_LASTARG_DEFAULT,
 +                      parse_opt_with_commit, (intptr_t)"HEAD",
 +              },
                {
                        OPTION_CALLBACK, 0, "points-at", NULL, N_("object"),
                        N_("print only tags of the object"), 0, parse_opt_points_at
                        copts.padding = 2;
                        run_column_filter(colopts, &copts);
                }
-               ret = list_tags(argv, lines == -1 ? 0 : lines, with_commit);
+               if (lines != -1 && sort)
+                       die(_("--sort and -n are incompatible"));
+               ret = list_tags(argv, lines == -1 ? 0 : lines, with_commit, sort);
                if (column_active(colopts))
                        stop_column_filter();
                return ret;
diff --combined cache.h
index b66cb49b7486e905993fef636b4d3696a57015d5,082a783943e4a18d15306806d8e6b7f272474a9c..107ac61b68f15b1e15532c09fda9e9799f830e44
+++ b/cache.h
@@@ -3,7 -3,7 +3,7 @@@
  
  #include "git-compat-util.h"
  #include "strbuf.h"
 -#include "hash.h"
 +#include "hashmap.h"
  #include "advice.h"
  #include "gettext.h"
  #include "convert.h"
@@@ -130,12 -130,12 +130,12 @@@ struct stat_data 
  };
  
  struct cache_entry {
 +      struct hashmap_entry ent;
        struct stat_data ce_stat_data;
        unsigned int ce_mode;
        unsigned int ce_flags;
        unsigned int ce_namelen;
        unsigned char sha1[20];
 -      struct cache_entry *next;
        char name[FLEX_ARRAY]; /* more */
  };
  
  #define CE_ADDED             (1 << 19)
  
  #define CE_HASHED            (1 << 20)
 -#define CE_UNHASHED          (1 << 21)
  #define CE_WT_REMOVE         (1 << 22) /* remove in work directory */
  #define CE_CONFLICTED        (1 << 23)
  
@@@ -194,18 -195,17 +194,18 @@@ struct pathspec
   * Copy the sha1 and stat state of a cache entry from one to
   * another. But we never change the name, or the hash state!
   */
 -#define CE_STATE_MASK (CE_HASHED | CE_UNHASHED)
  static inline void copy_cache_entry(struct cache_entry *dst,
                                    const struct cache_entry *src)
  {
 -      unsigned int state = dst->ce_flags & CE_STATE_MASK;
 +      unsigned int state = dst->ce_flags & CE_HASHED;
  
        /* Don't copy hash chain and name */
 -      memcpy(dst, src, offsetof(struct cache_entry, next));
 +      memcpy(&dst->ce_stat_data, &src->ce_stat_data,
 +                      offsetof(struct cache_entry, name) -
 +                      offsetof(struct cache_entry, ce_stat_data));
  
        /* Restore the hash state */
 -      dst->ce_flags = (dst->ce_flags & ~CE_STATE_MASK) | state;
 +      dst->ce_flags = (dst->ce_flags & ~CE_HASHED) | state;
  }
  
  static inline unsigned create_ce_flags(unsigned stage)
@@@ -277,8 -277,8 +277,8 @@@ struct index_state 
        struct cache_time timestamp;
        unsigned name_hash_initialized : 1,
                 initialized : 1;
 -      struct hash_table name_hash;
 -      struct hash_table dir_hash;
 +      struct hashmap name_hash;
 +      struct hashmap dir_hash;
  };
  
  extern struct index_state the_index;
@@@ -316,6 -316,7 +316,6 @@@ extern void free_name_hash(struct index
  #define ce_modified(ce, st, options) ie_modified(&the_index, (ce), (st), (options))
  #define cache_dir_exists(name, namelen) index_dir_exists(&the_index, (name), (namelen))
  #define cache_file_exists(name, namelen, igncase) index_file_exists(&the_index, (name), (namelen), (igncase))
 -#define cache_name_exists(name, namelen, igncase) index_name_exists(&the_index, (name), (namelen), (igncase))
  #define cache_name_is_other(name, namelen) index_name_is_other(&the_index, (name), (namelen))
  #define resolve_undo_clear() resolve_undo_clear_index(&the_index)
  #define unmerge_cache_entry_at(at) unmerge_index_entry_at(&the_index, at)
@@@ -433,7 -434,6 +433,7 @@@ extern int set_git_dir_init(const char 
  extern int init_db(const char *template_dir, unsigned int flags);
  
  extern void sanitize_stdfds(void);
 +extern int daemonize(void);
  
  #define alloc_nr(x) (((x)+16)*3/2)
  
@@@ -467,6 -467,7 +467,6 @@@ extern int unmerged_index(const struct 
  extern int verify_path(const char *path);
  extern struct cache_entry *index_dir_exists(struct index_state *istate, const char *name, int namelen);
  extern struct cache_entry *index_file_exists(struct index_state *istate, const char *name, int namelen, int igncase);
 -extern struct cache_entry *index_name_exists(struct index_state *istate, const char *name, int namelen, int igncase);
  extern int index_name_pos(const struct index_state *, const char *name, int namelen);
  #define ADD_CACHE_OK_TO_ADD 1         /* Ok to add */
  #define ADD_CACHE_OK_TO_REPLACE 2     /* Ok to replace file/directory */
@@@ -483,11 -484,11 +483,11 @@@ extern int remove_file_from_index(struc
  #define ADD_CACHE_IGNORE_ERRORS       4
  #define ADD_CACHE_IGNORE_REMOVAL 8
  #define ADD_CACHE_INTENT 16
 -#define ADD_CACHE_IMPLICIT_DOT 32     /* internal to "git add -u/-A" */
  extern int add_to_index(struct index_state *, const char *path, struct stat *, int flags);
  extern int add_file_to_index(struct index_state *, const char *path, int flags);
 -extern struct cache_entry *make_cache_entry(unsigned int mode, const unsigned char *sha1, const char *path, int stage, int refresh);
 +extern struct cache_entry *make_cache_entry(unsigned int mode, const unsigned char *sha1, const char *path, int stage, unsigned int refresh_options);
  extern int ce_same_name(const struct cache_entry *a, const struct cache_entry *b);
 +extern void set_object_name_for_intent_to_add_entry(struct cache_entry *ce);
  extern int index_name_is_other(const struct index_state *, const char *, int);
  extern void *read_blob_data_from_index(struct index_state *, const char *, unsigned long *);
  
  #define CE_MATCH_RACY_IS_DIRTY                02
  /* do stat comparison even if CE_SKIP_WORKTREE is true */
  #define CE_MATCH_IGNORE_SKIP_WORKTREE 04
 +/* ignore non-existent files during stat update  */
 +#define CE_MATCH_IGNORE_MISSING               0x08
 +/* enable stat refresh */
 +#define CE_MATCH_REFRESH              0x10
  extern int ie_match_stat(const struct index_state *, const struct cache_entry *, struct stat *, unsigned int);
  extern int ie_modified(const struct index_state *, const struct cache_entry *, struct stat *, unsigned int);
  
 -extern int ce_path_match(const struct cache_entry *ce, const struct pathspec *pathspec);
 -
  #define HASH_WRITE_OBJECT 1
  #define HASH_FORMAT_CHECK 2
  extern int index_fd(unsigned char *sha1, int fd, struct stat *st, enum object_type type, const char *path, unsigned flags);
@@@ -581,17 -580,7 +581,17 @@@ extern size_t packed_git_limit
  extern size_t delta_base_cache_limit;
  extern unsigned long big_file_threshold;
  extern unsigned long pack_size_limit_cfg;
 -extern int read_replace_refs;
 +
 +/*
 + * Do replace refs need to be checked this run?  This variable is
 + * initialized to true unless --no-replace-object is used or
 + * $GIT_NO_REPLACE_OBJECTS is set, but is set to false by some
 + * commands that do not want replace references to be active.  As an
 + * optimization it is also set to false if replace references have
 + * been sought but there were none.
 + */
 +extern int check_replace_refs;
 +
  extern int fsync_object_files;
  extern int core_preload_index;
  extern int core_apply_sparse_checkout;
@@@ -670,28 -659,9 +670,28 @@@ extern char *git_path(const char *fmt, 
  extern char *git_path_submodule(const char *path, const char *fmt, ...)
        __attribute__((format (printf, 2, 3)));
  
 -extern char *sha1_file_name(const unsigned char *sha1);
 +/*
 + * Return the name of the file in the local object database that would
 + * be used to store a loose object with the specified sha1.  The
 + * return value is a pointer to a statically allocated buffer that is
 + * overwritten each time the function is called.
 + */
 +extern const char *sha1_file_name(const unsigned char *sha1);
 +
 +/*
 + * Return the name of the (local) packfile with the specified sha1 in
 + * its name.  The return value is a pointer to memory that is
 + * overwritten each time this function is called.
 + */
  extern char *sha1_pack_name(const unsigned char *sha1);
 +
 +/*
 + * Return the name of the (local) pack index file with the specified
 + * sha1 in its name.  The return value is a pointer to memory that is
 + * overwritten each time this function is called.
 + */
  extern char *sha1_pack_index_name(const unsigned char *sha1);
 +
  extern const char *find_unique_abbrev(const unsigned char *sha1, int);
  extern const unsigned char null_sha1[20];
  
@@@ -818,26 -788,13 +818,26 @@@ static inline void *read_sha1_file(cons
  {
        return read_sha1_file_extended(sha1, type, size, LOOKUP_REPLACE_OBJECT);
  }
 +
 +/*
 + * This internal function is only declared here for the benefit of
 + * lookup_replace_object().  Please do not call it directly.
 + */
  extern const unsigned char *do_lookup_replace_object(const unsigned char *sha1);
 +
 +/*
 + * If object sha1 should be replaced, return the replacement object's
 + * name (replaced recursively, if necessary).  The return value is
 + * either sha1 or a pointer to a permanently-allocated value.  When
 + * object replacement is suppressed, always return sha1.
 + */
  static inline const unsigned char *lookup_replace_object(const unsigned char *sha1)
  {
 -      if (!read_replace_refs)
 +      if (!check_replace_refs)
                return sha1;
        return do_lookup_replace_object(sha1);
  }
 +
  static inline const unsigned char *lookup_replace_object_extended(const unsigned char *sha1, unsigned flag)
  {
        if (!(flag & LOOKUP_REPLACE_OBJECT))
@@@ -851,7 -808,6 +851,7 @@@ extern int hash_sha1_file(const void *b
  extern int write_sha1_file(const void *buf, unsigned long len, const char *type, unsigned char *return_sha1);
  extern int pretend_sha1_file(void *, unsigned long, enum object_type, unsigned char *);
  extern int force_object_loose(const unsigned char *sha1, time_t mtime);
 +extern int git_open_noatime(const char *name);
  extern void *map_sha1_file(const unsigned char *sha1, unsigned long *size);
  extern int unpack_sha1_header(git_zstream *stream, unsigned char *map, unsigned long mapsize, void *buffer, unsigned long bufsiz);
  extern int parse_sha1_header(const char *hdr, unsigned long *sizep);
@@@ -864,19 -820,7 +864,19 @@@ extern int check_sha1_signature(const u
  extern int move_temp_to_file(const char *tmpfile, const char *filename);
  
  extern int has_sha1_pack(const unsigned char *sha1);
 +
 +/*
 + * Return true iff we have an object named sha1, whether local or in
 + * an alternate object database, and whether packed or loose.  This
 + * function does not respect replace references.
 + */
  extern int has_sha1_file(const unsigned char *sha1);
 +
 +/*
 + * Return true iff an alternate object database has a loose object
 + * with the specified name.  This function does not respect replace
 + * references.
 + */
  extern int has_loose_object_nonlocal(const unsigned char *sha1);
  
  extern int has_pack_index(const unsigned char *sha1);
@@@ -1015,7 -959,6 +1015,7 @@@ void datestamp(char *buf, int bufsize)
  unsigned long approxidate_careful(const char *, int *);
  unsigned long approxidate_relative(const char *date, const struct timeval *now);
  enum date_mode parse_date_format(const char *format);
 +int date_overflows(unsigned long date);
  
  #define IDENT_STRICT         1
  #define IDENT_NO_DATE        2
@@@ -1140,46 -1083,17 +1140,46 @@@ extern struct packed_git *find_sha1_pac
                                         struct packed_git *packs);
  
  extern void pack_report(void);
 +
 +/*
 + * mmap the index file for the specified packfile (if it is not
 + * already mmapped).  Return 0 on success.
 + */
  extern int open_pack_index(struct packed_git *);
 +
 +/*
 + * munmap the index file for the specified packfile (if it is
 + * currently mmapped).
 + */
  extern void close_pack_index(struct packed_git *);
 +
  extern unsigned char *use_pack(struct packed_git *, struct pack_window **, off_t, unsigned long *);
  extern void close_pack_windows(struct packed_git *);
  extern void unuse_pack(struct pack_window **);
  extern void free_pack_by_name(const char *);
  extern void clear_delta_base_cache(void);
  extern struct packed_git *add_packed_git(const char *, int, int);
 -extern const unsigned char *nth_packed_object_sha1(struct packed_git *, uint32_t);
 -extern off_t nth_packed_object_offset(const struct packed_git *, uint32_t);
 -extern off_t find_pack_entry_one(const unsigned char *, struct packed_git *);
 +
 +/*
 + * Return the SHA-1 of the nth object within the specified packfile.
 + * Open the index if it is not already open.  The return value points
 + * at the SHA-1 within the mmapped index.  Return NULL if there is an
 + * error.
 + */
 +extern const unsigned char *nth_packed_object_sha1(struct packed_git *, uint32_t n);
 +
 +/*
 + * Return the offset of the nth object within the specified packfile.
 + * The index must already be opened.
 + */
 +extern off_t nth_packed_object_offset(const struct packed_git *, uint32_t n);
 +
 +/*
 + * If the object named sha1 is present in the specified packfile,
 + * return its offset within the packfile; otherwise, return 0.
 + */
 +extern off_t find_pack_entry_one(const unsigned char *sha1, struct packed_git *);
 +
  extern int is_pack_valid(struct packed_git *);
  extern void *unpack_entry(struct packed_git *, off_t, enum object_type *, unsigned long *);
  extern unsigned long unpack_object_header_buffer(const unsigned char *buf, unsigned long len, enum object_type *type, unsigned long *sizep);
@@@ -1232,12 -1146,6 +1232,12 @@@ extern int update_server_info(int)
  #define CONFIG_INVALID_PATTERN 6
  #define CONFIG_GENERIC_ERROR 7
  
 +struct git_config_source {
 +      unsigned int use_stdin:1;
 +      const char *file;
 +      const char *blob;
 +};
 +
  typedef int (*config_fn_t)(const char *, const char *, void *);
  extern int git_default_config(const char *, const char *, void *);
  extern int git_config_from_file(config_fn_t fn, const char *, void *);
@@@ -1247,7 -1155,8 +1247,7 @@@ extern void git_config_push_parameter(c
  extern int git_config_from_parameters(config_fn_t fn, void *data);
  extern int git_config(config_fn_t fn, void *);
  extern int git_config_with_options(config_fn_t fn, void *,
 -                                 const char *filename,
 -                                 const char *blob_ref,
 +                                 struct git_config_source *config_source,
                                   int respect_includes);
  extern int git_config_early(config_fn_t fn, void *, const char *repo_config);
  extern int git_parse_ulong(const char *, unsigned long *);
@@@ -1458,4 -1367,6 +1458,6 @@@ int stat_validity_check(struct stat_val
   */
  void stat_validity_update(struct stat_validity *sv, int fd);
  
+ int versioncmp(const char *s1, const char *s2);
  #endif /* CACHE_H */