Sync with 1.7.11.6
authorJunio C Hamano <gitster@pobox.com>
Tue, 11 Sep 2012 18:23:45 +0000 (11:23 -0700)
committerJunio C Hamano <gitster@pobox.com>
Tue, 11 Sep 2012 18:23:54 +0000 (11:23 -0700)
Signed-off-by: Junio C Hamano <gitster@pobox.com>
14 files changed:
1  2 
Documentation/git-config.txt
Documentation/git.txt
builtin/apply.c
builtin/blame.c
builtin/checkout.c
builtin/config.c
cache.h
diff.c
git-submodule.sh
merge-recursive.c
notes-merge.c
read-cache.c
revision.c
t/t7400-submodule-basic.sh
index 2d6ef32a087f3f7355251a84a7d0d294f18479a5,21b8f6110bfc2a9c7891c166e3ee78a8246dcb1e..eaea0791657386469e448def614b949c0a1f45e9
@@@ -54,16 -54,16 +54,16 @@@ configuration file by default, and opti
  '--file <filename>' can be used to tell the command to write to
  that location (you can say '--local' but that is the default).
  
- This command will fail (with exit code ret) if:
+ This command will fail with non-zero status upon error.  Some exit
+ codes are:
  
  . The config file is invalid (ret=3),
  . can not write to the config file (ret=4),
  . no section or name was provided (ret=2),
  . the section or key is invalid (ret=1),
  . you try to unset an option which does not exist (ret=5),
- . you try to unset/set an option for which multiple lines match (ret=5),
- . you try to use an invalid regexp (ret=6), or
- . you use '--global' option without $HOME being properly set (ret=128).
+ . you try to unset/set an option for which multiple lines match (ret=5), or
+ . you try to use an invalid regexp (ret=6).
  
  On success, the command returns the exit code 0.
  
@@@ -97,11 -97,10 +97,11 @@@ OPTION
  
  --global::
        For writing options: write to global ~/.gitconfig file rather than
 -      the repository .git/config.
 +      the repository .git/config, write to $XDG_CONFIG_HOME/git/config file
 +      if this file exists and the ~/.gitconfig file doesn't.
  +
 -For reading options: read only from global ~/.gitconfig rather than
 -from all available files.
 +For reading options: read only from global ~/.gitconfig and from
 +$XDG_CONFIG_HOME/git/config rather than from all available files.
  +
  See also <<FILES>>.
  
@@@ -195,7 -194,7 +195,7 @@@ See also <<FILES>>
  FILES
  -----
  
 -If not set explicitly with '--file', there are three files where
 +If not set explicitly with '--file', there are four files where
  'git config' will search for configuration options:
  
  $GIT_DIR/config::
        User-specific configuration file. Also called "global"
        configuration file.
  
 +$XDG_CONFIG_HOME/git/config::
 +      Second user-specific configuration file. If $XDG_CONFIG_HOME is not set
 +      or empty, $HOME/.config/git/config will be used. Any single-valued
 +      variable set in this file will be overwritten by whatever is in
 +      ~/.gitconfig.  It is a good idea not to create this file if
 +      you sometimes use older versions of Git, as support for this
 +      file was added fairly recently.
 +
  $(prefix)/etc/gitconfig::
        System-wide configuration file.
  
@@@ -267,7 -258,7 +267,7 @@@ Given a .git/config like this
  
        ; Proxy settings
        [core]
-               gitproxy="proxy-command" for kernel.org
+               gitproxy=proxy-command for kernel.org
                gitproxy=default-proxy ; for all the rest
  
  you can set the filemode to true with
@@@ -342,7 -333,7 +342,7 @@@ To actually match only values with an e
  To add a new proxy, without altering any of the existing ones, use
  
  ------------
- % git config core.gitproxy '"proxy-command" for example.com'
+ % git config --add core.gitproxy '"proxy-command" for example.com'
  ------------
  
  An example to use customized color from the configuration in your
diff --combined Documentation/git.txt
index 463d567a878eb2a66396ea673035b7ff530b264b,165d13ad227173628f05e2eb629ea2e4c7917f0a..fab6e77e02c9773a0230ac7dadf53670a60ac8a5
@@@ -22,17 -22,18 +22,17 @@@ unusually rich command set that provide
  and full access to internals.
  
  See linkgit:gittutorial[7] to get started, then see
 -link:everyday.html[Everyday Git] for a useful minimum set of commands, and
 -"man git-commandname" for documentation of each command.  CVS users may
 -also want to read linkgit:gitcvs-migration[7].  See
 -the link:user-manual.html[Git User's Manual] for a more in-depth
 -introduction.
 +link:everyday.html[Everyday Git] for a useful minimum set of
 +commands.  The link:user-manual.html[Git User's Manual] has a more
 +in-depth introduction.
  
 -The '<command>' is either a name of a Git command (see below) or an alias
 -as defined in the configuration file (see linkgit:git-config[1]).
 +After you mastered the basic concepts, you can come back to this
 +page to learn what commands git offers.  You can learn more about
 +individual git commands with "git help command".  linkgit:gitcli[7]
 +manual page gives you an overview of the command line command syntax.
  
 -Formatted and hyperlinked version of the latest git
 -documentation can be viewed at
 -`http://www.kernel.org/pub/software/scm/git/docs/`.
 +Formatted and hyperlinked version of the latest git documentation
 +can be viewed at `http://git-htmldocs.googlecode.com/git/git.html`.
  
  ifdef::stalenotes[]
  [NOTE]
@@@ -43,14 -44,10 +43,15 @@@ unreleased) version of git, that is ava
  branch of the `git.git` repository.
  Documentation for older releases are available here:
  
- * link:v1.7.11.5/git.html[documentation for release 1.7.11.5]
 +* link:v1.7.12/git.html[documentation for release 1.7.12]
 +
 +* release notes for
 +  link:RelNotes/1.7.12.txt[1.7.12].
 +
+ * link:v1.7.11.6/git.html[documentation for release 1.7.11.6]
  
  * release notes for
+   link:RelNotes/1.7.11.6.txt[1.7.11.6],
    link:RelNotes/1.7.11.5.txt[1.7.11.5],
    link:RelNotes/1.7.11.4.txt[1.7.11.4],
    link:RelNotes/1.7.11.3.txt[1.7.11.3],
@@@ -410,6 -407,24 +411,6 @@@ help ...`
        linkgit:git-replace[1] for more information.
  
  
 -FURTHER DOCUMENTATION
 ----------------------
 -
 -See the references above to get started using git.  The following is
 -probably more detail than necessary for a first-time user.
 -
 -The link:user-manual.html#git-concepts[git concepts chapter of the
 -user-manual] and linkgit:gitcore-tutorial[7] both provide
 -introductions to the underlying git architecture.
 -
 -See linkgit:gitworkflows[7] for an overview of recommended workflows.
 -
 -See also the link:howto-index.html[howto] documents for some useful
 -examples.
 -
 -The internals are documented in the
 -link:technical/api-index.html[GIT API documentation].
 -
  GIT COMMANDS
  ------------
  
@@@ -829,29 -844,6 +830,29 @@@ The index is also capable of storing mu
  for a given pathname.  These stages are used to hold the various
  unmerged version of a file when a merge is in progress.
  
 +FURTHER DOCUMENTATION
 +---------------------
 +
 +See the references in the "description" section to get started
 +using git.  The following is probably more detail than necessary
 +for a first-time user.
 +
 +The link:user-manual.html#git-concepts[git concepts chapter of the
 +user-manual] and linkgit:gitcore-tutorial[7] both provide
 +introductions to the underlying git architecture.
 +
 +See linkgit:gitworkflows[7] for an overview of recommended workflows.
 +
 +See also the link:howto-index.html[howto] documents for some useful
 +examples.
 +
 +The internals are documented in the
 +link:technical/api-index.html[GIT API documentation].
 +
 +Users migrating from CVS may also want to
 +read linkgit:gitcvs-migration[7].
 +
 +
  Authors
  -------
  Git was started by Linus Torvalds, and is currently maintained by Junio
diff --combined builtin/apply.c
index d453c833782c6aae4dd04fb9f9f68c3a8211d3d5,ca54ff3aaa76457d2838d39228b385661040dbd1..3bf71dc4522564463945673aaba0501a51141bb2
@@@ -16,9 -16,6 +16,9 @@@
  #include "dir.h"
  #include "diff.h"
  #include "parse-options.h"
 +#include "xdiff-interface.h"
 +#include "ll-merge.h"
 +#include "rerere.h"
  
  /*
   *  --check turns on checking that the working tree matches the
@@@ -49,7 -46,6 +49,7 @@@ static int apply_with_reject
  static int apply_verbosely;
  static int allow_overlap;
  static int no_add;
 +static int threeway;
  static const char *fake_ancestor;
  static int line_termination = '\n';
  static unsigned int p_context = UINT_MAX;
@@@ -188,7 -184,6 +188,6 @@@ struct patch 
        int is_new, is_delete;  /* -1 = unknown, 0 = false, 1 = true */
        int rejected;
        unsigned ws_rule;
-       unsigned long deflate_origlen;
        int lines_added, lines_deleted;
        int score;
        unsigned int is_toplevel_relative:1;
        unsigned int is_copy:1;
        unsigned int is_rename:1;
        unsigned int recount:1;
 +      unsigned int conflicted_threeway:1;
 +      unsigned int direct_to_threeway:1;
        struct fragment *fragments;
        char *result;
        size_t resultsize;
        char old_sha1_prefix[41];
        char new_sha1_prefix[41];
        struct patch *next;
 +
 +      /* three-way fallback result */
 +      unsigned char threeway_stage[3][20];
  };
  
  static void free_fragment_list(struct fragment *list)
@@@ -380,8 -370,8 +379,8 @@@ static void prepare_image(struct image 
  static void clear_image(struct image *image)
  {
        free(image->buf);
 -      image->buf = NULL;
 -      image->len = 0;
 +      free(image->line_allocated);
 +      memset(image, 0, sizeof(*image));
  }
  
  /* fmt must contain _one_ %s and no other substitution */
@@@ -2946,17 -2936,20 +2945,17 @@@ static int apply_fragments(struct imag
        return 0;
  }
  
 -static int read_file_or_gitlink(struct cache_entry *ce, struct strbuf *buf)
 +static int read_blob_object(struct strbuf *buf, const unsigned char *sha1, unsigned mode)
  {
 -      if (!ce)
 -              return 0;
 -
 -      if (S_ISGITLINK(ce->ce_mode)) {
 +      if (S_ISGITLINK(mode)) {
                strbuf_grow(buf, 100);
 -              strbuf_addf(buf, "Subproject commit %s\n", sha1_to_hex(ce->sha1));
 +              strbuf_addf(buf, "Subproject commit %s\n", sha1_to_hex(sha1));
        } else {
                enum object_type type;
                unsigned long sz;
                char *result;
  
 -              result = read_sha1_file(ce->sha1, &type, &sz);
 +              result = read_sha1_file(sha1, &type, &sz);
                if (!result)
                        return -1;
                /* XXX read_sha1_file NUL-terminates */
        return 0;
  }
  
 +static int read_file_or_gitlink(struct cache_entry *ce, struct strbuf *buf)
 +{
 +      if (!ce)
 +              return 0;
 +      return read_blob_object(buf, ce->sha1, ce->ce_mode);
 +}
 +
  static struct patch *in_fn_table(const char *name)
  {
        struct string_list_item *item;
   * item->util in the filename table records the status of the path.
   * Usually it points at a patch (whose result records the contents
   * of it after applying it), but it could be PATH_WAS_DELETED for a
 - * path that a previously applied patch has already removed.
 + * path that a previously applied patch has already removed, or
 + * PATH_TO_BE_DELETED for a path that a later patch would remove.
 + *
 + * The latter is needed to deal with a case where two paths A and B
 + * are swapped by first renaming A to B and then renaming B to A;
 + * moving A to B should not be prevented due to presense of B as we
 + * will remove it in a later patch.
   */
 - #define PATH_TO_BE_DELETED ((struct patch *) -2)
 +#define PATH_TO_BE_DELETED ((struct patch *) -2)
  #define PATH_WAS_DELETED ((struct patch *) -1)
  
  static int to_be_deleted(struct patch *patch)
@@@ -3050,324 -3030,127 +3049,324 @@@ static void prepare_fn_table(struct pat
        }
  }
  
 -static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *ce)
 +static int checkout_target(struct cache_entry *ce, struct stat *st)
 +{
 +      struct checkout costate;
 +
 +      memset(&costate, 0, sizeof(costate));
 +      costate.base_dir = "";
 +      costate.refresh_cache = 1;
 +      if (checkout_entry(ce, &costate, NULL) || lstat(ce->name, st))
 +              return error(_("cannot checkout %s"), ce->name);
 +      return 0;
 +}
 +
 +static struct patch *previous_patch(struct patch *patch, int *gone)
 +{
 +      struct patch *previous;
 +
 +      *gone = 0;
 +      if (patch->is_copy || patch->is_rename)
 +              return NULL; /* "git" patches do not depend on the order */
 +
 +      previous = in_fn_table(patch->old_name);
 +      if (!previous)
 +              return NULL;
 +
 +      if (to_be_deleted(previous))
 +              return NULL; /* the deletion hasn't happened yet */
 +
 +      if (was_deleted(previous))
 +              *gone = 1;
 +
 +      return previous;
 +}
 +
 +static int verify_index_match(struct cache_entry *ce, struct stat *st)
 +{
 +      if (S_ISGITLINK(ce->ce_mode)) {
 +              if (!S_ISDIR(st->st_mode))
 +                      return -1;
 +              return 0;
 +      }
 +      return ce_match_stat(ce, st, CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE);
 +}
 +
 +#define SUBMODULE_PATCH_WITHOUT_INDEX 1
 +
 +static int load_patch_target(struct strbuf *buf,
 +                           struct cache_entry *ce,
 +                           struct stat *st,
 +                           const char *name,
 +                           unsigned expected_mode)
 +{
 +      if (cached) {
 +              if (read_file_or_gitlink(ce, buf))
 +                      return error(_("read of %s failed"), name);
 +      } else if (name) {
 +              if (S_ISGITLINK(expected_mode)) {
 +                      if (ce)
 +                              return read_file_or_gitlink(ce, buf);
 +                      else
 +                              return SUBMODULE_PATCH_WITHOUT_INDEX;
 +              } else {
 +                      if (read_old_data(st, name, buf))
 +                              return error(_("read of %s failed"), name);
 +              }
 +      }
 +      return 0;
 +}
 +
 +/*
 + * We are about to apply "patch"; populate the "image" with the
 + * current version we have, from the working tree or from the index,
 + * depending on the situation e.g. --cached/--index.  If we are
 + * applying a non-git patch that incrementally updates the tree,
 + * we read from the result of a previous diff.
 + */
 +static int load_preimage(struct image *image,
 +                       struct patch *patch, struct stat *st, struct cache_entry *ce)
  {
        struct strbuf buf = STRBUF_INIT;
 -      struct image image;
        size_t len;
        char *img;
 -      struct patch *tpatch;
 +      struct patch *previous;
 +      int status;
  
 -      if (!(patch->is_copy || patch->is_rename) &&
 -          (tpatch = in_fn_table(patch->old_name)) != NULL && !to_be_deleted(tpatch)) {
 -              if (was_deleted(tpatch)) {
 -                      return error(_("patch %s has been renamed/deleted"),
 -                              patch->old_name);
 -              }
 +      previous = previous_patch(patch, &status);
 +      if (status)
 +              return error(_("path %s has been renamed/deleted"),
 +                           patch->old_name);
 +      if (previous) {
                /* We have a patched copy in memory; use that. */
 -              strbuf_add(&buf, tpatch->result, tpatch->resultsize);
 -      } else if (cached) {
 -              if (read_file_or_gitlink(ce, &buf))
 +              strbuf_add(&buf, previous->result, previous->resultsize);
 +      } else {
 +              status = load_patch_target(&buf, ce, st,
 +                                         patch->old_name, patch->old_mode);
 +              if (status < 0)
 +                      return status;
 +              else if (status == SUBMODULE_PATCH_WITHOUT_INDEX) {
 +                      /*
 +                       * There is no way to apply subproject
 +                       * patch without looking at the index.
 +                       * NEEDSWORK: shouldn't this be flagged
 +                       * as an error???
 +                       */
 +                      free_fragment_list(patch->fragments);
 +                      patch->fragments = NULL;
 +              } else if (status) {
                        return error(_("read of %s failed"), patch->old_name);
 -      } else if (patch->old_name) {
 -              if (S_ISGITLINK(patch->old_mode)) {
 -                      if (ce) {
 -                              read_file_or_gitlink(ce, &buf);
 -                      } else {
 -                              /*
 -                               * There is no way to apply subproject
 -                               * patch without looking at the index.
 -                               * NEEDSWORK: shouldn't this be flagged
 -                               * as an error???
 -                               */
 -                              free_fragment_list(patch->fragments);
 -                              patch->fragments = NULL;
 -                      }
 -              } else {
 -                      if (read_old_data(st, patch->old_name, &buf))
 -                              return error(_("read of %s failed"), patch->old_name);
                }
        }
  
        img = strbuf_detach(&buf, &len);
 -      prepare_image(&image, img, len, !patch->is_binary);
 +      prepare_image(image, img, len, !patch->is_binary);
 +      return 0;
 +}
  
 -      if (apply_fragments(&image, patch) < 0)
 -              return -1; /* note with --reject this succeeds. */
 -      patch->result = image.buf;
 -      patch->resultsize = image.len;
 -      add_to_fn_table(patch);
 -      free(image.line_allocated);
 +static int three_way_merge(struct image *image,
 +                         char *path,
 +                         const unsigned char *base,
 +                         const unsigned char *ours,
 +                         const unsigned char *theirs)
 +{
 +      mmfile_t base_file, our_file, their_file;
 +      mmbuffer_t result = { NULL };
 +      int status;
  
 -      if (0 < patch->is_delete && patch->resultsize)
 -              return error(_("removal patch leaves file contents"));
 +      read_mmblob(&base_file, base);
 +      read_mmblob(&our_file, ours);
 +      read_mmblob(&their_file, theirs);
 +      status = ll_merge(&result, path,
 +                        &base_file, "base",
 +                        &our_file, "ours",
 +                        &their_file, "theirs", NULL);
 +      free(base_file.ptr);
 +      free(our_file.ptr);
 +      free(their_file.ptr);
 +      if (status < 0 || !result.ptr) {
 +              free(result.ptr);
 +              return -1;
 +      }
 +      clear_image(image);
 +      image->buf = result.ptr;
 +      image->len = result.size;
  
 +      return status;
 +}
 +
 +/*
 + * When directly falling back to add/add three-way merge, we read from
 + * the current contents of the new_name.  In no cases other than that
 + * this function will be called.
 + */
 +static int load_current(struct image *image, struct patch *patch)
 +{
 +      struct strbuf buf = STRBUF_INIT;
 +      int status, pos;
 +      size_t len;
 +      char *img;
 +      struct stat st;
 +      struct cache_entry *ce;
 +      char *name = patch->new_name;
 +      unsigned mode = patch->new_mode;
 +
 +      if (!patch->is_new)
 +              die("BUG: patch to %s is not a creation", patch->old_name);
 +
 +      pos = cache_name_pos(name, strlen(name));
 +      if (pos < 0)
 +              return error(_("%s: does not exist in index"), name);
 +      ce = active_cache[pos];
 +      if (lstat(name, &st)) {
 +              if (errno != ENOENT)
 +                      return error(_("%s: %s"), name, strerror(errno));
 +              if (checkout_target(ce, &st))
 +                      return -1;
 +      }
 +      if (verify_index_match(ce, &st))
 +              return error(_("%s: does not match index"), name);
 +
 +      status = load_patch_target(&buf, ce, &st, name, mode);
 +      if (status < 0)
 +              return status;
 +      else if (status)
 +              return -1;
 +      img = strbuf_detach(&buf, &len);
 +      prepare_image(image, img, len, !patch->is_binary);
        return 0;
  }
  
 -static int check_to_create_blob(const char *new_name, int ok_if_exists)
 +static int try_threeway(struct image *image, struct patch *patch,
 +                      struct stat *st, struct cache_entry *ce)
  {
 -      struct stat nst;
 -      if (!lstat(new_name, &nst)) {
 -              if (S_ISDIR(nst.st_mode) || ok_if_exists)
 -                      return 0;
 -              /*
 -               * A leading component of new_name might be a symlink
 -               * that is going to be removed with this patch, but
 -               * still pointing at somewhere that has the path.
 -               * In such a case, path "new_name" does not exist as
 -               * far as git is concerned.
 -               */
 -              if (has_symlink_leading_path(new_name, strlen(new_name)))
 -                      return 0;
 +      unsigned char pre_sha1[20], post_sha1[20], our_sha1[20];
 +      struct strbuf buf = STRBUF_INIT;
 +      size_t len;
 +      int status;
 +      char *img;
 +      struct image tmp_image;
 +
 +      /* No point falling back to 3-way merge in these cases */
 +      if (patch->is_delete ||
 +          S_ISGITLINK(patch->old_mode) || S_ISGITLINK(patch->new_mode))
 +              return -1;
  
 -              return error(_("%s: already exists in working directory"), new_name);
 +      /* Preimage the patch was prepared for */
 +      if (patch->is_new)
 +              write_sha1_file("", 0, blob_type, pre_sha1);
 +      else if (get_sha1(patch->old_sha1_prefix, pre_sha1) ||
 +               read_blob_object(&buf, pre_sha1, patch->old_mode))
 +              return error("repository lacks the necessary blob to fall back on 3-way merge.");
 +
 +      fprintf(stderr, "Falling back to three-way merge...\n");
 +
 +      img = strbuf_detach(&buf, &len);
 +      prepare_image(&tmp_image, img, len, 1);
 +      /* Apply the patch to get the post image */
 +      if (apply_fragments(&tmp_image, patch) < 0) {
 +              clear_image(&tmp_image);
 +              return -1;
 +      }
 +      /* post_sha1[] is theirs */
 +      write_sha1_file(tmp_image.buf, tmp_image.len, blob_type, post_sha1);
 +      clear_image(&tmp_image);
 +
 +      /* our_sha1[] is ours */
 +      if (patch->is_new) {
 +              if (load_current(&tmp_image, patch))
 +                      return error("cannot read the current contents of '%s'",
 +                                   patch->new_name);
 +      } else {
 +              if (load_preimage(&tmp_image, patch, st, ce))
 +                      return error("cannot read the current contents of '%s'",
 +                                   patch->old_name);
 +      }
 +      write_sha1_file(tmp_image.buf, tmp_image.len, blob_type, our_sha1);
 +      clear_image(&tmp_image);
 +
 +      /* in-core three-way merge between post and our using pre as base */
 +      status = three_way_merge(image, patch->new_name,
 +                               pre_sha1, our_sha1, post_sha1);
 +      if (status < 0) {
 +              fprintf(stderr, "Failed to fall back on three-way merge...\n");
 +              return status;
 +      }
 +
 +      if (status) {
 +              patch->conflicted_threeway = 1;
 +              if (patch->is_new)
 +                      hashclr(patch->threeway_stage[0]);
 +              else
 +                      hashcpy(patch->threeway_stage[0], pre_sha1);
 +              hashcpy(patch->threeway_stage[1], our_sha1);
 +              hashcpy(patch->threeway_stage[2], post_sha1);
 +              fprintf(stderr, "Applied patch to '%s' with conflicts.\n", patch->new_name);
 +      } else {
 +              fprintf(stderr, "Applied patch to '%s' cleanly.\n", patch->new_name);
        }
 -      else if ((errno != ENOENT) && (errno != ENOTDIR))
 -              return error("%s: %s", new_name, strerror(errno));
        return 0;
  }
  
 -static int verify_index_match(struct cache_entry *ce, struct stat *st)
 +static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *ce)
  {
 -      if (S_ISGITLINK(ce->ce_mode)) {
 -              if (!S_ISDIR(st->st_mode))
 +      struct image image;
 +
 +      if (load_preimage(&image, patch, st, ce) < 0)
 +              return -1;
 +
 +      if (patch->direct_to_threeway ||
 +          apply_fragments(&image, patch) < 0) {
 +              /* Note: with --reject, apply_fragments() returns 0 */
 +              if (!threeway || try_threeway(&image, patch, st, ce) < 0)
                        return -1;
 -              return 0;
        }
 -      return ce_match_stat(ce, st, CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE);
 +      patch->result = image.buf;
 +      patch->resultsize = image.len;
 +      add_to_fn_table(patch);
 +      free(image.line_allocated);
 +
 +      if (0 < patch->is_delete && patch->resultsize)
 +              return error(_("removal patch leaves file contents"));
 +
 +      return 0;
  }
  
 +/*
 + * If "patch" that we are looking at modifies or deletes what we have,
 + * we would want it not to lose any local modification we have, either
 + * in the working tree or in the index.
 + *
 + * This also decides if a non-git patch is a creation patch or a
 + * modification to an existing empty file.  We do not check the state
 + * of the current tree for a creation patch in this function; the caller
 + * check_patch() separately makes sure (and errors out otherwise) that
 + * the path the patch creates does not exist in the current tree.
 + */
  static int check_preimage(struct patch *patch, struct cache_entry **ce, struct stat *st)
  {
        const char *old_name = patch->old_name;
 -      struct patch *tpatch = NULL;
 -      int stat_ret = 0;
 +      struct patch *previous = NULL;
 +      int stat_ret = 0, status;
        unsigned st_mode = 0;
  
 -      /*
 -       * Make sure that we do not have local modifications from the
 -       * index when we are looking at the index.  Also make sure
 -       * we have the preimage file to be patched in the work tree,
 -       * unless --cached, which tells git to apply only in the index.
 -       */
        if (!old_name)
                return 0;
  
        assert(patch->is_new <= 0);
 +      previous = previous_patch(patch, &status);
  
 -      if (!(patch->is_copy || patch->is_rename) &&
 -          (tpatch = in_fn_table(old_name)) != NULL && !to_be_deleted(tpatch)) {
 -              if (was_deleted(tpatch))
 -                      return error(_("%s: has been deleted/renamed"), old_name);
 -              st_mode = tpatch->new_mode;
 +      if (status)
 +              return error(_("path %s has been renamed/deleted"), old_name);
 +      if (previous) {
 +              st_mode = previous->new_mode;
        } else if (!cached) {
                stat_ret = lstat(old_name, st);
                if (stat_ret && errno != ENOENT)
                        return error(_("%s: %s"), old_name, strerror(errno));
        }
  
 -      if (to_be_deleted(tpatch))
 -              tpatch = NULL;
 -
 -      if (check_index && !tpatch) {
 +      if (check_index && !previous) {
                int pos = cache_name_pos(old_name, strlen(old_name));
                if (pos < 0) {
                        if (patch->is_new < 0)
                }
                *ce = active_cache[pos];
                if (stat_ret < 0) {
 -                      struct checkout costate;
 -                      /* checkout */
 -                      memset(&costate, 0, sizeof(costate));
 -                      costate.base_dir = "";
 -                      costate.refresh_cache = 1;
 -                      if (checkout_entry(*ce, &costate, NULL) ||
 -                          lstat(old_name, st))
 +                      if (checkout_target(*ce, st))
                                return -1;
                }
                if (!cached && verify_index_match(*ce, st))
                return error(_("%s: %s"), old_name, strerror(errno));
        }
  
 -      if (!cached && !tpatch)
 +      if (!cached && !previous)
                st_mode = ce_mode_from_stat(*ce, st->st_mode);
  
        if (patch->is_new < 0)
        return 0;
  }
  
 +
 +#define EXISTS_IN_INDEX 1
 +#define EXISTS_IN_WORKTREE 2
 +
 +static int check_to_create(const char *new_name, int ok_if_exists)
 +{
 +      struct stat nst;
 +
 +      if (check_index &&
 +          cache_name_pos(new_name, strlen(new_name)) >= 0 &&
 +          !ok_if_exists)
 +              return EXISTS_IN_INDEX;
 +      if (cached)
 +              return 0;
 +
 +      if (!lstat(new_name, &nst)) {
 +              if (S_ISDIR(nst.st_mode) || ok_if_exists)
 +                      return 0;
 +              /*
 +               * A leading component of new_name might be a symlink
 +               * that is going to be removed with this patch, but
 +               * still pointing at somewhere that has the path.
 +               * In such a case, path "new_name" does not exist as
 +               * far as git is concerned.
 +               */
 +              if (has_symlink_leading_path(new_name, strlen(new_name)))
 +                      return 0;
 +
 +              return EXISTS_IN_WORKTREE;
 +      } else if ((errno != ENOENT) && (errno != ENOTDIR)) {
 +              return error("%s: %s", new_name, strerror(errno));
 +      }
 +      return 0;
 +}
 +
  /*
   * Check and apply the patch in-core; leave the result in patch->result
   * for the caller to write it out to the final destination.
@@@ -3470,45 -3224,31 +3469,45 @@@ static int check_patch(struct patch *pa
                return status;
        old_name = patch->old_name;
  
 +      /*
 +       * A type-change diff is always split into a patch to delete
 +       * old, immediately followed by a patch to create new (see
 +       * diff.c::run_diff()); in such a case it is Ok that the entry
 +       * to be deleted by the previous patch is still in the working
 +       * tree and in the index.
 +       *
 +       * A patch to swap-rename between A and B would first rename A
 +       * to B and then rename B to A.  While applying the first one,
 +       * the presense of B should not stop A from getting renamed to
 +       * B; ask to_be_deleted() about the later rename.  Removal of
 +       * B and rename from A to B is handled the same way by asking
 +       * was_deleted().
 +       */
        if ((tpatch = in_fn_table(new_name)) &&
 -                      (was_deleted(tpatch) || to_be_deleted(tpatch)))
 -              /*
 -               * A type-change diff is always split into a patch to
 -               * delete old, immediately followed by a patch to
 -               * create new (see diff.c::run_diff()); in such a case
 -               * it is Ok that the entry to be deleted by the
 -               * previous patch is still in the working tree and in
 -               * the index.
 -               */
 +          (was_deleted(tpatch) || to_be_deleted(tpatch)))
                ok_if_exists = 1;
        else
                ok_if_exists = 0;
  
        if (new_name &&
            ((0 < patch->is_new) | (0 < patch->is_rename) | patch->is_copy)) {
 -              if (check_index &&
 -                  cache_name_pos(new_name, strlen(new_name)) >= 0 &&
 -                  !ok_if_exists)
 +              int err = check_to_create(new_name, ok_if_exists);
 +
 +              if (err && threeway) {
 +                      patch->direct_to_threeway = 1;
 +              } else switch (err) {
 +              case 0:
 +                      break; /* happy */
 +              case EXISTS_IN_INDEX:
                        return error(_("%s: already exists in index"), new_name);
 -              if (!cached) {
 -                      int err = check_to_create_blob(new_name, ok_if_exists);
 -                      if (err)
 -                              return err;
 +                      break;
 +              case EXISTS_IN_WORKTREE:
 +                      return error(_("%s: already exists in working directory"),
 +                                   new_name);
 +              default:
 +                      return err;
                }
 +
                if (!patch->new_mode) {
                        if (0 < patch->is_new)
                                patch->new_mode = S_IFREG | 0644;
@@@ -3589,7 -3329,7 +3588,7 @@@ static void build_fake_ancestor(struct 
                name = patch->old_name ? patch->old_name : patch->new_name;
                if (0 < patch->is_new)
                        continue;
 -              else if (get_sha1(patch->old_sha1_prefix, sha1))
 +              else if (get_sha1_blob(patch->old_sha1_prefix, sha1))
                        /* git diff has no index line for mode/type changes */
                        if (!patch->lines_added && !patch->lines_deleted) {
                                if (get_current_sha1(patch->old_name, sha1))
@@@ -3769,8 -3509,7 +3768,8 @@@ static void add_index_file(const char *
        ce = xcalloc(1, ce_size);
        memcpy(ce->name, path, namelen);
        ce->ce_mode = create_ce_mode(mode);
 -      ce->ce_flags = namelen;
 +      ce->ce_flags = create_ce_flags(0);
 +      ce->ce_namelen = namelen;
        if (S_ISGITLINK(mode)) {
                const char *s = buf;
  
@@@ -3872,33 -3611,6 +3871,33 @@@ static void create_one_file(char *path
        die_errno(_("unable to write file '%s' mode %o"), path, mode);
  }
  
 +static void add_conflicted_stages_file(struct patch *patch)
 +{
 +      int stage, namelen;
 +      unsigned ce_size, mode;
 +      struct cache_entry *ce;
 +
 +      if (!update_index)
 +              return;
 +      namelen = strlen(patch->new_name);
 +      ce_size = cache_entry_size(namelen);
 +      mode = patch->new_mode ? patch->new_mode : (S_IFREG | 0644);
 +
 +      remove_file_from_cache(patch->new_name);
 +      for (stage = 1; stage < 4; stage++) {
 +              if (is_null_sha1(patch->threeway_stage[stage - 1]))
 +                      continue;
 +              ce = xcalloc(1, ce_size);
 +              memcpy(ce->name, patch->new_name, namelen);
 +              ce->ce_mode = create_ce_mode(mode);
 +              ce->ce_flags = create_ce_flags(stage);
 +              ce->ce_namelen = namelen;
 +              hashcpy(ce->sha1, patch->threeway_stage[stage - 1]);
 +              if (add_cache_entry(ce, ADD_CACHE_OK_TO_ADD) < 0)
 +                      die(_("unable to add cache entry for %s"), patch->new_name);
 +      }
 +}
 +
  static void create_file(struct patch *patch)
  {
        char *path = patch->new_name;
        if (!mode)
                mode = S_IFREG | 0644;
        create_one_file(path, mode, buf, size);
 -      add_index_file(path, mode, buf, size);
 +
 +      if (patch->conflicted_threeway)
 +              add_conflicted_stages_file(patch);
 +      else
 +              add_index_file(path, mode, buf, size);
  }
  
  /* phase zero is to remove, phase one is to create */
@@@ -4015,7 -3723,6 +4014,7 @@@ static int write_out_results(struct pat
        int phase;
        int errs = 0;
        struct patch *l;
 +      struct string_list cpath = STRING_LIST_INIT_DUP;
  
        for (phase = 0; phase < 2; phase++) {
                l = list;
                                errs = 1;
                        else {
                                write_out_one_result(l, phase);
 -                              if (phase == 1 && write_out_one_reject(l))
 -                                      errs = 1;
 +                              if (phase == 1) {
 +                                      if (write_out_one_reject(l))
 +                                              errs = 1;
 +                                      if (l->conflicted_threeway) {
 +                                              string_list_append(&cpath, l->new_name);
 +                                              errs = 1;
 +                                      }
 +                              }
                        }
                        l = l->next;
                }
        }
 +
 +      if (cpath.nr) {
 +              struct string_list_item *item;
 +
 +              sort_string_list(&cpath);
 +              for_each_string_list_item(item, &cpath)
 +                      fprintf(stderr, "U %s\n", item->string);
 +              string_list_clear(&cpath, 0);
 +
 +              rerere(0);
 +      }
 +
        return errs;
  }
  
@@@ -4170,12 -3859,8 +4169,12 @@@ static int apply_patch(int fd, const ch
            !apply_with_reject)
                exit(1);
  
 -      if (apply && write_out_results(list))
 -              exit(1);
 +      if (apply && write_out_results(list)) {
 +              if (apply_with_reject)
 +                      exit(1);
 +              /* with --3way, we still need to write the index out */
 +              return 1;
 +      }
  
        if (fake_ancestor)
                build_fake_ancestor(list, fake_ancestor);
@@@ -4308,8 -3993,6 +4307,8 @@@ int cmd_apply(int argc, const char **ar
                        N_("apply a patch without touching the working tree")),
                OPT_BOOLEAN(0, "apply", &force_apply,
                        N_("also apply the patch (use with --stat/--summary/--check)")),
 +              OPT_BOOL('3', "3way", &threeway,
 +                       N_( "attempt three-way merge if a patch does not apply")),
                OPT_FILENAME(0, "build-fake-ancestor", &fake_ancestor,
                        N_("build a temporary index based on embedded index information")),
                { OPTION_CALLBACK, 'z', NULL, NULL, NULL,
        argc = parse_options(argc, argv, prefix, builtin_apply_options,
                        apply_usage, 0);
  
 +      if (apply_with_reject && threeway)
 +              die("--reject and --3way cannot be used together.");
 +      if (cached && threeway)
 +              die("--cached and --3way cannot be used together.");
 +      if (threeway) {
 +              if (is_not_gitdir)
 +                      die(_("--3way outside a repository"));
 +              check_index = 1;
 +      }
        if (apply_with_reject)
                apply = apply_verbosely = 1;
        if (!force_apply && (diffstat || numstat || summary || check || fake_ancestor))
diff --combined builtin/blame.c
index f2c48ef5afc11966ba6df354978be52ccfa92814,cad4111a36a5b880d9d851463ef5f554f56d27d3..ed5d01b36a309a53619c2615aed2382b2aebf056
@@@ -407,8 -407,7 +407,7 @@@ static struct origin *find_origin(struc
        paths[1] = NULL;
  
        diff_tree_setup_paths(paths, &diff_opts);
-       if (diff_setup_done(&diff_opts) < 0)
-               die("diff-setup");
+       diff_setup_done(&diff_opts);
  
        if (is_null_sha1(origin->commit->object.sha1))
                do_diff_cache(parent->tree->object.sha1, &diff_opts);
@@@ -494,8 -493,7 +493,7 @@@ static struct origin *find_rename(struc
        diff_opts.single_follow = origin->path;
        paths[0] = NULL;
        diff_tree_setup_paths(paths, &diff_opts);
-       if (diff_setup_done(&diff_opts) < 0)
-               die("diff-setup");
+       diff_setup_done(&diff_opts);
  
        if (is_null_sha1(origin->commit->object.sha1))
                do_diff_cache(parent->tree->object.sha1, &diff_opts);
@@@ -1075,8 -1073,7 +1073,7 @@@ static int find_copy_in_parent(struct s
  
        paths[0] = NULL;
        diff_tree_setup_paths(paths, &diff_opts);
-       if (diff_setup_done(&diff_opts) < 0)
-               die("diff-setup");
+       diff_setup_done(&diff_opts);
  
        /* Try "find copies harder" on new path if requested;
         * we do not want to use diffcore_rename() actually to
@@@ -2172,8 -2169,7 +2169,8 @@@ static struct commit *fake_working_tree
        ce = xcalloc(1, size);
        hashcpy(ce->sha1, origin->blob_sha1);
        memcpy(ce->name, path, len);
 -      ce->ce_flags = create_ce_flags(len, 0);
 +      ce->ce_flags = create_ce_flags(0);
 +      ce->ce_namelen = len;
        ce->ce_mode = create_ce_mode(mode);
        add_cache_entry(ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE);
  
diff --combined builtin/checkout.c
index d812219b30247795b6db7487329605a088057db1,45aa0a87019c4f51802ea896edead95379eab5fb..7d922c612a9ef0784fa381c89899ba7a959338f2
@@@ -73,8 -73,7 +73,8 @@@ static int update_some(const unsigned c
        hashcpy(ce->sha1, sha1);
        memcpy(ce->name, base, baselen);
        memcpy(ce->name + baselen, pathname, len - baselen);
 -      ce->ce_flags = create_ce_flags(len, 0) | CE_UPDATE;
 +      ce->ce_flags = create_ce_flags(0) | CE_UPDATE;
 +      ce->ce_namelen = len;
        ce->ce_mode = create_ce_mode(mode);
        add_cache_entry(ce, ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE);
        return 0;
@@@ -316,8 -315,7 +316,7 @@@ static void show_local_changes(struct o
        init_revisions(&rev, NULL);
        rev.diffopt.flags = opts->flags;
        rev.diffopt.output_format |= DIFF_FORMAT_NAME_STATUS;
-       if (diff_setup_done(&rev.diffopt) < 0)
-               die(_("diff_setup_done failed"));
+       diff_setup_done(&rev.diffopt);
        add_pending_object(&rev, head, NULL);
        run_diff_index(&rev, 0);
  }
diff --combined builtin/config.c
index 8cd08da99122bc79025d2a78204d316f1b7ba478,b44277c23e293f42186230cc7feb9099f2058b2b..ada6e1211462558f307dce6142b7b65d641c8e02
@@@ -160,8 -160,8 +160,8 @@@ static int show_config(const char *key_
  
  static int get_value(const char *key_, const char *regex_)
  {
-       int ret = -1;
+       int ret = CONFIG_GENERIC_ERROR;
 -      char *global = NULL, *repo_config = NULL;
 +      char *global = NULL, *xdg = NULL, *repo_config = NULL;
        const char *system_wide = NULL, *local;
        struct config_include_data inc = CONFIG_INCLUDE_INIT;
        config_fn_t fn;
  
        local = given_config_file;
        if (!local) {
 -              const char *home = getenv("HOME");
                local = repo_config = git_pathdup("config");
 -              if (home)
 -                      global = xstrdup(mkpath("%s/.gitconfig", home));
                if (git_config_system())
                        system_wide = git_etc_gitconfig();
 +              home_config_paths(&global, &xdg, "config");
        }
  
        if (use_key_regexp) {
                if (regcomp(key_regexp, key, REG_EXTENDED)) {
                        fprintf(stderr, "Invalid key pattern: %s\n", key_);
                        free(key);
+                       ret = CONFIG_INVALID_PATTERN;
                        goto free_strings;
                }
        } else {
-               if (git_config_parse_key(key_, &key, NULL))
+               if (git_config_parse_key(key_, &key, NULL)) {
+                       ret = CONFIG_INVALID_KEY;
                        goto free_strings;
+               }
        }
  
        if (regex_) {
                regexp = (regex_t*)xmalloc(sizeof(regex_t));
                if (regcomp(regexp, regex_, REG_EXTENDED)) {
                        fprintf(stderr, "Invalid pattern: %s\n", regex_);
+                       ret = CONFIG_INVALID_PATTERN;
                        goto free_strings;
                }
        }
  
        if (do_all && system_wide)
                git_config_from_file(fn, system_wide, data);
 +      if (do_all && xdg)
 +              git_config_from_file(fn, xdg, data);
        if (do_all && global)
                git_config_from_file(fn, global, data);
        if (do_all)
                git_config_from_file(fn, local, data);
        if (!do_all && !seen && global)
                git_config_from_file(fn, global, data);
 +      if (!do_all && !seen && xdg)
 +              git_config_from_file(fn, xdg, data);
        if (!do_all && !seen && system_wide)
                git_config_from_file(fn, system_wide, data);
  
  free_strings:
        free(repo_config);
        free(global);
 +      free(xdg);
        return ret;
  }
  
@@@ -382,25 -383,13 +386,25 @@@ int cmd_config(int argc, const char **a
        }
  
        if (use_global_config) {
 -              char *home = getenv("HOME");
 -              if (home) {
 -                      char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
 -                      given_config_file = user_config;
 -              } else {
 +              char *user_config = NULL;
 +              char *xdg_config = NULL;
 +
 +              home_config_paths(&user_config, &xdg_config, "config");
 +
 +              if (!user_config)
 +                      /*
 +                       * It is unknown if HOME/.gitconfig exists, so
 +                       * we do not know if we should write to XDG
 +                       * location; error out even if XDG_CONFIG_HOME
 +                       * is set and points at a sane location.
 +                       */
                        die("$HOME not set");
 -              }
 +
 +              if (access(user_config, R_OK) &&
 +                  xdg_config && !access(xdg_config, R_OK))
 +                      given_config_file = xdg_config;
 +              else
 +                      given_config_file = user_config;
        }
        else if (use_system_config)
                given_config_file = git_etc_gitconfig();
diff --combined cache.h
index 95daa690aa897c47cde113c27c954ddb7ef0c103,75b3bea92dc3139b21541e37eb736c3ca625171d..eb4a0316d2d654160a51789dce5ad69fc9d1af45
+++ b/cache.h
@@@ -128,13 -128,13 +128,13 @@@ struct cache_entry 
        unsigned int ce_gid;
        unsigned int ce_size;
        unsigned int ce_flags;
 +      unsigned int ce_namelen;
        unsigned char sha1[20];
        struct cache_entry *next;
        struct cache_entry *dir_next;
        char name[FLEX_ARRAY]; /* more */
  };
  
 -#define CE_NAMEMASK  (0x0fff)
  #define CE_STAGEMASK (0x3000)
  #define CE_EXTENDED  (0x4000)
  #define CE_VALID     (0x8000)
@@@ -198,12 -198,21 +198,12 @@@ static inline void copy_cache_entry(str
        dst->ce_flags = (dst->ce_flags & ~CE_STATE_MASK) | state;
  }
  
 -static inline unsigned create_ce_flags(size_t len, unsigned stage)
 +static inline unsigned create_ce_flags(unsigned stage)
  {
 -      if (len >= CE_NAMEMASK)
 -              len = CE_NAMEMASK;
 -      return (len | (stage << CE_STAGESHIFT));
 -}
 -
 -static inline size_t ce_namelen(const struct cache_entry *ce)
 -{
 -      size_t len = ce->ce_flags & CE_NAMEMASK;
 -      if (len < CE_NAMEMASK)
 -              return len;
 -      return strlen(ce->name + CE_NAMEMASK) + CE_NAMEMASK;
 +      return (stage << CE_STAGESHIFT);
  }
  
 +#define ce_namelen(ce) ((ce)->ce_namelen)
  #define ce_size(ce) cache_entry_size(ce_namelen(ce))
  #define ce_stage(ce) ((CE_STAGEMASK & (ce)->ce_flags) >> CE_STAGESHIFT)
  #define ce_uptodate(ce) ((ce)->ce_flags & CE_UPTODATE)
@@@ -442,7 -451,6 +442,7 @@@ extern int discard_index(struct index_s
  extern int unmerged_index(const struct index_state *);
  extern int verify_path(const char *path);
  extern struct cache_entry *index_name_exists(struct index_state *istate, const char *name, int namelen, int igncase);
 +extern int index_name_stage_pos(const struct index_state *, const char *name, int namelen, int stage);
  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 */
@@@ -555,7 -563,6 +555,7 @@@ extern int read_replace_refs
  extern int fsync_object_files;
  extern int core_preload_index;
  extern int core_apply_sparse_checkout;
 +extern int precomposed_unicode;
  
  enum branch_track {
        BRANCH_TRACK_UNSPECIFIED = -1,
@@@ -615,8 -622,6 +615,8 @@@ extern char *git_snpath(char *buf, size
        __attribute__((format (printf, 3, 4)));
  extern char *git_pathdup(const char *fmt, ...)
        __attribute__((format (printf, 1, 2)));
 +extern char *mkpathdup(const char *fmt, ...)
 +      __attribute__((format (printf, 1, 2)));
  
  /* Return a statically allocated filename matching the sha1 signature */
  extern char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
@@@ -706,7 -711,6 +706,7 @@@ int set_shared_perm(const char *path, i
  int safe_create_leading_directories(char *path);
  int safe_create_leading_directories_const(const char *path);
  int mkdir_in_gitdir(const char *path);
 +extern void home_config_paths(char **global, char **xdg, char *file);
  extern char *expand_user_path(const char *path);
  const char *enter_repo(const char *path, int strict);
  static inline int is_absolute_path(const char *path)
@@@ -782,25 -786,17 +782,25 @@@ struct object_context 
        unsigned mode;
  };
  
 +#define GET_SHA1_QUIETLY        01
 +#define GET_SHA1_COMMIT         02
 +#define GET_SHA1_COMMITTISH     04
 +#define GET_SHA1_TREE          010
 +#define GET_SHA1_TREEISH       020
 +#define GET_SHA1_BLOB        040
 +#define GET_SHA1_ONLY_TO_DIE 04000
 +
  extern int get_sha1(const char *str, unsigned char *sha1);
 -extern int get_sha1_with_mode_1(const char *str, unsigned char *sha1, unsigned *mode, int only_to_die, const char *prefix);
 -static inline int get_sha1_with_mode(const char *str, unsigned char *sha1, unsigned *mode)
 -{
 -      return get_sha1_with_mode_1(str, sha1, mode, 0, NULL);
 -}
 -extern int get_sha1_with_context_1(const char *name, unsigned char *sha1, struct object_context *orc, int only_to_die, const char *prefix);
 -static inline int get_sha1_with_context(const char *str, unsigned char *sha1, struct object_context *orc)
 -{
 -      return get_sha1_with_context_1(str, sha1, orc, 0, NULL);
 -}
 +extern int get_sha1_commit(const char *str, unsigned char *sha1);
 +extern int get_sha1_committish(const char *str, unsigned char *sha1);
 +extern int get_sha1_tree(const char *str, unsigned char *sha1);
 +extern int get_sha1_treeish(const char *str, unsigned char *sha1);
 +extern int get_sha1_blob(const char *str, unsigned char *sha1);
 +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);
 +
 +typedef int each_abbrev_fn(const unsigned char *sha1, void *);
 +extern int for_each_abbrev(const char *prefix, each_abbrev_fn, void *);
  
  /*
   * Try to read a SHA1 in hexadecimal format from the 40 characters
@@@ -864,7 -860,6 +864,7 @@@ extern int validate_headref(const char 
  extern int base_name_compare(const char *name1, int len1, int mode1, const char *name2, int len2, int mode2);
  extern int df_name_compare(const char *name1, int len1, int mode1, const char *name2, int len2, int mode2);
  extern int cache_name_compare(const char *name1, int len1, const char *name2, int len2);
 +extern int cache_name_stage_compare(const char *name1, int len1, int stage1, const char *name2, int len2, int stage2);
  
  extern void *read_object_with_reference(const unsigned char *sha1,
                                        const char *required_type,
@@@ -1038,9 -1033,7 +1038,9 @@@ struct extra_have_objects 
  };
  extern struct ref **get_remote_heads(int in, struct ref **list, unsigned int flags, struct extra_have_objects *);
  extern int server_supports(const char *feature);
 -extern const char *parse_feature_request(const char *features, const char *feature);
 +extern int parse_feature_request(const char *features, const char *feature);
 +extern const char *server_feature_value(const char *feature, int *len_ret);
 +extern const char *parse_feature_value(const char *feature_list, const char *feature, int *len_ret);
  
  extern struct packed_git *parse_pack_index(unsigned char *sha1, const char *idx_path);
  
@@@ -1110,6 -1103,7 +1110,7 @@@ extern int update_server_info(int)
  #define CONFIG_NO_WRITE 4
  #define CONFIG_NOTHING_SET 5
  #define CONFIG_INVALID_PATTERN 6
+ #define CONFIG_GENERIC_ERROR 7
  
  typedef int (*config_fn_t)(const char *, const char *, void *);
  extern int git_default_config(const char *, const char *, void *);
diff --combined diff.c
index 359f40a2101bb0247a4a685bf23565d9debe8633,f1b044780ffb0e590f8dd1d609ae2b2c3b54b473..e6846ca7507aa8a423c5e1f89390fa37723248ff
--- 1/diff.c
--- 2/diff.c
+++ b/diff.c
@@@ -574,6 -574,7 +574,7 @@@ static void emit_rewrite_lines(struct e
        if (!endp) {
                const char *plain = diff_get_color(ecb->color_diff,
                                                   DIFF_PLAIN);
+               putc('\n', ecb->opt->file);
                emit_line_0(ecb->opt, plain, reset, '\\',
                            nneof, strlen(nneof));
        }
@@@ -1397,7 -1398,7 +1398,7 @@@ int print_stat_summary(FILE *fp, int fi
  
        if (!files) {
                assert(insertions == 0 && deletions == 0);
 -              return fputs(_(" 0 files changed\n"), fp);
 +              return fprintf(fp, "%s\n", _(" 0 files changed"));
        }
  
        strbuf_addf(&sb,
@@@ -3187,7 -3188,7 +3188,7 @@@ void diff_setup(struct diff_options *op
        }
  }
  
int diff_setup_done(struct diff_options *options)
void diff_setup_done(struct diff_options *options)
  {
        int count = 0;
  
                options->output_format = DIFF_FORMAT_NO_OUTPUT;
                DIFF_OPT_SET(options, EXIT_WITH_STATUS);
        }
-       return 0;
  }
  
  static int opt_arg(const char *arg, int arg_short, const char *arg_long, int *val)
diff --combined git-submodule.sh
index aac575e74f833c9bce28b779733b28a7611246b2,e89b516039347ce8d3f28efaf8894d75e6bf1d8e..3e2045e52daf43cc351af23af0fd770fb1a5044f
@@@ -30,22 -30,7 +30,22 @@@ nofetch
  update=
  prefix=
  
 -# Resolve relative url by appending to parent's url
 +# The function takes at most 2 arguments. The first argument is the
 +# URL that navigates to the submodule origin repo. When relative, this URL
 +# is relative to the superproject origin URL repo. The second up_path
 +# argument, if specified, is the relative path that navigates
 +# from the submodule working tree to the superproject working tree.
 +#
 +# The output of the function is the origin URL of the submodule.
 +#
 +# The output will either be an absolute URL or filesystem path (if the
 +# superproject origin URL is an absolute URL or filesystem path,
 +# respectively) or a relative file system path (if the superproject
 +# origin URL is a relative file system path).
 +#
 +# When the output is a relative file system path, the path is either
 +# relative to the submodule working tree, if up_path is specified, or to
 +# the superproject working tree otherwise.
  resolve_relative_url ()
  {
        remote=$(get_default_remote)
        url="$1"
        remoteurl=${remoteurl%/}
        sep=/
 +      up_path="$2"
 +
 +      case "$remoteurl" in
 +      *:*|/*)
 +              is_relative=
 +              ;;
 +      ./*|../*)
 +              is_relative=t
 +              ;;
 +      *)
 +              is_relative=t
 +              remoteurl="./$remoteurl"
 +              ;;
 +      esac
 +
        while test -n "$url"
        do
                case "$url" in
                                sep=:
                                ;;
                        *)
 -                              die "$(eval_gettext "cannot strip one component off url '\$remoteurl'")"
 +                              if test -z "$is_relative" || test "." = "$remoteurl"
 +                              then
 +                                      die "$(eval_gettext "cannot strip one component off url '\$remoteurl'")"
 +                              else
 +                                      remoteurl=.
 +                              fi
                                ;;
                        esac
                        ;;
@@@ -99,8 -64,7 +99,8 @@@
                        break;;
                esac
        done
 -      echo "$remoteurl$sep${url%/}"
 +      remoteurl="$remoteurl$sep${url%/}"
 +      echo "${is_relative:+${up_path}}${remoteurl#./}"
  }
  
  #
  #
  module_list()
  {
-       git ls-files --error-unmatch --stage -- "$@" |
+       (
+               git ls-files --error-unmatch --stage -- "$@" ||
+               echo "unmatched pathspec exists"
+       ) |
        perl -e '
        my %unmerged = ();
        my ($null_sha1) = ("0" x 40);
+       my @out = ();
+       my $unmatched = 0;
        while (<STDIN>) {
+               if (/^unmatched pathspec/) {
+                       $unmatched = 1;
+                       next;
+               }
                chomp;
                my ($mode, $sha1, $stage, $path) =
                        /^([0-7]+) ([0-9a-f]{40}) ([0-3])\t(.*)$/;
                next unless $mode eq "160000";
                if ($stage ne "0") {
                        if (!$unmerged{$path}++) {
-                               print "$mode $null_sha1 U\t$path\n";
+                               push @out, "$mode $null_sha1 U\t$path\n";
                        }
                        next;
                }
-               print "$_\n";
+               push @out, "$_\n";
+       }
+       if ($unmatched) {
+               print "#unmatched\n";
+       } else {
+               print for (@out);
        }
        '
  }
  
+ die_if_unmatched ()
+ {
+       if test "$1" = "#unmatched"
+       then
+               exit 1
+       fi
+ }
  #
  # Map submodule path to submodule name
  #
@@@ -181,11 -167,8 +203,11 @@@ module_clone(
                rm -f "$gitdir/index"
        else
                mkdir -p "$gitdir_base"
 -              git clone $quiet -n ${reference:+"$reference"} \
 -                      --separate-git-dir "$gitdir" "$url" "$sm_path" ||
 +              (
 +                      clear_local_git_env
 +                      git clone $quiet -n ${reference:+"$reference"} \
 +                              --separate-git-dir "$gitdir" "$url" "$sm_path"
 +              ) ||
                die "$(eval_gettext "Clone of '\$url' into submodule path '\$sm_path' failed")"
        fi
  
@@@ -385,6 -368,7 +407,7 @@@ cmd_foreach(
        module_list |
        while read mode sha1 stage sm_path
        do
+               die_if_unmatched "$mode"
                if test -e "$sm_path"/.git
                then
                        say "$(eval_gettext "Entering '\$prefix\$sm_path'")"
@@@ -437,6 -421,7 +460,7 @@@ cmd_init(
        module_list "$@" |
        while read mode sha1 stage sm_path
        do
+               die_if_unmatched "$mode"
                name=$(module_name "$sm_path") || exit
  
                # Copy url setting when it is not set yet
@@@ -537,6 -522,7 +561,7 @@@ cmd_update(
        err=
        while read mode sha1 stage sm_path
        do
+               die_if_unmatched "$mode"
                if test "$stage" = U
                then
                        echo >&2 "Skipping unmerged submodule $sm_path"
@@@ -578,7 -564,7 +603,7 @@@ Maybe you want to use 'update --init'?"
                        die "$(eval_gettext "Unable to find current revision in submodule path '\$sm_path'")"
                fi
  
-               if test "$subsha1" != "$sha1"
+               if test "$subsha1" != "$sha1" -o -n "$force"
                then
                        subforce=$force
                        # If we don't already have a -f flag and the submodule has never been checked out
@@@ -751,7 -737,7 +776,7 @@@ cmd_summary() 
        if [ -n "$files" ]
        then
                test -n "$cached" &&
 -              die "$(gettext -- "--cached cannot be used with --files")"
 +              die "$(gettext "The --cached option cannot be used with the --files option")"
                diff_cmd=diff-files
                head=
        fi
@@@ -932,6 -918,7 +957,7 @@@ cmd_status(
        module_list "$@" |
        while read mode sha1 stage sm_path
        do
+               die_if_unmatched "$mode"
                name=$(module_name "$sm_path") || exit
                url=$(git config submodule."$name".url)
                displaypath="$prefix$sm_path"
@@@ -1000,32 -987,21 +1026,33 @@@ cmd_sync(
        module_list "$@" |
        while read mode sha1 stage sm_path
        do
+               die_if_unmatched "$mode"
                name=$(module_name "$sm_path")
                url=$(git config -f .gitmodules --get submodule."$name".url)
  
                # Possibly a url relative to parent
                case "$url" in
                ./*|../*)
 -                      url=$(resolve_relative_url "$url") || exit
 +                      # rewrite foo/bar as ../.. to find path from
 +                      # submodule work tree to superproject work tree
 +                      up_path="$(echo "$sm_path" | sed "s/[^/][^/]*/../g")" &&
 +                      # guarantee a trailing /
 +                      up_path=${up_path%/}/ &&
 +                      # path from submodule work tree to submodule origin repo
 +                      sub_origin_url=$(resolve_relative_url "$url" "$up_path") &&
 +                      # path from superproject work tree to submodule origin repo
 +                      super_config_url=$(resolve_relative_url "$url") || exit
 +                      ;;
 +              *)
 +                      sub_origin_url="$url"
 +                      super_config_url="$url"
                        ;;
                esac
  
                if git config "submodule.$name.url" >/dev/null 2>/dev/null
                then
                        say "$(eval_gettext "Synchronizing submodule url for '\$name'")"
 -                      git config submodule."$name".url "$url"
 +                      git config submodule."$name".url "$super_config_url"
  
                        if test -e "$sm_path"/.git
                        then
                                clear_local_git_env
                                cd "$sm_path"
                                remote=$(get_default_remote)
 -                              git config remote."$remote".url "$url"
 +                              git config remote."$remote".url "$sub_origin_url"
                        )
                        fi
                fi
diff --combined merge-recursive.c
index 39b2e165e05472daf38cd6f458541b6db4abc9a8,e02da3556d08f02abf87cb1ece75a2e1d0c8ab78..7866ca1026730e2e0446f711e3c621e44cef9f60
@@@ -187,7 -187,7 +187,7 @@@ static void output_commit_title(struct 
        else {
                printf("%s ", find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV));
                if (parse_commit(commit) != 0)
 -                      printf("(bad commit)\n");
 +                      printf(_("(bad commit)\n"));
                else {
                        const char *title;
                        int len = find_commit_subject(commit->buffer, &title);
@@@ -203,7 -203,7 +203,7 @@@ static int add_cacheinfo(unsigned int m
        struct cache_entry *ce;
        ce = make_cache_entry(mode, sha1 ? sha1 : null_sha1, path, stage, refresh);
        if (!ce)
 -              return error("addinfo_cache failed for path '%s'", path);
 +              return error(_("addinfo_cache failed for path '%s'"), path);
        return add_cache_entry(ce, options);
  }
  
@@@ -265,7 -265,7 +265,7 @@@ struct tree *write_tree_from_memory(str
        if (!cache_tree_fully_valid(active_cache_tree) &&
            cache_tree_update(active_cache_tree,
                              active_cache, active_nr, 0) < 0)
 -              die("error building trees");
 +              die(_("error building trees"));
  
        result = lookup_tree(active_cache_tree->sha1);
  
@@@ -493,8 -493,7 +493,7 @@@ static struct string_list *get_renames(
        opts.rename_score = o->rename_score;
        opts.show_rename_progress = o->show_rename_progress;
        opts.output_format = DIFF_FORMAT_NO_OUTPUT;
-       if (diff_setup_done(&opts) < 0)
-               die(_("diff setup failed"));
+       diff_setup_done(&opts);
        diff_tree_sha1(o_tree->object.sha1, tree->object.sha1, "", &opts);
        diffcore_std(&opts);
        if (opts.needed_rename_limit > o->needed_rename_limit)
@@@ -614,23 -613,6 +613,6 @@@ static char *unique_path(struct merge_o
        return newpath;
  }
  
- static void flush_buffer(int fd, const char *buf, unsigned long size)
- {
-       while (size > 0) {
-               long ret = write_in_full(fd, buf, size);
-               if (ret < 0) {
-                       /* Ignore epipe */
-                       if (errno == EPIPE)
-                               break;
-                       die_errno("merge-recursive");
-               } else if (!ret) {
-                       die(_("merge-recursive: disk full?"));
-               }
-               size -= ret;
-               buf += ret;
-       }
- }
  static int dir_in_way(const char *path, int check_working_copy)
  {
        int pos, pathlen = strlen(path);
@@@ -687,7 -669,7 +669,7 @@@ static int would_lose_untracked(const c
  static int make_room_for_path(struct merge_options *o, const char *path)
  {
        int status, i;
 -      const char *msg = "failed to create path '%s'%s";
 +      const char *msg = _("failed to create path '%s'%s");
  
        /* Unlink any D/F conflict files that are in the way */
        for (i = 0; i < o->df_conflict_file_set.nr; i++) {
                    path[df_pathlen] == '/' &&
                    strncmp(path, df_path, df_pathlen) == 0) {
                        output(o, 3,
 -                             "Removing %s to make room for subdirectory\n",
 +                             _("Removing %s to make room for subdirectory\n"),
                               df_path);
                        unlink(df_path);
                        unsorted_string_list_delete_item(&o->df_conflict_file_set,
        if (status) {
                if (status == -3) {
                        /* something else exists */
 -                      error(msg, path, ": perhaps a D/F conflict?");
 +                      error(msg, path, _(": perhaps a D/F conflict?"));
                        return -1;
                }
                die(msg, path, "");
         * tracking it.
         */
        if (would_lose_untracked(path))
 -              return error("refusing to lose untracked file at '%s'",
 +              return error(_("refusing to lose untracked file at '%s'"),
                             path);
  
        /* Successful unlink is good.. */
        if (errno == ENOENT)
                return 0;
        /* .. but not some other error (who really cares what?) */
 -      return error(msg, path, ": perhaps a D/F conflict?");
 +      return error(msg, path, _(": perhaps a D/F conflict?"));
  }
  
  static void update_file_flags(struct merge_options *o,
  
                buf = read_sha1_file(sha, &type, &size);
                if (!buf)
 -                      die("cannot read object %s '%s'", sha1_to_hex(sha), path);
 +                      die(_("cannot read object %s '%s'"), sha1_to_hex(sha), path);
                if (type != OBJ_BLOB)
 -                      die("blob expected for %s '%s'", sha1_to_hex(sha), path);
 +                      die(_("blob expected for %s '%s'"), sha1_to_hex(sha), path);
                if (S_ISREG(mode)) {
                        struct strbuf strbuf = STRBUF_INIT;
                        if (convert_to_working_tree(path, buf, size, &strbuf)) {
                                mode = 0666;
                        fd = open(path, O_WRONLY | O_TRUNC | O_CREAT, mode);
                        if (fd < 0)
 -                              die_errno("failed to open '%s'", path);
 +                              die_errno(_("failed to open '%s'"), path);
-                       flush_buffer(fd, buf, size);
+                       write_in_full(fd, buf, size);
                        close(fd);
                } else if (S_ISLNK(mode)) {
                        char *lnk = xmemdupz(buf, size);
                        safe_create_leading_directories_const(path);
                        unlink(path);
                        if (symlink(lnk, path))
 -                              die_errno("failed to symlink '%s'", path);
 +                              die_errno(_("failed to symlink '%s'"), path);
                        free(lnk);
                } else
 -                      die("do not know what to do with %06o %s '%s'",
 +                      die(_("do not know what to do with %06o %s '%s'"),
                            mode, sha1_to_hex(sha), path);
                free(buf);
        }
@@@ -936,11 -918,11 +918,11 @@@ static struct merge_file_info merge_fil
                                                  branch1, branch2);
  
                        if ((merge_status < 0) || !result_buf.ptr)
 -                              die("Failed to execute internal merge");
 +                              die(_("Failed to execute internal merge"));
  
                        if (write_sha1_file(result_buf.ptr, result_buf.size,
                                            blob_type, result.sha))
 -                              die("Unable to add %s to database",
 +                              die(_("Unable to add %s to database"),
                                    a->path);
  
                        free(result_buf.ptr);
                        if (!sha_eq(a->sha1, b->sha1))
                                result.clean = 0;
                } else {
 -                      die("unsupported object type in the tree");
 +                      die(_("unsupported object type in the tree"));
                }
        }
  
@@@ -1034,32 -1016,22 +1016,32 @@@ static void handle_change_delete(struc
                remove_file_from_cache(path);
                update_file(o, 0, o_sha, o_mode, renamed ? renamed : path);
        } else if (!a_sha) {
 -              output(o, 1, "CONFLICT (%s/delete): %s deleted in %s "
 -                     "and %s in %s. Version %s of %s left in tree%s%s.",
 -                     change, path, o->branch1,
 -                     change_past, o->branch2, o->branch2, path,
 -                     NULL == renamed ? "" : " at ",
 -                     NULL == renamed ? "" : renamed);
 -              update_file(o, 0, b_sha, b_mode, renamed ? renamed : path);
 +              if (!renamed) {
 +                      output(o, 1, _("CONFLICT (%s/delete): %s deleted in %s "
 +                             "and %s in %s. Version %s of %s left in tree."),
 +                             change, path, o->branch1, change_past,
 +                             o->branch2, o->branch2, path);
 +                      update_file(o, 0, b_sha, b_mode, path);
 +              } else {
 +                      output(o, 1, _("CONFLICT (%s/delete): %s deleted in %s "
 +                             "and %s in %s. Version %s of %s left in tree at %s."),
 +                             change, path, o->branch1, change_past,
 +                             o->branch2, o->branch2, path, renamed);
 +                      update_file(o, 0, b_sha, b_mode, renamed);
 +              }
        } else {
 -              output(o, 1, "CONFLICT (%s/delete): %s deleted in %s "
 -                     "and %s in %s. Version %s of %s left in tree%s%s.",
 -                     change, path, o->branch2,
 -                     change_past, o->branch1, o->branch1, path,
 -                     NULL == renamed ? "" : " at ",
 -                     NULL == renamed ? "" : renamed);
 -              if (renamed)
 +              if (!renamed) {
 +                      output(o, 1, _("CONFLICT (%s/delete): %s deleted in %s "
 +                             "and %s in %s. Version %s of %s left in tree."),
 +                             change, path, o->branch2, change_past,
 +                             o->branch1, o->branch1, path);
 +              } else {
 +                      output(o, 1, _("CONFLICT (%s/delete): %s deleted in %s "
 +                             "and %s in %s. Version %s of %s left in tree at %s."),
 +                             change, path, o->branch2, change_past,
 +                             o->branch1, o->branch1, path, renamed);
                        update_file(o, 0, a_sha, a_mode, renamed);
 +              }
                /*
                 * No need to call update_file() on path when !renamed, since
                 * that would needlessly touch path.  We could call
@@@ -1095,7 -1067,7 +1077,7 @@@ static void conflict_rename_delete(stru
                             orig->sha1, orig->mode,
                             a_sha, a_mode,
                             b_sha, b_mode,
 -                           "rename", "renamed");
 +                           _("rename"), _("renamed"));
  
        if (o->call_depth) {
                remove_file_from_cache(dest->path);
@@@ -1151,7 -1123,7 +1133,7 @@@ static void handle_file(struct merge_op
        } else {
                if (dir_in_way(rename->path, !o->call_depth)) {
                        dst_name = unique_path(o, rename->path, cur_branch);
 -                      output(o, 1, "%s is a directory in %s adding as %s instead",
 +                      output(o, 1, _("%s is a directory in %s adding as %s instead"),
                               rename->path, other_branch, dst_name);
                }
        }
@@@ -1173,12 -1145,12 +1155,12 @@@ static void conflict_rename_rename_1to2
        struct diff_filespec *a = ci->pair1->two;
        struct diff_filespec *b = ci->pair2->two;
  
 -      output(o, 1, "CONFLICT (rename/rename): "
 +      output(o, 1, _("CONFLICT (rename/rename): "
               "Rename \"%s\"->\"%s\" in branch \"%s\" "
 -             "rename \"%s\"->\"%s\" in \"%s\"%s",
 +             "rename \"%s\"->\"%s\" in \"%s\"%s"),
               one->path, a->path, ci->branch1,
               one->path, b->path, ci->branch2,
 -             o->call_depth ? " (left unresolved)" : "");
 +             o->call_depth ? _(" (left unresolved)") : "");
        if (o->call_depth) {
                struct merge_file_info mfi;
                struct diff_filespec other;
@@@ -1232,9 -1204,9 +1214,9 @@@ static void conflict_rename_rename_2to1
        struct merge_file_info mfi_c1;
        struct merge_file_info mfi_c2;
  
 -      output(o, 1, "CONFLICT (rename/rename): "
 +      output(o, 1, _("CONFLICT (rename/rename): "
               "Rename %s->%s in %s. "
 -             "Rename %s->%s in %s",
 +             "Rename %s->%s in %s"),
               a->path, c1->path, ci->branch1,
               b->path, c2->path, ci->branch2);
  
        } else {
                char *new_path1 = unique_path(o, path, ci->branch1);
                char *new_path2 = unique_path(o, path, ci->branch2);
 -              output(o, 1, "Renaming %s to %s and %s to %s instead",
 +              output(o, 1, _("Renaming %s to %s and %s to %s instead"),
                       a->path, new_path1, b->path, new_path2);
                remove_file(o, 0, path, 0);
                update_file(o, 0, mfi_c1.sha, mfi_c1.mode, new_path1);
@@@ -1461,8 -1433,8 +1443,8 @@@ static int process_renames(struct merge
                        } else if (!sha_eq(dst_other.sha1, null_sha1)) {
                                clean_merge = 0;
                                try_merge = 1;
 -                              output(o, 1, "CONFLICT (rename/add): Rename %s->%s in %s. "
 -                                     "%s added in %s",
 +                              output(o, 1, _("CONFLICT (rename/add): Rename %s->%s in %s. "
 +                                     "%s added in %s"),
                                       ren1_src, ren1_dst, branch1,
                                       ren1_dst, branch2);
                                if (o->call_depth) {
                                                         ren1->pair->two->sha1, ren1->pair->two->mode,
                                                         dst_other.sha1, dst_other.mode,
                                                         branch1, branch2);
 -                                      output(o, 1, "Adding merged %s", ren1_dst);
 +                                      output(o, 1, _("Adding merged %s"), ren1_dst);
                                        update_file(o, 0, mfi.sha, mfi.mode, ren1_dst);
                                        try_merge = 0;
                                } else {
                                        char *new_path = unique_path(o, ren1_dst, branch2);
 -                                      output(o, 1, "Adding as %s instead", new_path);
 +                                      output(o, 1, _("Adding as %s instead"), new_path);
                                        update_file(o, 0, dst_other.sha1, dst_other.mode, new_path);
                                        free(new_path);
                                }
@@@ -1527,10 -1499,10 +1509,10 @@@ static int read_sha1_strbuf(const unsig
        unsigned long size;
        buf = read_sha1_file(sha1, &type, &size);
        if (!buf)
 -              return error("cannot read object %s", sha1_to_hex(sha1));
 +              return error(_("cannot read object %s"), sha1_to_hex(sha1));
        if (type != OBJ_BLOB) {
                free(buf);
 -              return error("object %s is not a blob", sha1_to_hex(sha1));
 +              return error(_("object %s is not a blob"), sha1_to_hex(sha1));
        }
        strbuf_attach(dst, buf, size, size + 1);
        return 0;
@@@ -1578,7 -1550,7 +1560,7 @@@ static void handle_modify_delete(struc
                             o_sha, o_mode,
                             a_sha, a_mode,
                             b_sha, b_mode,
 -                           "modify", "modified");
 +                           _("modify"), _("modified"));
  }
  
  static int merge_content(struct merge_options *o,
                         unsigned char *b_sha, int b_mode,
                         struct rename_conflict_info *rename_conflict_info)
  {
 -      const char *reason = "content";
 +      const char *reason = _("content");
        const char *path1 = NULL, *path2 = NULL;
        struct merge_file_info mfi;
        struct diff_filespec one, a, b;
        unsigned df_conflict_remains = 0;
  
        if (!o_sha) {
 -              reason = "add/add";
 +              reason = _("add/add");
                o_sha = (unsigned char *)null_sha1;
        }
        one.path = a.path = b.path = (char *)path;
        if (mfi.clean && !df_conflict_remains &&
            sha_eq(mfi.sha, a_sha) && mfi.mode == a_mode) {
                int path_renamed_outside_HEAD;
 -              output(o, 3, "Skipped %s (merged same as existing)", path);
 +              output(o, 3, _("Skipped %s (merged same as existing)"), path);
                /*
                 * The content merge resulted in the same file contents we
                 * already had.  We can return early if those file contents
                        return mfi.clean;
                }
        } else
 -              output(o, 2, "Auto-merging %s", path);
 +              output(o, 2, _("Auto-merging %s"), path);
  
        if (!mfi.clean) {
                if (S_ISGITLINK(mfi.mode))
 -                      reason = "submodule";
 -              output(o, 1, "CONFLICT (%s): Merge conflict in %s",
 +                      reason = _("submodule");
 +              output(o, 1, _("CONFLICT (%s): Merge conflict in %s"),
                                reason, path);
                if (rename_conflict_info && !df_conflict_remains)
                        update_stages(path, &one, &a, &b);
  
                }
                new_path = unique_path(o, path, rename_conflict_info->branch1);
 -              output(o, 1, "Adding as %s instead", new_path);
 +              output(o, 1, _("Adding as %s instead"), new_path);
                update_file(o, 0, mfi.sha, mfi.mode, new_path);
                free(new_path);
                mfi.clean = 0;
@@@ -1738,7 -1710,7 +1720,7 @@@ static int process_entry(struct merge_o
                        /* Deleted in both or deleted in one and
                         * unchanged in the other */
                        if (a_sha)
 -                              output(o, 2, "Removing %s", path);
 +                              output(o, 2, _("Removing %s"), path);
                        /* do not touch working file if it did not exist */
                        remove_file(o, 1, path, !a_sha);
                } else {
                        other_branch = o->branch2;
                        mode = a_mode;
                        sha = a_sha;
 -                      conf = "file/directory";
 +                      conf = _("file/directory");
                } else {
                        add_branch = o->branch2;
                        other_branch = o->branch1;
                        mode = b_mode;
                        sha = b_sha;
 -                      conf = "directory/file";
 +                      conf = _("directory/file");
                }
                if (dir_in_way(path, !o->call_depth)) {
                        char *new_path = unique_path(o, path, add_branch);
                        clean_merge = 0;
 -                      output(o, 1, "CONFLICT (%s): There is a directory with name %s in %s. "
 -                             "Adding %s as %s",
 +                      output(o, 1, _("CONFLICT (%s): There is a directory with name %s in %s. "
 +                             "Adding %s as %s"),
                               conf, path, other_branch, path, new_path);
                        if (o->call_depth)
                                remove_file_from_cache(path);
                                remove_file_from_cache(path);
                        free(new_path);
                } else {
 -                      output(o, 2, "Adding %s", path);
 +                      output(o, 2, _("Adding %s"), path);
                        /* do not overwrite file if already present */
                        update_file_flags(o, sha, mode, path, 1, !a_sha);
                }
                 */
                remove_file(o, 1, path, !a_mode);
        } else
 -              die("Fatal merge failure, shouldn't happen.");
 +              die(_("Fatal merge failure, shouldn't happen."));
  
        return clean_merge;
  }
@@@ -1820,7 -1792,7 +1802,7 @@@ int merge_trees(struct merge_options *o
        }
  
        if (sha_eq(common->object.sha1, merge->object.sha1)) {
 -              output(o, 0, "Already up-to-date!");
 +              output(o, 0, _("Already up-to-date!"));
                *result = head;
                return 1;
        }
  
        if (code != 0) {
                if (show(o, 4) || o->call_depth)
 -                      die("merging of trees %s and %s failed",
 +                      die(_("merging of trees %s and %s failed"),
                            sha1_to_hex(head->object.sha1),
                            sha1_to_hex(merge->object.sha1));
                else
                for (i = 0; i < entries->nr; i++) {
                        struct stage_data *e = entries->items[i].util;
                        if (!e->processed)
 -                              die("Unprocessed path??? %s",
 +                              die(_("Unprocessed path??? %s"),
                                    entries->items[i].string);
                }
  
@@@ -1904,7 -1876,7 +1886,7 @@@ int merge_recursive(struct merge_option
        int clean;
  
        if (show(o, 4)) {
 -              output(o, 4, "Merging:");
 +              output(o, 4, _("Merging:"));
                output_commit_title(o, h1);
                output_commit_title(o, h2);
        }
        }
  
        if (show(o, 5)) {
 -              output(o, 5, "found %u common ancestor(s):", commit_list_count(ca));
 +              unsigned cnt = commit_list_count(ca);
 +
 +              output(o, 5, Q_("found %u common ancestor:",
 +                              "found %u common ancestors:", cnt), cnt);
                for (iter = ca; iter; iter = iter->next)
                        output_commit_title(o, iter->item);
        }
                o->call_depth--;
  
                if (!merged_common_ancestors)
 -                      die("merge returned no commit");
 +                      die(_("merge returned no commit"));
        }
  
        discard_cache();
@@@ -2011,7 -1980,7 +1993,7 @@@ int merge_recursive_generic(struct merg
                for (i = 0; i < num_base_list; ++i) {
                        struct commit *base;
                        if (!(base = get_ref(base_list[i], sha1_to_hex(base_list[i]))))
 -                              return error("Could not parse object '%s'",
 +                              return error(_("Could not parse object '%s'"),
                                        sha1_to_hex(base_list[i]));
                        commit_list_insert(base, &ca);
                }
        if (active_cache_changed &&
                        (write_cache(index_fd, active_cache, active_nr) ||
                         commit_locked_index(lock)))
 -              return error("Unable to write index.");
 +              return error(_("Unable to write index."));
  
        return clean ? 0 : 1;
  }
diff --combined notes-merge.c
index 29c6411fc63a01460f95b25bf62115c350ef2191,7d62904f619fcd775f7ed7e7cff00d44005f3a5b..0f67bd3f9605aa7a3c98b88b4ae4aae037ace3d7
@@@ -126,8 -126,7 +126,7 @@@ static struct notes_merge_pair *diff_tr
        diff_setup(&opt);
        DIFF_OPT_SET(&opt, RECURSIVE);
        opt.output_format = DIFF_FORMAT_NO_OUTPUT;
-       if (diff_setup_done(&opt) < 0)
-               die("diff_setup_done failed");
+       diff_setup_done(&opt);
        diff_tree_sha1(base, remote, "", &opt);
        diffcore_std(&opt);
  
@@@ -190,8 -189,7 +189,7 @@@ static void diff_tree_local(struct note
        diff_setup(&opt);
        DIFF_OPT_SET(&opt, RECURSIVE);
        opt.output_format = DIFF_FORMAT_NO_OUTPUT;
-       if (diff_setup_done(&opt) < 0)
-               die("diff_setup_done failed");
+       diff_setup_done(&opt);
        diff_tree_sha1(base, local, "", &opt);
        diffcore_std(&opt);
  
@@@ -524,10 -522,8 +522,10 @@@ static int merge_from_diffs(struct note
        free(changes);
  
        if (o->verbosity >= 4)
 -              printf("Merge result: %i unmerged notes and a %s notes tree\n",
 -                      conflicts, t->dirty ? "dirty" : "clean");
 +              printf(t->dirty ?
 +                     "Merge result: %i unmerged notes and a dirty notes tree\n" :
 +                     "Merge result: %i unmerged notes and a clean notes tree\n",
 +                     conflicts);
  
        return conflicts ? -1 : 1;
  }
diff --combined read-cache.c
index d2be78ea95e2e554b085721bafa939c9024125ed,d8543e4d42f0cf7f8850751806cc40bc05578117..79e3bbe0240e16629e8ba4b755d60f986132802a
  
  static struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really);
  
 +/* Mask for the name length in ce_flags in the on-disk index */
 +
 +#define CE_NAMEMASK  (0x0fff)
 +
  /* Index extensions.
   *
   * The first letter should be 'A'..'Z' for extensions that are not
@@@ -58,8 -54,8 +58,8 @@@ void rename_index_entry_at(struct index
  
        new = xmalloc(cache_entry_size(namelen));
        copy_cache_entry(new, old);
 -      new->ce_flags &= ~(CE_STATE_MASK | CE_NAMEMASK);
 -      new->ce_flags |= (namelen >= CE_NAMEMASK ? CE_NAMEMASK : namelen);
 +      new->ce_flags &= ~CE_STATE_MASK;
 +      new->ce_namelen = namelen;
        memcpy(new->name, new_name, namelen + 1);
  
        cache_tree_invalidate_path(istate->cache_tree, old->name);
@@@ -399,10 -395,17 +399,10 @@@ int df_name_compare(const char *name1, 
        return c1 - c2;
  }
  
 -int cache_name_compare(const char *name1, int flags1, const char *name2, int flags2)
 +int cache_name_stage_compare(const char *name1, int len1, int stage1, const char *name2, int len2, int stage2)
  {
 -      int len1, len2, len, cmp;
 -
 -      len1 = flags1 & CE_NAMEMASK;
 -      if (CE_NAMEMASK <= len1)
 -              len1 = strlen(name1 + CE_NAMEMASK) + CE_NAMEMASK;
 -      len2 = flags2 & CE_NAMEMASK;
 -      if (CE_NAMEMASK <= len2)
 -              len2 = strlen(name2 + CE_NAMEMASK) + CE_NAMEMASK;
 -      len = len1 < len2 ? len1 : len2;
 +      int len = len1 < len2 ? len1 : len2;
 +      int cmp;
  
        cmp = memcmp(name1, name2, len);
        if (cmp)
        if (len1 > len2)
                return 1;
  
 -      /* Compare stages  */
 -      flags1 &= CE_STAGEMASK;
 -      flags2 &= CE_STAGEMASK;
 -
 -      if (flags1 < flags2)
 +      if (stage1 < stage2)
                return -1;
 -      if (flags1 > flags2)
 +      if (stage1 > stage2)
                return 1;
        return 0;
  }
  
 -int index_name_pos(const struct index_state *istate, const char *name, int namelen)
 +int cache_name_compare(const char *name1, int len1, const char *name2, int len2)
 +{
 +      return cache_name_stage_compare(name1, len1, 0, name2, len2, 0);
 +}
 +
 +int index_name_stage_pos(const struct index_state *istate, const char *name, int namelen, int stage)
  {
        int first, last;
  
        while (last > first) {
                int next = (last + first) >> 1;
                struct cache_entry *ce = istate->cache[next];
 -              int cmp = cache_name_compare(name, namelen, ce->name, ce->ce_flags);
 +              int cmp = cache_name_stage_compare(name, namelen, stage, ce->name, ce_namelen(ce), ce_stage(ce));
                if (!cmp)
                        return next;
                if (cmp < 0) {
        return -first-1;
  }
  
 +int index_name_pos(const struct index_state *istate, const char *name, int namelen)
 +{
 +      return index_name_stage_pos(istate, name, namelen, 0);
 +}
 +
  /* Remove entry, return true if there are more entries to go.. */
  int remove_index_entry_at(struct index_state *istate, int pos)
  {
@@@ -589,7 -586,7 +589,7 @@@ int add_to_index(struct index_state *is
        size = cache_entry_size(namelen);
        ce = xcalloc(1, size);
        memcpy(ce->name, path, namelen);
 -      ce->ce_flags = namelen;
 +      ce->ce_namelen = namelen;
        if (!intent_only)
                fill_stat_cache_info(ce, st);
        else
@@@ -691,8 -688,7 +691,8 @@@ struct cache_entry *make_cache_entry(un
  
        hashcpy(ce->sha1, sha1);
        memcpy(ce->name, path, len);
 -      ce->ce_flags = create_ce_flags(len, stage);
 +      ce->ce_flags = create_ce_flags(stage);
 +      ce->ce_namelen = len;
        ce->ce_mode = create_ce_mode(mode);
  
        if (refresh)
@@@ -829,7 -825,7 +829,7 @@@ static int has_dir_name(struct index_st
                }
                len = slash - name;
  
 -              pos = index_name_pos(istate, name, create_ce_flags(len, stage));
 +              pos = index_name_stage_pos(istate, name, len, stage);
                if (pos >= 0) {
                        /*
                         * Found one, but not so fast.  This could
@@@ -919,7 -915,7 +919,7 @@@ static int add_index_entry_with_check(s
        int new_only = option & ADD_CACHE_NEW_ONLY;
  
        cache_tree_invalidate_path(istate->cache_tree, ce->name);
 -      pos = index_name_pos(istate, ce->name, ce->ce_flags);
 +      pos = index_name_stage_pos(istate, ce->name, ce_namelen(ce), ce_stage(ce));
  
        /* existing match? Just replace it. */
        if (pos >= 0) {
                if (!ok_to_replace)
                        return error("'%s' appears as both a file and as a directory",
                                     ce->name);
 -              pos = index_name_pos(istate, ce->name, ce->ce_flags);
 +              pos = index_name_stage_pos(istate, ce->name, ce_namelen(ce), ce_stage(ce));
                pos = -pos-1;
        }
        return pos + 1;
@@@ -1128,7 -1124,7 +1128,7 @@@ int refresh_index(struct index_state *i
                        continue;
  
                if (pathspec &&
 -                  !match_pathspec(pathspec, ce->name, strlen(ce->name), 0, seen))
 +                  !match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, seen))
                        filtered = 1;
  
                if (ce_stage(ce)) {
@@@ -1328,8 -1324,7 +1328,8 @@@ static struct cache_entry *cache_entry_
        ce->ce_uid   = ntoh_l(ondisk->uid);
        ce->ce_gid   = ntoh_l(ondisk->gid);
        ce->ce_size  = ntoh_l(ondisk->size);
 -      ce->ce_flags = flags;
 +      ce->ce_flags = flags & ~CE_NAMEMASK;
 +      ce->ce_namelen = len;
        hashcpy(ce->sha1, ondisk->sha1);
        memcpy(ce->name, name, len);
        ce->name[len] = '\0';
@@@ -1414,11 -1409,9 +1414,9 @@@ int read_index_from(struct index_state 
        size_t mmap_size;
        struct strbuf previous_name_buf = STRBUF_INIT, *previous_name;
  
-       errno = EBUSY;
        if (istate->initialized)
                return istate->cache_nr;
  
-       errno = ENOENT;
        istate->timestamp.sec = 0;
        istate->timestamp.nsec = 0;
        fd = open(path, O_RDONLY);
        if (fstat(fd, &st))
                die_errno("cannot stat the open index");
  
-       errno = EINVAL;
        mmap_size = xsize_t(st.st_size);
        if (mmap_size < sizeof(struct cache_header) + 20)
                die("index file smaller than expected");
  
        mmap = xmmap(NULL, mmap_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
-       close(fd);
        if (mmap == MAP_FAILED)
                die_errno("unable to map index file");
+       close(fd);
  
        hdr = mmap;
        if (verify_hdr(hdr, mmap_size) < 0)
  
  unmap:
        munmap(mmap, mmap_size);
-       errno = EINVAL;
        die("index file corrupt");
  }
  
@@@ -1656,8 -1647,6 +1652,8 @@@ static void ce_smudge_racily_clean_entr
  static char *copy_cache_entry_to_ondisk(struct ondisk_cache_entry *ondisk,
                                       struct cache_entry *ce)
  {
 +      short flags;
 +
        ondisk->ctime.sec = htonl(ce->ce_ctime.sec);
        ondisk->mtime.sec = htonl(ce->ce_mtime.sec);
        ondisk->ctime.nsec = htonl(ce->ce_ctime.nsec);
        ondisk->gid  = htonl(ce->ce_gid);
        ondisk->size = htonl(ce->ce_size);
        hashcpy(ondisk->sha1, ce->sha1);
 -      ondisk->flags = htons(ce->ce_flags);
 +
 +      flags = ce->ce_flags;
 +      flags |= (ce_namelen(ce) >= CE_NAMEMASK ? CE_NAMEMASK : ce_namelen(ce));
 +      ondisk->flags = htons(flags);
        if (ce->ce_flags & CE_EXTENDED) {
                struct ondisk_cache_entry_extended *ondisk2;
                ondisk2 = (struct ondisk_cache_entry_extended *)ondisk;
@@@ -1858,12 -1844,11 +1854,12 @@@ int read_index_unmerged(struct index_st
                if (!ce_stage(ce))
                        continue;
                unmerged = 1;
 -              len = strlen(ce->name);
 +              len = ce_namelen(ce);
                size = cache_entry_size(len);
                new_ce = xcalloc(1, size);
                memcpy(new_ce->name, ce->name, len);
 -              new_ce->ce_flags = create_ce_flags(len, 0) | CE_CONFLICTED;
 +              new_ce->ce_flags = create_ce_flags(0) | CE_CONFLICTED;
 +              new_ce->ce_namelen = len;
                new_ce->ce_mode = ce->ce_mode;
                if (add_index_entry(istate, new_ce, 0))
                        return error("%s: cannot drop to stage #0",
diff --combined revision.c
index 04c7de87d089e576d6101628dc0417344a12f67e,6d21ac7ee1ccb1aa014dc977955d7fce6d92ede2..442a9452334704d90e4457fdeb11014fb886c58a
@@@ -1002,7 -1002,7 +1002,7 @@@ static int add_parents_only(struct rev_
                flags ^= UNINTERESTING;
                arg++;
        }
 -      if (get_sha1(arg, sha1))
 +      if (get_sha1_committish(arg, sha1))
                return 0;
        while (1) {
                it = get_reference(revs, arg, sha1, 0);
@@@ -1116,16 -1116,16 +1116,16 @@@ static void prepare_show_merge(struct r
        revs->limited = 1;
  }
  
 -int handle_revision_arg(const char *arg_, struct rev_info *revs,
 -                      int flags,
 -                      int cant_be_filename)
 +int handle_revision_arg(const char *arg_, struct rev_info *revs, int flags, unsigned revarg_opt)
  {
 -      unsigned mode;
 +      struct object_context oc;
        char *dotdot;
        struct object *object;
        unsigned char sha1[20];
        int local_flags;
        const char *arg = arg_;
 +      int cant_be_filename = revarg_opt & REVARG_CANNOT_BE_FILENAME;
 +      unsigned get_sha1_flags = 0;
  
        dotdot = strstr(arg, "..");
        if (dotdot) {
                        next = "HEAD";
                if (dotdot == arg)
                        this = "HEAD";
 -              if (!get_sha1(this, from_sha1) &&
 -                  !get_sha1(next, sha1)) {
 +              if (!get_sha1_committish(this, from_sha1) &&
 +                  !get_sha1_committish(next, sha1)) {
                        struct commit *a, *b;
                        struct commit_list *exclude;
  
                local_flags = UNINTERESTING;
                arg++;
        }
 -      if (get_sha1_with_mode(arg, sha1, &mode))
 +
 +      if (revarg_opt & REVARG_COMMITTISH)
 +              get_sha1_flags = GET_SHA1_COMMITTISH;
 +
 +      if (get_sha1_with_context(arg, get_sha1_flags, sha1, &oc))
                return revs->ignore_missing ? 0 : -1;
        if (!cant_be_filename)
                verify_non_filename(revs->prefix, arg);
        object = get_reference(revs, arg, sha1, flags ^ local_flags);
        add_rev_cmdline(revs, object, arg_, REV_CMD_REV, flags ^ local_flags);
 -      add_pending_object_with_mode(revs, object, arg, mode);
 +      add_pending_object_with_mode(revs, object, arg, oc.mode);
        return 0;
  }
  
@@@ -1263,7 -1259,7 +1263,7 @@@ static void read_revisions_from_stdin(s
                        }
                        die("options not supported in --stdin mode");
                }
 -              if (handle_revision_arg(sb.buf, revs, 0, 1))
 +              if (handle_revision_arg(sb.buf, revs, 0, REVARG_CANNOT_BE_FILENAME))
                        die("bad revision '%s'", sb.buf);
        }
        if (seen_dashdash)
@@@ -1714,7 -1710,7 +1714,7 @@@ static int handle_revision_pseudo_opt(c
   */
  int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct setup_revision_opt *opt)
  {
 -      int i, flags, left, seen_dashdash, read_from_stdin, got_rev_arg = 0;
 +      int i, flags, left, seen_dashdash, read_from_stdin, got_rev_arg = 0, revarg_opt;
        struct cmdline_pathspec prune_data;
        const char *submodule = NULL;
  
  
        /* Second, deal with arguments and options */
        flags = 0;
 +      revarg_opt = opt ? opt->revarg_opt : 0;
 +      if (seen_dashdash)
 +              revarg_opt |= REVARG_CANNOT_BE_FILENAME;
        read_from_stdin = 0;
        for (left = i = 1; i < argc; i++) {
                const char *arg = argv[i];
                        continue;
                }
  
 -              if (handle_revision_arg(arg, revs, flags, seen_dashdash)) {
 +
 +              if (handle_revision_arg(arg, revs, flags, revarg_opt)) {
                        int j;
                        if (seen_dashdash || *arg == '^')
                                die("bad revision '%s'", arg);
        if (revs->def && !revs->pending.nr && !got_rev_arg) {
                unsigned char sha1[20];
                struct object *object;
 -              unsigned mode;
 -              if (get_sha1_with_mode(revs->def, sha1, &mode))
 +              struct object_context oc;
 +              if (get_sha1_with_context(revs->def, 0, sha1, &oc))
                        die("bad default revision '%s'", revs->def);
                object = get_reference(revs, revs->def, sha1, 0);
 -              add_pending_object_with_mode(revs, object, revs->def, mode);
 +              add_pending_object_with_mode(revs, object, revs->def, oc.mode);
        }
  
        /* Did the user ask for any diff output? Run the diff! */
        if (revs->combine_merges)
                revs->ignore_merges = 0;
        revs->diffopt.abbrev = revs->abbrev;
-       if (diff_setup_done(&revs->diffopt) < 0)
-               die("diff_setup_done failed");
+       diff_setup_done(&revs->diffopt);
  
        compile_grep_patterns(&revs->grep_filter);
  
@@@ -2371,28 -2362,29 +2370,28 @@@ static struct commit *get_revision_inte
        }
  
        /*
 -       * Now pick up what they want to give us
 +       * If our max_count counter has reached zero, then we are done. We
 +       * don't simply return NULL because we still might need to show
 +       * boundary commits. But we want to avoid calling get_revision_1, which
 +       * might do a considerable amount of work finding the next commit only
 +       * for us to throw it away.
 +       *
 +       * If it is non-zero, then either we don't have a max_count at all
 +       * (-1), or it is still counting, in which case we decrement.
         */
 -      c = get_revision_1(revs);
 -      if (c) {
 -              while (0 < revs->skip_count) {
 -                      revs->skip_count--;
 -                      c = get_revision_1(revs);
 -                      if (!c)
 -                              break;
 +      if (revs->max_count) {
 +              c = get_revision_1(revs);
 +              if (c) {
 +                      while (0 < revs->skip_count) {
 +                              revs->skip_count--;
 +                              c = get_revision_1(revs);
 +                              if (!c)
 +                                      break;
 +                      }
                }
 -      }
  
 -      /*
 -       * Check the max_count.
 -       */
 -      switch (revs->max_count) {
 -      case -1:
 -              break;
 -      case 0:
 -              c = NULL;
 -              break;
 -      default:
 -              revs->max_count--;
 +              if (revs->max_count > 0)
 +                      revs->max_count--;
        }
  
        if (c)
index c73bec9551eb27dab25aad69c83ae7ce9f9b11a8,0278f48396e0d22d434b421b2f74cf05244a17a3..56a81cd7486716897cc4f08196d0815a62461ffd
@@@ -258,6 -258,27 +258,27 @@@ test_expect_success 'init should regist
        test_cmp expect url
  '
  
+ test_failure_with_unknown_submodule () {
+       test_must_fail git submodule $1 no-such-submodule 2>output.err &&
+       grep "^error: .*no-such-submodule" output.err
+ }
+ test_expect_success 'init should fail with unknown submodule' '
+       test_failure_with_unknown_submodule init
+ '
+ test_expect_success 'update should fail with unknown submodule' '
+       test_failure_with_unknown_submodule update
+ '
+ test_expect_success 'status should fail with unknown submodule' '
+       test_failure_with_unknown_submodule status
+ '
+ test_expect_success 'sync should fail with unknown submodule' '
+       test_failure_with_unknown_submodule sync
+ '
  test_expect_success 'update should fail when path is used by a file' '
        echo hello >expect &&
  
@@@ -418,10 -439,7 +439,7 @@@ test_expect_success 'moving to a commi
  '
  
  test_expect_success 'submodule <invalid-path> warns' '
-       git submodule no-such-submodule 2> output.err &&
-       grep "^error: .*no-such-submodule" output.err
+       test_failure_with_unknown_submodule
  '
  
  test_expect_success 'add submodules without specifying an explicit path' '
@@@ -483,72 -501,21 +501,72 @@@ test_expect_success 'set up for relativ
                git add sub &&
                git config -f .gitmodules submodule.sub.path sub &&
                git config -f .gitmodules submodule.sub.url ../subrepo &&
 -              cp .git/config pristine-.git-config
 +              cp .git/config pristine-.git-config &&
 +              cp .gitmodules pristine-.gitmodules
        )
  '
  
 -test_expect_success 'relative path works with URL' '
 +test_expect_success '../subrepo works with URL - ssh://hostname/repo' '
        (
                cd reltest &&
                cp pristine-.git-config .git/config &&
 +              cp pristine-.gitmodules .gitmodules &&
                git config remote.origin.url ssh://hostname/repo &&
                git submodule init &&
                test "$(git config submodule.sub.url)" = ssh://hostname/subrepo
        )
  '
  
 -test_expect_success 'relative path works with user@host:path' '
 +test_expect_success '../subrepo works with port-qualified URL - ssh://hostname:22/repo' '
 +      (
 +              cd reltest &&
 +              cp pristine-.git-config .git/config &&
 +              cp pristine-.gitmodules .gitmodules &&
 +              git config remote.origin.url ssh://hostname:22/repo &&
 +              git submodule init &&
 +              test "$(git config submodule.sub.url)" = ssh://hostname:22/subrepo
 +      )
 +'
 +
 +# About the choice of the path in the next test:
 +# - double-slash side-steps path mangling issues on Windows
 +# - it is still an absolute local path
 +# - there cannot be a server with a blank in its name just in case the
 +#   path is used erroneously to access a //server/share style path
 +test_expect_success '../subrepo path works with local path - //somewhere else/repo' '
 +      (
 +              cd reltest &&
 +              cp pristine-.git-config .git/config &&
 +              cp pristine-.gitmodules .gitmodules &&
 +              git config remote.origin.url "//somewhere else/repo" &&
 +              git submodule init &&
 +              test "$(git config submodule.sub.url)" = "//somewhere else/subrepo"
 +      )
 +'
 +
 +test_expect_success '../subrepo works with file URL - file:///tmp/repo' '
 +      (
 +              cd reltest &&
 +              cp pristine-.git-config .git/config &&
 +              cp pristine-.gitmodules .gitmodules &&
 +              git config remote.origin.url file:///tmp/repo &&
 +              git submodule init &&
 +              test "$(git config submodule.sub.url)" = file:///tmp/subrepo
 +      )
 +'
 +
 +test_expect_success '../subrepo works with helper URL- helper:://hostname/repo' '
 +      (
 +              cd reltest &&
 +              cp pristine-.git-config .git/config &&
 +              cp pristine-.gitmodules .gitmodules &&
 +              git config remote.origin.url helper:://hostname/repo &&
 +              git submodule init &&
 +              test "$(git config submodule.sub.url)" = helper:://hostname/subrepo
 +      )
 +'
 +
 +test_expect_success '../subrepo works with scp-style URL - user@host:repo' '
        (
                cd reltest &&
                cp pristine-.git-config .git/config &&
        )
  '
  
 +test_expect_success '../subrepo works with scp-style URL - user@host:path/to/repo' '
 +      (
 +              cd reltest &&
 +              cp pristine-.git-config .git/config &&
 +              cp pristine-.gitmodules .gitmodules &&
 +              git config remote.origin.url user@host:path/to/repo &&
 +              git submodule init &&
 +              test "$(git config submodule.sub.url)" = user@host:path/to/subrepo
 +      )
 +'
 +
 +test_expect_success '../subrepo works with relative local path - foo' '
 +      (
 +              cd reltest &&
 +              cp pristine-.git-config .git/config &&
 +              cp pristine-.gitmodules .gitmodules &&
 +              git config remote.origin.url foo &&
 +              # actual: fails with an error
 +              git submodule init &&
 +              test "$(git config submodule.sub.url)" = subrepo
 +      )
 +'
 +
 +test_expect_success '../subrepo works with relative local path - foo/bar' '
 +      (
 +              cd reltest &&
 +              cp pristine-.git-config .git/config &&
 +              cp pristine-.gitmodules .gitmodules &&
 +              git config remote.origin.url foo/bar &&
 +              git submodule init &&
 +              test "$(git config submodule.sub.url)" = foo/subrepo
 +      )
 +'
 +
 +test_expect_success '../subrepo works with relative local path - ./foo' '
 +      (
 +              cd reltest &&
 +              cp pristine-.git-config .git/config &&
 +              cp pristine-.gitmodules .gitmodules &&
 +              git config remote.origin.url ./foo &&
 +              git submodule init &&
 +              test "$(git config submodule.sub.url)" = subrepo
 +      )
 +'
 +
 +test_expect_success '../subrepo works with relative local path - ./foo/bar' '
 +      (
 +              cd reltest &&
 +              cp pristine-.git-config .git/config &&
 +              cp pristine-.gitmodules .gitmodules &&
 +              git config remote.origin.url ./foo/bar &&
 +              git submodule init &&
 +              test "$(git config submodule.sub.url)" = foo/subrepo
 +      )
 +'
 +
 +test_expect_success '../subrepo works with relative local path - ../foo' '
 +      (
 +              cd reltest &&
 +              cp pristine-.git-config .git/config &&
 +              cp pristine-.gitmodules .gitmodules &&
 +              git config remote.origin.url ../foo &&
 +              git submodule init &&
 +              test "$(git config submodule.sub.url)" = ../subrepo
 +      )
 +'
 +
 +test_expect_success '../subrepo works with relative local path - ../foo/bar' '
 +      (
 +              cd reltest &&
 +              cp pristine-.git-config .git/config &&
 +              cp pristine-.gitmodules .gitmodules &&
 +              git config remote.origin.url ../foo/bar &&
 +              git submodule init &&
 +              test "$(git config submodule.sub.url)" = ../foo/subrepo
 +      )
 +'
 +
 +test_expect_success '../bar/a/b/c works with relative local path - ../foo/bar.git' '
 +      (
 +              cd reltest &&
 +              cp pristine-.git-config .git/config &&
 +              cp pristine-.gitmodules .gitmodules &&
 +              mkdir -p a/b/c &&
 +              (cd a/b/c; git init) &&
 +              git config remote.origin.url ../foo/bar.git &&
 +              git submodule add ../bar/a/b/c ./a/b/c &&
 +              git submodule init &&
 +              test "$(git config submodule.a/b/c.url)" = ../foo/bar/a/b/c
 +      )
 +'
 +
  test_expect_success 'moving the superproject does not break submodules' '
        (
                cd addtest &&