Merge branch 'mh/maint-revisions-doc' into maint
authorJunio C Hamano <gitster@pobox.com>
Mon, 6 Aug 2012 22:30:57 +0000 (15:30 -0700)
committerJunio C Hamano <gitster@pobox.com>
Mon, 6 Aug 2012 22:30:57 +0000 (15:30 -0700)
* mh/maint-revisions-doc:
Enumerate revision range specifiers in the documentation
Make <refname> documentation more consistent.

91 files changed:
Documentation/RelNotes/1.7.11.2.txt [new file with mode: 0644]
Documentation/RelNotes/1.7.11.3.txt [new file with mode: 0644]
Documentation/RelNotes/1.7.11.4.txt [new file with mode: 0644]
Documentation/config.txt
Documentation/git-cherry-pick.txt
Documentation/git-commit-tree.txt
Documentation/git-commit.txt
Documentation/git-mergetool.txt
Documentation/git.txt
Documentation/rev-list-options.txt
GIT-VERSION-GEN
Makefile
RelNotes
advice.c
archive-tar.c
builtin.h
builtin/add.c
builtin/blame.c
builtin/checkout.c
builtin/clone.c
builtin/commit-tree.c
builtin/commit.c
builtin/diff.c
builtin/fast-export.c
builtin/grep.c
builtin/index-pack.c
builtin/log.c
builtin/ls-files.c
builtin/reset.c
builtin/rev-parse.c
builtin/update-index.c
bundle.c
cache.h
date.c
diff-no-index.c
diff.c
diffcore.h
dir.c
dir.h
git-am.sh
git-filter-branch.sh
git-mergetool--lib.sh
git-mergetool.sh
git-request-pull.sh
git-submodule.sh
read-cache.c
remote.c
rerere.c
revision.c
setup.c
sha1_name.c
t/README
t/t1010-mktree.sh
t/t1100-commit-tree-options.sh
t/t1506-rev-parse-diagnosis.sh
t/t2017-checkout-orphan.sh
t/t3006-ls-files-long.sh [new file with mode: 0755]
t/t3300-funny-names.sh
t/t3401-rebase-partial.sh
t/t4014-format-patch.sh
t/t4020-diff-external.sh
t/t4029-diff-trailing-space.sh
t/t4030-diff-textconv.sh
t/t4031-diff-rewrite-binary.sh
t/t4035-diff-quiet.sh
t/t4053-diff-no-index.sh
t/t4103-apply-binary.sh
t/t4116-apply-reverse.sh
t/t4200-rerere.sh
t/t5300-pack-object.sh
t/t5303-pack-corruption-resilience.sh
t/t5500-fetch-pack.sh
t/t5532-fetch-proxy.sh
t/t5551-http-fetch.sh
t/t6011-rev-list-with-bad-commit.sh
t/t6013-rev-list-reverse-parents.sh
t/t7003-filter-branch.sh
t/t7007-show.sh
t/t7406-submodule-update.sh
t/t7501-commit.sh
t/t7508-status.sh
t/t8006-blame-textconv.sh
t/t9129-git-svn-i18n-commitencoding.sh
t/t9137-git-svn-dcommit-clobber-series.sh
t/t9300-fast-import.sh
t/t9350-fast-export.sh
t/t9810-git-p4-rcs.sh
t/test-lib-functions.sh
t/test-lib.sh
unpack-trees.c
unpack-trees.h
diff --git a/Documentation/RelNotes/1.7.11.2.txt b/Documentation/RelNotes/1.7.11.2.txt
new file mode 100644 (file)
index 0000000..a0d24d1
--- /dev/null
@@ -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 (file)
index 0000000..64494f8
--- /dev/null
@@ -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 (file)
index 0000000..3a640c2
--- /dev/null
@@ -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.
index 915cb5a547896966377e9f39059527e3142b27c8..b49feb582ef6c780a9dd1831bcd7e013e774b7c6 100644 (file)
@@ -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::
index 9f3dae631e5437662e9fb3583b24f414c93bb140..0e170a51cac1de3f20b31f8dba7f832c292b815c 100644 (file)
@@ -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
index ff73286509782bf3c7d6168066358b02830db797..6d5a04c83b6461396b44b3972a539eaae6368a19 100644 (file)
@@ -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
 -----------
index 2d695f619ceff358a3bc7c1e66532cc077ca3065..81853e9646dbe657e89e353785c4beda01c545b3 100644 (file)
@@ -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
 --------
index 2a49de7cfe5188b531bc02f1115e253bfa10e0e0..d7207bd9b9bba59a0e1f97341fb77927026e1b52 100644 (file)
@@ -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
index d58fad71bd861ef6f3c342f20619ce72b99b16bd..7af8aaa0478239ec14446854bcb52adbd73fc2cf 100644 (file)
@@ -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].
 
index 1ae3c899ef4bb6d37bc5cbcb25ed927011378d90..84e34b1abaf23ef87fcccd21b0500fd21c5a1912 100644 (file)
@@ -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::
 
index a7570decfb6f5331f7dc2e2e1fb29f5d1151489d..a9dea5c023d8b0d98ba877ab0f0a1caed4b3505a 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 GVF=GIT-VERSION-FILE
-DEF_VER=v1.7.11.1
+DEF_VER=v1.7.11.4
 
 LF='
 '
index 4592f1f2ee82a656c9dfd2fcf9132e4fd132bc67..67d761e83adad8e3332b22fbe753e0cdb81b1a83 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -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
index ceedb902ca9fb8c9ee58b7c06348eaf767f715bc..9f0b313a19f38194dad3995cced06e21d103aec7 120000 (symlink)
--- a/RelNotes
+++ b/RelNotes
@@ -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
index a492eea24f71ad2d2082efce9d1d925a5766b111..edfbd4a6fb01a6905671d6d842d22c4869fad729 100644 (file)
--- a/advice.c
+++ b/advice.c
@@ -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) {
index dc91c6b50d56ad8fd9921d0e47f5b45cafdcfc4d..0ba3f25cf579d6629566a39d4d5ac19b51293ed5 100644 (file)
@@ -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;
 }
index 338f540e39af7093b39668a3bed16158a4483566..e426de3ff7148e03dfe76665bd0b7bc3f94d1227 100644 (file)
--- a/builtin.h
+++ b/builtin.h
@@ -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);
 
index b79336d712b4c71cc2f026b0e9f42ea0bcebfc6f..89dce56a240d69ccb224590bf134c9656d8a0522 100644 (file)
@@ -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();
index 24d3dd52920542b993d4945ccb2642a74da5f759..960c58d855a6f1a04ad1d08637fc75c3da240a30 100644 (file)
@@ -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);
index e8c1b1f189f077529ef2a79accb46ef21a9b8fe7..3980d5d06ea5aba4f4d6d30089307fe76c8adff9 100644 (file)
@@ -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);
index a4d8d25ee319c2bbcfe5b450468cfb41d3fcd0d6..920ef7f8c9fff25f613b4261f215a0cb7dc83b61 100644 (file)
@@ -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);
index 164b655df93fea1ec2f63f5238c1ad7a377c8385..a0df12ce16abda416fc9f33448bc895e74f4b0d1 100644 (file)
@@ -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")) {
index f43eaafb3b0afc1fb2dcc994433a6ad3be725654..95eeab1d5146628277b0ba2c4e4bc7a6f77f3a4a 100644 (file)
@@ -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";
index 9069dc41be33a362ff04d52c00b4830eed272826..da8f6aac2bde9bb93cb059898a21c19c9bb27634 100644 (file)
@@ -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();
+}
index ef7c0120949c4ce1667c9d1d8e74a9c63c8adc02..9ab6db3fb042d0cb7ee3a1919788b9a6cd26a3d6 100644 (file)
@@ -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);
 }
index fe1726f5ef60d054938eaa849f2ae6020a95f805..29adb0ac9399002b07942711863fa3b353926468 100644 (file)
@@ -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);
index dc2cfe6e6f63b6628f8a358f2f3b3e65c14e3b8d..470547835ca41888817b85dc4b7ed39273ede784 100644 (file)
@@ -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
 
index 906dca475af0ed51d499cce4a7c0a34f038c5810..54f24e2088651b70fadb6996f9558989b19d723f 100644 (file)
@@ -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++) {
index 7cff175745d680d9cde24280e569b4f513d28673..31b3f2d9006e0f5703ca9fb37bea247012581c0e 100644 (file)
@@ -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);
 }
 
 /*
index 8c2c1d52a227334a3d6456bf0989cd561628ffa0..4cc34c908446fe2d3db5acf315e47f2768ba07bd 100644 (file)
@@ -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);
                }
        }
 
index 733f626f6c3e4ef54d54df923230f7ae4fbb2d7d..13495b88f5da1efc2094c0e69abfe93605ee8c03 100644 (file)
@@ -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) {
index 5f038d64da38820ebaa73ff73d1082e17c3c80d2..5a4e9ea55a10afe2eb0f6e138cb7fce1ef74393f 100644 (file)
@@ -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);
 }
 
index 8d31b98f58b9e9bf156615130ec80684f788fcaa..8d12816b9d0bc682ed9c019a7a5d5cec4b859171 100644 (file)
--- a/bundle.c
+++ b/bundle.c
@@ -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;
 }
diff --git a/cache.h b/cache.h
index 06413e1584dc762063feaa3728209a4d2864ebc7..89581041ce82603ae82866f8f8a5c01b4f7f6d0d 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -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
 
diff --git a/date.c b/date.c
index 1fdcf7c6eae0386552c5d7e069f5242fca3c2e0e..57331ed406e2391e0a2bf327fbb86d3b62012324 100644 (file)
--- a/date.c
+++ b/date.c
@@ -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] != '-'))
index f0b0010aedd67f9b34f43426c47e837dfe2a522b..7d805a06afacae7eaa36a192e3a16406ef0fb41f 100644 (file)
@@ -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));
 }
diff --git a/diff.c b/diff.c
index 1a594df4f45bf0bc8409e871535f7ebd34684c6c..62cbe141efb411e831484fc36c0cba95a2b8846b 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -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);
index 8f32b824cdc1bac1f094d743f3bee9f32890edca..be0739c5c401c059a0d3030acbc99a7744f17065 100644 (file)
@@ -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 */
diff --git a/dir.c b/dir.c
index ed1510fbc808f4c9799eb84a3c38030b7565f3bc..2c02b312b77f3363c234bdc66faaeafd5899586d 100644 (file)
--- a/dir.c
+++ b/dir.c
@@ -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;
diff --git a/dir.h b/dir.h
index 58b6fc7c86df1bd5ac6f072672027a1474732ac6..6c73e4151de8374d35427358cde50b506a2d7de9 100644 (file)
--- a/dir.h
+++ b/dir.h
@@ -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);
index f8b7a0cb602d2d2425f68f8c27338cc003b70f6b..9abad36abdea89c88d7d0378fd2d556057bc065b 100755 (executable)
--- a/git-am.sh
+++ b/git-am.sh
@@ -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
 
index add2c0247fa91e0f629428c295fc581f19cf85e1..178e45305d2b66bbe5a0c0902d989ea66888869b 100755 (executable)
@@ -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
 
index ed630b208a80a36d729b5074a39bc53df0cabd59..f730253c0eac181ec8507d2c837d4ec85a0ae991 100644 (file)
@@ -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.
index a9f23f7fcdff610f2b206bc121db7c9217bbf0c7..0db0c44845f54920e26d97391f577e76305ecc56 100755 (executable)
@@ -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
                *,*=*)
index e6438e24c7c787b55428a48eca9461d772db7ee6..d566015975d317683c89bfcfde93ae998efd1058 100755 (executable)
@@ -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
index fbf2fafaaf49ec65090ec4eadb33d1ccedc60436..30fa93a8a0a4985f7ce980d4abf69410af22976c 100755 (executable)
@@ -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
index ef355cc9a89b948688756b8c3681ac607518492b..b645827c06a268ee4721fda5fc8cdcd84775c9ec 100644 (file)
@@ -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)
index 6833538829e1d3e5fe4a525a1b44cbebd9f96efb..04fd9ea4bd2f99003c9c5abb7bbbad7dafca3937 100644 (file)
--- a/remote.c
+++ b/remote.c
@@ -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
index dcb525a4d03faeba53d108d2e175a6d04f99d160..651c5def92e3f864a99ed7e97d008aa04cce3782 100644 (file)
--- a/rerere.c
+++ b/rerere.c
@@ -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);
index 935e7a7ba413668c95a6c3e846b9058be07f0425..5b81a92e3ac65ab0295f25198511fc83b4bbf1c9 100644 (file)
@@ -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);
diff --git a/setup.c b/setup.c
index 731851a4a85161af49a38c481672615a6ac0bbc9..e11497720e01dd14a66e152883e675669fc3b548 100644 (file)
--- a/setup.c
+++ b/setup.c
@@ -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);
 }
 
 /*
index c6331136d19c5224078fa78b6e5e794fcc587fe2..5d81ea0564c8d90b417eb8ec5ed8c32baa2c3ea3 100644 (file)
@@ -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);
index 3534f43d016ae56fdd20a824cf76e2b63339d66d..4c3ea25e6649007c9dde7ae4570d6311824051b6 100644 (file)
--- a/t/README
+++ b/t/README
@@ -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
index b946f8768649dd76d8a175877c63d49244e00ffb..df573c4978c9d6b665b56eeae7bc9997c7df4207 100755 (executable)
@@ -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
 '
index c4414ff576fc03b3234c532bfdcd0f2c8eca9c09..a3b77239f48ade053c3514c9ba65cd72286d0783 100755 (executable)
@@ -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
index 0843a1c13b3e1458418ee59c548e5441f113bbe7..c5cb77a0e1f34ac46dd8727341948389624e8f38 100755 (executable)
@@ -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
index 0e3b8582f2a3edebb0d9eea7fcebaa88f305fd73..655f278c5f87926311979732eb6c129a14dd87d3 100755 (executable)
@@ -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 (executable)
index 0000000..202ad65
--- /dev/null
@@ -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
index c53c9f65ebd2824d4a0d528b25d85e1e0b26f4df..1f35e55ee3be1b2bbdb8aa9f3248f6fe5ebf46cb 100755 (executable)
@@ -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
 '
 
index 7ba17974c585d005fb4f1c757b76377f0c0518a5..7f8693b928fdb827906f7c51ec0a13b2f36c5b83 100755 (executable)
@@ -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
index b473b6d6ebbf75f77be99085c26b68781b7f5fc6..959aa26ef5d96f4be79e6051fb6ae159e03b556e 100755 (executable)
@@ -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/) {
index 083f62d1d6bb6bfd908b0a03db1a47f80071ef91..2e7d73f0906e6a2808706236328470b2d855e9f9 100755 (executable)
@@ -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" &&
index 3ccc237a8d4443bfc8763fbb9cb51033f846b0e8..36e2f075c9f94286a05474b58e7600f2a9de2f20 100755 (executable)
@@ -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 &&
index d4ab4f2ccf9a1bbbc1e6af84df5f09c373f9f465..eebb1eed8b1e084ddc048dc20797dfcd2f37e3ea 100755 (executable)
@@ -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
 
index c8296fa4fc1fbfe2645554d4818ae586d1cc2a14..eacc6694f785acb2e6287dd4c5bce9a5e834a361 100755 (executable)
@@ -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
index cdb9202f57ea75983cf8a25f892bbf868724250d..231412d1008e45e1d788660930cab708d3912ed4 100755 (executable)
@@ -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
index 4dc8c67edc683fd7fe492c7373226df74a0127bc..979e98398bebc21fe664ca4a19770e5b251bfc97 100755 (executable)
@@ -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
index dbbf56cba9f5108f79d767ad48f3092dc821a232..99627bc6d69f17a8dce0ad318764e32cd9d9f507 100755 (executable)
@@ -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' &&
index 2298ece8019d79ef718ef658bdac74493d265b92..fca815392e305da095486888a38b6bff41e3d750 100755 (executable)
@@ -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 &&
index 36255d608a7af7d85f479986e302138401f25a8d..3ab670d36aea890e07827b14486e4c49de83bdb5 100755 (executable)
@@ -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
 '
index d9d856b87b2a896d4f80a3e62e6d1925b680a680..4fd69a19ebab07cc0ca784b63a7f02ddd613f306 100755 (executable)
@@ -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
index 5f6cd4f3332f600888c402d2f1b72ddc8840b8cf..5b1250f0d2d69369fccacbefa3fa24488e9c4b4e 100755 (executable)
@@ -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'
index 1d1ca98588bd7e8ae264179b5a4a93371c567346..e80a2af348565a0a3d001ef28cb76427acfee495 100755 (executable)
@@ -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
index 62f246004771090aac71f816cadb8b0ed7aa0cb5..5531bd1af42dac808d64d75a6fc3e848ef968a34 100755 (executable)
@@ -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);
index be6094be774587314a5dd249403eaaa313afde70..fadf2f258ea5305fb52d418a6409fb07889bc205 100755 (executable)
@@ -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
        )
 '
index e51eb41f4b9575d2b51d8d4d255ff5ab7a0889ad..bbb0581f88a874c74e296754544300544429ccc4 100755 (executable)
@@ -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
    '
 
index 59fc2f06e0b5895af60b6eb4084fe7a38d3aa948..892a537989fd7e877f698925fb0a8a33a1e20939 100755 (executable)
@@ -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
index e0227730deb88413301b37501fdb165a2c90460e..4d13e10de1f2594ab304b3a2b7b5905d75d6ff84 100755 (executable)
@@ -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 &&
index cce222f052177fd235af3d3f864c0a8cb9505a91..a40cd3630c28a13f4e0f36ef9f56925d3c8579ed 100755 (executable)
@@ -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
index dcb195b4cf67af3cf5ce94d0f5ca75bf94664b9a..ce61d4c0fa3d916757e09224ed79bc191fb0cb3d 100755 (executable)
@@ -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
index b20ca0eace9dd8f9a11227ebfb932e0446278ea1..195e7477d883f39d51f5740b5b309a489dd92d3d 100755 (executable)
@@ -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
index 28e184829c0f12d4060f0b793db8511259bef91e..c206f4777a36a28687def873bd9fe60ed322fbbc 100755 (executable)
@@ -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
 '
index c3c22f7764adc1542579dfddf1b47a687a93607a..bf6caa4dc3d42230757526dd215ab777f77ae369 100755 (executable)
@@ -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
 
index 8cfdfe790f1e0bb7cd0ddb72a72a55073368ec60..9a40f1e1993a1bc04e3e1cba6452dd290a8e00e9 100755 (executable)
@@ -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>;
index d60da63f7aced3e13a411eee661509ae3790e68f..c17aa3186f7dbf02f474345ba507969060f867ab 100755 (executable)
@@ -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 &&
index c17f52e586747198a74323b578a654edec436f57..2fcf2694696fedb5e7e3d57c869f7dbbbf23dbec 100755 (executable)
@@ -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;
index b00196bd238f538f78ce421979e725ce501e84e1..3e821f958bf10afc739e014ed854254a625affd9 100755 (executable)
@@ -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 &&
index d8d9ca46793a6c09a19beb350e2f18dd199eb2c4..b00ad09d23d8e859d3b52c73579e84ad4620b36c 100755 (executable)
@@ -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)) &&
 
index 7b3b4bef3019d7fd81648073419506ac017bd2e5..80daaca7806cbe1a6de0ddeba40400c8a811328e 100644 (file)
@@ -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"
 }
index 9e2b71132ab7bca267be755999211783c9b77f43..acda33d177197c4288e8b7a33385f11c63c44698 100644 (file)
@@ -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"
index ad40109432971b8b26f107a84b02aeb405e8daf9..33a581924e11167dc546bdf97c8d49460b43674e 100644 (file)
@@ -1023,6 +1023,10 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
                        o->el = &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.
index 5e432f576eb2304a63510a61a71182e11f777092..ec74a9f19a47c39de61def9709da6d4d6f1dcbdb 100644 (file)
@@ -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];