Merge branch 'nd/init-core-worktree-in-multi-worktree-world'
authorJunio C Hamano <gitster@pobox.com>
Mon, 3 Oct 2016 20:30:34 +0000 (13:30 -0700)
committerJunio C Hamano <gitster@pobox.com>
Mon, 3 Oct 2016 20:30:35 +0000 (13:30 -0700)
"git init" tried to record core.worktree in the repository's
'config' file when GIT_WORK_TREE environment variable was set and
it was different from where GIT_DIR appears as ".git" at its top,
but the logic was faulty when .git is a "gitdir:" file that points
at the real place, causing trouble in working trees that are
managed by "git worktree".  This has been corrected.

* nd/init-core-worktree-in-multi-worktree-world:
  init: kill git_link variable
  init: do not set unnecessary core.worktree
  init: kill set_git_dir_init()
  init: call set_git_dir_init() from within init_db()
  init: correct re-initialization from a linked worktree

1  2 
builtin/clone.c
builtin/init-db.c
cache.h

diff --combined builtin/clone.c
@@@ -40,7 -40,6 +40,7 @@@ static const char * const builtin_clone
  
  static int option_no_checkout, option_bare, option_mirror, option_single_branch = -1;
  static int option_local = -1, option_no_hardlinks, option_shared, option_recursive;
 +static int option_shallow_submodules;
  static char *option_template, *option_depth;
  static char *option_origin = NULL;
  static char *option_branch = NULL;
@@@ -49,11 -48,9 +49,11 @@@ static char *option_upload_pack = "git-
  static int option_verbosity;
  static int option_progress = -1;
  static enum transport_family family;
 -static struct string_list option_config;
 -static struct string_list option_reference;
 +static struct string_list option_config = STRING_LIST_INIT_NODUP;
 +static struct string_list option_required_reference = STRING_LIST_INIT_NODUP;
 +static struct string_list option_optional_reference = STRING_LIST_INIT_NODUP;
  static int option_dissociate;
 +static int max_jobs = -1;
  
  static struct option builtin_clone_options[] = {
        OPT__VERBOSITY(&option_verbosity),
                    N_("initialize submodules in the clone")),
        OPT_BOOL(0, "recurse-submodules", &option_recursive,
                    N_("initialize submodules in the clone")),
 +      OPT_INTEGER('j', "jobs", &max_jobs,
 +                  N_("number of submodules cloned in parallel")),
        OPT_STRING(0, "template", &option_template, N_("template-directory"),
                   N_("directory from which templates will be used")),
 -      OPT_STRING_LIST(0, "reference", &option_reference, N_("repo"),
 +      OPT_STRING_LIST(0, "reference", &option_required_reference, N_("repo"),
                        N_("reference repository")),
 +      OPT_STRING_LIST(0, "reference-if-able", &option_optional_reference,
 +                      N_("repo"), N_("reference repository")),
        OPT_BOOL(0, "dissociate", &option_dissociate,
                 N_("use --reference only while cloning")),
        OPT_STRING('o', "origin", &option_origin, N_("name"),
@@@ -96,8 -89,6 +96,8 @@@
                    N_("create a shallow clone of that depth")),
        OPT_BOOL(0, "single-branch", &option_single_branch,
                    N_("clone only one branch, HEAD or --branch")),
 +      OPT_BOOL(0, "shallow-submodules", &option_shallow_submodules,
 +                  N_("any cloned submodules will be shallow")),
        OPT_STRING(0, "separate-git-dir", &real_git_dir, N_("gitdir"),
                   N_("separate git dir from working tree")),
        OPT_STRING_LIST('c', "config", &option_config, N_("key=value"),
        OPT_END()
  };
  
 -static const char *argv_submodule[] = {
 -      "submodule", "update", "--init", "--recursive", NULL
 -};
 -
  static const char *get_repo_path_1(struct strbuf *path, int *is_bundle)
  {
        static char *suffix[] = { "/.git", "", ".git/.git", ".git" };
@@@ -285,37 -280,50 +285,37 @@@ static void strip_trailing_slashes(cha
  
  static int add_one_reference(struct string_list_item *item, void *cb_data)
  {
 -      char *ref_git;
 -      const char *repo;
 -      struct strbuf alternate = STRBUF_INIT;
 -
 -      /* Beware: read_gitfile(), real_path() and mkpath() return static buffer */
 -      ref_git = xstrdup(real_path(item->string));
 -
 -      repo = read_gitfile(ref_git);
 -      if (!repo)
 -              repo = read_gitfile(mkpath("%s/.git", ref_git));
 -      if (repo) {
 -              free(ref_git);
 -              ref_git = xstrdup(repo);
 -      }
 +      struct strbuf err = STRBUF_INIT;
 +      int *required = cb_data;
 +      char *ref_git = compute_alternate_path(item->string, &err);
  
 -      if (!repo && is_directory(mkpath("%s/.git/objects", ref_git))) {
 -              char *ref_git_git = mkpathdup("%s/.git", ref_git);
 -              free(ref_git);
 -              ref_git = ref_git_git;
 -      } else if (!is_directory(mkpath("%s/objects", ref_git))) {
 +      if (!ref_git) {
 +              if (*required)
 +                      die("%s", err.buf);
 +              else
 +                      fprintf(stderr,
 +                              _("info: Could not add alternate for '%s': %s\n"),
 +                              item->string, err.buf);
 +      } else {
                struct strbuf sb = STRBUF_INIT;
 -              if (get_common_dir(&sb, ref_git))
 -                      die(_("reference repository '%s' as a linked checkout is not supported yet."),
 -                          item->string);
 -              die(_("reference repository '%s' is not a local repository."),
 -                  item->string);
 +              strbuf_addf(&sb, "%s/objects", ref_git);
 +              add_to_alternates_file(sb.buf);
 +              strbuf_release(&sb);
        }
  
 -      if (!access(mkpath("%s/shallow", ref_git), F_OK))
 -              die(_("reference repository '%s' is shallow"), item->string);
 -
 -      if (!access(mkpath("%s/info/grafts", ref_git), F_OK))
 -              die(_("reference repository '%s' is grafted"), item->string);
 -
 -      strbuf_addf(&alternate, "%s/objects", ref_git);
 -      add_to_alternates_file(alternate.buf);
 -      strbuf_release(&alternate);
 +      strbuf_release(&err);
        free(ref_git);
        return 0;
  }
  
  static void setup_reference(void)
  {
 -      for_each_string_list(&option_reference, add_one_reference, NULL);
 +      int required = 1;
 +      for_each_string_list(&option_required_reference,
 +                           add_one_reference, &required);
 +      required = 0;
 +      for_each_string_list(&option_optional_reference,
 +                           add_one_reference, &required);
  }
  
  static void copy_alternates(struct strbuf *src, struct strbuf *dst,
@@@ -614,13 -622,13 +614,13 @@@ static void update_remote_refs(const st
        const struct ref *rm = mapped_refs;
  
        if (check_connectivity) {
 -              if (transport->progress)
 -                      fprintf(stderr, _("Checking connectivity... "));
 -              if (check_everything_connected_with_transport(iterate_ref_map,
 -                                                            0, &rm, transport))
 +              struct check_connected_options opt = CHECK_CONNECTED_INIT;
 +
 +              opt.transport = transport;
 +              opt.progress = transport->progress;
 +
 +              if (check_connected(iterate_ref_map, &rm, &opt))
                        die(_("remote did not send all necessary objects"));
 -              if (transport->progress)
 -                      fprintf(stderr, _("done.\n"));
        }
  
        if (refs) {
@@@ -670,7 -678,7 +670,7 @@@ static void update_head(const struct re
        }
  }
  
 -static int checkout(void)
 +static int checkout(int submodule_progress)
  {
        unsigned char sha1[20];
        char *head;
        err |= run_hook_le(NULL, "post-checkout", sha1_to_hex(null_sha1),
                           sha1_to_hex(sha1), "1", NULL);
  
 -      if (!err && option_recursive)
 -              err = run_command_v_opt(argv_submodule, RUN_GIT_CMD);
 +      if (!err && option_recursive) {
 +              struct argv_array args = ARGV_ARRAY_INIT;
 +              argv_array_pushl(&args, "submodule", "update", "--init", "--recursive", NULL);
 +
 +              if (option_shallow_submodules == 1)
 +                      argv_array_push(&args, "--depth=1");
 +
 +              if (max_jobs != -1)
 +                      argv_array_pushf(&args, "--jobs=%d", max_jobs);
 +
 +              if (submodule_progress)
 +                      argv_array_push(&args, "--progress");
 +
 +              err = run_command_v_opt(args.argv, RUN_GIT_CMD);
 +              argv_array_clear(&args);
 +      }
  
        return err;
  }
@@@ -844,7 -838,6 +844,7 @@@ int cmd_clone(int argc, const char **ar
        const char *src_ref_prefix = "refs/heads/";
        struct remote *remote;
        int err = 0, complete_refs_before_fetch = 1;
 +      int submodule_progress;
  
        struct refspec *refspec;
        const char *fetch_pattern;
                set_git_work_tree(work_tree);
        }
  
-       junk_git_dir = git_dir;
+       junk_git_dir = real_git_dir ? real_git_dir : git_dir;
        if (safe_create_leading_directories_const(git_dir) < 0)
                die(_("could not create leading directories of '%s'"), git_dir);
  
-       set_git_dir_init(git_dir, real_git_dir, 0);
-       if (real_git_dir) {
-               git_dir = real_git_dir;
-               junk_git_dir = real_git_dir;
-       }
        if (0 <= option_verbosity) {
                if (option_bare)
                        fprintf(stderr, _("Cloning into bare repository '%s'...\n"), dir);
                        fprintf(stderr, _("Cloning into '%s'...\n"), dir);
        }
  
-       init_db(option_template, INIT_DB_QUIET);
 +      if (option_recursive) {
 +              if (option_required_reference.nr &&
 +                  option_optional_reference.nr)
 +                      die(_("clone --recursive is not compatible with "
 +                            "both --reference and --reference-if-able"));
 +              else if (option_required_reference.nr) {
 +                      string_list_append(&option_config,
 +                              "submodule.alternateLocation=superproject");
 +                      string_list_append(&option_config,
 +                              "submodule.alternateErrorStrategy=die");
 +              } else if (option_optional_reference.nr) {
 +                      string_list_append(&option_config,
 +                              "submodule.alternateLocation=superproject");
 +                      string_list_append(&option_config,
 +                              "submodule.alternateErrorStrategy=info");
 +              }
 +      }
 +
+       init_db(git_dir, real_git_dir, option_template, INIT_DB_QUIET);
+       if (real_git_dir)
+               git_dir = real_git_dir;
        write_config(&option_config);
  
        git_config(git_default_config, NULL);
        git_config_set(key.buf, repo);
        strbuf_reset(&key);
  
 -      if (option_reference.nr)
 +      if (option_required_reference.nr || option_optional_reference.nr)
                setup_reference();
  
        fetch_pattern = value.buf;
  
        update_head(our_head_points_at, remote_head, reflog_msg.buf);
  
 +      /*
 +       * We want to show progress for recursive submodule clones iff
 +       * we did so for the main clone. But only the transport knows
 +       * the final decision for this flag, so we need to rescue the value
 +       * before we free the transport.
 +       */
 +      submodule_progress = transport->progress;
 +
        transport_unlock_pack(transport);
        transport_disconnect(transport);
  
        }
  
        junk_mode = JUNK_LEAVE_REPO;
 -      err = checkout();
 +      err = checkout(submodule_progress);
  
        strbuf_release(&reflog_msg);
        strbuf_release(&branch_top);
diff --combined builtin/init-db.c
@@@ -22,7 -22,6 +22,6 @@@
  static int init_is_bare_repository = 0;
  static int init_shared_repository = -1;
  static const char *init_db_template_dir;
- static const char *git_link;
  
  static void copy_templates_1(struct strbuf *path, struct strbuf *template,
                             DIR *dir)
@@@ -138,7 -137,7 +137,7 @@@ static void copy_templates(const char *
                goto close_free_return;
        }
  
-       strbuf_addstr(&path, get_git_dir());
+       strbuf_addstr(&path, get_git_common_dir());
        strbuf_complete(&path, '/');
        copy_templates_1(&path, &template_path, dir);
  close_free_return:
@@@ -171,7 -170,8 +170,8 @@@ static int needs_work_tree_config(cons
        return 1;
  }
  
- static int create_default_files(const char *template_path)
+ static int create_default_files(const char *template_path,
+                               const char *original_git_dir)
  {
        struct stat st1;
        struct strbuf buf = STRBUF_INIT;
        char junk[2];
        int reinit;
        int filemode;
 -
 -      /*
 -       * Create .git/refs/{heads,tags}
 -       */
 -      safe_create_dir(git_path_buf(&buf, "refs"), 1);
 -      safe_create_dir(git_path_buf(&buf, "refs/heads"), 1);
 -      safe_create_dir(git_path_buf(&buf, "refs/tags"), 1);
 +      struct strbuf err = STRBUF_INIT;
  
        /* Just look for `init.templatedir` */
        git_config(git_init_db_config, NULL);
         */
        if (get_shared_repository()) {
                adjust_shared_perm(get_git_dir());
 -              adjust_shared_perm(git_path_buf(&buf, "refs"));
 -              adjust_shared_perm(git_path_buf(&buf, "refs/heads"));
 -              adjust_shared_perm(git_path_buf(&buf, "refs/tags"));
        }
  
 +      /*
 +       * We need to create a "refs" dir in any case so that older
 +       * versions of git can tell that this is a repository.
 +       */
 +      safe_create_dir(git_path("refs"), 1);
 +      adjust_shared_perm(git_path("refs"));
 +
 +      if (refs_init_db(&err))
 +              die("failed to set up refs db: %s", err.buf);
 +
        /*
         * Create the default symlink from ".git/HEAD" to the "master"
         * branch, if it does not exist yet.
                /* allow template config file to override the default */
                if (log_all_ref_updates == -1)
                        git_config_set("core.logallrefupdates", "true");
-               if (needs_work_tree_config(get_git_dir(), work_tree))
+               if (needs_work_tree_config(original_git_dir, work_tree))
                        git_config_set("core.worktree", work_tree);
        }
  
@@@ -312,34 -311,7 +312,7 @@@ static void create_object_directory(voi
        strbuf_release(&path);
  }
  
- int set_git_dir_init(const char *git_dir, const char *real_git_dir,
-                    int exist_ok)
- {
-       if (real_git_dir) {
-               struct stat st;
-               if (!exist_ok && !stat(git_dir, &st))
-                       die(_("%s already exists"), git_dir);
-               if (!exist_ok && !stat(real_git_dir, &st))
-                       die(_("%s already exists"), real_git_dir);
-               /*
-                * make sure symlinks are resolved because we'll be
-                * moving the target repo later on in separate_git_dir()
-                */
-               git_link = xstrdup(real_path(git_dir));
-               set_git_dir(real_path(real_git_dir));
-       }
-       else {
-               set_git_dir(real_path(git_dir));
-               git_link = NULL;
-       }
-       startup_info->have_repository = 1;
-       return 0;
- }
- static void separate_git_dir(const char *git_dir)
+ static void separate_git_dir(const char *git_dir, const char *git_link)
  {
        struct stat st;
  
        write_file(git_link, "gitdir: %s", git_dir);
  }
  
- int init_db(const char *template_dir, unsigned int flags)
+ int init_db(const char *git_dir, const char *real_git_dir,
+           const char *template_dir, unsigned int flags)
  {
        int reinit;
-       const char *git_dir = get_git_dir();
+       int exist_ok = flags & INIT_DB_EXIST_OK;
+       char *original_git_dir = xstrdup(real_path(git_dir));
+       if (real_git_dir) {
+               struct stat st;
+               if (!exist_ok && !stat(git_dir, &st))
+                       die(_("%s already exists"), git_dir);
+               if (!exist_ok && !stat(real_git_dir, &st))
+                       die(_("%s already exists"), real_git_dir);
  
-       if (git_link)
-               separate_git_dir(git_dir);
+               set_git_dir(real_path(real_git_dir));
+               git_dir = get_git_dir();
+               separate_git_dir(git_dir, original_git_dir);
+       }
+       else {
+               set_git_dir(real_path(git_dir));
+               git_dir = get_git_dir();
+       }
+       startup_info->have_repository = 1;
  
        safe_create_dir(git_dir, 0);
  
         */
        check_repository_format();
  
-       reinit = create_default_files(template_dir);
+       reinit = create_default_files(template_dir, original_git_dir);
  
        create_object_directory();
  
        if (!(flags & INIT_DB_QUIET)) {
                int len = strlen(git_dir);
  
 -              /* TRANSLATORS: The first '%s' is either "Reinitialized
 -                 existing" or "Initialized empty", the second " shared" or
 -                 "", and the last '%s%s' is the verbatim directory name. */
 -              printf(_("%s%s Git repository in %s%s\n"),
 -                     reinit ? _("Reinitialized existing") : _("Initialized empty"),
 -                     get_shared_repository() ? _(" shared") : "",
 -                     git_dir, len && git_dir[len-1] != '/' ? "/" : "");
 +              if (reinit)
 +                      printf(get_shared_repository()
 +                             ? _("Reinitialized existing shared Git repository in %s%s\n")
 +                             : _("Reinitialized existing Git repository in %s%s\n"),
 +                             git_dir, len && git_dir[len-1] != '/' ? "/" : "");
 +              else
 +                      printf(get_shared_repository()
 +                             ? _("Initialized empty shared Git repository in %s%s\n")
 +                             : _("Initialized empty Git repository in %s%s\n"),
 +                             git_dir, len && git_dir[len-1] != '/' ? "/" : "");
        }
  
+       free(original_git_dir);
        return 0;
  }
  
@@@ -586,7 -574,6 +578,6 @@@ int cmd_init_db(int argc, const char **
                        set_git_work_tree(work_tree);
        }
  
-       set_git_dir_init(git_dir, real_git_dir, 1);
-       return init_db(template_dir, flags);
+       flags |= INIT_DB_EXIST_OK;
+       return init_db(git_dir, real_git_dir, template_dir, flags);
  }
diff --combined cache.h
+++ b/cache.h
@@@ -173,7 -173,7 +173,7 @@@ struct cache_entry 
        unsigned int ce_flags;
        unsigned int ce_namelen;
        unsigned int index;     /* for link extension */
 -      unsigned char sha1[20];
 +      struct object_id oid;
        char name[FLEX_ARRAY]; /* more */
  };
  
@@@ -369,7 -369,6 +369,7 @@@ extern void free_name_hash(struct index
  #define remove_file_from_cache(path) remove_file_from_index(&the_index, (path))
  #define add_to_cache(path, st, flags) add_to_index(&the_index, (path), (st), (flags))
  #define add_file_to_cache(path, flags) add_file_to_index(&the_index, (path), (flags))
 +#define chmod_cache_entry(ce, flip) chmod_index_entry(&the_index, (ce), (flip))
  #define refresh_cache(flags) refresh_index(&the_index, (flags), NULL, NULL, NULL)
  #define ce_match_stat(ce, st, options) ie_match_stat(&the_index, (ce), (st), (options))
  #define ce_modified(ce, st, options) ie_modified(&the_index, (ce), (st), (options))
@@@ -526,9 -525,10 +526,10 @@@ extern void verify_non_filename(const c
  extern int path_inside_repo(const char *prefix, const char *path);
  
  #define INIT_DB_QUIET 0x0001
+ #define INIT_DB_EXIST_OK 0x0002
  
- extern int set_git_dir_init(const char *git_dir, const char *real_git_dir, int);
extern int init_db(const char *template_dir, unsigned int flags);
+ extern int init_db(const char *git_dir, const char *real_git_dir,
                 const char *template_dir, unsigned int flags);
  
  extern void sanitize_stdfds(void);
  extern int daemonize(void);
@@@ -591,7 -591,6 +592,7 @@@ extern int remove_file_from_index(struc
  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, unsigned int refresh_options);
 +extern int chmod_index_entry(struct index_state *, struct cache_entry *ce, char flip);
  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);
@@@ -640,7 -639,6 +641,7 @@@ extern void fill_stat_cache_info(struc
  #define REFRESH_IGNORE_SUBMODULES     0x0010  /* ignore submodules */
  #define REFRESH_IN_PORCELAIN  0x0020  /* user friendly output, not "needs update" */
  extern int refresh_index(struct index_state *, unsigned int flags, const struct pathspec *pathspec, char *seen, const char *header_msg);
 +extern struct cache_entry *refresh_cache_entry(struct cache_entry *, unsigned int);
  
  extern void update_index_if_able(struct index_state *, struct lock_file *);
  
@@@ -663,7 -661,6 +664,7 @@@ extern int warn_on_object_refname_ambig
  extern const char *apply_default_whitespace;
  extern const char *apply_default_ignorewhitespace;
  extern const char *git_attributes_file;
 +extern const char *git_hooks_path;
  extern int zlib_compression_level;
  extern int core_compression_level;
  extern int core_compression_seen;
@@@ -824,18 -821,15 +825,18 @@@ extern void check_repository_format(voi
   */
  extern const char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
  extern const char *git_path(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
 +extern const char *git_common_path(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
  
  extern char *mksnpath(char *buf, size_t n, const char *fmt, ...)
        __attribute__((format (printf, 3, 4)));
  extern void strbuf_git_path(struct strbuf *sb, const char *fmt, ...)
        __attribute__((format (printf, 2, 3)));
 +extern void strbuf_git_common_path(struct strbuf *sb, const char *fmt, ...)
 +      __attribute__((format (printf, 2, 3)));
  extern char *git_path_buf(struct strbuf *buf, const char *fmt, ...)
        __attribute__((format (printf, 2, 3)));
 -extern void strbuf_git_path_submodule(struct strbuf *sb, const char *path,
 -                                    const char *fmt, ...)
 +extern int strbuf_git_path_submodule(struct strbuf *sb, const char *path,
 +                                   const char *fmt, ...)
        __attribute__((format (printf, 3, 4)));
  extern char *git_pathdup(const char *fmt, ...)
        __attribute__((format (printf, 1, 2)));
@@@ -968,39 -962,22 +969,39 @@@ static inline void oidclr(struct object
  #define EMPTY_TREE_SHA1_BIN_LITERAL \
         "\x4b\x82\x5d\xc6\x42\xcb\x6e\xb9\xa0\x60" \
         "\xe5\x4b\xf8\xd6\x92\x88\xfb\xee\x49\x04"
 -#define EMPTY_TREE_SHA1_BIN \
 -       ((const unsigned char *) EMPTY_TREE_SHA1_BIN_LITERAL)
 +extern const struct object_id empty_tree_oid;
 +#define EMPTY_TREE_SHA1_BIN (empty_tree_oid.hash)
  
  #define EMPTY_BLOB_SHA1_HEX \
        "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391"
  #define EMPTY_BLOB_SHA1_BIN_LITERAL \
        "\xe6\x9d\xe2\x9b\xb2\xd1\xd6\x43\x4b\x8b" \
        "\x29\xae\x77\x5a\xd8\xc2\xe4\x8c\x53\x91"
 -#define EMPTY_BLOB_SHA1_BIN \
 -      ((const unsigned char *) EMPTY_BLOB_SHA1_BIN_LITERAL)
 +extern const struct object_id empty_blob_oid;
 +#define EMPTY_BLOB_SHA1_BIN (empty_blob_oid.hash)
 +
  
  static inline int is_empty_blob_sha1(const unsigned char *sha1)
  {
        return !hashcmp(sha1, EMPTY_BLOB_SHA1_BIN);
  }
  
 +static inline int is_empty_blob_oid(const struct object_id *oid)
 +{
 +      return !hashcmp(oid->hash, EMPTY_BLOB_SHA1_BIN);
 +}
 +
 +static inline int is_empty_tree_sha1(const unsigned char *sha1)
 +{
 +      return !hashcmp(sha1, EMPTY_TREE_SHA1_BIN);
 +}
 +
 +static inline int is_empty_tree_oid(const struct object_id *oid)
 +{
 +      return !hashcmp(oid->hash, EMPTY_TREE_SHA1_BIN);
 +}
 +
 +
  int git_mkstemp(char *path, size_t n, const char *template);
  
  /* set default permissions by passing mode arguments to open(2) */
@@@ -1036,11 -1013,6 +1037,11 @@@ int adjust_shared_perm(const char *path
   * directory while we were working.  To be robust against this kind of
   * race, callers might want to try invoking the function again when it
   * returns SCLD_VANISHED.
 + *
 + * safe_create_leading_directories() temporarily changes path while it
 + * is working but restores it before returning.
 + * safe_create_leading_directories_const() doesn't modify path, even
 + * temporarily.
   */
  enum scld_error {
        SCLD_OK = 0,
@@@ -1171,16 -1143,6 +1172,16 @@@ static inline unsigned int hexval(unsig
        return hexval_table[c];
  }
  
 +/*
 + * Convert two consecutive hexadecimal digits into a char.  Return a
 + * negative value on error.  Don't run over the end of short strings.
 + */
 +static inline int hex2chr(const char *s)
 +{
 +      int val = hexval(s[0]);
 +      return (val < 0) ? val : (val << 4) | hexval(s[1]);
 +}
 +
  /* Convert to/from hex/sha1 representation */
  #define MINIMUM_ABBREV minimum_abbrev
  #define DEFAULT_ABBREV default_abbrev
@@@ -1214,8 -1176,6 +1215,8 @@@ extern int get_sha1_blob(const char *st
  extern void maybe_die_on_misspelt_object_name(const char *name, const char *prefix);
  extern int get_sha1_with_context(const char *str, unsigned flags, unsigned char *sha1, struct object_context *orc);
  
 +extern int get_oid(const char *str, struct object_id *oid);
 +
  typedef int each_abbrev_fn(const unsigned char *sha1, void *);
  extern int for_each_abbrev(const char *prefix, each_abbrev_fn, void *);
  
@@@ -1241,12 -1201,11 +1242,12 @@@ extern int get_oid_hex(const char *hex
   *   printf("%s -> %s", sha1_to_hex(one), sha1_to_hex(two));
   */
  extern char *sha1_to_hex_r(char *out, const unsigned char *sha1);
 +extern char *oid_to_hex_r(char *out, const struct object_id *oid);
  extern char *sha1_to_hex(const unsigned char *sha1);  /* static buffer result! */
  extern char *oid_to_hex(const struct object_id *oid); /* same static buffer as sha1_to_hex */
  
  extern int interpret_branch_name(const char *str, int len, struct strbuf *);
 -extern int get_sha1_mb(const char *str, unsigned char *sha1);
 +extern int get_oid_mb(const char *str, struct object_id *oid);
  
  extern int validate_headref(const char *ref);
  
@@@ -1272,8 -1231,7 +1273,8 @@@ struct date_mode 
                DATE_ISO8601_STRICT,
                DATE_RFC2822,
                DATE_STRFTIME,
 -              DATE_RAW
 +              DATE_RAW,
 +              DATE_UNIX
        } type;
        const char *strftime_fmt;
        int local;
@@@ -1312,7 -1270,6 +1313,7 @@@ extern const char *ident_default_email(
  extern const char *git_editor(void);
  extern const char *git_pager(int stdout_is_tty);
  extern int git_ident_config(const char *, const char *, void *);
 +extern void reset_ident_date(void);
  
  struct ident_split {
        const char *name_begin;
@@@ -1356,7 -1313,6 +1357,7 @@@ struct checkout 
                 not_new:1,
                 refresh_cache:1;
  };
 +#define CHECKOUT_INIT { NULL, "" }
  
  #define TEMPORARY_FILENAME_LENGTH 25
  extern int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *topath);
@@@ -1387,7 -1343,6 +1388,7 @@@ extern struct alternate_object_databas
  } *alt_odb_list;
  extern void prepare_alt_odb(void);
  extern void read_info_alternates(const char * relative_base, int depth);
 +extern char *compute_alternate_path(const char *path, struct strbuf *err);
  extern void add_to_alternates_file(const char *reference);
  typedef int alt_odb_fn(struct alternate_object_database *, void *);
  extern int foreach_alt_odb(alt_odb_fn, void*);
@@@ -1423,13 -1378,6 +1424,13 @@@ extern struct packed_git 
        char pack_name[FLEX_ARRAY]; /* more */
  } *packed_git;
  
 +/*
 + * A most-recently-used ordered version of the packed_git list, which can
 + * be iterated instead of packed_git (and marked via mru_mark).
 + */
 +struct mru;
 +extern struct mru *packed_git_mru;
 +
  struct pack_entry {
        off_t offset;
        unsigned char sha1[20];
@@@ -1469,6 -1417,7 +1470,6 @@@ extern unsigned char *use_pack(struct p
  extern void close_pack_windows(struct packed_git *);
  extern void close_all_packs(void);
  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 *path, size_t path_len, int local);
  
@@@ -1567,7 -1516,7 +1568,7 @@@ struct object_info 
        /* Request */
        enum object_type *typep;
        unsigned long *sizep;
 -      unsigned long *disk_sizep;
 +      off_t *disk_sizep;
        unsigned char *delta_base_sha1;
        struct strbuf *typename;
  
@@@ -1618,18 -1567,10 +1619,18 @@@ struct git_config_source 
        const char *blob;
  };
  
 +enum config_origin_type {
 +      CONFIG_ORIGIN_BLOB,
 +      CONFIG_ORIGIN_FILE,
 +      CONFIG_ORIGIN_STDIN,
 +      CONFIG_ORIGIN_SUBMODULE_BLOB,
 +      CONFIG_ORIGIN_CMDLINE
 +};
 +
  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 *);
 -extern int git_config_from_mem(config_fn_t fn, const char *origin_type,
 +extern int git_config_from_mem(config_fn_t fn, const enum config_origin_type,
                                        const char *name, const char *buf, size_t len, void *data);
  extern void git_config_push_parameter(const char *text);
  extern int git_config_from_parameters(config_fn_t fn, void *data);
@@@ -1671,16 -1612,6 +1672,16 @@@ extern const char *get_log_output_encod
  extern const char *get_commit_output_encoding(void);
  
  extern int git_config_parse_parameter(const char *, config_fn_t fn, void *data);
 +
 +enum config_scope {
 +      CONFIG_SCOPE_UNKNOWN = 0,
 +      CONFIG_SCOPE_SYSTEM,
 +      CONFIG_SCOPE_GLOBAL,
 +      CONFIG_SCOPE_REPO,
 +      CONFIG_SCOPE_CMDLINE,
 +};
 +
 +extern enum config_scope current_config_scope(void);
  extern const char *current_config_origin_type(void);
  extern const char *current_config_name(void);
  
@@@ -1773,8 -1704,6 +1774,8 @@@ extern int ignore_untracked_cache_confi
  struct key_value_info {
        const char *filename;
        int linenr;
 +      enum config_origin_type origin_type;
 +      enum config_scope scope;
  };
  
  extern NORETURN void git_die_config(const char *key, const char *err, ...) __attribute__((format(printf, 2, 3)));
@@@ -1800,6 -1729,8 +1801,6 @@@ extern int copy_file(const char *dst, c
  extern int copy_file_with_time(const char *dst, const char *src, int mode);
  
  extern void write_or_die(int fd, const void *buf, size_t count);
 -extern int write_or_whine(int fd, const void *buf, size_t count, const char *msg);
 -extern int write_or_whine_pipe(int fd, const void *buf, size_t count, const char *msg);
  extern void fsync_or_die(int fd, const char *);
  
  extern ssize_t read_in_full(int fd, void *buf, size_t count);
@@@ -1811,21 -1742,8 +1812,21 @@@ static inline ssize_t write_str_in_full
        return write_in_full(fd, str, strlen(str));
  }
  
 -extern int write_file(const char *path, const char *fmt, ...);
 -extern int write_file_gently(const char *path, const char *fmt, ...);
 +/**
 + * Open (and truncate) the file at path, write the contents of buf to it,
 + * and close it. Dies if any errors are encountered.
 + */
 +extern void write_file_buf(const char *path, const char *buf, size_t len);
 +
 +/**
 + * Like write_file_buf(), but format the contents into a buffer first.
 + * Additionally, write_file() will append a newline if one is not already
 + * present, making it convenient to write text files:
 + *
 + *   write_file(path, "counter: %d", ctr);
 + */
 +__attribute__((format (printf, 2, 3)))
 +extern void write_file(const char *path, const char *fmt, ...);
  
  /* pager.c */
  extern void setup_pager(void);
@@@ -1867,8 -1785,8 +1868,8 @@@ int add_files_to_cache(const char *pref
  extern int diff_auto_refresh_index;
  
  /* match-trees.c */
 -void shift_tree(const unsigned char *, const unsigned char *, unsigned char *, int);
 -void shift_tree_by(const unsigned char *, const unsigned char *, unsigned char *, const char *);
 +void shift_tree(const struct object_id *, const struct object_id *, struct object_id *, int);
 +void shift_tree_by(const struct object_id *, const struct object_id *, struct object_id *, const char *);
  
  /*
   * whitespace rules.