Merge branch 'tb/sanitize-decomposed-utf-8-pathname'
authorJunio C Hamano <gitster@pobox.com>
Fri, 13 Jul 2012 22:37:51 +0000 (15:37 -0700)
committerJunio C Hamano <gitster@pobox.com>
Fri, 13 Jul 2012 22:37:51 +0000 (15:37 -0700)
Teaches git to normalize pathnames read from readdir(3) and all
arguments from the command line into precomposed UTF-8 (assuming
that they come as decomposed UTF-8) to work around issues on Mac OS.

I think there still are other places that need conversion
(e.g. paths that are read from stdin for some commands), but this
should be a good first step in the right direction.

* tb/sanitize-decomposed-utf-8-pathname:
git on Mac OS and precomposed unicode

1  2 
Documentation/config.txt
Makefile
cache.h
config.c
diff --combined Documentation/config.txt
index c6ff15e59413eb731e983ac2c1de010e12336001,c92e7b92e91779d6a9c9341ee692a169cd3cfe85..7bc0e5384871dc4c10df038cacee7c9d9370c4da
@@@ -159,10 -159,9 +159,10 @@@ advice.*:
                specified a refspec that isn't your current branch) and
                it resulted in a non-fast-forward error.
        statusHints::
 -              Directions on how to stage/unstage/add shown in the
 -              output of linkgit:git-status[1] and the template shown
 -              when writing commit messages.
 +              Show directions on how to proceed from the current
 +              state in the output of linkgit:git-status[1] and in
 +              the template shown when writing commit messages in
 +              linkgit:git-commit[1].
        commitBeforeMerge::
                Advice shown when linkgit:git-merge[1] refuses to
                merge to avoid overwriting local changes.
@@@ -211,6 -210,15 +211,15 @@@ The default is false, except linkgit:gi
  will probe and set core.ignorecase true if appropriate when the repository
  is created.
  
+ core.precomposeunicode::
+       This option is only used by Mac OS implementation of git.
+       When core.precomposeunicode=true, git reverts the unicode decomposition
+       of filenames done by Mac OS. This is useful when sharing a repository
+       between Mac OS and Linux or Windows.
+       (Git for Windows 1.7.10 or higher is needed, or git under cygwin 1.7).
+       When false, file names are handled fully transparent by git,
+       which is backward compatible with older versions of git.
  core.trustctime::
        If false, the ctime differences between the index and the
        working tree are ignored; useful when the inode change time
@@@ -484,9 -492,7 +493,9 @@@ core.excludesfile:
        '.git/info/exclude', git looks into this file for patterns
        of files which are not meant to be tracked.  "`~/`" is expanded
        to the value of `$HOME` and "`~user/`" to the specified user's
 -      home directory.  See linkgit:gitignore[5].
 +      home directory. Its default value is $XDG_CONFIG_HOME/git/ignore.
 +      If $XDG_CONFIG_HOME is either not set or empty, $HOME/.config/git/ignore
 +      is used instead. See linkgit:gitignore[5].
  
  core.askpass::
        Some commands (e.g. svn and http interfaces) that interactively
@@@ -501,9 -507,7 +510,9 @@@ core.attributesfile:
        In addition to '.gitattributes' (per-directory) and
        '.git/info/attributes', git looks into this file for attributes
        (see linkgit:gitattributes[5]). Path expansions are made the same
 -      way as for `core.excludesfile`.
 +      way as for `core.excludesfile`. Its default value is
 +      $XDG_CONFIG_HOME/git/attributes. If $XDG_CONFIG_HOME is either not
 +      set or empty, $HOME/.config/git/attributes is used instead.
  
  core.editor::
        Commands such as `commit` and `tag` that lets you edit
@@@ -885,7 -889,7 +894,7 @@@ column.ui:
        make equal size columns
  --
  +
 -      This option defaults to 'never'.
 +This option defaults to 'never'.
  
  column.branch::
        Specify whether to output branch listing in `git branch` in columns.
@@@ -1725,7 -1729,6 +1734,7 @@@ push.default:
        no refspec is implied by any of the options given on the command
        line. Possible values are:
  +
 +--
  * `nothing` - do not push anything.
  * `matching` - push all branches having the same name in both ends.
    This is for those who prepare all the branches into a publishable
    option and is well-suited for beginners. It will become the default
    in Git 2.0.
  * `current` - push the current branch to a branch of the same name.
 -  +
 -  The `simple`, `current` and `upstream` modes are for those who want to
 -  push out a single branch after finishing work, even when the other
 -  branches are not yet ready to be pushed out. If you are working with
 -  other people to push into the same shared repository, you would want
 -  to use one of these.
 +--
 ++
 +The `simple`, `current` and `upstream` modes are for those who want to
 +push out a single branch after finishing work, even when the other
 +branches are not yet ready to be pushed out. If you are working with
 +other people to push into the same shared repository, you would want
 +to use one of these.
  
  rebase.stat::
        Whether to show a diffstat of what changed upstream since the last
diff --combined Makefile
index 169dda5453c38a9a7ab1ac7e49ac6a0a200bfa0f,ba9d6b6b2361dae55968ddd048a91ac50e4654de..dc709029632edc77ac509f24b6352ee48ffa3dc0
+++ b/Makefile
@@@ -158,9 -158,6 +158,9 @@@ all:
  # Define NO_PREAD if you have a problem with pread() system call (e.g.
  # cygwin1.dll before v1.5.22).
  #
 +# Define NO_THREAD_SAFE_PREAD if your pread() implementation is not
 +# thread-safe. (e.g. compat/pread.c or cygwin)
 +#
  # Define NO_FAST_WORKING_DIRECTORY if accessing objects in pack files is
  # generally faster on your platform than accessing the working directory.
  #
  # Define NO_ST_BLOCKS_IN_STRUCT_STAT if your platform does not have st_blocks
  # field that counts the on-disk footprint in 512-byte blocks.
  #
 -# Define ASCIIDOC7 if you want to format documentation with AsciiDoc 7
 -#
  # Define DOCBOOK_XSL_172 if you want to format man pages with DocBook XSL v1.72
  # (not v1.73 or v1.71).
  #
  # the diff algorithm.  It gives a nice speedup if your processor has
  # fast unaligned word loads.  Does NOT work on big-endian systems!
  # Enabled by default on x86_64.
 +#
 +# Define GIT_USER_AGENT if you want to change how git identifies itself during
 +# network interactions.  The default is "git/$(GIT_VERSION)".
 +#
 +# Define DEFAULT_HELP_FORMAT to "man", "info" or "html"
 +# (defaults to "man") if you want to have a different default when
 +# "git help" is called without a parameter specifying the format.
  
  GIT-VERSION-FILE: FORCE
        @$(SHELL_PATH) ./GIT-VERSION-GEN
@@@ -488,6 -480,7 +488,6 @@@ X 
  PROGRAMS += $(patsubst %.o,git-%$X,$(PROGRAM_OBJS))
  
  TEST_PROGRAMS_NEED_X += test-chmtime
 -TEST_PROGRAMS_NEED_X += test-credential
  TEST_PROGRAMS_NEED_X += test-ctype
  TEST_PROGRAMS_NEED_X += test-date
  TEST_PROGRAMS_NEED_X += test-delta
@@@ -607,6 -600,7 +607,7 @@@ LIB_H += compat/bswap.
  LIB_H += compat/cygwin.h
  LIB_H += compat/mingw.h
  LIB_H += compat/obstack.h
+ LIB_H += compat/precompose_utf8.h
  LIB_H += compat/terminal.h
  LIB_H += compat/win32/dirent.h
  LIB_H += compat/win32/poll.h
@@@ -806,7 -800,6 +807,7 @@@ LIB_OBJS += usage.
  LIB_OBJS += userdiff.o
  LIB_OBJS += utf8.o
  LIB_OBJS += varint.o
 +LIB_OBJS += version.o
  LIB_OBJS += walker.o
  LIB_OBJS += wrapper.o
  LIB_OBJS += write_or_die.o
@@@ -835,7 -828,6 +836,7 @@@ BUILTIN_OBJS += builtin/commit-tree.
  BUILTIN_OBJS += builtin/commit.o
  BUILTIN_OBJS += builtin/config.o
  BUILTIN_OBJS += builtin/count-objects.o
 +BUILTIN_OBJS += builtin/credential.o
  BUILTIN_OBJS += builtin/describe.o
  BUILTIN_OBJS += builtin/diff-files.o
  BUILTIN_OBJS += builtin/diff-index.o
@@@ -913,8 -905,6 +914,8 @@@ BUILTIN_OBJS += builtin/write-tree.
  GITLIBS = $(LIB_FILE) $(XDIFF_LIB)
  EXTLIBS =
  
 +GIT_USER_AGENT = git/$(GIT_VERSION)
 +
  #
  # Platform specific tweaks
  #
@@@ -1001,6 -991,8 +1002,8 @@@ ifeq ($(uname_S),Darwin
        NO_MEMMEM = YesPlease
        USE_ST_TIMESPEC = YesPlease
        HAVE_DEV_TTY = YesPlease
+       COMPAT_OBJS += compat/precompose_utf8.o
+       BASIC_CFLAGS += -DPRECOMPOSE_UNICODE
  endif
  ifeq ($(uname_S),SunOS)
        NEEDS_SOCKET = YesPlease
@@@ -1062,7 -1054,6 +1065,7 @@@ ifeq ($(uname_O),Cygwin
                NO_IPV6 = YesPlease
                OLD_ICONV = UnfortunatelyYes
        endif
 +      NO_THREAD_SAFE_PREAD = YesPlease
        NEEDS_LIBICONV = YesPlease
        NO_FAST_WORKING_DIRECTORY = UnfortunatelyYes
        NO_TRUSTABLE_FILEMODE = UnfortunatelyYes
@@@ -1248,7 -1239,6 +1251,7 @@@ ifeq ($(uname_S),Windows
        BLK_SHA1 = YesPlease
        NO_POSIX_GOODIES = UnfortunatelyYes
        NATIVE_CRLF = YesPlease
 +      DEFAULT_HELP_FORMAT = html
  
        CC = compat/vcbuild/scripts/clink.pl
        AR = compat/vcbuild/scripts/lib.pl
@@@ -1672,10 -1662,6 +1675,10 @@@ endi
  ifdef NO_PREAD
        COMPAT_CFLAGS += -DNO_PREAD
        COMPAT_OBJS += compat/pread.o
 +      NO_THREAD_SAFE_PREAD = YesPlease
 +endif
 +ifdef NO_THREAD_SAFE_PREAD
 +      BASIC_CFLAGS += -DNO_THREAD_SAFE_PREAD
  endif
  ifdef NO_FAST_WORKING_DIRECTORY
        BASIC_CFLAGS += -DNO_FAST_WORKING_DIRECTORY
@@@ -1851,6 -1837,10 +1854,6 @@@ ifndef 
  endif
  endif
  
 -ifdef ASCIIDOC7
 -      export ASCIIDOC7
 -endif
 -
  ifdef NO_INSTALL_HARDLINKS
        export NO_INSTALL_HARDLINKS
  endif
@@@ -1928,15 -1918,6 +1931,15 @@@ SHELL_PATH_CQ_SQ = $(subst ','\'',$(SHE
  BASIC_CFLAGS += -DSHELL_PATH='$(SHELL_PATH_CQ_SQ)'
  endif
  
 +GIT_USER_AGENT_SQ = $(subst ','\'',$(GIT_USER_AGENT))
 +GIT_USER_AGENT_CQ = "$(subst ",\",$(subst \,\\,$(GIT_USER_AGENT)))"
 +GIT_USER_AGENT_CQ_SQ = $(subst ','\'',$(GIT_USER_AGENT_CQ))
 +BASIC_CFLAGS += -DGIT_USER_AGENT='$(GIT_USER_AGENT_CQ_SQ)'
 +
 +ifdef DEFAULT_HELP_FORMAT
 +BASIC_CFLAGS += -DDEFAULT_HELP_FORMAT='"$(DEFAULT_HELP_FORMAT)"'
 +endif
 +
  ALL_CFLAGS += $(BASIC_CFLAGS)
  ALL_LDFLAGS += $(BASIC_LDFLAGS)
  
@@@ -1984,7 -1965,7 +1987,7 @@@ strip: $(PROGRAMS) git$
        $(STRIP) $(STRIP_OPTS) $(PROGRAMS) git$X
  
  git.o: common-cmds.h
 -git.sp git.s git.o: EXTRA_CPPFLAGS = -DGIT_VERSION='"$(GIT_VERSION)"' \
 +git.sp git.s git.o: EXTRA_CPPFLAGS = \
        '-DGIT_HTML_PATH="$(htmldir_SQ)"' \
        '-DGIT_MAN_PATH="$(mandir_SQ)"' \
        '-DGIT_INFO_PATH="$(infodir_SQ)"'
@@@ -2001,9 -1982,6 +2004,9 @@@ builtin/help.sp builtin/help.s builtin/
        '-DGIT_MAN_PATH="$(mandir_SQ)"' \
        '-DGIT_INFO_PATH="$(infodir_SQ)"'
  
 +version.sp version.s version.o: EXTRA_CPPFLAGS = \
 +      '-DGIT_VERSION="$(GIT_VERSION)"'
 +
  $(BUILT_INS): git$X
        $(QUIET_BUILT_IN)$(RM) $@ && \
        ln git$X $@ 2>/dev/null || \
@@@ -2021,7 -1999,6 +2024,7 @@@ sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|
      -e 's|@SHELL_PATH@|$(SHELL_PATH_SQ)|' \
      -e 's|@@DIFF@@|$(DIFF_SQ)|' \
      -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \
 +    -e 's|@@GIT_USER_AGENT@@|$(GIT_USER_AGENT_SQ)|g' \
      -e 's|@@LOCALEDIR@@|$(localedir_SQ)|g' \
      -e 's/@@NO_CURL@@/$(NO_CURL)/g' \
      -e 's/@@USE_GETTEXT_SCHEME@@/$(USE_GETTEXT_SCHEME)/g' \
@@@ -2115,7 -2092,7 +2118,7 @@@ configure: configure.a
        $(RM) $<+
  
  # These can record GIT_VERSION
 -git.o git.spec http.o \
 +version.o git.spec \
        $(patsubst %.sh,%,$(SCRIPT_SH)) \
        $(patsubst %.perl,%,$(SCRIPT_PERL)) \
        : GIT-VERSION-FILE
@@@ -2285,6 -2262,9 +2288,6 @@@ attr.sp attr.s attr.o: EXTRA_CPPFLAGS 
  gettext.sp gettext.s gettext.o: EXTRA_CPPFLAGS = \
        -DGIT_LOCALE_PATH='"$(localedir_SQ)"'
  
 -http.sp http.s http.o: EXTRA_CPPFLAGS = \
 -      -DGIT_HTTP_USER_AGENT='"git/$(GIT_VERSION)"'
 -
  ifdef NO_EXPAT
  http-walker.sp http-walker.s http-walker.o: EXTRA_CPPFLAGS = -DNO_EXPAT
  endif
diff --combined cache.h
index c22b9289808f708c68c94ff4a331466250e9b7e5,5e551d37adf115aa3c175a136552045e77390c81..6a1aff5e2aa0cbbdc6f1cb49425f45421b2ea18f
+++ b/cache.h
@@@ -409,11 -409,8 +409,11 @@@ extern const char *setup_git_directory(
  extern char *prefix_path(const char *prefix, int len, const char *path);
  extern const char *prefix_filename(const char *prefix, int len, const char *path);
  extern int check_filename(const char *prefix, const char *name);
 -extern void verify_filename(const char *prefix, const char *name);
 +extern void verify_filename(const char *prefix,
 +                          const char *name,
 +                          int diagnose_misspelt_rev);
  extern void verify_non_filename(const char *prefix, const char *name);
 +extern int path_inside_repo(const char *prefix, const char *path);
  
  #define INIT_DB_QUIET 0x0001
  
@@@ -563,6 -560,7 +563,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,
@@@ -622,8 -620,6 +623,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)));
@@@ -713,7 -709,6 +714,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)
diff --combined config.c
index d28a499b0b66b9e96317ea8eba24b59fc2cf5d49,eaef3b644375545f9c8e49c460132141269394a9..40818e872ffb61e725d63e0bbf1424ea8987009c
+++ b/config.c
@@@ -758,6 -758,11 +758,11 @@@ static int git_default_core_config(cons
                return 0;
        }
  
+       if (!strcmp(var, "core.precomposeunicode")) {
+               precomposed_unicode = git_config_bool(var, value);
+               return 0;
+       }
        /* Add other config variables here and to Documentation/config.txt. */
        return 0;
  }
@@@ -929,10 -934,7 +934,10 @@@ int git_config_system(void
  int git_config_early(config_fn_t fn, void *data, const char *repo_config)
  {
        int ret = 0, found = 0;
 -      const char *home = NULL;
 +      char *xdg_config = NULL;
 +      char *user_config = NULL;
 +
 +      home_config_paths(&user_config, &xdg_config, "config");
  
        if (git_config_system() && !access(git_etc_gitconfig(), R_OK)) {
                ret += git_config_from_file(fn, git_etc_gitconfig(),
                found += 1;
        }
  
 -      home = getenv("HOME");
 -      if (home) {
 -              char buf[PATH_MAX];
 -              char *user_config = mksnpath(buf, sizeof(buf), "%s/.gitconfig", home);
 -              if (!access(user_config, R_OK)) {
 -                      ret += git_config_from_file(fn, user_config, data);
 -                      found += 1;
 -              }
 +      if (!access(xdg_config, R_OK)) {
 +              ret += git_config_from_file(fn, xdg_config, data);
 +              found += 1;
 +      }
 +
 +      if (!access(user_config, R_OK)) {
 +              ret += git_config_from_file(fn, user_config, data);
 +              found += 1;
        }
  
        if (repo_config && !access(repo_config, R_OK)) {
                break;
        }
  
 +      free(xdg_config);
 +      free(user_config);
        return ret == 0 ? found : ret;
  }