From: Junio C Hamano Date: Mon, 6 Aug 2007 08:37:10 +0000 (-0700) Subject: Merge branch 'maint' X-Git-Tag: v1.5.3-rc5~65 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/a6954452ecf757523b31d6eaaf7e00c7a2d91e46?ds=inline;hp=-c Merge branch 'maint' * maint: apply: remove directory that becomes empty by renaming the last file away setup.c:verify_non_filename(): don't die unnecessarily while disambiguating --- a6954452ecf757523b31d6eaaf7e00c7a2d91e46 diff --combined builtin-apply.c index 0a0b4a9e3f,9ee9393662..da270755a7 --- a/builtin-apply.c +++ b/builtin-apply.c @@@ -55,7 -55,7 +55,7 @@@ static enum whitespace_eol } new_whitespace = warn_on_whitespace; static int whitespace_error; static int squelch_whitespace_errors = 5; -static int applied_after_stripping; +static int applied_after_fixing_ws; static const char *patch_input_file; static void parse_whitespace_option(const char *option) @@@ -1661,7 -1661,7 +1661,7 @@@ static int apply_line(char *output, con if (add_nl_to_tail) output[plen++] = '\n'; if (fixed) - applied_after_stripping++; + applied_after_fixing_ws++; return output + plen - buf; } @@@ -1675,7 -1675,6 +1675,7 @@@ static int apply_one_fragment(struct bu char *new = xmalloc(size); const char *oldlines, *newlines; int oldsize = 0, newsize = 0; + int new_blank_lines_at_end = 0; unsigned long leading, trailing; int pos, lines; @@@ -1683,7 -1682,6 +1683,7 @@@ char first; int len = linelen(patch, size); int plen; + int added_blank_line = 0; if (!len) break; @@@ -1705,7 -1703,6 +1705,7 @@@ else if (first == '+') first = '-'; } + switch (first) { case '\n': /* Newer GNU diff, empty context line */ @@@ -1723,14 -1720,9 +1723,14 @@@ break; /* Fall-through for ' ' */ case '+': - if (first != '+' || !no_add) - newsize += apply_line(new + newsize, patch, - plen); + if (first != '+' || !no_add) { + int added = apply_line(new + newsize, patch, + plen); + newsize += added; + if (first == '+' && + added == 1 && new[newsize-1] == '\n') + added_blank_line = 1; + } break; case '@': case '\\': /* Ignore it, we already handled it */ @@@ -1740,10 -1732,6 +1740,10 @@@ error("invalid start of line: '%c'", first); return -1; } + if (added_blank_line) + new_blank_lines_at_end++; + else + new_blank_lines_at_end = 0; patch += len; size -= len; } @@@ -1786,16 -1774,9 +1786,16 @@@ if (match_beginning && offset) offset = -1; if (offset >= 0) { - int diff = newsize - oldsize; - unsigned long size = desc->size + diff; - unsigned long alloc = desc->alloc; + int diff; + unsigned long size, alloc; + + if (new_whitespace == strip_whitespace && + (desc->size - oldsize - offset == 0)) /* end of file? */ + newsize -= new_blank_lines_at_end; + + diff = newsize - oldsize; + size = desc->size + diff; + alloc = desc->alloc; /* Warn if it was necessary to reduce the number * of context lines. @@@ -2508,7 -2489,7 +2508,7 @@@ static void write_out_one_result(struc * thing: remove the old, write the new */ if (phase == 0) - remove_file(patch, 0); + remove_file(patch, patch->is_rename); if (phase == 1) create_file(patch); } @@@ -2888,17 -2869,18 +2888,17 @@@ int cmd_apply(int argc, const char **ar squelched == 1 ? "" : "s"); } if (new_whitespace == error_on_whitespace) - die("%d line%s add%s trailing whitespaces.", + die("%d line%s add%s whitespace errors.", whitespace_error, whitespace_error == 1 ? "" : "s", whitespace_error == 1 ? "s" : ""); - if (applied_after_stripping) + if (applied_after_fixing_ws) fprintf(stderr, "warning: %d line%s applied after" - " stripping trailing whitespaces.\n", - applied_after_stripping, - applied_after_stripping == 1 ? "" : "s"); + " fixing whitespace errors.\n", + applied_after_fixing_ws, + applied_after_fixing_ws == 1 ? "" : "s"); else if (whitespace_error) - fprintf(stderr, "warning: %d line%s add%s trailing" - " whitespaces.\n", + fprintf(stderr, "warning: %d line%s add%s whitespace errors.\n", whitespace_error, whitespace_error == 1 ? "" : "s", whitespace_error == 1 ? "s" : ""); diff --combined setup.c index 4945eb3134,2b8e8c0e5e..b55b82c99e --- a/setup.c +++ b/setup.c @@@ -1,8 -1,4 +1,8 @@@ #include "cache.h" +#include "dir.h" + +static int inside_git_dir = -1; +static int inside_work_tree = -1; const char *prefix_path(const char *prefix, int len, const char *path) { @@@ -43,7 -39,7 +43,7 @@@ if (len) { int speclen = strlen(path); char *n = xmalloc(speclen + len + 1); - + memcpy(n, prefix, len); memcpy(n + len, path, speclen+1); path = n; @@@ -51,7 -47,7 +51,7 @@@ return path; } -/* +/* * Unlike prefix_path, this should be used if the named file does * not have to interact with index entry; i.e. name of a random file * on the filesystem. @@@ -99,7 -95,7 +99,7 @@@ void verify_non_filename(const char *pr const char *name; struct stat st; - if (is_inside_git_dir()) + if (!is_inside_work_tree() || is_inside_git_dir()) return; if (*arg == '-') return; /* flag */ @@@ -107,7 -103,7 +107,7 @@@ if (!lstat(name, &st)) die("ambiguous argument '%s': both revision and filename\n" "Use '--' to separate filenames from revisions", arg); - if (errno != ENOENT) + if (errno != ENOENT && errno != ENOTDIR) die("'%s': %s", arg, strerror(errno)); } @@@ -174,77 -170,30 +174,77 @@@ static int is_git_directory(const char return 1; } -static int inside_git_dir = -1; - int is_inside_git_dir(void) { - if (inside_git_dir < 0) { - char buffer[1024]; - - if (is_bare_repository()) - return (inside_git_dir = 1); - if (getcwd(buffer, sizeof(buffer))) { - const char *git_dir = get_git_dir(), *cwd = buffer; - while (*git_dir && *git_dir == *cwd) { - git_dir++; - cwd++; - } - inside_git_dir = !*git_dir; - } else - inside_git_dir = 0; - } + if (inside_git_dir < 0) + inside_git_dir = is_inside_dir(get_git_dir()); return inside_git_dir; } +int is_inside_work_tree(void) +{ + if (inside_work_tree < 0) + inside_work_tree = is_inside_dir(get_git_work_tree()); + return inside_work_tree; +} + +/* + * If no worktree was given, and we are outside of a default work tree, + * now is the time to set it. + * + * In other words, if the user calls git with something like + * + * git --git-dir=/some/where/else/.git bla + * + * default to /some/where/else as working directory; if the specified + * git-dir does not end in "/.git", the cwd is used as working directory. + */ +const char *set_work_tree(const char *dir) +{ + char dir_buffer[PATH_MAX], *rel = NULL; + static char buffer[PATH_MAX + 1]; + int len, suffix_len = strlen(DEFAULT_GIT_DIR_ENVIRONMENT) + 1; + + /* strip the variable 'dir' of the postfix "/.git" if it has it */ + len = strlen(dir); + if (len > suffix_len && + !strcmp(dir + len - suffix_len, "/" DEFAULT_GIT_DIR_ENVIRONMENT)) { + if ((len - suffix_len) >= sizeof(dir_buffer)) + die("directory name too long"); + memcpy(dir_buffer, dir, len - suffix_len); + dir_buffer[len - suffix_len] = '\0'; + + /* are we inside the default work tree? */ + rel = get_relative_cwd(buffer, sizeof(buffer), dir_buffer); + } + + /* if rel is set, the cwd is _not_ the current working tree */ + if (rel && *rel) { + if (!is_absolute_path(dir)) + set_git_dir(make_absolute_path(dir)); + dir = dir_buffer; + if (chdir(dir)) + die("cannot chdir to %s: %s", dir, strerror(errno)); + else + strcat(rel, "/"); + inside_git_dir = 0; + } else { + rel = NULL; + dir = getcwd(buffer, sizeof(buffer)); + } + git_work_tree_cfg = xstrdup(dir); + inside_work_tree = 1; + + return rel; +} + +/* + * We cannot decide in this function whether we are in the work tree or + * not, since the config can only be read _after_ this function was called. + */ const char *setup_git_directory_gently(int *nongit_ok) { + const char *work_tree_env = getenv(GIT_WORK_TREE_ENVIRONMENT); static char cwd[PATH_MAX+1]; const char *gitdirenv; int len, offset; @@@ -258,11 -207,8 +258,11 @@@ if (gitdirenv) { if (PATH_MAX - 40 < strlen(gitdirenv)) die("'$%s' too big", GIT_DIR_ENVIRONMENT); - if (is_git_directory(gitdirenv)) + if (is_git_directory(gitdirenv)) { + if (!work_tree_env) + return set_work_tree(gitdirenv); return NULL; + } if (nongit_ok) { *nongit_ok = 1; return NULL; @@@ -270,32 -216,23 +270,32 @@@ die("Not a git repository: '%s'", gitdirenv); } - if (!getcwd(cwd, sizeof(cwd)-1) || cwd[0] != '/') + if (!getcwd(cwd, sizeof(cwd)-1)) die("Unable to read current working directory"); + /* + * Test in the following order (relative to the cwd): + * - .git/ + * - ./ (bare) + * - ../.git/ + * - ../ (bare) + * - ../../.git/ + * etc. + */ offset = len = strlen(cwd); for (;;) { - if (is_git_directory(".git")) + if (is_git_directory(DEFAULT_GIT_DIR_ENVIRONMENT)) break; + if (is_git_directory(".")) { + inside_git_dir = 1; + if (!work_tree_env) + inside_work_tree = 0; + setenv(GIT_DIR_ENVIRONMENT, ".", 1); + return NULL; + } chdir(".."); do { if (!offset) { - if (is_git_directory(cwd)) { - if (chdir(cwd)) - die("Cannot come back to cwd"); - setenv(GIT_DIR_ENVIRONMENT, cwd, 1); - inside_git_dir = 1; - return NULL; - } if (nongit_ok) { if (chdir(cwd)) die("Cannot come back to cwd"); @@@ -307,10 -244,6 +307,10 @@@ } while (cwd[--offset] != '/'); } + inside_git_dir = 0; + if (!work_tree_env) + inside_work_tree = 1; + git_work_tree_cfg = xstrndup(cwd, offset); if (offset == len) return NULL; @@@ -318,13 -251,13 +318,13 @@@ offset++; cwd[len++] = '/'; cwd[len] = 0; - inside_git_dir = !prefixcmp(cwd + offset, ".git/"); return cwd + offset; } int git_config_perm(const char *var, const char *value) { if (value) { + int i; if (!strcmp(value, "umask")) return PERM_UMASK; if (!strcmp(value, "group")) @@@ -333,30 -266,17 +333,30 @@@ !strcmp(value, "world") || !strcmp(value, "everybody")) return PERM_EVERYBODY; + i = atoi(value); + if (i > 1) + return i; } return git_config_bool(var, value); } int check_repository_format_version(const char *var, const char *value) { - if (strcmp(var, "core.repositoryformatversion") == 0) - repository_format_version = git_config_int(var, value); + if (strcmp(var, "core.repositoryformatversion") == 0) + repository_format_version = git_config_int(var, value); else if (strcmp(var, "core.sharedrepository") == 0) shared_repository = git_config_perm(var, value); - return 0; + else if (strcmp(var, "core.bare") == 0) { + is_bare_repository_cfg = git_config_bool(var, value); + if (is_bare_repository_cfg == 1) + inside_work_tree = -1; + } else if (strcmp(var, "core.worktree") == 0) { + if (git_work_tree_cfg) + free(git_work_tree_cfg); + git_work_tree_cfg = xstrdup(value); + inside_work_tree = -1; + } + return 0; } int check_repository_format(void) @@@ -372,16 -292,5 +372,16 @@@ const char *setup_git_directory(void { const char *retval = setup_git_directory_gently(NULL); check_repository_format(); + + /* If the work tree is not the default one, recompute prefix */ + if (inside_work_tree < 0) { + static char buffer[PATH_MAX + 1]; + char *rel; + if (retval && chdir(retval)) + die ("Could not jump back into original cwd"); + rel = get_relative_cwd(buffer, PATH_MAX, get_git_work_tree()); + return rel && *rel ? strcat(rel, "/") : NULL; + } + return retval; }