Merge branch 'nd/extended-sha1-relpath'
authorJunio C Hamano <gitster@pobox.com>
Thu, 16 Dec 2010 20:51:05 +0000 (12:51 -0800)
committerJunio C Hamano <gitster@pobox.com>
Thu, 16 Dec 2010 20:51:05 +0000 (12:51 -0800)
* nd/extended-sha1-relpath:
get_sha1: teach ":$n:<path>" the same relative path logic
get_sha1: support relative path ":path" syntax
Make prefix_path() return char* without const

Conflicts:
sha1_name.c

1  2 
cache.h
setup.c
sha1_name.c
diff --combined cache.h
index 194f784808a4ead9b61f406d2ffe60fe864831bf,bd181c6e78b3e1d6ff5fa49ae8cc0d82eb4774db..b45525846d04088ad3900fe4986e62259879523d
+++ b/cache.h
@@@ -428,7 -428,7 +428,7 @@@ extern const char **get_pathspec(const 
  extern void setup_work_tree(void);
  extern const char *setup_git_directory_gently(int *);
  extern const char *setup_git_directory(void);
- extern const char *prefix_path(const char *prefix, int len, const char *path);
+ 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);
@@@ -545,7 -545,6 +545,7 @@@ extern int assume_unchanged
  extern int prefer_symlink_refs;
  extern int log_all_ref_updates;
  extern int warn_ambiguous_refs;
 +extern int unique_abbrev_extra_length;
  extern int shared_repository;
  extern const char *apply_default_whitespace;
  extern const char *apply_default_ignorewhitespace;
@@@ -860,7 -859,7 +860,7 @@@ struct cache_def 
  
  extern int has_symlink_leading_path(const char *name, int len);
  extern int threaded_has_symlink_leading_path(struct cache_def *, const char *, int);
 -extern int has_symlink_or_noent_leading_path(const char *name, int len);
 +extern int check_leading_path(const char *name, int len);
  extern int has_dirs_only_path(const char *name, int len, int prefix_len);
  extern void schedule_dir_for_removal(const char *name, int len);
  extern void remove_scheduled_dirs(void);
@@@ -1004,9 -1003,6 +1004,9 @@@ extern int git_env_bool(const char *, i
  extern int git_config_system(void);
  extern int git_config_global(void);
  extern int config_error_nonbool(const char *);
 +extern const char *get_log_output_encoding(void);
 +extern const char *get_commit_output_encoding(void);
 +
  extern const char *config_exclusive_filename;
  
  #define MAX_GITNAME (1000)
@@@ -1091,17 -1087,15 +1091,17 @@@ void shift_tree_by(const unsigned char 
  /*
   * whitespace rules.
   * used by both diff and apply
 + * last two digits are tab width
   */
 -#define WS_BLANK_AT_EOL         01
 -#define WS_SPACE_BEFORE_TAB   02
 -#define WS_INDENT_WITH_NON_TAB        04
 -#define WS_CR_AT_EOL           010
 -#define WS_BLANK_AT_EOF        020
 -#define WS_TAB_IN_INDENT       040
 +#define WS_BLANK_AT_EOL         0100
 +#define WS_SPACE_BEFORE_TAB     0200
 +#define WS_INDENT_WITH_NON_TAB  0400
 +#define WS_CR_AT_EOL           01000
 +#define WS_BLANK_AT_EOF        02000
 +#define WS_TAB_IN_INDENT       04000
  #define WS_TRAILING_SPACE      (WS_BLANK_AT_EOL|WS_BLANK_AT_EOF)
 -#define WS_DEFAULT_RULE (WS_TRAILING_SPACE|WS_SPACE_BEFORE_TAB)
 +#define WS_DEFAULT_RULE (WS_TRAILING_SPACE|WS_SPACE_BEFORE_TAB|8)
 +#define WS_TAB_WIDTH_MASK        077
  extern unsigned whitespace_rule_cfg;
  extern unsigned whitespace_rule(const char *);
  extern unsigned parse_whitespace_rule(const char *);
@@@ -1110,7 -1104,6 +1110,7 @@@ extern void ws_check_emit(const char *l
  extern char *whitespace_error_string(unsigned ws);
  extern void ws_fix_copy(struct strbuf *, const char *, int, unsigned, int *);
  extern int ws_blank_line(const char *line, int len, unsigned ws_rule);
 +#define ws_tab_width(rule)     ((rule) & WS_TAB_WIDTH_MASK)
  
  /* ls-files */
  int report_path_error(const char *ps_matched, const char **pathspec, int prefix_offset);
diff --combined setup.c
index 14f91e39353bcfa1ee2b08d6a5b5f53a024a280c,f930dc09631f454a2d268dc03beb6eaeb960b142..91887a40b79d3bc2c82479bf7f09580c4c468665
+++ b/setup.c
@@@ -4,7 -4,7 +4,7 @@@
  static int inside_git_dir = -1;
  static int inside_work_tree = -1;
  
- const char *prefix_path(const char *prefix, int len, const char *path)
+ char *prefix_path(const char *prefix, int len, const char *path)
  {
        const char *orig = path;
        char *sanitized = xmalloc(len + strlen(path) + 1);
@@@ -46,7 -46,7 +46,7 @@@ const char *prefix_filename(const char 
  {
        static char path[PATH_MAX];
  #ifndef WIN32
 -      if (!pfx || !*pfx || is_absolute_path(arg))
 +      if (!pfx_len || is_absolute_path(arg))
                return arg;
        memcpy(path, pfx, pfx_len);
        strcpy(path + pfx_len, arg);
@@@ -55,7 -55,7 +55,7 @@@
        /* don't add prefix to absolute paths, but still replace '\' by '/' */
        if (is_absolute_path(arg))
                pfx_len = 0;
 -      else
 +      else if (pfx_len)
                memcpy(path, pfx, pfx_len);
        strcpy(path + pfx_len, arg);
        for (p = path + pfx_len; *p; p++)
diff --combined sha1_name.c
index 2c3a5fb363ff9b11a971b45e85819b2c0aaad157,207405688bb919363c0fdde31083f2e57d26e050..8f49279642bf1aa8ce74fee351772e3fb28a73c4
@@@ -206,9 -206,7 +206,9 @@@ const char *find_unique_abbrev(const un
                if (exists
                    ? !status
                    : status == SHORT_NAME_NOT_FOUND) {
 -                      hex[len] = 0;
 +                      int cut_at = len + unique_abbrev_extra_length;
 +                      cut_at = (cut_at < 40) ? cut_at : 40;
 +                      hex[cut_at] = 0;
                        return hex;
                }
                len++;
@@@ -936,24 -934,6 +936,24 @@@ int interpret_branch_name(const char *n
        return len;
  }
  
 +int strbuf_branchname(struct strbuf *sb, const char *name)
 +{
 +      int len = strlen(name);
 +      if (interpret_branch_name(name, sb) == len)
 +              return 0;
 +      strbuf_add(sb, name, len);
 +      return len;
 +}
 +
 +int strbuf_check_branch_ref(struct strbuf *sb, const char *name)
 +{
 +      strbuf_branchname(sb, name);
 +      if (name[0] == '-')
 +              return CHECK_REF_FORMAT_ERROR;
 +      strbuf_splice(sb, 0, 0, "refs/heads/", 11);
 +      return check_ref_format(sb->buf);
 +}
 +
  /*
   * This is like "get_sha1_basic()", except it allows "sha1 expressions",
   * notably "xyz^" for "parent of xyz"
@@@ -1066,6 -1046,23 +1066,23 @@@ int get_sha1_with_mode_1(const char *na
        return ret;
  }
  
+ static char *resolve_relative_path(const char *rel)
+ {
+       if (prefixcmp(rel, "./") && prefixcmp(rel, "../"))
+               return NULL;
+       if (!startup_info)
+               die("BUG: startup_info struct is not initialized.");
+       if (!is_inside_work_tree())
+               die("relative path syntax can't be used outside working tree.");
+       /* die() inside prefix_path() if resolved path is outside worktree */
+       return prefix_path(startup_info->prefix,
+                          startup_info->prefix ? strlen(startup_info->prefix) : 0,
+                          rel);
+ }
  int get_sha1_with_context_1(const char *name, unsigned char *sha1,
                            struct object_context *oc,
                            int gently, const char *prefix)
        if (!ret)
                return ret;
        /* sha1:path --> object name of path in ent sha1
-        * :path -> object name of path in index
+        * :path -> object name of absolute path in index
+        * :./path -> object name of path relative to cwd in index
         * :[0-3]:path -> object name of path in index at stage
         * :/foo -> recent commit matching foo
         */
        if (name[0] == ':') {
                int stage = 0;
                struct cache_entry *ce;
+               char *new_path = NULL;
                int pos;
                if (namelen > 2 && name[1] == '/')
 +                      /* don't need mode for commit */
                        return get_sha1_oneline(name + 2, sha1);
                if (namelen < 3 ||
                    name[2] != ':' ||
                        stage = name[1] - '0';
                        cp = name + 3;
                }
-               namelen = namelen - (cp - name);
+               new_path = resolve_relative_path(cp);
+               if (!new_path) {
+                       namelen = namelen - (cp - name);
+               } else {
+                       cp = new_path;
+                       namelen = strlen(cp);
+               }
  
                strncpy(oc->path, cp,
                        sizeof(oc->path));
                                break;
                        if (ce_stage(ce) == stage) {
                                hashcpy(sha1, ce->sha1);
 +                              oc->mode = ce->ce_mode;
+                               free(new_path);
                                return 0;
                        }
                        pos++;
                }
                if (!gently)
                        diagnose_invalid_index_path(stage, prefix, cp);
+               free(new_path);
                return -1;
        }
        for (cp = name, bracket_depth = 0; *cp; cp++) {
                }
                if (!get_sha1_1(name, cp-name, tree_sha1)) {
                        const char *filename = cp+1;
+                       char *new_filename = NULL;
+                       new_filename = resolve_relative_path(filename);
+                       if (new_filename)
+                               filename = new_filename;
                        ret = get_tree_entry(tree_sha1, filename, sha1, &oc->mode);
                        if (!gently) {
                                diagnose_invalid_sha1_path(prefix, filename,
                                sizeof(oc->path));
                        oc->path[sizeof(oc->path)-1] = '\0';
  
+                       free(new_filename);
                        return ret;
                } else {
                        if (!gently)