diff options
91 files changed, 1059 insertions, 230 deletions
diff --git a/Documentation/RelNotes/1.7.11.2.txt b/Documentation/RelNotes/1.7.11.2.txt new file mode 100644 index 0000000000..a0d24d1270 --- /dev/null +++ b/Documentation/RelNotes/1.7.11.2.txt @@ -0,0 +1,53 @@ +Git v1.7.11.2 Release Notes +=========================== + +Fixes since v1.7.11.1 +--------------------- + + * On Cygwin, the platform pread(2) is not thread safe, just like our + own compat/ emulation, and cannot be used in the index-pack + program. Makefile variable NO_THREAD_SAFE_PREAD can be defined to + avoid use of this function in a threaded program. + + * "git add" allows adding a regular file to the path where a + submodule used to exist, but "git update-index" does not allow an + equivalent operation to Porcelain writers. + + * "git archive" incorrectly computed the header checksum; the symptom + was observed only when using pathnames with hi-bit set. + + * "git blame" did not try to make sure that the abbreviated commit + object names in its output are unique. + + * Running "git bundle verify" on a bundle that records a complete + history said "it requires these 0 commits". + + * "git clone --single-branch" to clone a single branch did not limit + the cloning to the specified branch. + + * "git diff --no-index" did not correctly handle relative paths and + did not correctly give exit codes when run under "--quiet" option. + + * "git diff --no-index" did not work with pagers correctly. + + * "git diff COPYING HEAD:COPYING" gave a nonsense error message that + claimed that the treeish HEAD did not have COPYING in it. + + * When "git log" gets "--simplify-merges/by-decoration" together with + "--first-parent", the combination of these options makes the + simplification logic to use in-core commit objects that haven't + been examined for relevance, either producing incorrect result or + taking too long to produce any output. Teach the simplification + logic to ignore commits that the first-parent traversal logic + ignored when both are in effect to work around the issue. + + * "git ls-files --exclude=t -i" did not consider anything under t/ as + excluded, as it did not pay attention to exclusion of leading paths + while walking the index. Other two users of excluded() are also + updated. + + * "git request-pull $url dev" when the tip of "dev" branch was tagged + with "ext4-for-linus" used the contents from the tag in the output + but still asked the "dev" branch to be pulled, not the tag. + +Also contains minor typofixes and documentation updates. diff --git a/Documentation/RelNotes/1.7.11.3.txt b/Documentation/RelNotes/1.7.11.3.txt new file mode 100644 index 0000000000..64494f89d9 --- /dev/null +++ b/Documentation/RelNotes/1.7.11.3.txt @@ -0,0 +1,53 @@ +Git v1.7.11.3 Release Notes +=========================== + +Fixes since v1.7.11.3 +--------------------- + + * The error message from "git push $there :bogo" (and its equivalent + "git push $there --delete bogo") mentioned that we tried and failed + to guess what ref is being deleted based on the LHS of the refspec, + which we don't. + + * A handful of files and directories we create had tighter than + necessary permission bits when the user wanted to have group + writability (e.g. by setting "umask 002"). + + * "commit --amend" used to refuse amending a commit with an empty log + message, with or without "--allow-empty-message". + + * "git commit --amend --only --" was meant to allow "Clever" people to + rewrite the commit message without making any change even when they + have already changes for the next commit added to their index, but + it never worked as advertised since it was introduced in 1.3.0 era. + + * Even though the index can record pathnames longer than 1<<12 bytes, + in some places we were not comparing them in full, potentially + replacing index entries instead of adding. + + * "git show"'s auto-walking behaviour was an unreliable and + unpredictable hack; it now behaves just like "git log" does when it + walks. + + * "git diff", "git status" and anything that internally uses the + comparison machinery was utterly broken when the difference + involved a file with "-" as its name. This was due to the way "git + diff --no-index" was incorrectly bolted on to the system, making + any comparison that involves a file "-" at the root level + incorrectly read from the standard input. + + * We did not have test to make sure "git rebase" without extra options + filters out an empty commit in the original history. + + * "git fast-export" produced an input stream for fast-import without + properly quoting pathnames when they contain SPs in them. + + * "git checkout --detach", when you are still on an unborn branch, + should be forbidden, but it wasn't. + + * Some implementations of Perl terminates "lines" with CRLF even when + the script is operating on just a sequence of bytes. Make sure to + use "$PERL_PATH", the version of Perl the user told Git to use, in + our tests to avoid unnecessary breakages in tests. + +Also contains minor typofixes and documentation updates. diff --git a/Documentation/RelNotes/1.7.11.4.txt b/Documentation/RelNotes/1.7.11.4.txt new file mode 100644 index 0000000000..3a640c2d4d --- /dev/null +++ b/Documentation/RelNotes/1.7.11.4.txt @@ -0,0 +1,31 @@ +Git v1.7.11.4 Release Notes +=========================== + +Fixes since v1.7.11.3 +--------------------- + + * "$GIT_DIR/COMMIT_EDITMSG" file that is used to hold the commit log + message user edits was not documented. + + * The advise() function did not use varargs correctly to format + its message. + + * When "git am" failed, old timers knew to check .git/rebase-apply/patch + to see what went wrong, but we never told the users about it. + + * "git commit-tree" learned a more natural "-p <parent> <tree>" order + of arguments long time ago, but recently forgot it by mistake. + + * "git diff --no-ext-diff" did not output anything for a typechange + filepair when GIT_EXTERNAL_DIFF is in effect. + + * In 1.7.9 era, we taught "git rebase" about the raw timestamp format + but we did not teach the same trick to "filter-branch", which rolled + a similar logic on its own. + + * When "git submodule add" clones a submodule repository, it can get + confused where to store the resulting submodule repository in the + superproject's .git/ directory when there is a symbolic link in the + path to the current directory. + +Also contains minor typofixes and documentation updates. diff --git a/Documentation/config.txt b/Documentation/config.txt index 915cb5a547..b49feb582e 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -176,6 +176,9 @@ advice.*:: Advice shown when you used linkgit:git-checkout[1] to move to the detach HEAD state, to instruct how to create a local branch after the fact. + amWorkDir:: + Advice that shows the location of the patch file when + linkgit:git-am[1] fails to apply it. -- core.fileMode:: diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt index 9f3dae631e..0e170a51ca 100644 --- a/Documentation/git-cherry-pick.txt +++ b/Documentation/git-cherry-pick.txt @@ -47,7 +47,9 @@ OPTIONS linkgit:gitrevisions[7]. Sets of commits can be passed but no traversal is done by default, as if the '--no-walk' option was specified, see - linkgit:git-rev-list[1]. + linkgit:git-rev-list[1]. Note that specifying a range will + feed all <commit>... arguments to a single revision walk + (see a later example that uses 'maint master..next'). -e:: --edit:: @@ -149,6 +151,15 @@ EXAMPLES Apply the changes introduced by all commits that are ancestors of master but not of HEAD to produce new commits. +`git cherry-pick maint next ^master`:: +`git cherry-pick maint master..next`:: + + Apply the changes introduced by all commits that are + ancestors of maint or next, but not master or any of its + ancestors. Note that the latter does not mean `maint` and + everything between `master` and `next`; specifically, + `maint` will not be used if it is included in `master`. + `git cherry-pick master~4 master~2`:: Apply the changes introduced by the fifth and third last diff --git a/Documentation/git-commit-tree.txt b/Documentation/git-commit-tree.txt index ff73286509..6d5a04c83b 100644 --- a/Documentation/git-commit-tree.txt +++ b/Documentation/git-commit-tree.txt @@ -10,7 +10,7 @@ SYNOPSIS -------- [verse] 'git commit-tree' <tree> [(-p <parent>)...] < changelog -'git commit-tree' <tree> [(-p <parent>)...] [(-m <message>)...] [(-F <file>)...] +'git commit-tree' [(-p <parent>)...] [(-m <message>)...] [(-F <file>)...] <tree> DESCRIPTION ----------- diff --git a/Documentation/git-commit.txt b/Documentation/git-commit.txt index 2d695f619c..81853e9646 100644 --- a/Documentation/git-commit.txt +++ b/Documentation/git-commit.txt @@ -399,6 +399,15 @@ This command can run `commit-msg`, `prepare-commit-msg`, `pre-commit`, and `post-commit` hooks. See linkgit:githooks[5] for more information. +FILES +----- + +`$GIT_DIR/COMMIT_EDITMSG`:: + This file contains the commit message of a commit in progress. + If `git commit` exits due to an error before creating a commit, + any commit message that has been provided by the user (e.g., in + an editor session) will be available in this file, but will be + overwritten by the next invocation of `git commit`. SEE ALSO -------- diff --git a/Documentation/git-mergetool.txt b/Documentation/git-mergetool.txt index 2a49de7cfe..d7207bd9b9 100644 --- a/Documentation/git-mergetool.txt +++ b/Documentation/git-mergetool.txt @@ -27,9 +27,9 @@ OPTIONS -t <tool>:: --tool=<tool>:: Use the merge resolution program specified by <tool>. - Valid merge tools are: - araxis, bc3, diffuse, ecmerge, emerge, gvimdiff, kdiff3, - meld, opendiff, p4merge, tkdiff, tortoisemerge, vimdiff and xxdiff. + Valid values include emerge, gvimdiff, kdiff3, + meld, vimdiff, and tortoisemerge. Run `git mergetool --tool-help` + for the list of valid <tool> settings. + If a merge resolution program is not specified, 'git mergetool' will use the configuration variable `merge.tool`. If the diff --git a/Documentation/git.txt b/Documentation/git.txt index d58fad71bd..7af8aaa047 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -44,9 +44,12 @@ unreleased) version of git, that is available from 'master' branch of the `git.git` repository. Documentation for older releases are available here: -* link:v1.7.11.1/git.html[documentation for release 1.7.11.1] +* link:v1.7.11.4/git.html[documentation for release 1.7.11.4] * release notes for + link:RelNotes/1.7.11.4.txt[1.7.11.4], + link:RelNotes/1.7.11.3.txt[1.7.11.3], + link:RelNotes/1.7.11.2.txt[1.7.11.2], link:RelNotes/1.7.11.1.txt[1.7.11.1], link:RelNotes/1.7.11.txt[1.7.11]. diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt index 1ae3c899ef..84e34b1aba 100644 --- a/Documentation/rev-list-options.txt +++ b/Documentation/rev-list-options.txt @@ -622,6 +622,7 @@ These options are mostly targeted for packing of git repositories. --no-walk:: Only show the given revs, but do not traverse their ancestors. + This has no effect if a range is specified. --do-walk:: diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN index a7570decfb..a9dea5c023 100755 --- a/GIT-VERSION-GEN +++ b/GIT-VERSION-GEN @@ -1,7 +1,7 @@ #!/bin/sh GVF=GIT-VERSION-FILE -DEF_VER=v1.7.11.1 +DEF_VER=v1.7.11.4 LF=' ' @@ -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. # @@ -1051,6 +1054,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 @@ -1659,6 +1663,10 @@ endif 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 @@ -1 +1 @@ -Documentation/RelNotes/1.7.11.1.txt
\ No newline at end of file +Documentation/RelNotes/1.7.11.4.txt
\ No newline at end of file @@ -32,7 +32,7 @@ void advise(const char *advice, ...) const char *cp, *np; va_start(params, advice); - strbuf_addf(&buf, advice, params); + strbuf_vaddf(&buf, advice, params); va_end(params); for (cp = buf.buf; *cp; cp = np) { diff --git a/archive-tar.c b/archive-tar.c index dc91c6b50d..0ba3f25cf5 100644 --- a/archive-tar.c +++ b/archive-tar.c @@ -139,13 +139,13 @@ static void strbuf_append_ext_header(struct strbuf *sb, const char *keyword, static unsigned int ustar_header_chksum(const struct ustar_header *header) { - const char *p = (const char *)header; + const unsigned char *p = (const unsigned char *)header; unsigned int chksum = 0; - while (p < header->chksum) + while (p < (const unsigned char *)header->chksum) chksum += *p++; chksum += sizeof(header->chksum) * ' '; p += sizeof(header->chksum); - while (p < (const char *)header + sizeof(struct ustar_header)) + while (p < (const unsigned char *)header + sizeof(struct ustar_header)) chksum += *p++; return chksum; } @@ -41,6 +41,8 @@ int copy_note_for_rewrite(struct notes_rewrite_cfg *c, void finish_copy_notes_for_rewrite(struct notes_rewrite_cfg *c); extern int check_pager_config(const char *cmd); +struct diff_options; +extern void setup_diff_pager(struct diff_options *); extern int textconv_object(const char *path, unsigned mode, const unsigned char *sha1, char **buf, unsigned long *buf_size); diff --git a/builtin/add.c b/builtin/add.c index b79336d712..89dce56a24 100644 --- a/builtin/add.c +++ b/builtin/add.c @@ -281,7 +281,7 @@ static int edit_patch(int argc, const char **argv, const char *prefix) argc = setup_revisions(argc, argv, &rev, NULL); rev.diffopt.output_format = DIFF_FORMAT_PATCH; DIFF_OPT_SET(&rev.diffopt, IGNORE_DIRTY_SUBMODULES); - out = open(file, O_CREAT | O_WRONLY, 0644); + out = open(file, O_CREAT | O_WRONLY, 0666); if (out < 0) die (_("Could not open '%s' for writing."), file); rev.diffopt.file = xfdopen(out, "w"); @@ -443,6 +443,9 @@ int cmd_add(int argc, const char **argv, const char *prefix) if (pathspec) { int i; + struct path_exclude_check check; + + path_exclude_check_init(&check, &dir); if (!seen) seen = find_used_pathspec(pathspec); for (i = 0; pathspec[i]; i++) { @@ -450,7 +453,7 @@ int cmd_add(int argc, const char **argv, const char *prefix) && !file_exists(pathspec[i])) { if (ignore_missing) { int dtype = DT_UNKNOWN; - if (excluded(&dir, pathspec[i], &dtype)) + if (path_excluded(&check, pathspec[i], -1, &dtype)) dir_add_ignored(&dir, pathspec[i], strlen(pathspec[i])); } else die(_("pathspec '%s' did not match any files"), @@ -458,6 +461,7 @@ int cmd_add(int argc, const char **argv, const char *prefix) } } free(seen); + path_exclude_check_clear(&check); } plug_bulk_checkin(); diff --git a/builtin/blame.c b/builtin/blame.c index 24d3dd5292..960c58d855 100644 --- a/builtin/blame.c +++ b/builtin/blame.c @@ -1837,6 +1837,16 @@ static int read_ancestry(const char *graft_file) return 0; } +static int update_auto_abbrev(int auto_abbrev, struct origin *suspect) +{ + const char *uniq = find_unique_abbrev(suspect->commit->object.sha1, + auto_abbrev); + int len = strlen(uniq); + if (auto_abbrev < len) + return len; + return auto_abbrev; +} + /* * How many columns do we need to show line numbers, authors, * and filenames? @@ -1847,12 +1857,16 @@ static void find_alignment(struct scoreboard *sb, int *option) int longest_dst_lines = 0; unsigned largest_score = 0; struct blame_entry *e; + int compute_auto_abbrev = (abbrev < 0); + int auto_abbrev = default_abbrev; for (e = sb->ent; e; e = e->next) { struct origin *suspect = e->suspect; struct commit_info ci; int num; + if (compute_auto_abbrev) + auto_abbrev = update_auto_abbrev(auto_abbrev, suspect); if (strcmp(suspect->path, sb->path)) *option |= OUTPUT_SHOW_NAME; num = strlen(suspect->path); @@ -1880,6 +1894,10 @@ static void find_alignment(struct scoreboard *sb, int *option) max_orig_digits = decimal_width(longest_src_lines); max_digits = decimal_width(longest_dst_lines); max_score_digits = decimal_width(largest_score); + + if (compute_auto_abbrev) + /* one more abbrev length is needed for the boundary commit */ + abbrev = auto_abbrev + 1; } /* @@ -2353,10 +2371,9 @@ int cmd_blame(int argc, const char **argv, const char *prefix) parse_done: argc = parse_options_end(&ctx); - if (abbrev == -1) - abbrev = default_abbrev; - /* one more abbrev length is needed for the boundary commit */ - abbrev++; + if (0 < abbrev) + /* one more abbrev length is needed for the boundary commit */ + abbrev++; if (revs_file && read_ancestry(revs_file)) die_errno("reading graft file '%s' failed", revs_file); diff --git a/builtin/checkout.c b/builtin/checkout.c index e8c1b1f189..3980d5d06e 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -915,6 +915,8 @@ static int switch_unborn_to_new_branch(struct checkout_opts *opts) int status; struct strbuf branch_ref = STRBUF_INIT; + if (!opts->new_branch) + die(_("You are on a branch yet to be born")); strbuf_addf(&branch_ref, "refs/heads/%s", opts->new_branch); status = create_symref("HEAD", branch_ref.buf, "checkout -b"); strbuf_release(&branch_ref); diff --git a/builtin/clone.c b/builtin/clone.c index a4d8d25ee3..920ef7f8c9 100644 --- a/builtin/clone.c +++ b/builtin/clone.c @@ -433,8 +433,11 @@ static struct ref *wanted_peer_refs(const struct ref *refs, if (!option_branch) remote_head = guess_remote_head(head, refs, 0); - else - remote_head = find_remote_branch(refs, option_branch); + else { + local_refs = NULL; + tail = &local_refs; + remote_head = copy_ref(find_remote_branch(refs, option_branch)); + } if (!remote_head && option_branch) warning(_("Could not find remote branch %s to clone."), @@ -705,7 +708,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix) if (safe_create_leading_directories_const(work_tree) < 0) die_errno(_("could not create leading directories of '%s'"), work_tree); - if (!dest_exists && mkdir(work_tree, 0755)) + if (!dest_exists && mkdir(work_tree, 0777)) die_errno(_("could not create work tree dir '%s'."), work_tree); set_git_work_tree(work_tree); diff --git a/builtin/commit-tree.c b/builtin/commit-tree.c index 164b655df9..a0df12ce16 100644 --- a/builtin/commit-tree.c +++ b/builtin/commit-tree.c @@ -48,9 +48,6 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix) if (argc < 2 || !strcmp(argv[1], "-h")) usage(commit_tree_usage); - if (get_sha1(argv[1], tree_sha1)) - die("Not a valid object name %s", argv[1]); - for (i = 1; i < argc; i++) { const char *arg = argv[i]; if (!strcmp(arg, "-p")) { diff --git a/builtin/commit.c b/builtin/commit.c index f43eaafb3b..95eeab1d51 100644 --- a/builtin/commit.c +++ b/builtin/commit.c @@ -184,6 +184,9 @@ static int list_paths(struct string_list *list, const char *with_tree, int i; char *m; + if (!pattern) + return 0; + for (i = 0; pattern[i]; i++) ; m = xcalloc(1, i); @@ -345,7 +348,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix, * and create commit from the_index. * We still need to refresh the index here. */ - if (!pathspec || !*pathspec) { + if (!only && (!pathspec || !*pathspec)) { fd = hold_locked_index(&index_lock, 1); refresh_cache_or_die(refresh_flags); if (active_cache_changed) { @@ -640,7 +643,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix, hook_arg1 = "message"; } else if (use_message) { buffer = strstr(use_message_buffer, "\n\n"); - if (!buffer || buffer[2] == '\0') + if (!use_editor && (!buffer || buffer[2] == '\0')) die(_("commit has empty message")); strbuf_add(&sb, buffer + 2, strlen(buffer + 2)); hook_arg1 = "commit"; diff --git a/builtin/diff.c b/builtin/diff.c index 9069dc41be..da8f6aac2b 100644 --- a/builtin/diff.c +++ b/builtin/diff.c @@ -304,13 +304,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix) DIFF_OPT_SET(&rev.diffopt, RECURSIVE); - /* - * If the user asked for our exit code then don't start a - * pager or we would end up reporting its exit code instead. - */ - if (!DIFF_OPT_TST(&rev.diffopt, EXIT_WITH_STATUS) && - check_pager_config("diff") != 0) - setup_pager(); + setup_diff_pager(&rev.diffopt); /* * Do we have --cached and not have a pending object, then @@ -421,3 +415,19 @@ int cmd_diff(int argc, const char **argv, const char *prefix) refresh_index_quietly(); return result; } + +void setup_diff_pager(struct diff_options *opt) +{ + /* + * If the user asked for our exit code, then either they want --quiet + * or --exit-code. We should definitely not bother with a pager in the + * former case, as we will generate no output. Since we still properly + * report our exit code even when a pager is run, we _could_ run a + * pager with --exit-code. But since we have not done so historically, + * and because it is easy to find people oneline advising "git diff + * --exit-code" in hooks and other scripts, we do not do so. + */ + if (!DIFF_OPT_TST(opt, EXIT_WITH_STATUS) && + check_pager_config("diff") != 0) + setup_pager(); +} diff --git a/builtin/fast-export.c b/builtin/fast-export.c index ef7c012094..9ab6db3fb0 100644 --- a/builtin/fast-export.c +++ b/builtin/fast-export.c @@ -185,6 +185,8 @@ static void print_path(const char *path) int need_quote = quote_c_style(path, NULL, NULL, 0); if (need_quote) quote_c_style(path, NULL, stdout, 0); + else if (strchr(path, ' ')) + printf("\"%s\"", path); else printf("%s", path); } diff --git a/builtin/grep.c b/builtin/grep.c index fe1726f5ef..29adb0ac93 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -928,7 +928,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix) if (!seen_dashdash) { int j; for (j = i; j < argc; j++) - verify_filename(prefix, argv[j]); + verify_filename(prefix, argv[j], j == i); } paths = get_pathspec(prefix, argv + i); diff --git a/builtin/index-pack.c b/builtin/index-pack.c index dc2cfe6e6f..470547835c 100644 --- a/builtin/index-pack.c +++ b/builtin/index-pack.c @@ -39,8 +39,8 @@ struct base_data { int ofs_first, ofs_last; }; -#if !defined(NO_PTHREADS) && defined(NO_PREAD) -/* NO_PREAD uses compat/pread.c, which is not thread-safe. Disable threading. */ +#if !defined(NO_PTHREADS) && defined(NO_THREAD_SAFE_PREAD) +/* pread() emulation is not thread-safe. Disable threading. */ #define NO_PTHREADS #endif diff --git a/builtin/log.c b/builtin/log.c index 906dca475a..54f24e2088 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -462,6 +462,9 @@ int cmd_show(int argc, const char **argv, const char *prefix) opt.tweak = show_rev_tweak_rev; cmd_log_init(argc, argv, prefix, &rev, &opt); + if (!rev.no_walk) + return cmd_log_walk(&rev); + count = rev.pending.nr; objects = rev.pending.objects; for (i = 0; i < count && !ret; i++) { diff --git a/builtin/ls-files.c b/builtin/ls-files.c index 7cff175745..31b3f2d900 100644 --- a/builtin/ls-files.c +++ b/builtin/ls-files.c @@ -200,9 +200,19 @@ static void show_ru_info(void) } } +static int ce_excluded(struct path_exclude_check *check, struct cache_entry *ce) +{ + int dtype = ce_to_dtype(ce); + return path_excluded(check, ce->name, ce_namelen(ce), &dtype); +} + static void show_files(struct dir_struct *dir) { int i; + struct path_exclude_check check; + + if ((dir->flags & DIR_SHOW_IGNORED)) + path_exclude_check_init(&check, dir); /* For cached/deleted files we don't need to even do the readdir */ if (show_others || show_killed) { @@ -215,9 +225,8 @@ static void show_files(struct dir_struct *dir) if (show_cached | show_stage) { for (i = 0; i < active_nr; i++) { struct cache_entry *ce = active_cache[i]; - int dtype = ce_to_dtype(ce); - if (dir->flags & DIR_SHOW_IGNORED && - !excluded(dir, ce->name, &dtype)) + if ((dir->flags & DIR_SHOW_IGNORED) && + !ce_excluded(&check, ce)) continue; if (show_unmerged && !ce_stage(ce)) continue; @@ -232,9 +241,8 @@ static void show_files(struct dir_struct *dir) struct cache_entry *ce = active_cache[i]; struct stat st; int err; - int dtype = ce_to_dtype(ce); - if (dir->flags & DIR_SHOW_IGNORED && - !excluded(dir, ce->name, &dtype)) + if ((dir->flags & DIR_SHOW_IGNORED) && + !ce_excluded(&check, ce)) continue; if (ce->ce_flags & CE_UPDATE) continue; @@ -247,6 +255,9 @@ static void show_files(struct dir_struct *dir) show_ce_entry(tag_modified, ce); } } + + if ((dir->flags & DIR_SHOW_IGNORED)) + path_exclude_check_clear(&check); } /* diff --git a/builtin/reset.c b/builtin/reset.c index 8c2c1d52a2..4cc34c9084 100644 --- a/builtin/reset.c +++ b/builtin/reset.c @@ -285,7 +285,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix) rev = argv[i++]; } else { /* Otherwise we treat this as a filename */ - verify_filename(prefix, argv[i]); + verify_filename(prefix, argv[i], 1); } } diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c index 733f626f6c..13495b88f5 100644 --- a/builtin/rev-parse.c +++ b/builtin/rev-parse.c @@ -486,7 +486,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix) if (as_is) { if (show_file(arg) && as_is < 2) - verify_filename(prefix, arg); + verify_filename(prefix, arg, 0); continue; } if (!strcmp(arg,"-n")) { @@ -734,7 +734,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix) as_is = 1; if (!show_file(arg)) continue; - verify_filename(prefix, arg); + verify_filename(prefix, arg, 1); } if (verify) { if (revs_count == 1) { diff --git a/builtin/update-index.c b/builtin/update-index.c index 5f038d64da..5a4e9ea55a 100644 --- a/builtin/update-index.c +++ b/builtin/update-index.c @@ -211,12 +211,6 @@ static int process_path(const char *path) if (S_ISDIR(st.st_mode)) return process_directory(path, len, &st); - /* - * Process a regular file - */ - if (ce && S_ISGITLINK(ce->ce_mode)) - return error("%s is already a gitlink, not replacing", path); - return add_one_path(ce, path, len, &st); } @@ -188,12 +188,16 @@ int verify_bundle(struct bundle_header *header, int verbose) r->nr), r->nr); list_refs(r, 0, NULL); - r = &header->prerequisites; - printf_ln(Q_("The bundle requires this ref", - "The bundle requires these %d refs", - r->nr), - r->nr); - list_refs(r, 0, NULL); + if (!r->nr) { + printf_ln(_("The bundle records a complete history.")); + } else { + r = &header->prerequisites; + printf_ln(Q_("The bundle requires this ref", + "The bundle requires these %d refs", + r->nr), + r->nr); + list_refs(r, 0, NULL); + } } return ret; } @@ -409,8 +409,11 @@ extern const char *setup_git_directory(void); 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 @@ -624,7 +624,7 @@ static int match_object_header_date(const char *date, unsigned long *timestamp, unsigned long stamp; int ofs; - if (*date < '0' || '9' <= *date) + if (*date < '0' || '9' < *date) return -1; stamp = strtoul(date, &end, 10); if (*end != ' ' || stamp == ULONG_MAX || (end[1] != '+' && end[1] != '-')) diff --git a/diff-no-index.c b/diff-no-index.c index f0b0010aed..7d805a06af 100644 --- a/diff-no-index.c +++ b/diff-no-index.c @@ -32,6 +32,13 @@ static int read_directory(const char *path, struct string_list *list) return 0; } +/* + * This should be "(standard input)" or something, but it will + * probably expose many more breakages in the way no-index code + * is bolted onto the diff callchain. + */ +static const char file_from_standard_input[] = "-"; + static int get_mode(const char *path, int *mode) { struct stat st; @@ -42,7 +49,7 @@ static int get_mode(const char *path, int *mode) else if (!strcasecmp(path, "nul")) *mode = 0; #endif - else if (!strcmp(path, "-")) + else if (path == file_from_standard_input) *mode = create_ce_mode(0666); else if (lstat(path, &st)) return error("Could not access '%s'", path); @@ -51,6 +58,36 @@ static int get_mode(const char *path, int *mode) return 0; } +static int populate_from_stdin(struct diff_filespec *s) +{ + struct strbuf buf = STRBUF_INIT; + size_t size = 0; + + if (strbuf_read(&buf, 0, 0) < 0) + return error("error while reading from stdin %s", + strerror(errno)); + + s->should_munmap = 0; + s->data = strbuf_detach(&buf, &size); + s->size = size; + s->should_free = 1; + s->is_stdin = 1; + return 0; +} + +static struct diff_filespec *noindex_filespec(const char *name, int mode) +{ + struct diff_filespec *s; + + if (!name) + name = "/dev/null"; + s = alloc_filespec(name); + fill_filespec(s, null_sha1, mode); + if (name == file_from_standard_input) + populate_from_stdin(s); + return s; +} + static int queue_diff(struct diff_options *o, const char *name1, const char *name2) { @@ -137,44 +174,21 @@ static int queue_diff(struct diff_options *o, tmp_c = name1; name1 = name2; name2 = tmp_c; } - if (!name1) - name1 = "/dev/null"; - if (!name2) - name2 = "/dev/null"; - d1 = alloc_filespec(name1); - d2 = alloc_filespec(name2); - fill_filespec(d1, null_sha1, mode1); - fill_filespec(d2, null_sha1, mode2); - + d1 = noindex_filespec(name1, mode1); + d2 = noindex_filespec(name2, mode2); diff_queue(&diff_queued_diff, d1, d2); return 0; } } -static int path_outside_repo(const char *path) -{ - const char *work_tree; - size_t len; - - if (!is_absolute_path(path)) - return 0; - work_tree = get_git_work_tree(); - if (!work_tree) - return 1; - len = strlen(work_tree); - if (strncmp(path, work_tree, len) || - (path[len] != '\0' && path[len] != '/')) - return 1; - return 0; -} - void diff_no_index(struct rev_info *revs, int argc, const char **argv, int nongit, const char *prefix) { - int i; + int i, prefixlen; int no_index = 0; unsigned options = 0; + const char *paths[2]; /* Were we asked to do --no-index explicitly? */ for (i = 1; i < argc; i++) { @@ -197,8 +211,8 @@ void diff_no_index(struct rev_info *revs, * a colourful "diff" replacement. */ if ((argc != i + 2) || - (!path_outside_repo(argv[i]) && - !path_outside_repo(argv[i+1]))) + (path_inside_repo(prefix, argv[i]) && + path_inside_repo(prefix, argv[i+1]))) return; } if (argc != i + 2) @@ -224,46 +238,33 @@ void diff_no_index(struct rev_info *revs, } } - /* - * If the user asked for our exit code then don't start a - * pager or we would end up reporting its exit code instead. - */ - if (!DIFF_OPT_TST(&revs->diffopt, EXIT_WITH_STATUS)) - setup_pager(); - - if (prefix) { - int len = strlen(prefix); - const char *paths[3]; - memset(paths, 0, sizeof(paths)); - - for (i = 0; i < 2; i++) { - const char *p = argv[argc - 2 + i]; + prefixlen = prefix ? strlen(prefix) : 0; + for (i = 0; i < 2; i++) { + const char *p = argv[argc - 2 + i]; + if (!strcmp(p, "-")) /* - * stdin should be spelled as '-'; if you have - * path that is '-', spell it as ./-. + * stdin should be spelled as "-"; if you have + * path that is "-", spell it as "./-". */ - p = (strcmp(p, "-") - ? xstrdup(prefix_filename(prefix, len, p)) - : p); - paths[i] = p; - } - diff_tree_setup_paths(paths, &revs->diffopt); + p = file_from_standard_input; + else if (prefixlen) + p = xstrdup(prefix_filename(prefix, prefixlen, p)); + paths[i] = p; } - else - diff_tree_setup_paths(argv + argc - 2, &revs->diffopt); revs->diffopt.skip_stat_unmatch = 1; if (!revs->diffopt.output_format) revs->diffopt.output_format = DIFF_FORMAT_PATCH; - DIFF_OPT_SET(&revs->diffopt, EXIT_WITH_STATUS); DIFF_OPT_SET(&revs->diffopt, NO_INDEX); revs->max_count = -2; if (diff_setup_done(&revs->diffopt) < 0) die("diff_setup_done failed"); - if (queue_diff(&revs->diffopt, revs->diffopt.pathspec.raw[0], - revs->diffopt.pathspec.raw[1])) + setup_diff_pager(&revs->diffopt); + DIFF_OPT_SET(&revs->diffopt, EXIT_WITH_STATUS); + + if (queue_diff(&revs->diffopt, paths[0], paths[1])) exit(1); diff_set_mnemonic_prefix(&revs->diffopt, "1/", "2/"); diffcore_std(&revs->diffopt); @@ -273,5 +274,5 @@ void diff_no_index(struct rev_info *revs, * The return code for --no-index imitates diff(1): * 0 = no changes, 1 = changes, else error */ - exit(revs->diffopt.found_changes); + exit(diff_result_code(&revs->diffopt, 0)); } @@ -2619,22 +2619,6 @@ static int reuse_worktree_file(const char *name, const unsigned char *sha1, int return 0; } -static int populate_from_stdin(struct diff_filespec *s) -{ - struct strbuf buf = STRBUF_INIT; - size_t size = 0; - - if (strbuf_read(&buf, 0, 0) < 0) - return error("error while reading from stdin %s", - strerror(errno)); - - s->should_munmap = 0; - s->data = strbuf_detach(&buf, &size); - s->size = size; - s->should_free = 1; - return 0; -} - static int diff_populate_gitlink(struct diff_filespec *s, int size_only) { int len; @@ -2684,9 +2668,6 @@ int diff_populate_filespec(struct diff_filespec *s, int size_only) struct stat st; int fd; - if (!strcmp(s->path, "-")) - return populate_from_stdin(s); - if (lstat(s->path, &st) < 0) { if (errno == ENOENT) { err_empty: @@ -3011,9 +2992,8 @@ static void run_diff_cmd(const char *pgm, int complete_rewrite = (p->status == DIFF_STATUS_MODIFIED) && p->score; int must_show_header = 0; - if (!DIFF_OPT_TST(o, ALLOW_EXTERNAL)) - pgm = NULL; - else { + + if (DIFF_OPT_TST(o, ALLOW_EXTERNAL)) { struct userdiff_driver *drv = userdiff_find_by_path(attr_path); if (drv && drv->external) pgm = drv->external; @@ -3048,7 +3028,7 @@ static void diff_fill_sha1_info(struct diff_filespec *one) if (DIFF_FILE_VALID(one)) { if (!one->sha1_valid) { struct stat st; - if (!strcmp(one->path, "-")) { + if (one->is_stdin) { hashcpy(one->sha1, null_sha1); return; } @@ -3093,6 +3073,9 @@ static void run_diff(struct diff_filepair *p, struct diff_options *o) if (o->prefix_length) strip_prefix(o->prefix_length, &name, &other); + if (!DIFF_OPT_TST(o, ALLOW_EXTERNAL)) + pgm = NULL; + if (DIFF_PAIR_UNMERGED(p)) { run_diff_cmd(pgm, name, NULL, attr_path, NULL, NULL, NULL, o, p); diff --git a/diffcore.h b/diffcore.h index 8f32b824cd..be0739c5c4 100644 --- a/diffcore.h +++ b/diffcore.h @@ -43,6 +43,7 @@ struct diff_filespec { unsigned should_free : 1; /* data should be free()'ed */ unsigned should_munmap : 1; /* data should be munmap()'ed */ unsigned dirty_submodule : 2; /* For submodules: its work tree is dirty */ + unsigned is_stdin : 1; #define DIRTY_SUBMODULE_UNTRACKED 1 #define DIRTY_SUBMODULE_MODIFIED 2 unsigned has_more_entries : 1; /* only appear in combined diff */ @@ -553,7 +553,7 @@ int excluded_from_list(const char *pathname, return -1; /* undecided */ } -int excluded(struct dir_struct *dir, const char *pathname, int *dtype_p) +static int excluded(struct dir_struct *dir, const char *pathname, int *dtype_p) { int pathlen = strlen(pathname); int st; @@ -573,6 +573,64 @@ int excluded(struct dir_struct *dir, const char *pathname, int *dtype_p) return 0; } +void path_exclude_check_init(struct path_exclude_check *check, + struct dir_struct *dir) +{ + check->dir = dir; + strbuf_init(&check->path, 256); +} + +void path_exclude_check_clear(struct path_exclude_check *check) +{ + strbuf_release(&check->path); +} + +/* + * Is this name excluded? This is for a caller like show_files() that + * do not honor directory hierarchy and iterate through paths that are + * possibly in an ignored directory. + * + * A path to a directory known to be excluded is left in check->path to + * optimize for repeated checks for files in the same excluded directory. + */ +int path_excluded(struct path_exclude_check *check, + const char *name, int namelen, int *dtype) +{ + int i; + struct strbuf *path = &check->path; + + /* + * we allow the caller to pass namelen as an optimization; it + * must match the length of the name, as we eventually call + * excluded() on the whole name string. + */ + if (namelen < 0) + namelen = strlen(name); + + if (path->len && + path->len <= namelen && + !memcmp(name, path->buf, path->len) && + (!name[path->len] || name[path->len] == '/')) + return 1; + + strbuf_setlen(path, 0); + for (i = 0; name[i]; i++) { + int ch = name[i]; + + if (ch == '/') { + int dt = DT_DIR; + if (excluded(check->dir, path->buf, &dt)) + return 1; + } + strbuf_addch(path, ch); + } + + /* An entry in the index; cannot be a directory with subentries */ + strbuf_setlen(path, 0); + + return excluded(check->dir, name, dtype); +} + static struct dir_entry *dir_entry_new(const char *pathname, int len) { struct dir_entry *ent; @@ -1,6 +1,8 @@ #ifndef DIR_H #define DIR_H +#include "strbuf.h" + struct dir_entry { unsigned int len; char name[FLEX_ARRAY]; /* more */ @@ -76,8 +78,22 @@ extern int read_directory(struct dir_struct *, const char *path, int len, const extern int excluded_from_list(const char *pathname, int pathlen, const char *basename, int *dtype, struct exclude_list *el); -extern int excluded(struct dir_struct *, const char *, int *); struct dir_entry *dir_add_ignored(struct dir_struct *dir, const char *pathname, int len); + +/* + * The excluded() API is meant for callers that check each level of leading + * directory hierarchies with excluded() to avoid recursing into excluded + * directories. Callers that do not do so should use this API instead. + */ +struct path_exclude_check { + struct dir_struct *dir; + struct strbuf path; +}; +extern void path_exclude_check_init(struct path_exclude_check *, struct dir_struct *); +extern void path_exclude_check_clear(struct path_exclude_check *); +extern int path_excluded(struct path_exclude_check *, const char *, int namelen, int *dtype); + + extern int add_excludes_from_file_to_list(const char *fname, const char *base, int baselen, char **buf_p, struct exclude_list *which, int check_index); extern void add_excludes_from_file(struct dir_struct *, const char *fname); @@ -855,6 +855,11 @@ did you forget to use 'git add'?" if test $apply_status != 0 then eval_gettextln 'Patch failed at $msgnum $FIRSTLINE' + if test "$(git config --bool advice.amworkdir)" != false + then + eval_gettextln "The copy of the patch that failed is found in: + $dotest/patch" + fi stop_here_user_resolve $this fi diff --git a/git-filter-branch.sh b/git-filter-branch.sh index add2c0247f..178e45305d 100755 --- a/git-filter-branch.sh +++ b/git-filter-branch.sh @@ -84,7 +84,7 @@ set_ident () { s/.*/GIT_'$uid'_EMAIL='\''&'\''; export GIT_'$uid'_EMAIL/p g - s/^'$lid' [^<]* <[^>]*> \(.*\)$/\1/ + s/^'$lid' [^<]* <[^>]*> \(.*\)$/@\1/ s/'\''/'\''\'\'\''/g s/.*/GIT_'$uid'_DATE='\''&'\''; export GIT_'$uid'_DATE/p diff --git a/git-mergetool--lib.sh b/git-mergetool--lib.sh index ed630b208a..f730253c0e 100644 --- a/git-mergetool--lib.sh +++ b/git-mergetool--lib.sh @@ -111,7 +111,7 @@ run_merge_tool () { return $status } -guess_merge_tool () { +list_merge_tool_candidates () { if merge_mode then tools="tortoisemerge" @@ -136,6 +136,10 @@ guess_merge_tool () { tools="$tools emerge vimdiff" ;; esac +} + +guess_merge_tool () { + list_merge_tool_candidates echo >&2 "merge tool candidates: $tools" # Loop over each candidate and stop when a valid merge tool is found. diff --git a/git-mergetool.sh b/git-mergetool.sh index a9f23f7fcd..0db0c44845 100755 --- a/git-mergetool.sh +++ b/git-mergetool.sh @@ -8,7 +8,7 @@ # at the discretion of Junio C Hamano. # -USAGE='[--tool=tool] [-y|--no-prompt|--prompt] [file to merge] ...' +USAGE='[--tool=tool] [--tool-help] [-y|--no-prompt|--prompt] [file to merge] ...' SUBDIRECTORY_OK=Yes OPTIONS_SPEC= TOOL_MODE=merge @@ -284,11 +284,51 @@ merge_file () { return 0 } +show_tool_help () { + TOOL_MODE=merge + list_merge_tool_candidates + unavailable= available= LF=' +' + for i in $tools + do + merge_tool_path=$(translate_merge_tool_path "$i") + if type "$merge_tool_path" >/dev/null 2>&1 + then + available="$available$i$LF" + else + unavailable="$unavailable$i$LF" + fi + done + if test -n "$available" + then + echo "'git mergetool --tool=<tool>' may be set to one of the following:" + echo "$available" | sort | sed -e 's/^/ /' + else + echo "No suitable tool for 'git mergetool --tool=<tool>' found." + fi + if test -n "$unavailable" + then + echo + echo 'The following tools are valid, but not currently available:' + echo "$unavailable" | sort | sed -e 's/^/ /' + fi + if test -n "$unavailable$available" + then + echo + echo "Some of the tools listed above only work in a windowed" + echo "environment. If run in a terminal-only session, they will fail." + fi + exit 0 +} + prompt=$(git config --bool mergetool.prompt || echo true) while test $# != 0 do case "$1" in + --tool-help) + show_tool_help + ;; -t|--tool*) case "$#,$1" in *,*=*) diff --git a/git-request-pull.sh b/git-request-pull.sh index e6438e24c7..d566015975 100755 --- a/git-request-pull.sh +++ b/git-request-pull.sh @@ -57,9 +57,13 @@ headrev=$(git rev-parse --verify "$head"^0) || exit merge_base=$(git merge-base $baserev $headrev) || die "fatal: No commits in common between $base and $head" -# $head is the token given from the command line. If a ref with that -# name exists at the remote and their values match, we should use it. -# Otherwise find a ref that matches $headrev. +# $head is the token given from the command line, and $tag_name, if +# exists, is the tag we are going to show the commit information for. +# If that tag exists at the remote and it points at the commit, use it. +# Otherwise, if a branch with the same name as $head exists at the remote +# and their values match, use that instead. +# +# Otherwise find a random ref that matches $headrev. find_matching_ref=' sub abbr { my $ref = shift; @@ -70,24 +74,29 @@ find_matching_ref=' } } - my ($exact, $found); + my ($tagged, $branch, $found); while (<STDIN>) { my ($sha1, $ref, $deref) = /^(\S+)\s+(\S+?)(\^\{\})?$/; next unless ($sha1 eq $ARGV[1]); $found = abbr($ref); + if ($deref && $ref eq "tags/$ARGV[2]") { + $tagged = $found; + last; + } if ($ref =~ m|/\Q$ARGV[0]\E$|) { $exact = $found; - last; } } - if ($exact) { + if ($tagged) { + print "$tagged\n"; + } elsif ($exact) { print "$exact\n"; } elsif ($found) { print "$found\n"; } ' -ref=$(git ls-remote "$url" | perl -e "$find_matching_ref" "$head" "$headrev") +ref=$(git ls-remote "$url" | perl -e "$find_matching_ref" "$head" "$headrev" "$tag_name") url=$(git ls-remote --get-url "$url") @@ -114,6 +123,12 @@ fi && if test -n "$tag_name" then + if test -z "$ref" || test "$ref" != "tags/$tag_name" + then + echo >&2 "warn: You locally have $tag_name but it does not (yet)" + echo >&2 "warn: appear to be at $url" + echo >&2 "warn: Do you want to push it there, perhaps?" + fi git cat-file tag "$tag_name" | sed -n -e '1,/^$/d' -e '/^-----BEGIN PGP /q' -e p echo diff --git a/git-submodule.sh b/git-submodule.sh index fbf2fafaaf..30fa93a8a0 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -150,8 +150,10 @@ module_clone() die "$(eval_gettext "Clone of '\$url' into submodule path '\$sm_path' failed")" fi - a=$(cd "$gitdir" && pwd)/ - b=$(cd "$sm_path" && pwd)/ + # We already are at the root of the work tree but cd_to_toplevel will + # resolve any symlinks that might be present in $PWD + a=$(cd_to_toplevel && cd "$gitdir" && pwd)/ + b=$(cd_to_toplevel && cd "$sm_path" && pwd)/ # normalize Windows-style absolute paths to POSIX-style absolute paths case $a in [a-zA-Z]:/*) a=/${a%%:*}${a#*:} ;; esac case $b in [a-zA-Z]:/*) b=/${b%%:*}${b#*:} ;; esac diff --git a/read-cache.c b/read-cache.c index ef355cc9a8..b645827c06 100644 --- a/read-cache.c +++ b/read-cache.c @@ -397,10 +397,15 @@ int df_name_compare(const char *name1, int len1, int mode1, int cache_name_compare(const char *name1, int flags1, const char *name2, int flags2) { - int len1 = flags1 & CE_NAMEMASK; - int len2 = flags2 & CE_NAMEMASK; - int len = len1 < len2 ? len1 : len2; - int cmp; + 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; cmp = memcmp(name1, name2, len); if (cmp) @@ -1100,6 +1100,9 @@ static int match_explicit(struct ref *src, struct ref *dst, case 0: if (!memcmp(dst_value, "refs/", 5)) matched_dst = make_linked_ref(dst_value, dst_tail); + else if (is_null_sha1(matched_src->new_sha1)) + error("unable to delete '%s': remote ref does not exist", + dst_value); else if ((dst_guess = guess_ref(dst_value, matched_src))) matched_dst = make_linked_ref(dst_guess, dst_tail); else @@ -524,7 +524,7 @@ static int do_plain_rerere(struct string_list *rr, int fd) continue; hex = xstrdup(sha1_to_hex(sha1)); string_list_insert(rr, path)->util = hex; - if (mkdir(git_path("rr-cache/%s", hex), 0755)) + if (mkdir_in_gitdir(git_path("rr-cache/%s", hex))) continue; handle_file(path, NULL, rerere_path(hex, "preimage")); fprintf(stderr, "Recorded preimage for '%s'\n", path); diff --git a/revision.c b/revision.c index 935e7a7ba4..5b81a92e3a 100644 --- a/revision.c +++ b/revision.c @@ -1358,11 +1358,13 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg revs->topo_order = 1; } else if (!strcmp(arg, "--simplify-merges")) { revs->simplify_merges = 1; + revs->topo_order = 1; revs->rewrite_parents = 1; revs->simplify_history = 0; revs->limited = 1; } else if (!strcmp(arg, "--simplify-by-decoration")) { revs->simplify_merges = 1; + revs->topo_order = 1; revs->rewrite_parents = 1; revs->simplify_history = 0; revs->simplify_by_decoration = 1; @@ -1781,7 +1783,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s * but the latter we have checked in the main loop. */ for (j = i; j < argc; j++) - verify_filename(revs->prefix, argv[j]); + verify_filename(revs->prefix, argv[j], j == i); append_prune_data(&prune_data, argv + i); break; @@ -1947,8 +1949,9 @@ static struct commit_list **simplify_one(struct rev_info *revs, struct commit *c } /* - * Do we know what commit all of our parents should be rewritten to? - * Otherwise we are not ready to rewrite this one yet. + * Do we know what commit all of our parents that matter + * should be rewritten to? Otherwise we are not ready to + * rewrite this one yet. */ for (cnt = 0, p = commit->parents; p; p = p->next) { pst = locate_simplify_state(revs, p->item); @@ -1956,6 +1959,8 @@ static struct commit_list **simplify_one(struct rev_info *revs, struct commit *c tail = &commit_list_insert(p->item, tail)->next; cnt++; } + if (revs->first_parent_only) + break; } if (cnt) { tail = &commit_list_insert(commit, tail)->next; @@ -1968,8 +1973,13 @@ static struct commit_list **simplify_one(struct rev_info *revs, struct commit *c for (p = commit->parents; p; p = p->next) { pst = locate_simplify_state(revs, p->item); p->item = pst->simplified; + if (revs->first_parent_only) + break; } - cnt = remove_duplicate_parents(commit); + if (!revs->first_parent_only) + cnt = remove_duplicate_parents(commit); + else + cnt = 1; /* * It is possible that we are a merge and one side branch @@ -2013,25 +2023,31 @@ static struct commit_list **simplify_one(struct rev_info *revs, struct commit *c static void simplify_merges(struct rev_info *revs) { - struct commit_list *list; + struct commit_list *list, *next; struct commit_list *yet_to_do, **tail; + struct commit *commit; - if (!revs->topo_order) - sort_in_topological_order(&revs->commits, revs->lifo); if (!revs->prune) return; /* feed the list reversed */ yet_to_do = NULL; - for (list = revs->commits; list; list = list->next) - commit_list_insert(list->item, &yet_to_do); + for (list = revs->commits; list; list = next) { + commit = list->item; + next = list->next; + /* + * Do not free(list) here yet; the original list + * is used later in this function. + */ + commit_list_insert(commit, &yet_to_do); + } while (yet_to_do) { list = yet_to_do; yet_to_do = NULL; tail = &yet_to_do; while (list) { - struct commit *commit = list->item; - struct commit_list *next = list->next; + commit = list->item; + next = list->next; free(list); list = next; tail = simplify_one(revs, commit, tail); @@ -2043,9 +2059,10 @@ static void simplify_merges(struct rev_info *revs) revs->commits = NULL; tail = &revs->commits; while (list) { - struct commit *commit = list->item; - struct commit_list *next = list->next; struct merge_simplify_state *st; + + commit = list->item; + next = list->next; free(list); list = next; st = locate_simplify_state(revs, commit); @@ -4,7 +4,7 @@ static int inside_git_dir = -1; static int inside_work_tree = -1; -char *prefix_path(const char *prefix, int len, const char *path) +static char *prefix_path_gently(const char *prefix, int len, const char *path) { const char *orig = path; char *sanitized; @@ -31,7 +31,8 @@ char *prefix_path(const char *prefix, int len, const char *path) if (strncmp(sanitized, work_tree, len) || (len > root_len && sanitized[len] != '\0' && sanitized[len] != '/')) { error_out: - die("'%s' is outside repository", orig); + free(sanitized); + return NULL; } if (sanitized[len] == '/') len++; @@ -40,6 +41,25 @@ char *prefix_path(const char *prefix, int len, const char *path) return sanitized; } +char *prefix_path(const char *prefix, int len, const char *path) +{ + char *r = prefix_path_gently(prefix, len, path); + if (!r) + die("'%s' is outside repository", path); + return r; +} + +int path_inside_repo(const char *prefix, const char *path) +{ + int len = prefix ? strlen(prefix) : 0; + char *r = prefix_path_gently(prefix, len, path); + if (r) { + free(r); + return 1; + } + return 0; +} + int check_filename(const char *prefix, const char *arg) { const char *name; @@ -53,11 +73,17 @@ int check_filename(const char *prefix, const char *arg) die_errno("failed to stat '%s'", arg); } -static void NORETURN die_verify_filename(const char *prefix, const char *arg) +static void NORETURN die_verify_filename(const char *prefix, + const char *arg, + int diagnose_misspelt_rev) { unsigned char sha1[20]; unsigned mode; + if (!diagnose_misspelt_rev) + die("%s: no such path in the working tree.\n" + "Use '-- <path>...' to specify paths that do not exist locally.", + arg); /* * Saying "'(icase)foo' does not exist in the index" when the * user gave us ":(icase)foo" is just stupid. A magic pathspec @@ -80,14 +106,29 @@ static void NORETURN die_verify_filename(const char *prefix, const char *arg) * as true, because even if such a filename were to exist, we want * it to be preceded by the "--" marker (or we want the user to * use a format like "./-filename") + * + * The "diagnose_misspelt_rev" is used to provide a user-friendly + * diagnosis when dying upon finding that "name" is not a pathname. + * If set to 1, the diagnosis will try to diagnose "name" as an + * invalid object name (e.g. HEAD:foo). If set to 0, the diagnosis + * will only complain about an inexisting file. + * + * This function is typically called to check that a "file or rev" + * argument is unambiguous. In this case, the caller will want + * diagnose_misspelt_rev == 1 when verifying the first non-rev + * argument (which could have been a revision), and + * diagnose_misspelt_rev == 0 for the next ones (because we already + * saw a filename, there's not ambiguity anymore). */ -void verify_filename(const char *prefix, const char *arg) +void verify_filename(const char *prefix, + const char *arg, + int diagnose_misspelt_rev) { if (*arg == '-') die("bad flag '%s' used after filename", arg); if (check_filename(prefix, arg)) return; - die_verify_filename(prefix, arg); + die_verify_filename(prefix, arg, diagnose_misspelt_rev); } /* diff --git a/sha1_name.c b/sha1_name.c index c6331136d1..5d81ea0564 100644 --- a/sha1_name.c +++ b/sha1_name.c @@ -1127,7 +1127,7 @@ int get_sha1_with_context_1(const char *name, unsigned char *sha1, if (new_filename) filename = new_filename; ret = get_tree_entry(tree_sha1, filename, sha1, &oc->mode); - if (only_to_die) { + if (ret && only_to_die) { diagnose_invalid_sha1_path(prefix, filename, tree_sha1, object_name); free(object_name); @@ -307,6 +307,25 @@ Don't: Use test_done instead if you need to stop the tests early (see "Skipping tests" below). + - use '! git cmd' when you want to make sure the git command exits + with failure in a controlled way by calling "die()". Instead, + use 'test_must_fail git cmd'. This will signal a failure if git + dies in an unexpected way (e.g. segfault). + + - use perl without spelling it as "$PERL_PATH". This is to help our + friends on Windows where the platform Perl often adds CR before + the end of line, and they bundle Git with a version of Perl that + does not do so, whose path is specified with $PERL_PATH. + + - use sh without spelling it as "$SHELL_PATH", when the script can + be misinterpreted by broken platform shell (e.g. Solaris). + + - chdir around in tests. It is not sufficient to chdir to + somewhere and then chdir back to the original location later in + the test, as any intermediate step can fail and abort the test, + causing the next test to start in an unexpected directory. Do so + inside a subshell if necessary. + - Break the TAP output The raw output from your test may be interpreted by a TAP harness. TAP @@ -342,9 +361,9 @@ If you need to skip tests you should do so by using the three-arg form of the test_* functions (see the "Test harness library" section below), e.g.: - test_expect_success PERL 'I need Perl' " - '$PERL_PATH' -e 'hlagh() if unf_unf()' - " + test_expect_success PERL 'I need Perl' ' + "$PERL_PATH" -e "hlagh() if unf_unf()" + ' The advantage of skipping tests like this is that platforms that don't have the PERL and other optional dependencies get an indication of how diff --git a/t/t1010-mktree.sh b/t/t1010-mktree.sh index b946f87686..df573c4978 100755 --- a/t/t1010-mktree.sh +++ b/t/t1010-mktree.sh @@ -42,13 +42,13 @@ test_expect_success 'ls-tree piped to mktree (2)' ' ' test_expect_success 'ls-tree output in wrong order given to mktree (1)' ' - perl -e "print reverse <>" <top | + "$PERL_PATH" -e "print reverse <>" <top | git mktree >actual && test_cmp tree actual ' test_expect_success 'ls-tree output in wrong order given to mktree (2)' ' - perl -e "print reverse <>" <top.withsub | + "$PERL_PATH" -e "print reverse <>" <top.withsub | git mktree >actual && test_cmp tree.withsub actual ' diff --git a/t/t1100-commit-tree-options.sh b/t/t1100-commit-tree-options.sh index c4414ff576..a3b77239f4 100755 --- a/t/t1100-commit-tree-options.sh +++ b/t/t1100-commit-tree-options.sh @@ -7,6 +7,9 @@ test_description='git commit-tree options test This test checks that git commit-tree can create a specific commit object by defining all environment variables that it understands. + +Also make sure that command line parser understands the normal +"flags first and then non flag arguments" command line. ' . ./test-lib.sh @@ -42,4 +45,18 @@ test_expect_success \ 'compare commit' \ 'test_cmp expected commit' + +test_expect_success 'flags and then non flags' ' + echo comment text | + git commit-tree $(cat treeid) >commitid && + echo comment text | + git commit-tree $(cat treeid) -p $(cat commitid) >childid-1 && + echo comment text | + git commit-tree -p $(cat commitid) $(cat treeid) >childid-2 && + test_cmp childid-1 childid-2 && + git commit-tree $(cat treeid) -m foo >childid-3 && + git commit-tree -m foo $(cat treeid) >childid-4 && + test_cmp childid-3 childid-4 +' + test_done diff --git a/t/t1506-rev-parse-diagnosis.sh b/t/t1506-rev-parse-diagnosis.sh index 0843a1c13b..c5cb77a0e1 100755 --- a/t/t1506-rev-parse-diagnosis.sh +++ b/t/t1506-rev-parse-diagnosis.sh @@ -171,4 +171,15 @@ test_expect_success 'relative path when startup_info is NULL' ' grep "BUG: startup_info struct is not initialized." error ' +test_expect_success '<commit>:file correctly diagnosed after a pathname' ' + test_must_fail git rev-parse file.txt HEAD:file.txt 1>actual 2>error && + test_i18ngrep ! "exists on disk" error && + test_i18ngrep "no such path in the working tree" error && + cat >expect <<-\EOF && + file.txt + HEAD:file.txt + EOF + test_cmp expect actual +' + test_done diff --git a/t/t2017-checkout-orphan.sh b/t/t2017-checkout-orphan.sh index 0e3b8582f2..655f278c5f 100755 --- a/t/t2017-checkout-orphan.sh +++ b/t/t2017-checkout-orphan.sh @@ -116,4 +116,10 @@ test_expect_success '--orphan refuses to switch if a merge is needed' ' git reset --hard ' +test_expect_success 'cannot --detach on an unborn branch' ' + git checkout master && + git checkout --orphan new && + test_must_fail git checkout --detach +' + test_done diff --git a/t/t3006-ls-files-long.sh b/t/t3006-ls-files-long.sh new file mode 100755 index 0000000000..202ad658b8 --- /dev/null +++ b/t/t3006-ls-files-long.sh @@ -0,0 +1,39 @@ +#!/bin/sh + +test_description='overly long paths' +. ./test-lib.sh + +test_expect_success setup ' + p=filefilefilefilefilefilefilefile && + p=$p$p$p$p$p$p$p$p$p$p$p$p$p$p$p$p && + p=$p$p$p$p$p$p$p$p$p$p$p$p$p$p$p$p && + + path_a=${p}_a && + path_z=${p}_z && + + blob_a=$(echo frotz | git hash-object -w --stdin) && + blob_z=$(echo nitfol | git hash-object -w --stdin) && + + pat="100644 %s 0\t%s\n" +' + +test_expect_success 'overly-long path by itself is not a problem' ' + printf "$pat" "$blob_a" "$path_a" | + git update-index --add --index-info && + echo "$path_a" >expect && + git ls-files >actual && + test_cmp expect actual +' + +test_expect_success 'overly-long path does not replace another by mistake' ' + printf "$pat" "$blob_a" "$path_a" "$blob_z" "$path_z" | + git update-index --add --index-info && + ( + echo "$path_a" + echo "$path_z" + ) >expect && + git ls-files >actual && + test_cmp expect actual +' + +test_done diff --git a/t/t3300-funny-names.sh b/t/t3300-funny-names.sh index c53c9f65eb..1f35e55ee3 100755 --- a/t/t3300-funny-names.sh +++ b/t/t3300-funny-names.sh @@ -71,7 +71,7 @@ test_expect_success 'ls-files -z does not quote funny filename' ' tabs ," (dq) and spaces EOF git ls-files -z >ls-files.z && - perl -pe "y/\000/\012/" <ls-files.z >current && + "$PERL_PATH" -pe "y/\000/\012/" <ls-files.z >current && test_cmp expected current ' @@ -108,7 +108,7 @@ test_expect_success 'diff-index -z does not quote funny filename' ' tabs ," (dq) and spaces EOF git diff-index -z --name-status $t0 >diff-index.z && - perl -pe "y/\000/\012/" <diff-index.z >current && + "$PERL_PATH" -pe "y/\000/\012/" <diff-index.z >current && test_cmp expected current ' @@ -118,7 +118,7 @@ test_expect_success 'diff-tree -z does not quote funny filename' ' tabs ," (dq) and spaces EOF git diff-tree -z --name-status $t0 $t1 >diff-tree.z && - perl -pe y/\\000/\\012/ <diff-tree.z >current && + "$PERL_PATH" -pe y/\\000/\\012/ <diff-tree.z >current && test_cmp expected current ' diff --git a/t/t3401-rebase-partial.sh b/t/t3401-rebase-partial.sh index 7ba17974c5..7f8693b928 100755 --- a/t/t3401-rebase-partial.sh +++ b/t/t3401-rebase-partial.sh @@ -42,4 +42,12 @@ test_expect_success 'rebase --merge topic branch that was partially merged upstr test_path_is_missing .git/rebase-merge ' +test_expect_success 'rebase ignores empty commit' ' + git reset --hard A && + git commit --allow-empty -m empty && + test_commit D && + git rebase C && + test $(git log --format=%s C..) = "D" +' + test_done diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh index b473b6d6eb..959aa26ef5 100755 --- a/t/t4014-format-patch.sh +++ b/t/t4014-format-patch.sh @@ -243,7 +243,7 @@ check_threading () { (git format-patch --stdout "$@"; echo $? > status.out) | # Prints everything between the Message-ID and In-Reply-To, # and replaces all Message-ID-lookalikes by a sequence number - perl -ne ' + "$PERL_PATH" -ne ' if (/^(message-id|references|in-reply-to)/i) { $printing = 1; } elsif (/^\S/) { diff --git a/t/t4020-diff-external.sh b/t/t4020-diff-external.sh index 083f62d1d6..2e7d73f090 100755 --- a/t/t4020-diff-external.sh +++ b/t/t4020-diff-external.sh @@ -48,7 +48,53 @@ test_expect_success 'GIT_EXTERNAL_DIFF environment and --no-ext-diff' ' ' +test_expect_success SYMLINKS 'typechange diff' ' + rm -f file && + ln -s elif file && + GIT_EXTERNAL_DIFF=echo git diff | { + read path oldfile oldhex oldmode newfile newhex newmode && + test "z$path" = zfile && + test "z$oldmode" = z100644 && + test "z$newhex" = "z$_z40" && + test "z$newmode" = z120000 && + oh=$(git rev-parse --verify HEAD:file) && + test "z$oh" = "z$oldhex" + } && + GIT_EXTERNAL_DIFF=echo git diff --no-ext-diff >actual && + git diff >expect && + test_cmp expect actual +' + +test_expect_success 'diff.external' ' + git reset --hard && + echo third >file && + test_config diff.external echo && + git diff | { + read path oldfile oldhex oldmode newfile newhex newmode && + test "z$path" = zfile && + test "z$oldmode" = z100644 && + test "z$newhex" = "z$_z40" && + test "z$newmode" = z100644 && + oh=$(git rev-parse --verify HEAD:file) && + test "z$oh" = "z$oldhex" + } +' + +test_expect_success 'diff.external should apply only to diff' ' + test_config diff.external echo && + git log -p -1 HEAD | + grep "^diff --git a/file b/file" +' + +test_expect_success 'diff.external and --no-ext-diff' ' + test_config diff.external echo && + git diff --no-ext-diff | + grep "^diff --git a/file b/file" +' + test_expect_success 'diff attribute' ' + git reset --hard && + echo third >file && git config diff.parrot.command echo && @@ -113,12 +159,25 @@ test_expect_success 'diff attribute and --no-ext-diff' ' ' +test_expect_success 'GIT_EXTERNAL_DIFF trumps diff.external' ' + >.gitattributes && + test_config diff.external "echo ext-global" && + GIT_EXTERNAL_DIFF="echo ext-env" git diff | grep ext-env +' + +test_expect_success 'attributes trump GIT_EXTERNAL_DIFF and diff.external' ' + test_config diff.foo.command "echo ext-attribute" && + test_config diff.external "echo ext-global" && + echo "file diff=foo" >.gitattributes && + GIT_EXTERNAL_DIFF="echo ext-env" git diff | grep ext-attribute +' + test_expect_success 'no diff with -diff' ' echo >.gitattributes "file -diff" && git diff | grep Binary ' -echo NULZbetweenZwords | perl -pe 'y/Z/\000/' > file +echo NULZbetweenZwords | "$PERL_PATH" -pe 'y/Z/\000/' > file test_expect_success 'force diff with "diff"' ' echo >.gitattributes "file diff" && diff --git a/t/t4029-diff-trailing-space.sh b/t/t4029-diff-trailing-space.sh index 3ccc237a8d..36e2f075c9 100755 --- a/t/t4029-diff-trailing-space.sh +++ b/t/t4029-diff-trailing-space.sh @@ -27,7 +27,7 @@ test_expect_success \ git config --bool diff.suppressBlankEmpty true && git diff f > actual && test_cmp exp actual && - perl -i.bak -p -e "s/^\$/ /" exp && + "$PERL_PATH" -i.bak -p -e "s/^\$/ /" exp && git config --bool diff.suppressBlankEmpty false && git diff f > actual && test_cmp exp actual && diff --git a/t/t4030-diff-textconv.sh b/t/t4030-diff-textconv.sh index d4ab4f2ccf..eebb1eed8b 100755 --- a/t/t4030-diff-textconv.sh +++ b/t/t4030-diff-textconv.sh @@ -21,7 +21,7 @@ EOF cat >hexdump <<'EOF' #!/bin/sh -perl -e '$/ = undef; $_ = <>; s/./ord($&)/ge; print $_' < "$1" +"$PERL_PATH" -e '$/ = undef; $_ = <>; s/./ord($&)/ge; print $_' < "$1" EOF chmod +x hexdump diff --git a/t/t4031-diff-rewrite-binary.sh b/t/t4031-diff-rewrite-binary.sh index c8296fa4fc..eacc6694f7 100755 --- a/t/t4031-diff-rewrite-binary.sh +++ b/t/t4031-diff-rewrite-binary.sh @@ -60,7 +60,7 @@ test_expect_success 'diff --stat counts binary rewrite as 0 lines' ' { echo "#!$SHELL_PATH" cat <<'EOF' -perl -e '$/ = undef; $_ = <>; s/./ord($&)/ge; print $_' < "$1" +"$PERL_PATH" -e '$/ = undef; $_ = <>; s/./ord($&)/ge; print $_' < "$1" EOF } >dump chmod +x dump diff --git a/t/t4035-diff-quiet.sh b/t/t4035-diff-quiet.sh index cdb9202f57..231412d100 100755 --- a/t/t4035-diff-quiet.sh +++ b/t/t4035-diff-quiet.sh @@ -10,7 +10,22 @@ test_expect_success 'setup' ' git commit -m first && echo 2 >b && git add . && - git commit -a -m second + git commit -a -m second && + mkdir -p test-outside/repo && ( + cd test-outside/repo && + git init && + echo "1 1" >a && + git add . && + git commit -m 1 + ) && + mkdir -p test-outside/non/git && ( + cd test-outside/non/git && + echo "1 1" >a && + echo "1 1" >matching-file && + echo "1 1 " >trailing-space && + echo "1 1" >extra-space && + echo "2" >never-match + ) ' test_expect_success 'git diff-tree HEAD^ HEAD' ' @@ -77,4 +92,60 @@ test_expect_success 'git diff-index --cached HEAD' ' } ' +test_expect_success 'git diff, one file outside repo' ' + ( + cd test-outside/repo && + test_expect_code 0 git diff --quiet a ../non/git/matching-file && + test_expect_code 1 git diff --quiet a ../non/git/extra-space + ) +' + +test_expect_success 'git diff, both files outside repo' ' + ( + GIT_CEILING_DIRECTORIES="$TRASH_DIRECTORY/test-outside" && + export GIT_CEILING_DIRECTORIES && + cd test-outside/non/git && + test_expect_code 0 git diff --quiet a matching-file && + test_expect_code 1 git diff --quiet a extra-space + ) +' + +test_expect_success 'git diff --ignore-space-at-eol, one file outside repo' ' + ( + cd test-outside/repo && + test_expect_code 0 git diff --quiet --ignore-space-at-eol a ../non/git/trailing-space && + test_expect_code 1 git diff --quiet --ignore-space-at-eol a ../non/git/extra-space + ) +' + +test_expect_success 'git diff --ignore-space-at-eol, both files outside repo' ' + ( + GIT_CEILING_DIRECTORIES="$TRASH_DIRECTORY/test-outside" && + export GIT_CEILING_DIRECTORIES && + cd test-outside/non/git && + test_expect_code 0 git diff --quiet --ignore-space-at-eol a trailing-space && + test_expect_code 1 git diff --quiet --ignore-space-at-eol a extra-space + ) +' + +test_expect_success 'git diff --ignore-all-space, one file outside repo' ' + ( + cd test-outside/repo && + test_expect_code 0 git diff --quiet --ignore-all-space a ../non/git/trailing-space && + test_expect_code 0 git diff --quiet --ignore-all-space a ../non/git/extra-space && + test_expect_code 1 git diff --quiet --ignore-all-space a ../non/git/never-match + ) +' + +test_expect_success 'git diff --ignore-all-space, both files outside repo' ' + ( + GIT_CEILING_DIRECTORIES="$TRASH_DIRECTORY/test-outside" && + export GIT_CEILING_DIRECTORIES && + cd test-outside/non/git && + test_expect_code 0 git diff --quiet --ignore-all-space a trailing-space && + test_expect_code 0 git diff --quiet --ignore-all-space a extra-space && + test_expect_code 1 git diff --quiet --ignore-all-space a never-match + ) +' + test_done diff --git a/t/t4053-diff-no-index.sh b/t/t4053-diff-no-index.sh index 4dc8c67edc..979e98398b 100755 --- a/t/t4053-diff-no-index.sh +++ b/t/t4053-diff-no-index.sh @@ -8,7 +8,12 @@ test_expect_success 'setup' ' mkdir a && mkdir b && echo 1 >a/1 && - echo 2 >a/2 + echo 2 >a/2 && + git init repo && + echo 1 >repo/a && + mkdir -p non/git && + echo 1 >non/git/a && + echo 1 >non/git/b ' test_expect_success 'git diff --no-index directories' ' @@ -16,4 +21,12 @@ test_expect_success 'git diff --no-index directories' ' test $? = 1 && test_line_count = 14 cnt ' +test_expect_success 'git diff --no-index relative path outside repo' ' + ( + cd repo && + test_expect_code 0 git diff --no-index a ../non/git/a && + test_expect_code 0 git diff --no-index ../non/git/a ../non/git/b + ) +' + test_done diff --git a/t/t4103-apply-binary.sh b/t/t4103-apply-binary.sh index dbbf56cba9..99627bc6d6 100755 --- a/t/t4103-apply-binary.sh +++ b/t/t4103-apply-binary.sh @@ -25,10 +25,10 @@ test_expect_success 'setup' " git commit -m 'Initial Version' 2>/dev/null && git checkout -b binary && - perl -pe 'y/x/\000/' <file1 >file3 && + "$PERL_PATH" -pe 'y/x/\000/' <file1 >file3 && cat file3 >file4 && git add file2 && - perl -pe 'y/\000/v/' <file3 >file1 && + "$PERL_PATH" -pe 'y/\000/v/' <file3 >file1 && rm -f file2 && git update-index --add --remove file1 file2 file3 file4 && git commit -m 'Second Version' && diff --git a/t/t4116-apply-reverse.sh b/t/t4116-apply-reverse.sh index 2298ece801..fca815392e 100755 --- a/t/t4116-apply-reverse.sh +++ b/t/t4116-apply-reverse.sh @@ -12,14 +12,14 @@ test_description='git apply in reverse test_expect_success setup ' for i in a b c d e f g h i j k l m n; do echo $i; done >file1 && - perl -pe "y/ijk/\\000\\001\\002/" <file1 >file2 && + "$PERL_PATH" -pe "y/ijk/\\000\\001\\002/" <file1 >file2 && git add file1 file2 && git commit -m initial && git tag initial && for i in a b c g h i J K L m o n p q; do echo $i; done >file1 && - perl -pe "y/mon/\\000\\001\\002/" <file1 >file2 && + "$PERL_PATH" -pe "y/mon/\\000\\001\\002/" <file1 >file2 && git commit -a -m second && git tag second && diff --git a/t/t4200-rerere.sh b/t/t4200-rerere.sh index 36255d608a..3ab670d36a 100755 --- a/t/t4200-rerere.sh +++ b/t/t4200-rerere.sh @@ -78,7 +78,7 @@ test_expect_success 'activate rerere, old style (conflicting merge)' ' test_might_fail git config --unset rerere.enabled && test_must_fail git merge first && - sha1=$(perl -pe "s/ .*//" .git/MERGE_RR) && + sha1=$("$PERL_PATH" -pe "s/ .*//" .git/MERGE_RR) && rr=.git/rr-cache/$sha1 && grep "^=======\$" $rr/preimage && ! test -f $rr/postimage && @@ -91,7 +91,7 @@ test_expect_success 'rerere.enabled works, too' ' git reset --hard && test_must_fail git merge first && - sha1=$(perl -pe "s/ .*//" .git/MERGE_RR) && + sha1=$("$PERL_PATH" -pe "s/ .*//" .git/MERGE_RR) && rr=.git/rr-cache/$sha1 && grep ^=======$ $rr/preimage ' @@ -101,7 +101,7 @@ test_expect_success 'set up rr-cache' ' git config rerere.enabled true && git reset --hard && test_must_fail git merge first && - sha1=$(perl -pe "s/ .*//" .git/MERGE_RR) && + sha1=$("$PERL_PATH" -pe "s/ .*//" .git/MERGE_RR) && rr=.git/rr-cache/$sha1 ' @@ -185,7 +185,7 @@ test_expect_success 'rerere updates postimage timestamp' ' test_expect_success 'rerere clear' ' rm $rr/postimage && - echo "$sha1 a1" | perl -pe "y/\012/\000/" >.git/MERGE_RR && + echo "$sha1 a1" | "$PERL_PATH" -pe "y/\012/\000/" >.git/MERGE_RR && git rerere clear && ! test -d $rr ' diff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh index d9d856b87b..4fd69a19eb 100755 --- a/t/t5300-pack-object.sh +++ b/t/t5300-pack-object.sh @@ -13,9 +13,9 @@ TRASH=`pwd` test_expect_success \ 'setup' \ 'rm -f .git/index* && - perl -e "print \"a\" x 4096;" > a && - perl -e "print \"b\" x 4096;" > b && - perl -e "print \"c\" x 4096;" > c && + "$PERL_PATH" -e "print \"a\" x 4096;" > a && + "$PERL_PATH" -e "print \"b\" x 4096;" > b && + "$PERL_PATH" -e "print \"c\" x 4096;" > c && test-genrandom "seed a" 2097152 > a_big && test-genrandom "seed b" 2097152 > b_big && git update-index --add a a_big b b_big c && @@ -129,7 +129,7 @@ test_expect_success \ cd "$TRASH" test_expect_success 'compare delta flavors' ' - perl -e '\'' + "$PERL_PATH" -e '\'' defined($_ = -s $_) or die for @ARGV; exit 1 if $ARGV[0] <= $ARGV[1]; '\'' test-2-$packname_2.pack test-3-$packname_3.pack diff --git a/t/t5303-pack-corruption-resilience.sh b/t/t5303-pack-corruption-resilience.sh index 5f6cd4f333..5b1250f0d2 100755 --- a/t/t5303-pack-corruption-resilience.sh +++ b/t/t5303-pack-corruption-resilience.sh @@ -98,7 +98,7 @@ test_expect_success \ 'create_new_pack && git prune-packed && chmod +w ${pack}.pack && - perl -i.bak -pe "s/ base /abcdef/" ${pack}.pack && + "$PERL_PATH" -i.bak -pe "s/ base /abcdef/" ${pack}.pack && test_must_fail git cat-file blob $blob_1 > /dev/null && test_must_fail git cat-file blob $blob_2 > /dev/null && test_must_fail git cat-file blob $blob_3 > /dev/null' @@ -155,7 +155,7 @@ test_expect_success \ 'create_new_pack && git prune-packed && chmod +w ${pack}.pack && - perl -i.bak -pe "s/ delta1 /abcdefgh/" ${pack}.pack && + "$PERL_PATH" -i.bak -pe "s/ delta1 /abcdefgh/" ${pack}.pack && git cat-file blob $blob_1 > /dev/null && test_must_fail git cat-file blob $blob_2 > /dev/null && test_must_fail git cat-file blob $blob_3 > /dev/null' diff --git a/t/t5500-fetch-pack.sh b/t/t5500-fetch-pack.sh index 1d1ca98588..e80a2af348 100755 --- a/t/t5500-fetch-pack.sh +++ b/t/t5500-fetch-pack.sh @@ -125,6 +125,11 @@ test_expect_success 'single branch object count' ' test_cmp expected count.singlebranch ' +test_expect_success 'single given branch clone' ' + git clone --single-branch --branch A "file://$(pwd)/." branch-a && + test_must_fail git --git-dir=branch-a/.git rev-parse origin/B +' + test_expect_success 'clone shallow' ' git clone --no-single-branch --depth 2 "file://$(pwd)/." shallow ' @@ -276,7 +281,7 @@ test_expect_success 'clone shallow with --branch' ' ' test_expect_success 'clone shallow object count' ' - echo "in-pack: 12" > count3.expected && + echo "in-pack: 6" > count3.expected && GIT_DIR=shallow3/.git git count-objects -v | grep "^in-pack" > count3.actual && test_cmp count3.expected count3.actual diff --git a/t/t5532-fetch-proxy.sh b/t/t5532-fetch-proxy.sh index 62f2460047..5531bd1af4 100755 --- a/t/t5532-fetch-proxy.sh +++ b/t/t5532-fetch-proxy.sh @@ -15,7 +15,7 @@ test_expect_success 'setup remote repo' ' cat >proxy <<'EOF' #!/bin/sh echo >&2 "proxying for $*" -cmd=`perl -e ' +cmd=`"$PERL_PATH" -e ' read(STDIN, $buf, 4); my $n = hex($buf) - 4; read(STDIN, $buf, $n); diff --git a/t/t5551-http-fetch.sh b/t/t5551-http-fetch.sh index be6094be77..fadf2f258e 100755 --- a/t/t5551-http-fetch.sh +++ b/t/t5551-http-fetch.sh @@ -130,7 +130,7 @@ test_expect_success EXPENSIVE 'create 50,000 tags in the repo' ' done | git fast-import --export-marks=marks && # now assign tags to all the dangling commits we created above - tag=$(perl -e "print \"bla\" x 30") && + tag=$("$PERL_PATH" -e "print \"bla\" x 30") && sed -e "s/^:\(.\+\) \(.\+\)$/\2 refs\/tags\/$tag-\1/" <marks >>packed-refs ) ' diff --git a/t/t6011-rev-list-with-bad-commit.sh b/t/t6011-rev-list-with-bad-commit.sh index e51eb41f4b..bbb0581f88 100755 --- a/t/t6011-rev-list-with-bad-commit.sh +++ b/t/t6011-rev-list-with-bad-commit.sh @@ -37,7 +37,7 @@ test_expect_success 'verify number of revisions' \ test_expect_success 'corrupt second commit object' \ ' - perl -i.bak -pe "s/second commit/socond commit/" .git/objects/pack/*.pack && + "$PERL_PATH" -i.bak -pe "s/second commit/socond commit/" .git/objects/pack/*.pack && test_must_fail git fsck --full ' diff --git a/t/t6013-rev-list-reverse-parents.sh b/t/t6013-rev-list-reverse-parents.sh index 59fc2f06e0..892a537989 100755 --- a/t/t6013-rev-list-reverse-parents.sh +++ b/t/t6013-rev-list-reverse-parents.sh @@ -25,7 +25,7 @@ test_expect_success 'set up --reverse example' ' test_expect_success '--reverse --parents --full-history combines correctly' ' git rev-list --parents --full-history master -- foo | - perl -e "print reverse <>" > expected && + "$PERL_PATH" -e "print reverse <>" > expected && git rev-list --reverse --parents --full-history master -- foo \ > actual && test_cmp actual expected @@ -33,7 +33,7 @@ test_expect_success '--reverse --parents --full-history combines correctly' ' test_expect_success '--boundary does too' ' git rev-list --boundary --parents --full-history master ^root -- foo | - perl -e "print reverse <>" > expected && + "$PERL_PATH" -e "print reverse <>" > expected && git rev-list --boundary --reverse --parents --full-history \ master ^root -- foo > actual && test_cmp actual expected diff --git a/t/t7003-filter-branch.sh b/t/t7003-filter-branch.sh index e0227730de..4d13e10de1 100755 --- a/t/t7003-filter-branch.sh +++ b/t/t7003-filter-branch.sh @@ -5,7 +5,8 @@ test_description='git filter-branch' test_expect_success 'setup' ' test_commit A && - test_commit B && + GIT_COMMITTER_DATE="@0 +0000" GIT_AUTHOR_DATE="@0 +0000" && + test_commit --notick B && git checkout -b branch B && test_commit D && mkdir dir && diff --git a/t/t7007-show.sh b/t/t7007-show.sh index cce222f052..a40cd3630c 100755 --- a/t/t7007-show.sh +++ b/t/t7007-show.sh @@ -17,4 +17,95 @@ test_expect_success 'showing a tag that point at a missing object' ' test_must_fail git --no-pager show foo-tag ' +test_expect_success 'set up a bit of history' ' + test_commit main1 && + test_commit main2 && + test_commit main3 && + git tag -m "annotated tag" annotated && + git checkout -b side HEAD^^ && + test_commit side2 && + test_commit side3 +' + +test_expect_success 'showing two commits' ' + cat >expect <<-EOF && + commit $(git rev-parse main2) + commit $(git rev-parse main3) + EOF + git show main2 main3 >actual && + grep ^commit actual >actual.filtered && + test_cmp expect actual.filtered +' + +test_expect_success 'showing a range walks (linear)' ' + cat >expect <<-EOF && + commit $(git rev-parse main3) + commit $(git rev-parse main2) + EOF + git show main1..main3 >actual && + grep ^commit actual >actual.filtered && + test_cmp expect actual.filtered +' + +test_expect_success 'showing a range walks (Y shape, ^ first)' ' + cat >expect <<-EOF && + commit $(git rev-parse main3) + commit $(git rev-parse main2) + EOF + git show ^side3 main3 >actual && + grep ^commit actual >actual.filtered && + test_cmp expect actual.filtered +' + +test_expect_success 'showing a range walks (Y shape, ^ last)' ' + cat >expect <<-EOF && + commit $(git rev-parse main3) + commit $(git rev-parse main2) + EOF + git show main3 ^side3 >actual && + grep ^commit actual >actual.filtered && + test_cmp expect actual.filtered +' + +test_expect_success 'showing with -N walks' ' + cat >expect <<-EOF && + commit $(git rev-parse main3) + commit $(git rev-parse main2) + EOF + git show -2 main3 >actual && + grep ^commit actual >actual.filtered && + test_cmp expect actual.filtered +' + +test_expect_success 'showing annotated tag' ' + cat >expect <<-EOF && + tag annotated + commit $(git rev-parse annotated^{commit}) + EOF + git show annotated >actual && + grep -E "^(commit|tag)" actual >actual.filtered && + test_cmp expect actual.filtered +' + +test_expect_success 'showing annotated tag plus commit' ' + cat >expect <<-EOF && + tag annotated + commit $(git rev-parse annotated^{commit}) + commit $(git rev-parse side3) + EOF + git show annotated side3 >actual && + grep -E "^(commit|tag)" actual >actual.filtered && + test_cmp expect actual.filtered +' + +test_expect_success 'showing range' ' + cat >expect <<-EOF && + commit $(git rev-parse main3) + commit $(git rev-parse main2) + EOF + git show ^side3 annotated >actual && + grep -E "^(commit|tag)" actual >actual.filtered && + test_cmp expect actual.filtered +' + test_done diff --git a/t/t7406-submodule-update.sh b/t/t7406-submodule-update.sh index dcb195b4cf..ce61d4c0fa 100755 --- a/t/t7406-submodule-update.sh +++ b/t/t7406-submodule-update.sh @@ -636,4 +636,17 @@ test_expect_success 'submodule update properly revives a moved submodule' ' ) ' +test_expect_success SYMLINKS 'submodule update can handle symbolic links in pwd' ' + mkdir -p linked/dir && + ln -s linked/dir linkto && + ( + cd linkto && + git clone "$TRASH_DIRECTORY"/super_update_r2 super && + ( + cd super && + git submodule update --init --recursive + ) + ) +' + test_done diff --git a/t/t7501-commit.sh b/t/t7501-commit.sh index b20ca0eace..195e7477d8 100755 --- a/t/t7501-commit.sh +++ b/t/t7501-commit.sh @@ -108,6 +108,16 @@ test_expect_success 'amend commit' ' EDITOR=./editor git commit --amend ' +test_expect_success 'amend --only ignores staged contents' ' + cp file file.expect && + echo changed >file && + git add file && + git commit --no-edit --amend --only && + git cat-file blob HEAD:file >file.actual && + test_cmp file.expect file.actual && + git diff --exit-code +' + test_expect_success 'set up editor' ' cat >editor <<-\EOF && #!/bin/sh @@ -138,6 +148,21 @@ test_expect_success '--amend --edit' ' test_cmp expect msg ' +test_expect_success '--amend --edit of empty message' ' + cat >replace <<-\EOF && + #!/bin/sh + echo "amended" >"$1" + EOF + chmod 755 replace && + git commit --allow-empty --allow-empty-message -m "" && + echo more bongo >file && + git add file && + EDITOR=./replace git commit --edit --amend && + git diff-tree -s --format=%s HEAD >msg && + ./replace expect && + test_cmp expect msg +' + test_expect_success '-m --edit' ' echo amended >expect && git commit --allow-empty -m buffer && @@ -487,4 +512,16 @@ test_expect_success 'amend can copy notes' ' ' +test_expect_success 'commit a file whose name is a dash' ' + git reset --hard && + for i in 1 2 3 4 5 + do + echo $i + done >./- && + git add ./- && + test_tick && + git commit -m "add dash" >output </dev/null && + test_i18ngrep " changed, 5 insertions" output +' + test_done diff --git a/t/t7508-status.sh b/t/t7508-status.sh index 28e184829c..c206f4777a 100755 --- a/t/t7508-status.sh +++ b/t/t7508-status.sh @@ -941,7 +941,7 @@ test_expect_success 'status -s submodule summary (clean submodule)' ' test_expect_success 'status -z implies porcelain' ' git status --porcelain | - perl -pe "s/\012/\000/g" >expect && + "$PERL_PATH" -pe "s/\012/\000/g" >expect && git status -z >output && test_cmp expect output ' diff --git a/t/t8006-blame-textconv.sh b/t/t8006-blame-textconv.sh index c3c22f7764..bf6caa4dc3 100755 --- a/t/t8006-blame-textconv.sh +++ b/t/t8006-blame-textconv.sh @@ -10,7 +10,7 @@ find_blame() { cat >helper <<'EOF' #!/bin/sh grep -q '^bin: ' "$1" || { echo "E: $1 is not \"binary\" file" 1>&2; exit 1; } -perl -p -e 's/^bin: /converted: /' "$1" +"$PERL_PATH" -p -e 's/^bin: /converted: /' "$1" EOF chmod +x helper diff --git a/t/t9129-git-svn-i18n-commitencoding.sh b/t/t9129-git-svn-i18n-commitencoding.sh index 8cfdfe790f..9a40f1e199 100755 --- a/t/t9129-git-svn-i18n-commitencoding.sh +++ b/t/t9129-git-svn-i18n-commitencoding.sh @@ -29,7 +29,7 @@ fi compare_svn_head_with () { # extract just the log message and strip out committer info. # don't use --limit here since svn 1.1.x doesn't have it, - LC_ALL="$a_utf8_locale" svn log `git svn info --url` | perl -w -e ' + LC_ALL="$a_utf8_locale" svn log `git svn info --url` | "$PERL_PATH" -w -e ' use bytes; $/ = ("-"x72) . "\n"; my @x = <STDIN>; diff --git a/t/t9137-git-svn-dcommit-clobber-series.sh b/t/t9137-git-svn-dcommit-clobber-series.sh index d60da63f7a..c17aa3186f 100755 --- a/t/t9137-git-svn-dcommit-clobber-series.sh +++ b/t/t9137-git-svn-dcommit-clobber-series.sh @@ -20,8 +20,8 @@ test_expect_success '(supposedly) non-conflicting change from SVN' ' test x"`sed -n -e 61p < file`" = x61 && svn_cmd co "$svnrepo" tmp && (cd tmp && - perl -i.bak -p -e "s/^58$/5588/" file && - perl -i.bak -p -e "s/^61$/6611/" file && + "$PERL_PATH" -i.bak -p -e "s/^58$/5588/" file && + "$PERL_PATH" -i.bak -p -e "s/^61$/6611/" file && poke file && test x"`sed -n -e 58p < file`" = x5588 && test x"`sed -n -e 61p < file`" = x6611 && @@ -40,8 +40,8 @@ test_expect_success 'some unrelated changes to git' " test_expect_success 'change file but in unrelated area' " test x\"\`sed -n -e 4p < file\`\" = x4 && test x\"\`sed -n -e 7p < file\`\" = x7 && - perl -i.bak -p -e 's/^4\$/4444/' file && - perl -i.bak -p -e 's/^7\$/7777/' file && + "$PERL_PATH" -i.bak -p -e 's/^4\$/4444/' file && + "$PERL_PATH" -i.bak -p -e 's/^7\$/7777/' file && test x\"\`sed -n -e 4p < file\`\" = x4444 && test x\"\`sed -n -e 7p < file\`\" = x7777 && git commit -m '4 => 4444, 7 => 7777' file && diff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh index c17f52e586..2fcf269469 100755 --- a/t/t9300-fast-import.sh +++ b/t/t9300-fast-import.sh @@ -12,7 +12,7 @@ test_description='test git fast-import utility' # This could be written as "head -c $1", but IRIX "head" does not # support the -c option. head_c () { - perl -e ' + "$PERL_PATH" -e ' my $len = $ARGV[1]; while ($len > 0) { my $s; diff --git a/t/t9350-fast-export.sh b/t/t9350-fast-export.sh index b00196bd23..3e821f958b 100755 --- a/t/t9350-fast-export.sh +++ b/t/t9350-fast-export.sh @@ -424,13 +424,13 @@ test_expect_success 'fast-export quotes pathnames' ' --cacheinfo 100644 $blob "path with \\backslash" \ --cacheinfo 100644 $blob "path with space" && git commit -m addition && - git ls-files -z -s | perl -0pe "s{\\t}{$&subdir/}" >index && + git ls-files -z -s | "$PERL_PATH" -0pe "s{\\t}{$&subdir/}" >index && git read-tree --empty && git update-index -z --index-info <index && git commit -m rename && git read-tree --empty && git commit -m deletion && - git fast-export HEAD >export.out && + git fast-export -M HEAD >export.out && git rev-list HEAD >expect && git init result && cd result && diff --git a/t/t9810-git-p4-rcs.sh b/t/t9810-git-p4-rcs.sh index d8d9ca4679..b00ad09d23 100755 --- a/t/t9810-git-p4-rcs.sh +++ b/t/t9810-git-p4-rcs.sh @@ -246,7 +246,7 @@ test_expect_success 'cope with rcs keyword expansion damage' ' git config git-p4.attemptRCSCleanup true && (cd ../cli && p4_append_to_file kwfile1.c) && old_lines=$(wc -l <kwfile1.c) && - perl -n -i -e "print unless m/Revision:/" kwfile1.c && + "$PERL_PATH" -n -i -e "print unless m/Revision:/" kwfile1.c && new_lines=$(wc -l <kwfile1.c) && test $new_lines = $(($old_lines - 1)) && diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh index 7b3b4bef30..80daaca780 100644 --- a/t/test-lib-functions.sh +++ b/t/test-lib-functions.sh @@ -76,11 +76,11 @@ test_decode_color () { } nul_to_q () { - perl -pe 'y/\000/Q/' + "$PERL_PATH" -pe 'y/\000/Q/' } q_to_nul () { - perl -pe 'y/Q/\000/' + "$PERL_PATH" -pe 'y/Q/\000/' } q_to_cr () { @@ -143,10 +143,19 @@ test_pause () { # Both <file> and <contents> default to <message>. test_commit () { - file=${2:-"$1.t"} + notick= && + if test "z$1" = "z--notick" + then + notick=yes + shift + fi && + file=${2:-"$1.t"} && echo "${3-$1}" > "$file" && git add "$file" && - test_tick && + if test -z "$notick" + then + test_tick + fi && git commit -m "$1" && git tag "$1" } diff --git a/t/test-lib.sh b/t/test-lib.sh index 9e2b71132a..acda33d177 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -494,6 +494,8 @@ export PATH GIT_EXEC_PATH GIT_TEMPLATE_DIR GIT_CONFIG_NOSYSTEM GIT_ATTR_NOSYSTEM . "$GIT_BUILD_DIR"/GIT-BUILD-OPTIONS +export PERL_PATH + if test -z "$GIT_TEST_CMP" then if test -n "$GIT_TEST_CMP_USE_COPIED_CONTEXT" diff --git a/unpack-trees.c b/unpack-trees.c index ad40109432..33a581924e 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -1023,6 +1023,10 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options o->el = ⪙ } + if (o->dir) { + o->path_exclude_check = xmalloc(sizeof(struct path_exclude_check)); + path_exclude_check_init(o->path_exclude_check, o->dir); + } memset(&o->result, 0, sizeof(o->result)); o->result.initialized = 1; o->result.timestamp.sec = o->src_index->timestamp.sec; @@ -1148,6 +1152,10 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options done: free_excludes(&el); + if (o->path_exclude_check) { + path_exclude_check_clear(o->path_exclude_check); + free(o->path_exclude_check); + } return ret; return_failed: @@ -1363,7 +1371,8 @@ static int check_ok_to_remove(const char *name, int len, int dtype, if (ignore_case && icase_exists(o, name, len, st)) return 0; - if (o->dir && excluded(o->dir, name, &dtype)) + if (o->dir && + path_excluded(o->path_exclude_check, name, -1, &dtype)) /* * ce->name is explicitly excluded, so it is Ok to * overwrite it. diff --git a/unpack-trees.h b/unpack-trees.h index 5e432f576e..ec74a9f19a 100644 --- a/unpack-trees.h +++ b/unpack-trees.h @@ -52,6 +52,7 @@ struct unpack_trees_options { const char *prefix; int cache_bottom; struct dir_struct *dir; + struct path_exclude_check *path_exclude_check; struct pathspec *pathspec; merge_fn_t fn; const char *msgs[NB_UNPACK_TREES_ERROR_TYPES]; |