Merge tag 'v2.13.5' into maint
authorJunio C Hamano <gitster@pobox.com>
Fri, 4 Aug 2017 19:40:37 +0000 (12:40 -0700)
committerJunio C Hamano <gitster@pobox.com>
Fri, 4 Aug 2017 19:40:37 +0000 (12:40 -0700)
1  2 
cache.h
connect.c
path.c
diff --combined cache.h
index 71fe092644c2c4032ed29c2801fefdf976736db0,c1041cc02b79ea49f265d89be31bf95ff9eff543..a09a5017fb940a72f7a9a08c6652563b8651f2a8
+++ b/cache.h
@@@ -11,8 -11,6 +11,8 @@@
  #include "string-list.h"
  #include "pack-revindex.h"
  #include "hash.h"
 +#include "path.h"
 +#include "sha1-array.h"
  
  #ifndef platform_SHA_CTX
  /*
@@@ -464,8 -462,6 +464,8 @@@ static inline enum object_type object_t
   */
  extern const char * const local_repo_env[];
  
 +extern void setup_git_env(void);
 +
  /*
   * Returns true iff we have a configured git repository (either via
   * setup_git_directory, or in the environment via $GIT_DIR).
@@@ -529,15 -525,12 +529,15 @@@ extern void set_git_work_tree(const cha
  
  extern void setup_work_tree(void);
  /*
 - * Find GIT_DIR of the repository that contains the current working directory,
 - * without changing the working directory or other global state. The result is
 - * appended to gitdir. The return value is either NULL if no repository was
 - * found, or pointing to the path inside gitdir's buffer.
 + * Find the commondir and gitdir of the repository that contains the current
 + * working directory, without changing the working directory or other global
 + * state. The result is appended to commondir and gitdir.  If the discovered
 + * gitdir does not correspond to a worktree, then 'commondir' and 'gitdir' will
 + * both have the same result appended to the buffer.  The return value is
 + * either 0 upon success and non-zero if no repository was found.
   */
 -extern const char *discover_git_directory(struct strbuf *gitdir);
 +extern int discover_git_directory(struct strbuf *commondir,
 +                                struct strbuf *gitdir);
  extern const char *setup_git_directory_gently(int *);
  extern const char *setup_git_directory(void);
  extern char *prefix_path(const char *prefix, int len, const char *path);
@@@ -604,7 -597,6 +604,7 @@@ extern int read_index_unmerged(struct i
  #define CLOSE_LOCK            (1 << 1)
  extern int write_locked_index(struct index_state *, struct lock_file *lock, unsigned flags);
  extern int discard_index(struct index_state *);
 +extern void move_index_extensions(struct index_state *dst, struct index_state *src);
  extern int unmerged_index(const struct index_state *);
  extern int verify_path(const char *path);
  extern int strcmp_offset(const char *s1, const char *s2, size_t *first_change);
@@@ -773,6 -765,7 +773,6 @@@ extern int core_apply_sparse_checkout
  extern int precomposed_unicode;
  extern int protect_hfs;
  extern int protect_ntfs;
 -extern int git_db_env, git_index_env, git_graft_env, git_common_dir_env;
  
  /*
   * Include broken refs in all ref iterations, which will
@@@ -894,6 -887,64 +894,6 @@@ extern void check_repository_format(voi
  #define DATA_CHANGED    0x0020
  #define TYPE_CHANGED    0x0040
  
 -/*
 - * Return a statically allocated filename, either generically (mkpath), in
 - * the repository directory (git_path), or in a submodule's repository
 - * directory (git_path_submodule). In all cases, note that the result
 - * may be overwritten by another call to _any_ of the functions. Consider
 - * using the safer "dup" or "strbuf" formats below (in some cases, the
 - * unsafe versions have already been removed).
 - */
 -extern const char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
 -extern const char *git_path(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
 -extern const char *git_common_path(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
 -
 -extern char *mksnpath(char *buf, size_t n, const char *fmt, ...)
 -      __attribute__((format (printf, 3, 4)));
 -extern void strbuf_git_path(struct strbuf *sb, const char *fmt, ...)
 -      __attribute__((format (printf, 2, 3)));
 -extern void strbuf_git_common_path(struct strbuf *sb, const char *fmt, ...)
 -      __attribute__((format (printf, 2, 3)));
 -extern char *git_path_buf(struct strbuf *buf, const char *fmt, ...)
 -      __attribute__((format (printf, 2, 3)));
 -extern int strbuf_git_path_submodule(struct strbuf *sb, const char *path,
 -                                   const char *fmt, ...)
 -      __attribute__((format (printf, 3, 4)));
 -extern char *git_pathdup(const char *fmt, ...)
 -      __attribute__((format (printf, 1, 2)));
 -extern char *mkpathdup(const char *fmt, ...)
 -      __attribute__((format (printf, 1, 2)));
 -extern char *git_pathdup_submodule(const char *path, const char *fmt, ...)
 -      __attribute__((format (printf, 2, 3)));
 -
 -extern void report_linked_checkout_garbage(void);
 -
 -/*
 - * You can define a static memoized git path like:
 - *
 - *    static GIT_PATH_FUNC(git_path_foo, "FOO");
 - *
 - * or use one of the global ones below.
 - */
 -#define GIT_PATH_FUNC(func, filename) \
 -      const char *func(void) \
 -      { \
 -              static char *ret; \
 -              if (!ret) \
 -                      ret = git_pathdup(filename); \
 -              return ret; \
 -      }
 -
 -const char *git_path_cherry_pick_head(void);
 -const char *git_path_revert_head(void);
 -const char *git_path_squash_msg(void);
 -const char *git_path_merge_msg(void);
 -const char *git_path_merge_rr(void);
 -const char *git_path_merge_mode(void);
 -const char *git_path_merge_head(void);
 -const char *git_path_fetch_head(void);
 -const char *git_path_shallow(void);
 -
  /*
   * Return the name of the file in the local object database that would
   * be used to store a loose object with the specified sha1.  The
@@@ -974,13 -1025,6 +974,13 @@@ static inline void oidcpy(struct object
        hashcpy(dst->hash, src->hash);
  }
  
 +static inline struct object_id *oiddup(const struct object_id *src)
 +{
 +      struct object_id *dst = xmalloc(sizeof(struct object_id));
 +      oidcpy(dst, src);
 +      return dst;
 +}
 +
  static inline void hashclr(unsigned char *hash)
  {
        memset(hash, 0, GIT_SHA1_RAWSZ);
@@@ -1146,6 -1190,14 +1146,14 @@@ char *strip_path_suffix(const char *pat
  int daemon_avoid_alias(const char *path);
  extern int is_ntfs_dotgit(const char *name);
  
+ /*
+  * Returns true iff "str" could be confused as a command-line option when
+  * passed to a sub-program like "ssh". Note that this has nothing to do with
+  * shell-quoting, which should be handled separately; we're assuming here that
+  * the string makes it verbatim to the sub-program.
+  */
+ int looks_like_command_line_option(const char *str);
  /**
   * Return a newly allocated string with the evaluation of
   * "$XDG_CONFIG_HOME/git/$filename" if $XDG_CONFIG_HOME is non-empty, otherwise
@@@ -1160,12 -1212,13 +1168,12 @@@ extern char *xdg_config_home(const cha
   */
  extern char *xdg_cache_home(const char *filename);
  
 -/* object replacement */
 -#define LOOKUP_REPLACE_OBJECT 1
 -#define LOOKUP_UNKNOWN_OBJECT 2
 -extern void *read_sha1_file_extended(const unsigned char *sha1, enum object_type *type, unsigned long *size, unsigned flag);
 +extern void *read_sha1_file_extended(const unsigned char *sha1,
 +                                   enum object_type *type,
 +                                   unsigned long *size, int lookup_replace);
  static inline void *read_sha1_file(const unsigned char *sha1, enum object_type *type, unsigned long *size)
  {
 -      return read_sha1_file_extended(sha1, type, size, LOOKUP_REPLACE_OBJECT);
 +      return read_sha1_file_extended(sha1, type, size, 1);
  }
  
  /*
@@@ -1187,6 -1240,13 +1195,6 @@@ static inline const unsigned char *look
        return do_lookup_replace_object(sha1);
  }
  
 -static inline const unsigned char *lookup_replace_object_extended(const unsigned char *sha1, unsigned flag)
 -{
 -      if (!(flag & LOOKUP_REPLACE_OBJECT))
 -              return sha1;
 -      return lookup_replace_object(sha1);
 -}
 -
  /* Read and unpack a sha1 file into memory, write memory to a sha1 file */
  extern int sha1_object_info(const unsigned char *, unsigned long *);
  extern int hash_sha1_file(const void *buf, unsigned long len, const char *type, unsigned char *sha1);
@@@ -1223,10 -1283,15 +1231,10 @@@ int read_loose_object(const char *path
                      void **contents);
  
  /*
 - * Return true iff we have an object named sha1, whether local or in
 - * an alternate object database, and whether packed or loose.  This
 - * function does not respect replace references.
 - *
 - * If the QUICK flag is set, do not re-check the pack directory
 - * when we cannot find the object (this means we may give a false
 - * negative answer if another process is simultaneously repacking).
 + * Convenience for sha1_object_info_extended() with a NULL struct
 + * object_info. OBJECT_INFO_SKIP_CACHED is automatically set; pass
 + * nonzero flags to also set other flags.
   */
 -#define HAS_SHA1_QUICK 0x1
  extern int has_sha1_file_with_flags(const unsigned char *sha1, int flags);
  static inline int has_sha1_file(const unsigned char *sha1)
  {
@@@ -1428,18 -1493,18 +1436,18 @@@ struct date_mode 
  #define DATE_MODE(t) date_mode_from_type(DATE_##t)
  struct date_mode *date_mode_from_type(enum date_mode_type type);
  
 -const char *show_date(unsigned long time, int timezone, const struct date_mode *mode);
 -void show_date_relative(unsigned long time, int tz, const struct timeval *now,
 +const char *show_date(timestamp_t time, int timezone, const struct date_mode *mode);
 +void show_date_relative(timestamp_t time, int tz, const struct timeval *now,
                        struct strbuf *timebuf);
  int parse_date(const char *date, struct strbuf *out);
 -int parse_date_basic(const char *date, unsigned long *timestamp, int *offset);
 -int parse_expiry_date(const char *date, unsigned long *timestamp);
 +int parse_date_basic(const char *date, timestamp_t *timestamp, int *offset);
 +int parse_expiry_date(const char *date, timestamp_t *timestamp);
  void datestamp(struct strbuf *out);
  #define approxidate(s) approxidate_careful((s), NULL)
 -unsigned long approxidate_careful(const char *, int *);
 -unsigned long approxidate_relative(const char *date, const struct timeval *now);
 +timestamp_t approxidate_careful(const char *, int *);
 +timestamp_t approxidate_relative(const char *date, const struct timeval *now);
  void parse_date_format(const char *format, struct date_mode *mode);
 -int date_overflows(unsigned long date);
 +int date_overflows(timestamp_t date);
  
  #define IDENT_STRICT         1
  #define IDENT_NO_DATE        2
@@@ -1528,16 -1593,6 +1536,16 @@@ extern struct alternate_object_databas
        struct strbuf scratch;
        size_t base_len;
  
 +      /*
 +       * Used to store the results of readdir(3) calls when searching
 +       * for unique abbreviated hashes.  This cache is never
 +       * invalidated, thus it's racy and not necessarily accurate.
 +       * That's fine for its purpose; don't use it for tasks requiring
 +       * greater accuracy!
 +       */
 +      char loose_objects_subdir_seen[256];
 +      struct oid_array loose_objects_cache;
 +
        char path[FLEX_ARRAY];
  } *alt_odb_list;
  extern void prepare_alt_odb(void);
@@@ -1753,15 -1808,9 +1761,15 @@@ typedef int each_loose_object_fn(const 
  typedef int each_loose_cruft_fn(const char *basename,
                                const char *path,
                                void *data);
 -typedef int each_loose_subdir_fn(int nr,
 +typedef int each_loose_subdir_fn(unsigned int nr,
                                 const char *path,
                                 void *data);
 +int for_each_file_in_obj_subdir(unsigned int subdir_nr,
 +                              struct strbuf *path,
 +                              each_loose_object_fn obj_cb,
 +                              each_loose_cruft_fn cruft_cb,
 +                              each_loose_subdir_fn subdir_cb,
 +                              void *data);
  int for_each_loose_file_in_objdir(const char *path,
                                  each_loose_object_fn obj_cb,
                                  each_loose_cruft_fn cruft_cb,
@@@ -1793,7 -1842,6 +1801,7 @@@ struct object_info 
        off_t *disk_sizep;
        unsigned char *delta_base_sha1;
        struct strbuf *typename;
 +      void **contentp;
  
        /* Response */
        enum {
   */
  #define OBJECT_INFO_INIT {NULL}
  
 +/* Invoke lookup_replace_object() on the given hash */
 +#define OBJECT_INFO_LOOKUP_REPLACE 1
 +/* Allow reading from a loose object file of unknown/bogus type */
 +#define OBJECT_INFO_ALLOW_UNKNOWN_TYPE 2
 +/* Do not check cached storage */
 +#define OBJECT_INFO_SKIP_CACHED 4
 +/* Do not retry packed storage after checking packed and loose storage */
 +#define OBJECT_INFO_QUICK 8
  extern int sha1_object_info_extended(const unsigned char *, struct object_info *, unsigned flags);
  extern int packed_object_info(struct packed_git *pack, off_t offset, struct object_info *);
  
  /* Dumb servers support */
  extern int update_server_info(int);
  
 -/* git_config_parse_key() returns these negated: */
 -#define CONFIG_INVALID_KEY 1
 -#define CONFIG_NO_SECTION_OR_NAME 2
 -/* git_config_set_gently(), git_config_set_multivar_gently() return the above or these: */
 -#define CONFIG_NO_LOCK -1
 -#define CONFIG_INVALID_FILE 3
 -#define CONFIG_NO_WRITE 4
 -#define CONFIG_NOTHING_SET 5
 -#define CONFIG_INVALID_PATTERN 6
 -#define CONFIG_GENERIC_ERROR 7
 -
 -#define CONFIG_REGEX_NONE ((void *)1)
 -
 -struct git_config_source {
 -      unsigned int use_stdin:1;
 -      const char *file;
 -      const char *blob;
 -};
 -
 -enum config_origin_type {
 -      CONFIG_ORIGIN_BLOB,
 -      CONFIG_ORIGIN_FILE,
 -      CONFIG_ORIGIN_STDIN,
 -      CONFIG_ORIGIN_SUBMODULE_BLOB,
 -      CONFIG_ORIGIN_CMDLINE
 -};
 -
 -struct config_options {
 -      unsigned int respect_includes : 1;
 -      const char *git_dir;
 -};
 -
 -typedef int (*config_fn_t)(const char *, const char *, void *);
 -extern int git_default_config(const char *, const char *, void *);
 -extern int git_config_from_file(config_fn_t fn, const char *, void *);
 -extern int git_config_from_mem(config_fn_t fn, const enum config_origin_type,
 -                                      const char *name, const char *buf, size_t len, void *data);
 -extern int git_config_from_blob_sha1(config_fn_t fn, const char *name,
 -                                   const unsigned char *sha1, void *data);
 -extern void git_config_push_parameter(const char *text);
 -extern int git_config_from_parameters(config_fn_t fn, void *data);
 -extern void read_early_config(config_fn_t cb, void *data);
 -extern void git_config(config_fn_t fn, void *);
 -extern int git_config_with_options(config_fn_t fn, void *,
 -                                 struct git_config_source *config_source,
 -                                 const struct config_options *opts);
 -extern int git_parse_ulong(const char *, unsigned long *);
 -extern int git_parse_maybe_bool(const char *);
 -extern int git_config_int(const char *, const char *);
 -extern int64_t git_config_int64(const char *, const char *);
 -extern unsigned long git_config_ulong(const char *, const char *);
 -extern ssize_t git_config_ssize_t(const char *, const char *);
 -extern int git_config_bool_or_int(const char *, const char *, int *);
 -extern int git_config_bool(const char *, const char *);
 -extern int git_config_maybe_bool(const char *, const char *);
 -extern int git_config_string(const char **, const char *, const char *);
 -extern int git_config_pathname(const char **, const char *, const char *);
 -extern int git_config_set_in_file_gently(const char *, const char *, const char *);
 -extern void git_config_set_in_file(const char *, const char *, const char *);
 -extern int git_config_set_gently(const char *, const char *);
 -extern void git_config_set(const char *, const char *);
 -extern int git_config_parse_key(const char *, char **, int *);
 -extern int git_config_key_is_valid(const char *key);
 -extern int git_config_set_multivar_gently(const char *, const char *, const char *, int);
 -extern void git_config_set_multivar(const char *, const char *, const char *, int);
 -extern int git_config_set_multivar_in_file_gently(const char *, const char *, const char *, const char *, int);
 -extern void git_config_set_multivar_in_file(const char *, const char *, const char *, const char *, int);
 -extern int git_config_rename_section(const char *, const char *);
 -extern int git_config_rename_section_in_file(const char *, const char *, const char *);
 -extern const char *git_etc_gitconfig(void);
 -extern int git_env_bool(const char *, int);
 -extern unsigned long git_env_ulong(const char *, unsigned long);
 -extern int git_config_system(void);
 -extern int config_error_nonbool(const char *);
 -#if defined(__GNUC__)
 -#define config_error_nonbool(s) (config_error_nonbool(s), const_error())
 -#endif
  extern const char *get_log_output_encoding(void);
  extern const char *get_commit_output_encoding(void);
  
 -extern int git_config_parse_parameter(const char *, config_fn_t fn, void *data);
 -
 -enum config_scope {
 -      CONFIG_SCOPE_UNKNOWN = 0,
 -      CONFIG_SCOPE_SYSTEM,
 -      CONFIG_SCOPE_GLOBAL,
 -      CONFIG_SCOPE_REPO,
 -      CONFIG_SCOPE_CMDLINE,
 -};
 -
 -extern enum config_scope current_config_scope(void);
 -extern const char *current_config_origin_type(void);
 -extern const char *current_config_name(void);
 -
 -struct config_include_data {
 -      int depth;
 -      config_fn_t fn;
 -      void *data;
 -      const struct config_options *opts;
 -};
 -#define CONFIG_INCLUDE_INIT { 0 }
 -extern int git_config_include(const char *name, const char *value, void *data);
 -
 -/*
 - * Match and parse a config key of the form:
 - *
 - *   section.(subsection.)?key
 - *
 - * (i.e., what gets handed to a config_fn_t). The caller provides the section;
 - * we return -1 if it does not match, 0 otherwise. The subsection and key
 - * out-parameters are filled by the function (and *subsection is NULL if it is
 - * missing).
 - *
 - * If the subsection pointer-to-pointer passed in is NULL, returns 0 only if
 - * there is no subsection at all.
 - */
 -extern int parse_config_key(const char *var,
 -                          const char *section,
 -                          const char **subsection, int *subsection_len,
 -                          const char **key);
 -
 -struct config_set_element {
 -      struct hashmap_entry ent;
 -      char *key;
 -      struct string_list value_list;
 -};
 -
 -struct configset_list_item {
 -      struct config_set_element *e;
 -      int value_index;
 -};
 -
 -/*
 - * the contents of the list are ordered according to their
 - * position in the config files and order of parsing the files.
 - * (i.e. key-value pair at the last position of .git/config will
 - * be at the last item of the list)
 - */
 -struct configset_list {
 -      struct configset_list_item *items;
 -      unsigned int nr, alloc;
 -};
 -
 -struct config_set {
 -      struct hashmap config_hash;
 -      int hash_initialized;
 -      struct configset_list list;
 -};
 -
 -extern void git_configset_init(struct config_set *cs);
 -extern int git_configset_add_file(struct config_set *cs, const char *filename);
 -extern int git_configset_get_value(struct config_set *cs, const char *key, const char **value);
 -extern const struct string_list *git_configset_get_value_multi(struct config_set *cs, const char *key);
 -extern void git_configset_clear(struct config_set *cs);
 -extern int git_configset_get_string_const(struct config_set *cs, const char *key, const char **dest);
 -extern int git_configset_get_string(struct config_set *cs, const char *key, char **dest);
 -extern int git_configset_get_int(struct config_set *cs, const char *key, int *dest);
 -extern int git_configset_get_ulong(struct config_set *cs, const char *key, unsigned long *dest);
 -extern int git_configset_get_bool(struct config_set *cs, const char *key, int *dest);
 -extern int git_configset_get_bool_or_int(struct config_set *cs, const char *key, int *is_bool, int *dest);
 -extern int git_configset_get_maybe_bool(struct config_set *cs, const char *key, int *dest);
 -extern int git_configset_get_pathname(struct config_set *cs, const char *key, const char **dest);
 -
 -extern int git_config_get_value(const char *key, const char **value);
 -extern const struct string_list *git_config_get_value_multi(const char *key);
 -extern void git_config_clear(void);
 -extern void git_config_iter(config_fn_t fn, void *data);
 -extern int git_config_get_string_const(const char *key, const char **dest);
 -extern int git_config_get_string(const char *key, char **dest);
 -extern int git_config_get_int(const char *key, int *dest);
 -extern int git_config_get_ulong(const char *key, unsigned long *dest);
 -extern int git_config_get_bool(const char *key, int *dest);
 -extern int git_config_get_bool_or_int(const char *key, int *is_bool, int *dest);
 -extern int git_config_get_maybe_bool(const char *key, int *dest);
 -extern int git_config_get_pathname(const char *key, const char **dest);
 -extern int git_config_get_untracked_cache(void);
 -extern int git_config_get_split_index(void);
 -extern int git_config_get_max_percent_split_change(void);
 -
 -/* This dies if the configured or default date is in the future */
 -extern int git_config_get_expiry(const char *key, const char **output);
 -
  /*
   * This is a hack for test programs like test-dump-untracked-cache to
   * ensure that they do not modify the untracked cache when reading it.
   */
  extern int ignore_untracked_cache_config;
  
 -struct key_value_info {
 -      const char *filename;
 -      int linenr;
 -      enum config_origin_type origin_type;
 -      enum config_scope scope;
 -};
 -
 -extern NORETURN void git_die_config(const char *key, const char *err, ...) __attribute__((format(printf, 2, 3)));
 -extern NORETURN void git_die_config_linenr(const char *key, const char *filename, int linenr);
 -
  extern int committer_ident_sufficiently_given(void);
  extern int author_ident_sufficiently_given(void);
  
@@@ -1964,8 -2193,7 +1972,8 @@@ extern int ws_blank_line(const char *li
  #define ws_tab_width(rule)     ((rule) & WS_TAB_WIDTH_MASK)
  
  /* ls-files */
 -void overlay_tree_on_cache(const char *tree_name, const char *prefix);
 +void overlay_tree_on_index(struct index_state *istate,
 +                         const char *tree_name, const char *prefix);
  
  char *alias_lookup(const char *alias);
  int split_cmdline(char *cmdline, const char ***argv);
@@@ -1984,8 -2212,8 +1992,8 @@@ struct commit_list
  int try_merge_command(const char *strategy, size_t xopts_nr,
                const char **xopts, struct commit_list *common,
                const char *head_arg, struct commit_list *remotes);
 -int checkout_fast_forward(const unsigned char *from,
 -                        const unsigned char *to,
 +int checkout_fast_forward(const struct object_id *from,
 +                        const struct object_id *to,
                          int overwrite_ignore);
  
  
diff --combined connect.c
index e78d3f43d84b7f90f4395cb289c9cf0cb34e8297,e43df44b0cfb6b8eaf09c662c8e631c05568a214..49b28b83be2717027ac33570b1041604db5a062d
+++ b/connect.c
@@@ -1,6 -1,5 +1,6 @@@
  #include "git-compat-util.h"
  #include "cache.h"
 +#include "config.h"
  #include "pkt-line.h"
  #include "quote.h"
  #include "refs.h"
@@@ -578,6 -577,11 +578,11 @@@ static struct child_process *git_proxy_
  
        get_host_and_port(&host, &port);
  
+       if (looks_like_command_line_option(host))
+               die("strange hostname '%s' blocked", host);
+       if (looks_like_command_line_option(port))
+               die("strange port '%s' blocked", port);
        proxy = xmalloc(sizeof(*proxy));
        child_process_init(proxy);
        argv_array_push(&proxy->args, git_proxy_command);
@@@ -824,6 -828,9 +829,9 @@@ struct child_process *git_connect(int f
                conn = xmalloc(sizeof(*conn));
                child_process_init(conn);
  
+               if (looks_like_command_line_option(path))
+                       die("strange pathname '%s' blocked", path);
                strbuf_addstr(&cmd, prog);
                strbuf_addch(&cmd, ' ');
                sq_quote_buf(&cmd, path);
                                return NULL;
                        }
  
+                       if (looks_like_command_line_option(ssh_host))
+                               die("strange hostname '%s' blocked", ssh_host);
                        ssh = get_ssh_command();
                        if (ssh)
                                handle_ssh_variant(ssh, 1, &port_option,
diff --combined path.c
index e485f9f93181778de3acfe3cd4b6811ec82c7940,0349a0ab7b8656130df89ef007f5921797cdab3e..e50d2befcf826680c70ac59295c06004dd6221cf
--- 1/path.c
--- 2/path.c
+++ b/path.c
@@@ -2,13 -2,11 +2,13 @@@
   * Utilities for paths and pathnames
   */
  #include "cache.h"
 +#include "repository.h"
  #include "strbuf.h"
  #include "string-list.h"
  #include "dir.h"
  #include "worktree.h"
  #include "submodule-config.h"
 +#include "path.h"
  
  static int get_st_mode_bits(const char *path, int *mode)
  {
@@@ -345,6 -343,8 +345,6 @@@ static void update_common_dir(struct st
  {
        char *base = buf->buf + git_dir_len;
        init_common_trie();
 -      if (!common_dir)
 -              common_dir = get_git_common_dir();
        if (trie_find(&common_trie, base, check_common, NULL) > 0)
                replace_dir(buf, git_dir_len, common_dir);
  }
@@@ -355,7 -355,7 +355,7 @@@ void report_linked_checkout_garbage(voi
        const struct common_dir *p;
        int len;
  
 -      if (!git_common_dir_env)
 +      if (!the_repository->different_commondir)
                return;
        strbuf_addf(&sb, "%s/", get_git_dir());
        len = sb.len;
        strbuf_release(&sb);
  }
  
 -static void adjust_git_path(struct strbuf *buf, int git_dir_len)
 +static void adjust_git_path(const struct repository *repo,
 +                          struct strbuf *buf, int git_dir_len)
  {
        const char *base = buf->buf + git_dir_len;
 -      if (git_graft_env && is_dir_file(base, "info", "grafts"))
 +      if (is_dir_file(base, "info", "grafts"))
                strbuf_splice(buf, 0, buf->len,
 -                            get_graft_file(), strlen(get_graft_file()));
 -      else if (git_index_env && !strcmp(base, "index"))
 +                            repo->graft_file, strlen(repo->graft_file));
 +      else if (!strcmp(base, "index"))
                strbuf_splice(buf, 0, buf->len,
 -                            get_index_file(), strlen(get_index_file()));
 -      else if (git_db_env && dir_prefix(base, "objects"))
 -              replace_dir(buf, git_dir_len + 7, get_object_directory());
 +                            repo->index_file, strlen(repo->index_file));
 +      else if (dir_prefix(base, "objects"))
 +              replace_dir(buf, git_dir_len + 7, repo->objectdir);
        else if (git_hooks_path && dir_prefix(base, "hooks"))
                replace_dir(buf, git_dir_len + 5, git_hooks_path);
 -      else if (git_common_dir_env)
 -              update_common_dir(buf, git_dir_len, NULL);
 +      else if (repo->different_commondir)
 +              update_common_dir(buf, git_dir_len, repo->commondir);
  }
  
 -static void do_git_path(const struct worktree *wt, struct strbuf *buf,
 +static void strbuf_worktree_gitdir(struct strbuf *buf,
 +                                 const struct repository *repo,
 +                                 const struct worktree *wt)
 +{
 +      if (!wt)
 +              strbuf_addstr(buf, repo->gitdir);
 +      else if (!wt->id)
 +              strbuf_addstr(buf, repo->commondir);
 +      else
 +              strbuf_git_common_path(buf, repo, "worktrees/%s", wt->id);
 +}
 +
 +static void do_git_path(const struct repository *repo,
 +                      const struct worktree *wt, struct strbuf *buf,
                        const char *fmt, va_list args)
  {
        int gitdir_len;
 -      strbuf_addstr(buf, get_worktree_git_dir(wt));
 +      strbuf_worktree_gitdir(buf, repo, wt);
        if (buf->len && !is_dir_sep(buf->buf[buf->len - 1]))
                strbuf_addch(buf, '/');
        gitdir_len = buf->len;
        strbuf_vaddf(buf, fmt, args);
 -      adjust_git_path(buf, gitdir_len);
 +      if (!wt)
 +              adjust_git_path(repo, buf, gitdir_len);
        strbuf_cleanup_path(buf);
  }
  
 +char *repo_git_path(const struct repository *repo,
 +                  const char *fmt, ...)
 +{
 +      struct strbuf path = STRBUF_INIT;
 +      va_list args;
 +      va_start(args, fmt);
 +      do_git_path(repo, NULL, &path, fmt, args);
 +      va_end(args);
 +      return strbuf_detach(&path, NULL);
 +}
 +
 +void strbuf_repo_git_path(struct strbuf *sb,
 +                        const struct repository *repo,
 +                        const char *fmt, ...)
 +{
 +      va_list args;
 +      va_start(args, fmt);
 +      do_git_path(repo, NULL, sb, fmt, args);
 +      va_end(args);
 +}
 +
  char *git_path_buf(struct strbuf *buf, const char *fmt, ...)
  {
        va_list args;
        strbuf_reset(buf);
        va_start(args, fmt);
 -      do_git_path(NULL, buf, fmt, args);
 +      do_git_path(the_repository, NULL, buf, fmt, args);
        va_end(args);
        return buf->buf;
  }
@@@ -451,7 -415,7 +451,7 @@@ void strbuf_git_path(struct strbuf *sb
  {
        va_list args;
        va_start(args, fmt);
 -      do_git_path(NULL, sb, fmt, args);
 +      do_git_path(the_repository, NULL, sb, fmt, args);
        va_end(args);
  }
  
@@@ -460,7 -424,7 +460,7 @@@ const char *git_path(const char *fmt, .
        struct strbuf *pathname = get_pathname();
        va_list args;
        va_start(args, fmt);
 -      do_git_path(NULL, pathname, fmt, args);
 +      do_git_path(the_repository, NULL, pathname, fmt, args);
        va_end(args);
        return pathname->buf;
  }
@@@ -470,7 -434,7 +470,7 @@@ char *git_pathdup(const char *fmt, ...
        struct strbuf path = STRBUF_INIT;
        va_list args;
        va_start(args, fmt);
 -      do_git_path(NULL, &path, fmt, args);
 +      do_git_path(the_repository, NULL, &path, fmt, args);
        va_end(args);
        return strbuf_detach(&path, NULL);
  }
@@@ -501,52 -465,11 +501,52 @@@ const char *worktree_git_path(const str
        struct strbuf *pathname = get_pathname();
        va_list args;
        va_start(args, fmt);
 -      do_git_path(wt, pathname, fmt, args);
 +      do_git_path(the_repository, wt, pathname, fmt, args);
        va_end(args);
        return pathname->buf;
  }
  
 +static void do_worktree_path(const struct repository *repo,
 +                           struct strbuf *buf,
 +                           const char *fmt, va_list args)
 +{
 +      strbuf_addstr(buf, repo->worktree);
 +      if(buf->len && !is_dir_sep(buf->buf[buf->len - 1]))
 +              strbuf_addch(buf, '/');
 +
 +      strbuf_vaddf(buf, fmt, args);
 +      strbuf_cleanup_path(buf);
 +}
 +
 +char *repo_worktree_path(const struct repository *repo, const char *fmt, ...)
 +{
 +      struct strbuf path = STRBUF_INIT;
 +      va_list args;
 +
 +      if (!repo->worktree)
 +              return NULL;
 +
 +      va_start(args, fmt);
 +      do_worktree_path(repo, &path, fmt, args);
 +      va_end(args);
 +
 +      return strbuf_detach(&path, NULL);
 +}
 +
 +void strbuf_repo_worktree_path(struct strbuf *sb,
 +                             const struct repository *repo,
 +                             const char *fmt, ...)
 +{
 +      va_list args;
 +
 +      if (!repo->worktree)
 +              return;
 +
 +      va_start(args, fmt);
 +      do_worktree_path(repo, sb, fmt, args);
 +      va_end(args);
 +}
 +
  /* Returns 0 on success, negative on failure. */
  static int do_submodule_path(struct strbuf *buf, const char *path,
                             const char *fmt, va_list args)
@@@ -601,12 -524,11 +601,12 @@@ int strbuf_git_path_submodule(struct st
        return err;
  }
  
 -static void do_git_common_path(struct strbuf *buf,
 +static void do_git_common_path(const struct repository *repo,
 +                             struct strbuf *buf,
                               const char *fmt,
                               va_list args)
  {
 -      strbuf_addstr(buf, get_git_common_dir());
 +      strbuf_addstr(buf, repo->commondir);
        if (buf->len && !is_dir_sep(buf->buf[buf->len - 1]))
                strbuf_addch(buf, '/');
        strbuf_vaddf(buf, fmt, args);
@@@ -618,18 -540,16 +618,18 @@@ const char *git_common_path(const char 
        struct strbuf *pathname = get_pathname();
        va_list args;
        va_start(args, fmt);
 -      do_git_common_path(pathname, fmt, args);
 +      do_git_common_path(the_repository, pathname, fmt, args);
        va_end(args);
        return pathname->buf;
  }
  
 -void strbuf_git_common_path(struct strbuf *sb, const char *fmt, ...)
 +void strbuf_git_common_path(struct strbuf *sb,
 +                          const struct repository *repo,
 +                          const char *fmt, ...)
  {
        va_list args;
        va_start(args, fmt);
 -      do_git_common_path(sb, fmt, args);
 +      do_git_common_path(repo, sb, fmt, args);
        va_end(args);
  }
  
@@@ -1321,6 -1241,11 +1321,11 @@@ int is_ntfs_dotgit(const char *name
                }
  }
  
+ int looks_like_command_line_option(const char *str)
+ {
+       return str && str[0] == '-';
+ }
  char *xdg_config_home(const char *filename)
  {
        const char *home, *config_home;