Merge branch 'pw/completion-stash' into maint
authorJunio C Hamano <gitster@pobox.com>
Mon, 22 Feb 2016 21:10:20 +0000 (13:10 -0800)
committerJunio C Hamano <gitster@pobox.com>
Mon, 22 Feb 2016 21:10:20 +0000 (13:10 -0800)
* pw/completion-stash:
  completion: fix mis-indentation in _git_stash()

79 files changed:
Documentation/RelNotes/2.7.1.txt [new file with mode: 0644]
Documentation/RelNotes/2.7.2.txt [new file with mode: 0644]
Documentation/fetch-options.txt
Documentation/git-add.txt
Documentation/git-am.txt
Documentation/git-cherry-pick.txt
Documentation/git-clean.txt
Documentation/git-clone.txt
Documentation/git-commit.txt
Documentation/git-for-each-ref.txt
Documentation/git-format-patch.txt
Documentation/git-revert.txt
Documentation/git-tag.txt
Documentation/git-worktree.txt
Documentation/git.txt
Documentation/gitignore.txt
Documentation/glossary-content.txt
Documentation/user-manual.txt
GIT-VERSION-GEN
RelNotes
builtin/am.c
builtin/clean.c
builtin/commit.c
builtin/diff.c
builtin/fast-export.c
builtin/fetch.c
builtin/merge.c
builtin/receive-pack.c
builtin/stripspace.c
builtin/tag.c
cache.h
compat/basename.c
compat/bswap.h
compat/mingw.c
compat/mingw.h
contrib/completion/git-completion.bash
contrib/subtree/git-subtree.sh
contrib/subtree/t/t7900-subtree.sh
diff-no-index.c
diff.c
diff.h
dir.c
environment.c
git-compat-util.h
git-cvsserver.perl
git-filter-branch.sh
git-rebase.sh
git-send-email.perl
gitweb/gitweb.perl
mergetools/vimdiff
path.c
perl/Git/SVN/Ra.pm
ref-filter.c
reflog-walk.c
refs/files-backend.c
remote.c
revision.c
setup.c
t/perf/p7300-clean.sh
t/t0002-gitfile.sh
t/t0060-path-utils.sh
t/t1410-reflog.sh
t/t3000-ls-files-others.sh
t/t3001-ls-files-others-exclude.sh
t/t3203-branch-output.sh
t/t4056-diff-order.sh
t/t5510-fetch.sh
t/t5533-push-cas.sh
t/t6023-merge-file.sh
t/t6050-replace.sh
t/t6300-for-each-ref.sh
t/t7003-filter-branch.sh
t/t7004-tag.sh
t/t9001-send-email.sh
t/test-lib.sh
test-path-utils.c
worktree.c
wrapper.c
xdiff/xmerge.c

diff --git a/Documentation/RelNotes/2.7.1.txt b/Documentation/RelNotes/2.7.1.txt
new file mode 100644 (file)
index 0000000..6553d69
--- /dev/null
@@ -0,0 +1,87 @@
+Git v2.7.1 Release Notes
+========================
+
+Fixes since v2.7
+----------------
+
+ * An earlier change in 2.5.x-era broke users' hooks and aliases by
+   exporting GIT_WORK_TREE to point at the root of the working tree,
+   interfering when they tried to use a different working tree without
+   setting GIT_WORK_TREE environment themselves.
+
+ * The "exclude_list" structure has the usual "alloc, nr" pair of
+   fields to be used by ALLOC_GROW(), but clear_exclude_list() forgot
+   to reset 'alloc' to 0 when it cleared 'nr' to discard the managed
+   array.
+
+ * "git send-email" was confused by escaped quotes stored in the alias
+   files saved by "mutt", which has been corrected.
+
+ * A few unportable C construct have been spotted by clang compiler
+   and have been fixed.
+
+ * The documentation has been updated to hint the connection between
+   the '--signoff' option and DCO.
+
+ * "git reflog" incorrectly assumed that all objects that used to be
+   at the tip of a ref must be commits, which caused it to segfault.
+
+ * The ignore mechanism saw a few regressions around untracked file
+   listing and sparse checkout selection areas in 2.7.0; the change
+   that is responsible for the regression has been reverted.
+
+ * Some codepaths used fopen(3) when opening a fixed path in $GIT_DIR
+   (e.g. COMMIT_EDITMSG) that is meant to be left after the command is
+   done.  This however did not work well if the repository is set to
+   be shared with core.sharedRepository and the umask of the previous
+   user is tighter.  They have been made to work better by calling
+   unlink(2) and retrying after fopen(3) fails with EPERM.
+
+ * Asking gitweb for a nonexistent commit left a warning in the server
+   log.
+
+ * "git rebase", unlike all other callers of "gc --auto", did not
+   ignore the exit code from "gc --auto".
+
+ * Many codepaths that run "gc --auto" before exiting kept packfiles
+   mapped and left the file descriptors to them open, which was not
+   friendly to systems that cannot remove files that are open.  They
+   now close the packs before doing so.
+
+ * A recent optimization to filter-branch in v2.7.0 introduced a
+   regression when --prune-empty filter is used, which has been
+   corrected.
+
+ * The description for SANITY prerequisite the test suite uses has
+   been clarified both in the comment and in the implementation.
+
+ * "git tag" started listing a tag "foo" as "tags/foo" when a branch
+   named "foo" exists in the same repository; remove this unnecessary
+   disambiguation, which is a regression introduced in v2.7.0.
+
+ * The way "git svn" uses auth parameter was broken by Subversion
+   1.9.0 and later.
+
+ * The "split" subcommand of "git subtree" (in contrib/) incorrectly
+   skipped merges when it shouldn't, which was corrected.
+
+ * A few options of "git diff" did not work well when the command was
+   run from a subdirectory.
+
+ * dirname() emulation has been added, as Msys2 lacks it.
+
+ * The underlying machinery used by "ls-files -o" and other commands
+   have been taught not to create empty submodule ref cache for a
+   directory that is not a submodule.  This removes a ton of wasted
+   CPU cycles.
+
+ * Drop a few old "todo" items by deciding that the change one of them
+   suggests is not such a good idea, and doing the change the other
+   one suggested to do.
+
+ * Documentation for "git fetch --depth" has been updated for clarity.
+
+ * The command line completion learned a handful of additional options
+   and command specific syntax.
+
+Also includes a handful of documentation and test updates.
diff --git a/Documentation/RelNotes/2.7.2.txt b/Documentation/RelNotes/2.7.2.txt
new file mode 100644 (file)
index 0000000..f7846a2
--- /dev/null
@@ -0,0 +1,27 @@
+Git v2.7.2 Release Notes
+========================
+
+Fixes since v2.7.1
+------------------
+
+ * The low-level merge machinery has been taught to use CRLF line
+   termination when inserting conflict markers to merged contents that
+   are themselves CRLF line-terminated.
+
+ * "git worktree" had a broken code that attempted to auto-fix
+   possible inconsistency that results from end-users moving a
+   worktree to different places without telling Git (the original
+   repository needs to maintain backpointers to its worktrees, but
+   "mv" run by end-users who are not familiar with that fact will
+   obviously not adjust them), which actually made things worse
+   when triggered.
+
+ * "git push --force-with-lease" has been taught to report if the push
+   needed to force (or fast-forwarded).
+
+ * The emulated "yes" command used in our test scripts has been
+   tweaked not to spend too much time generating unnecessary output
+   that is not used, to help those who test on Windows where it would
+   not stop until it fills the pipe buffer due to lack of SIGPIPE.
+
+Also includes tiny documentation and test updates.
index 45583d8..78cd265 100644 (file)
@@ -8,10 +8,11 @@
        option old data in `.git/FETCH_HEAD` will be overwritten.
 
 --depth=<depth>::
-       Deepen or shorten the history of a 'shallow' repository created by
-       `git clone` with `--depth=<depth>` option (see linkgit:git-clone[1])
-       to the specified number of commits from the tip of each remote
-       branch history. Tags for the deepened commits are not fetched.
+       Limit fetching to the specified number of commits from the tip of
+       each remote branch history. If fetching to a 'shallow' repository
+       created by `git clone` with `--depth=<depth>` option (see
+       linkgit:git-clone[1]), deepen or shorten the history to the specified
+       number of commits. Tags for the deepened commits are not fetched.
 
 --unshallow::
        If the source repository is complete, convert a shallow
index fe5282f..6a96a66 100644 (file)
@@ -24,7 +24,7 @@ remove paths that do not exist in the working tree anymore.
 
 The "index" holds a snapshot of the content of the working tree, and it
 is this snapshot that is taken as the contents of the next commit.  Thus
-after making any changes to the working directory, and before running
+after making any changes to the working tree, and before running
 the commit command, you must use the `add` command to add any new or
 modified files to the index.
 
index 452c1fe..13cdd7f 100644 (file)
@@ -35,6 +35,7 @@ OPTIONS
 --signoff::
        Add a `Signed-off-by:` line to the commit message, using
        the committer identity of yourself.
+       See the signoff option in linkgit:git-commit[1] for more information.
 
 -k::
 --keep::
index 77da29a..6154e57 100644 (file)
@@ -100,6 +100,7 @@ effect to your index in a row.
 -s::
 --signoff::
        Add Signed-off-by line at the end of the commit message.
+       See the signoff option in linkgit:git-commit[1] for more information.
 
 -S[<keyid>]::
 --gpg-sign[=<keyid>]::
index 641681f..51a7e26 100644 (file)
@@ -37,9 +37,7 @@ OPTIONS
        to false, 'git clean' will refuse to delete files or directories
        unless given -f, -n or -i. Git will refuse to delete directories
        with .git sub directory or file unless a second -f
-       is given. This affects also git submodules where the storage area
-       of the removed submodule under .git/modules/ is not removed until
-       -f is given twice.
+       is given.
 
 -i::
 --interactive::
index 6bf000d..789b668 100644 (file)
@@ -190,15 +190,14 @@ objects from the source repository into a pack in the cloned repository.
 
 --depth <depth>::
        Create a 'shallow' clone with a history truncated to the
-       specified number of revisions.
+       specified number of commits. Implies `--single-branch` unless
+       `--no-single-branch` is given to fetch the histories near the
+       tips of all branches.
 
 --[no-]single-branch::
        Clone only the history leading to the tip of a single branch,
        either specified by the `--branch` option or the primary
-       branch remote's `HEAD` points at. When creating a shallow
-       clone with the `--depth` option, this is the default, unless
-       `--no-single-branch` is given to fetch the histories near the
-       tips of all branches.
+       branch remote's `HEAD` points at.
        Further fetches into the resulting repository will only update the
        remote-tracking branch for the branch this option was used for the
        initial cloning.  If the HEAD at the remote did not point at any
index 7f34a5b..9ec6b3c 100644 (file)
@@ -154,7 +154,11 @@ OPTIONS
 -s::
 --signoff::
        Add Signed-off-by line by the committer at the end of the commit
-       log message.
+       log message.  The meaning of a signoff depends on the project,
+       but it typically certifies that committer has
+       the rights to submit this work under the same license and
+       agrees to a Developer Certificate of Origin
+       (see http://developercertificate.org/ for more information).
 
 -n::
 --no-verify::
index c6f073c..2e3e96f 100644 (file)
@@ -92,7 +92,11 @@ refname::
        The name of the ref (the part after $GIT_DIR/).
        For a non-ambiguous short name of the ref append `:short`.
        The option core.warnAmbiguousRefs is used to select the strict
-       abbreviation mode.
+       abbreviation mode. If `strip=<N>` is appended, strips `<N>`
+       slash-separated path components from the front of the refname
+       (e.g., `%(refname:strip=2)` turns `refs/tags/foo` into `foo`.
+       `<N>` must be a positive integer.  If a displayed ref has fewer
+       components than `<N>`, the command aborts with an error.
 
 objecttype::
        The type of the object (`blob`, `tree`, `commit`, `tag`).
@@ -142,6 +146,11 @@ In addition to the above, for commit and tag objects, the header
 field names (`tree`, `parent`, `object`, `type`, and `tag`) can
 be used to specify the value in the header field.
 
+For commit and tag objects, the special `creatordate` and `creator`
+fields will correspond to the appropriate date or name-email-date tuple
+from the `committer` or `tagger` fields depending on the object type.
+These are intended for working on a mix of annotated and lightweight tags.
+
 Fields that have name-email-date tuple as its value (`author`,
 `committer`, and `tagger`) can be suffixed with `name`, `email`,
 and `date` to extract the named component.
@@ -153,8 +162,8 @@ line is 'contents:body', where body is all of the lines after the first
 blank line.  The optional GPG signature is `contents:signature`.  The
 first `N` lines of the message is obtained using `contents:lines=N`.
 
-For sorting purposes, fields with numeric values sort in numeric
-order (`objectsize`, `authordate`, `committerdate`, `taggerdate`).
+For sorting purposes, fields with numeric values sort in numeric order
+(`objectsize`, `authordate`, `committerdate`, `creatordate`, `taggerdate`).
 All other fields are used to sort in their byte-value order.
 
 There is also an option to sort by versions, this can be done by using
index e3cdaeb..b149e09 100644 (file)
@@ -109,6 +109,7 @@ include::diff-options.txt[]
 --signoff::
        Add `Signed-off-by:` line to the commit message, using
        the committer identity of yourself.
+       See the signoff option in linkgit:git-commit[1] for more information.
 
 --stdout::
        Print all commits to the standard output in mbox format,
index b15139f..573616a 100644 (file)
@@ -89,6 +89,7 @@ effect to your index in a row.
 -s::
 --signoff::
        Add Signed-off-by line at the end of the commit message.
+       See the signoff option in linkgit:git-commit[1] for more information.
 
 --strategy=<strategy>::
        Use the given merge strategy.  Should only be used once.
index 7220e5e..abab481 100644 (file)
@@ -163,7 +163,7 @@ This option is only applicable when listing tags without annotation lines.
        A string that interpolates `%(fieldname)` from the object
        pointed at by a ref being shown.  The format is the same as
        that of linkgit:git-for-each-ref[1].  When unspecified,
-       defaults to `%(refname:short)`.
+       defaults to `%(refname:strip=2)`.
 
 --[no-]merged [<commit>]::
        Only list tags whose tips are reachable, or not reachable
index 5b9ad04..62c76c1 100644 (file)
@@ -32,11 +32,9 @@ The working tree's administrative files in the repository (see
 `git worktree prune` in the main or any linked working tree to
 clean up any stale administrative files.
 
-If you move a linked working tree to another file system, or
-within a file system that does not support hard links, you need to run
-at least one git command inside the linked working tree
-(e.g. `git status`) in order to update its administrative files in the
-repository so that they do not get automatically pruned.
+If you move a linked working tree, you need to manually update the
+administrative files so that they do not get pruned automatically. See
+section "DETAILS" for more information.
 
 If a linked working tree is stored on a portable device or network share
 which is not always mounted, you can prevent its administrative files from
@@ -137,6 +135,13 @@ thumb is do not make any assumption about whether a path belongs to
 $GIT_DIR or $GIT_COMMON_DIR when you need to directly access something
 inside $GIT_DIR. Use `git rev-parse --git-path` to get the final path.
 
+If you move a linked working tree, you need to update the 'gitdir' file
+in the entry's directory. For example, if a linked working tree is moved
+to `/newpath/test-next` and its `.git` file points to
+`/path/main/.git/worktrees/test-next`, then update
+`/path/main/.git/worktrees/test-next/gitdir` to reference `/newpath/test-next`
+instead.
+
 To prevent a $GIT_DIR/worktrees entry from being pruned (which
 can be useful in some situations, such as when the
 entry's working tree is stored on a portable device), add a file named
index bff6302..d987ad2 100644 (file)
@@ -43,9 +43,10 @@ unreleased) version of Git, that is available from the 'master'
 branch of the `git.git` repository.
 Documentation for older releases are available here:
 
-* link:v2.7.0/git.html[documentation for release 2.7]
+* link:v2.7.1/git.html[documentation for release 2.7.1]
 
 * release notes for
+  link:RelNotes/2.7.1.txt[2.7.1],
   link:RelNotes/2.7.0.txt[2.7].
 
 * link:v2.6.5/git.html[documentation for release 2.6.5]
index 79a1948..473623d 100644 (file)
@@ -82,12 +82,12 @@ PATTERN FORMAT
 
  - An optional prefix "`!`" which negates the pattern; any
    matching file excluded by a previous pattern will become
-   included again.
+   included again. It is not possible to re-include a file if a parent
+   directory of that file is excluded. Git doesn't list excluded
+   directories for performance reasons, so any patterns on contained
+   files have no effect, no matter where they are defined.
    Put a backslash ("`\`") in front of the first "`!`" for patterns
    that begin with a literal "`!`", for example, "`\!important!.txt`".
-   It is possible to re-include a file if a parent directory of that
-   file is excluded if certain conditions are met. See section NOTES
-   for detail.
 
  - If the pattern ends with a slash, it is removed for the
    purpose of the following description, but it would only find
@@ -141,21 +141,6 @@ not tracked by Git remain untracked.
 To stop tracking a file that is currently tracked, use
 'git rm --cached'.
 
-To re-include files or directories when their parent directory is
-excluded, the following conditions must be met:
-
- - The rules to exclude a directory and re-include a subset back must
-   be in the same .gitignore file.
-
- - The directory part in the re-include rules must be literal (i.e. no
-   wildcards)
-
- - The rules to exclude the parent directory must not end with a
-   trailing slash.
-
- - The rules to exclude the parent directory must have at least one
-   slash.
-
 EXAMPLES
 --------
 
index e225974..cafc284 100644 (file)
@@ -531,6 +531,11 @@ The most notable example is `HEAD`.
        "Secure Hash Algorithm 1"; a cryptographic hash function.
        In the context of Git used as a synonym for <<def_object_name,object name>>.
 
+[[def_shallow_clone]]shallow clone::
+       Mostly a synonym to <<def_shallow_repository,shallow repository>>
+       but the phrase makes it more explicit that it was created by
+       running `git clone --depth=...` command.
+
 [[def_shallow_repository]]shallow repository::
        A shallow <<def_repository,repository>> has an incomplete
        history some of whose <<def_commit,commits>> have <<def_parent,parents>> cauterized away (in other
index 1c790ac..ec6bacf 100644 (file)
@@ -2125,8 +2125,37 @@ Allowing web browsing of a repository
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 The gitweb cgi script provides users an easy way to browse your
-project's files and history without having to install Git; see the file
-gitweb/INSTALL in the Git source tree for instructions on setting it up.
+project's revisions, file contents and logs without having to install
+Git. Features like RSS/Atom feeds and blame/annotation details may
+optionally be enabled.
+
+The linkgit:git-instaweb[1] command provides a simple way to start
+browsing the repository using gitweb. The default server when using
+instaweb is lighttpd.
+
+See the file gitweb/INSTALL in the Git source tree and
+linkgit:gitweb[1] for instructions on details setting up a permament
+installation with a CGI or Perl capable server.
+
+[[how-to-get-a-git-repository-with-minimal-history]]
+How to get a Git repository with minimal history
+------------------------------------------------
+
+A <<def_shallow_clone,shallow clone>>, with its truncated
+history, is useful when one is interested only in recent history
+of a project and getting full history from the upstream is
+expensive.
+
+A <<def_shallow_clone,shallow clone>> is created by specifying
+the linkgit:git-clone[1] `--depth` switch. The depth can later be
+changed with the linkgit:git-fetch[1] `--depth` switch, or full
+history restored with `--unshallow`.
+
+Merging inside a <<def_shallow_clone,shallow clone>> will work as long
+as a merge base is in the recent history.
+Otherwise, it will be like merging unrelated histories and may
+have to result in huge conflicts.  This limitation may make such
+a repository unsuitable to be used in merge based workflows.
 
 [[sharing-development-examples]]
 Examples
@@ -4636,23 +4665,15 @@ Scan email archives for other stuff left out
 Scan man pages to see if any assume more background than this manual
 provides.
 
-Simplify beginning by suggesting disconnected head instead of
-temporary branch creation?
-
 Add more good examples.  Entire sections of just cookbook examples
 might be a good idea; maybe make an "advanced examples" section a
 standard end-of-chapter section?
 
 Include cross-references to the glossary, where appropriate.
 
-Document shallow clones?  See draft 1.5.0 release notes for some
-documentation.
-
 Add a section on working with other version control systems, including
 CVS, Subversion, and just imports of series of release tarballs.
 
-More details on gitweb?
-
 Write a chapter on using plumbing and writing scripts.
 
 Alternates, clone -reference, etc.
index 51aa9e6..330b339 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 GVF=GIT-VERSION-FILE
-DEF_VER=v2.7.0
+DEF_VER=v2.7.1
 
 LF='
 '
index 3ba13ce..64e8170 120000 (symlink)
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes/2.7.0.txt
\ No newline at end of file
+Documentation/RelNotes/2.7.2.txt
\ No newline at end of file
index 9fb42fd..95decc6 100644 (file)
@@ -1657,7 +1657,7 @@ static int fall_back_threeway(const struct am_state *state, const char *index_pa
 
                init_revisions(&rev_info, NULL);
                rev_info.diffopt.output_format = DIFF_FORMAT_NAME_STATUS;
-               diff_opt_parse(&rev_info.diffopt, &diff_filter_str, 1);
+               diff_opt_parse(&rev_info.diffopt, &diff_filter_str, 1, rev_info.prefix);
                add_pending_sha1(&rev_info, "HEAD", our_tree, 0);
                diff_setup_done(&rev_info.diffopt);
                run_diff_index(&rev_info, 1);
@@ -1939,6 +1939,7 @@ next:
         */
        if (!state->rebasing) {
                am_destroy(state);
+               close_all_packs();
                run_command_v_opt(argv_gc_auto, RUN_GIT_CMD);
        }
 }
index d7acb94..919157b 100644 (file)
@@ -147,30 +147,6 @@ static int exclude_cb(const struct option *opt, const char *arg, int unset)
        return 0;
 }
 
-/*
- * Return 1 if the given path is the root of a git repository or
- * submodule else 0. Will not return 1 for bare repositories with the
- * exception of creating a bare repository in "foo/.git" and calling
- * is_git_repository("foo").
- */
-static int is_git_repository(struct strbuf *path)
-{
-       int ret = 0;
-       int gitfile_error;
-       size_t orig_path_len = path->len;
-       assert(orig_path_len != 0);
-       strbuf_complete(path, '/');
-       strbuf_addstr(path, ".git");
-       if (read_gitfile_gently(path->buf, &gitfile_error) || is_git_directory(path->buf))
-               ret = 1;
-       if (gitfile_error == READ_GITFILE_ERR_OPEN_FAILED ||
-           gitfile_error == READ_GITFILE_ERR_READ_FAILED)
-               ret = 1;  /* This could be a real .git file, take the
-                          * safe option and avoid cleaning */
-       strbuf_setlen(path, orig_path_len);
-       return ret;
-}
-
 static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag,
                int dry_run, int quiet, int *dir_gone)
 {
@@ -182,7 +158,7 @@ static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag,
 
        *dir_gone = 1;
 
-       if ((force_flag & REMOVE_DIR_KEEP_NESTED_GIT) && is_git_repository(path)) {
+       if ((force_flag & REMOVE_DIR_KEEP_NESTED_GIT) && is_nonbare_repository_dir(path)) {
                if (!quiet) {
                        quote_path_relative(path->buf, prefix, &quoted);
                        printf(dry_run ?  _(msg_would_skip_git_dir) : _(msg_skip_git_dir),
index d054f84..89bf6ad 100644 (file)
@@ -761,7 +761,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
                hook_arg2 = "";
        }
 
-       s->fp = fopen(git_path(commit_editmsg), "w");
+       s->fp = fopen_for_writing(git_path(commit_editmsg));
        if (s->fp == NULL)
                die_errno(_("could not open '%s'"), git_path(commit_editmsg));
 
index ed0acca..52c98a9 100644 (file)
@@ -341,7 +341,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
        }
        if (no_index)
                /* If this is a no-index diff, just run it and exit there. */
-               diff_no_index(&rev, argc, argv, prefix);
+               diff_no_index(&rev, argc, argv);
 
        /* Otherwise, we are doing the usual "git" diff */
        rev.diffopt.skip_stat_unmatch = !!diff_auto_refresh_index;
index d9ac5d8..2471297 100644 (file)
@@ -880,7 +880,7 @@ static void export_marks(char *file)
        FILE *f;
        int e = 0;
 
-       f = fopen(file, "w");
+       f = fopen_for_writing(file);
        if (!f)
                die_errno("Unable to open marks file %s for writing.", file);
 
index c85f347..17f40e1 100644 (file)
@@ -837,7 +837,7 @@ static void check_not_current_branch(struct ref *ref_map)
 static int truncate_fetch_head(void)
 {
        const char *filename = git_path_fetch_head();
-       FILE *fp = fopen(filename, "w");
+       FILE *fp = fopen_for_writing(filename);
 
        if (!fp)
                return error(_("cannot open %s: %s\n"), filename, strerror(errno));
@@ -1221,6 +1221,8 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
        list.strdup_strings = 1;
        string_list_clear(&list, 0);
 
+       close_all_packs();
+
        argv_array_pushl(&argv_gc_auto, "gc", "--auto", NULL);
        if (verbosity < 0)
                argv_array_push(&argv_gc_auto, "--quiet");
index 15bf95b..b98a348 100644 (file)
@@ -404,6 +404,7 @@ static void finish(struct commit *head_commit,
                         * We ignore errors in 'gc --auto', since the
                         * user should see them.
                         */
+                       close_all_packs();
                        run_command_v_opt(argv_gc_auto, RUN_GIT_CMD);
                }
        }
index ca38131..f2d6761 100644 (file)
@@ -1618,7 +1618,7 @@ static void prepare_shallow_update(struct command *commands,
                                continue;
                        si->need_reachability_test[i]++;
                        for (k = 0; k < 32; k++)
-                               if (si->used_shallow[i][j] & (1 << k))
+                               if (si->used_shallow[i][j] & (1U << k))
                                        si->shallow_ref[j * 32 + k]++;
                }
 
@@ -1796,6 +1796,7 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
                                "gc", "--auto", "--quiet", NULL,
                        };
                        int opt = RUN_GIT_CMD | RUN_COMMAND_STDOUT_TO_STDERR;
+                       close_all_packs();
                        run_command_v_opt(argv_gc_auto, opt);
                }
                if (auto_update_server_info)
index 7ff8434..15e716e 100644 (file)
@@ -35,7 +35,7 @@ int cmd_stripspace(int argc, const char **argv, const char *prefix)
                            N_("skip and remove all lines starting with comment character"),
                            STRIP_COMMENTS),
                OPT_CMDMODE('c', "comment-lines", &mode,
-                           N_("prepend comment character and blank to each line"),
+                           N_("prepend comment character and space to each line"),
                            COMMENT_LINES),
                OPT_END()
        };
index 8db8c87..1705c94 100644 (file)
@@ -44,11 +44,11 @@ static int list_tags(struct ref_filter *filter, struct ref_sorting *sorting, con
        if (!format) {
                if (filter->lines) {
                        to_free = xstrfmt("%s %%(contents:lines=%d)",
-                                         "%(align:15)%(refname:short)%(end)",
+                                         "%(align:15)%(refname:strip=2)%(end)",
                                          filter->lines);
                        format = to_free;
                } else
-                       format = "%(refname:short)";
+                       format = "%(refname:strip=2)";
        }
 
        verify_ref_format(format);
diff --git a/cache.h b/cache.h
index c63fcc1..3efd7ac 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -214,7 +214,7 @@ struct cache_entry {
 #define CE_INTENT_TO_ADD     (1 << 29)
 #define CE_SKIP_WORKTREE     (1 << 30)
 /* CE_EXTENDED2 is for future extension */
-#define CE_EXTENDED2         (1 << 31)
+#define CE_EXTENDED2         (1U << 31)
 
 #define CE_EXTENDED_FLAGS (CE_INTENT_TO_ADD | CE_SKIP_WORKTREE)
 
@@ -456,7 +456,6 @@ extern char *git_work_tree_cfg;
 extern int is_inside_work_tree(void);
 extern const char *get_git_dir(void);
 extern const char *get_git_common_dir(void);
-extern int is_git_directory(const char *path);
 extern char *get_object_directory(void);
 extern char *get_index_file(void);
 extern char *get_graft_file(void);
@@ -467,6 +466,25 @@ extern const char *get_git_namespace(void);
 extern const char *strip_namespace(const char *namespaced_ref);
 extern const char *get_git_work_tree(void);
 
+/*
+ * Return true if the given path is a git directory; note that this _just_
+ * looks at the directory itself. If you want to know whether "foo/.git"
+ * is a repository, you must feed that path, not just "foo".
+ */
+extern int is_git_directory(const char *path);
+
+/*
+ * Return 1 if the given path is the root of a git repository or
+ * submodule, else 0. Will not return 1 for bare repositories with the
+ * exception of creating a bare repository in "foo/.git" and calling
+ * is_git_repository("foo").
+ *
+ * If we run into read errors, we err on the side of saying "yes, it is",
+ * as we usually consider sub-repos precious, and would prefer to err on the
+ * side of not disrupting or deleting them.
+ */
+extern int is_nonbare_repository_dir(struct strbuf *path);
+
 #define READ_GITFILE_ERR_STAT_FAILED 1
 #define READ_GITFILE_ERR_NOT_A_FILE 2
 #define READ_GITFILE_ERR_OPEN_FAILED 3
index d8f8a3c..96bd953 100644 (file)
@@ -1,15 +1,71 @@
 #include "../git-compat-util.h"
+#include "../strbuf.h"
 
 /* Adapted from libiberty's basename.c.  */
 char *gitbasename (char *path)
 {
        const char *base;
-       /* Skip over the disk name in MSDOS pathnames. */
-       if (has_dos_drive_prefix(path))
-               path += 2;
+
+       if (path)
+               skip_dos_drive_prefix(&path);
+
+       if (!path || !*path)
+               return ".";
+
        for (base = path; *path; path++) {
-               if (is_dir_sep(*path))
-                       base = path + 1;
+               if (!is_dir_sep(*path))
+                       continue;
+               do {
+                       path++;
+               } while (is_dir_sep(*path));
+               if (*path)
+                       base = path;
+               else
+                       while (--path != base && is_dir_sep(*path))
+                               *path = '\0';
        }
        return (char *)base;
 }
+
+char *gitdirname(char *path)
+{
+       static struct strbuf buf = STRBUF_INIT;
+       char *p = path, *slash = NULL, c;
+       int dos_drive_prefix;
+
+       if (!p)
+               return ".";
+
+       if ((dos_drive_prefix = skip_dos_drive_prefix(&p)) && !*p)
+               goto dot;
+
+       /*
+        * POSIX.1-2001 says dirname("/") should return "/", and dirname("//")
+        * should return "//", but dirname("///") should return "/" again.
+        */
+       if (is_dir_sep(*p)) {
+               if (!p[1] || (is_dir_sep(p[1]) && !p[2]))
+                       return path;
+               slash = ++p;
+       }
+       while ((c = *(p++)))
+               if (is_dir_sep(c)) {
+                       char *tentative = p - 1;
+
+                       /* POSIX.1-2001 says to ignore trailing slashes */
+                       while (is_dir_sep(*p))
+                               p++;
+                       if (*p)
+                               slash = tentative;
+               }
+
+       if (slash) {
+               *slash = '\0';
+               return path;
+       }
+
+dot:
+       strbuf_reset(&buf);
+       strbuf_addf(&buf, "%.*s.", dos_drive_prefix, path);
+       return buf.buf;
+}
index 7fed637..d47c003 100644 (file)
@@ -149,11 +149,12 @@ static inline uint64_t git_bswap64(uint64_t x)
  * and is faster on architectures with memory alignment issues.
  */
 
-#if defined(__i386__) || defined(__x86_64__) || \
+#if !defined(NO_UNALIGNED_LOADS) && ( \
+    defined(__i386__) || defined(__x86_64__) || \
     defined(_M_IX86) || defined(_M_X64) || \
     defined(__ppc__) || defined(__ppc64__) || \
     defined(__powerpc__) || defined(__powerpc64__) || \
-    defined(__s390__) || defined(__s390x__)
+    defined(__s390__) || defined(__s390x__))
 
 #define get_be16(p)    ntohs(*(unsigned short *)(p))
 #define get_be32(p)    ntohl(*(unsigned int *)(p))
index 5edea29..9b2a1f5 100644 (file)
@@ -1932,28 +1932,31 @@ pid_t waitpid(pid_t pid, int *status, int options)
        return -1;
 }
 
+int mingw_skip_dos_drive_prefix(char **path)
+{
+       int ret = has_dos_drive_prefix(*path);
+       *path += ret;
+       return ret;
+}
+
 int mingw_offset_1st_component(const char *path)
 {
-       int offset = 0;
-       if (has_dos_drive_prefix(path))
-               offset = 2;
+       char *pos = (char *)path;
 
        /* unc paths */
-       else if (is_dir_sep(path[0]) && is_dir_sep(path[1])) {
-
+       if (!skip_dos_drive_prefix(&pos) &&
+                       is_dir_sep(pos[0]) && is_dir_sep(pos[1])) {
                /* skip server name */
-               char *pos = strpbrk(path + 2, "\\/");
+               pos = strpbrk(pos + 2, "\\/");
                if (!pos)
                        return 0; /* Error: malformed unc path */
 
                do {
                        pos++;
                } while (*pos && !is_dir_sep(*pos));
-
-               offset = pos - path;
        }
 
-       return offset + is_dir_sep(path[offset]);
+       return pos + is_dir_sep(*pos) - path;
 }
 
 int xutftowcsn(wchar_t *wcs, const char *utfs, size_t wcslen, int utflen)
index 57ca477..a5fb52f 100644 (file)
@@ -361,7 +361,10 @@ HANDLE winansi_get_osfhandle(int fd);
  * git specific compatibility
  */
 
-#define has_dos_drive_prefix(path) (isalpha(*(path)) && (path)[1] == ':')
+#define has_dos_drive_prefix(path) \
+       (isalpha(*(path)) && (path)[1] == ':' ? 2 : 0)
+int mingw_skip_dos_drive_prefix(char **path);
+#define skip_dos_drive_prefix mingw_skip_dos_drive_prefix
 #define is_dir_sep(c) ((c) == '/' || (c) == '\\')
 static inline char *mingw_find_last_dir_sep(const char *path)
 {
index 02a0489..00d7299 100644 (file)
@@ -1169,7 +1169,7 @@ __git_diff_common_options="--stat --numstat --shortstat --summary
                        --no-prefix --src-prefix= --dst-prefix=
                        --inter-hunk-context=
                        --patience --histogram --minimal
-                       --raw --word-diff
+                       --raw --word-diff --word-diff-regex=
                        --dirstat --dirstat= --dirstat-by-file
                        --dirstat-by-file= --cumulative
                        --diff-algorithm=
@@ -1687,8 +1687,12 @@ _git_rebase ()
                        --preserve-merges --stat --no-stat
                        --committer-date-is-author-date --ignore-date
                        --ignore-whitespace --whitespace=
-                       --autosquash --fork-point --no-fork-point
-                       --autostash
+                       --autosquash --no-autosquash
+                       --fork-point --no-fork-point
+                       --autostash --no-autostash
+                       --verify --no-verify
+                       --keep-empty --root --force-rebase --no-ff
+                       --exec
                        "
 
                return
@@ -2368,7 +2372,7 @@ _git_show_branch ()
        case "$cur" in
        --*)
                __gitcomp "
-                       --all --remotes --topo-order --current --more=
+                       --all --remotes --topo-order --date-order --current --more=
                        --list --independent --merge-base --no-name
                        --color --no-color
                        --sha1-name --sparse --topics --reflog
index edf36f8..5c83727 100755 (executable)
@@ -479,8 +479,16 @@ copy_or_skip()
                        p="$p -p $parent"
                fi
        done
-       
-       if [ -n "$identical" ]; then
+
+       copycommit=
+       if [ -n "$identical" ] && [ -n "$nonidentical" ]; then
+               extras=$(git rev-list --count $identical..$nonidentical)
+               if [ "$extras" -ne 0 ]; then
+                       # we need to preserve history along the other branch
+                       copycommit=1
+               fi
+       fi
+       if [ -n "$identical" ] && [ -z "$copycommit" ]; then
                echo $identical
        else
                copy_commit $rev $tree "$p" || exit $?
index 751aee3..3bf96a9 100755 (executable)
@@ -1014,4 +1014,64 @@ test_expect_success 'push split to subproj' '
        )
 '
 
+#
+# This test covers 2 cases in subtree split copy_or_skip code
+# 1) Merges where one parent is a superset of the changes of the other
+#    parent regarding changes to the subtree, in this case the merge
+#    commit should be copied
+# 2) Merges where only one parent operate on the subtree, and the merge
+#    commit should be skipped
+#
+# (1) is checked by ensuring subtree_tip is a descendent of subtree_branch
+# (2) should have a check added (not_a_subtree_change shouldn't be present
+#     on the produced subtree)
+#
+# Other related cases which are not tested (or currently handled correctly)
+# - Case (1) where there are more than 2 parents, it will sometimes correctly copy
+#   the merge, and sometimes not
+# - Merge commit where both parents have same tree as the merge, currently
+#   will always be skipped, even if they reached that state via different
+#   set of commits.
+#
+
+next_test
+test_expect_success 'subtree descendant check' '
+       subtree_test_create_repo "$subtree_test_count" &&
+       test_create_commit "$subtree_test_count" folder_subtree/a &&
+       (
+               cd "$subtree_test_count" &&
+               git branch branch
+       ) &&
+       test_create_commit "$subtree_test_count" folder_subtree/0 &&
+       test_create_commit "$subtree_test_count" folder_subtree/b &&
+       cherry=$(cd "$subtree_test_count"; git rev-parse HEAD) &&
+       (
+               cd "$subtree_test_count" &&
+               git checkout branch
+       ) &&
+       test_create_commit "$subtree_test_count" commit_on_branch &&
+       (
+               cd "$subtree_test_count" &&
+               git cherry-pick $cherry &&
+               git checkout master &&
+               git merge -m "merge should be kept on subtree" branch &&
+               git branch no_subtree_work_branch
+       ) &&
+       test_create_commit "$subtree_test_count" folder_subtree/d &&
+       (
+               cd "$subtree_test_count" &&
+               git checkout no_subtree_work_branch
+       ) &&
+       test_create_commit "$subtree_test_count" not_a_subtree_change &&
+       (
+               cd "$subtree_test_count" &&
+               git checkout master &&
+               git merge -m "merge should be skipped on subtree" no_subtree_work_branch &&
+
+               git subtree split --prefix folder_subtree/ --branch subtree_tip master &&
+               git subtree split --prefix folder_subtree/ --branch subtree_branch branch &&
+               check_equal $(git rev-list --count subtree_tip..subtree_branch) 0
+       )
+'
+
 test_done
index 8e0fd27..03daadb 100644 (file)
@@ -237,12 +237,12 @@ static void fixup_paths(const char **path, struct strbuf *replacement)
 }
 
 void diff_no_index(struct rev_info *revs,
-                  int argc, const char **argv,
-                  const char *prefix)
+                  int argc, const char **argv)
 {
        int i, prefixlen;
        const char *paths[2];
        struct strbuf replacement = STRBUF_INIT;
+       const char *prefix = revs->prefix;
 
        diff_setup(&revs->diffopt);
        for (i = 1; i < argc - 2; ) {
@@ -252,7 +252,8 @@ void diff_no_index(struct rev_info *revs,
                else if (!strcmp(argv[i], "--"))
                        i++;
                else {
-                       j = diff_opt_parse(&revs->diffopt, argv + i, argc - i);
+                       j = diff_opt_parse(&revs->diffopt, argv + i, argc - i,
+                                          revs->prefix);
                        if (j <= 0)
                                die("invalid diff option/value: %s", argv[i]);
                        i += j;
diff --git a/diff.c b/diff.c
index 80eb0c2..2136b69 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -3693,12 +3693,16 @@ static int parse_ws_error_highlight(struct diff_options *opt, const char *arg)
        return 1;
 }
 
-int diff_opt_parse(struct diff_options *options, const char **av, int ac)
+int diff_opt_parse(struct diff_options *options,
+                  const char **av, int ac, const char *prefix)
 {
        const char *arg = av[0];
        const char *optarg;
        int argcount;
 
+       if (!prefix)
+               prefix = "";
+
        /* Output format options */
        if (!strcmp(arg, "-p") || !strcmp(arg, "-u") || !strcmp(arg, "--patch")
            || opt_arg(arg, 'U', "unified", &options->context))
@@ -3915,7 +3919,8 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
        else if (!strcmp(arg, "--pickaxe-regex"))
                options->pickaxe_opts |= DIFF_PICKAXE_REGEX;
        else if ((argcount = short_opt('O', av, &optarg))) {
-               options->orderfile = optarg;
+               const char *path = prefix_filename(prefix, strlen(prefix), optarg);
+               options->orderfile = xstrdup(path);
                return argcount;
        }
        else if ((argcount = parse_long_opt("diff-filter", av, &optarg))) {
@@ -3954,9 +3959,10 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
        else if (!strcmp(arg, "--no-function-context"))
                DIFF_OPT_CLR(options, FUNCCONTEXT);
        else if ((argcount = parse_long_opt("output", av, &optarg))) {
-               options->file = fopen(optarg, "w");
+               const char *path = prefix_filename(prefix, strlen(prefix), optarg);
+               options->file = fopen(path, "w");
                if (!options->file)
-                       die_errno("Could not open '%s'", optarg);
+                       die_errno("Could not open '%s'", path);
                options->close_file = 1;
                return argcount;
        } else
diff --git a/diff.h b/diff.h
index f7208ad..70b2d70 100644 (file)
--- a/diff.h
+++ b/diff.h
@@ -91,7 +91,7 @@ typedef struct strbuf *(*diff_prefix_fn_t)(struct diff_options *opt, void *data)
 #define DIFF_OPT_DIRSTAT_BY_LINE     (1 << 28)
 #define DIFF_OPT_FUNCCONTEXT         (1 << 29)
 #define DIFF_OPT_PICKAXE_IGNORE_CASE (1 << 30)
-#define DIFF_OPT_DEFAULT_FOLLOW_RENAMES (1 << 31)
+#define DIFF_OPT_DEFAULT_FOLLOW_RENAMES (1U << 31)
 
 #define DIFF_OPT_TST(opts, flag)    ((opts)->flags & DIFF_OPT_##flag)
 #define DIFF_OPT_TOUCHED(opts, flag)    ((opts)->touched_flags & DIFF_OPT_##flag)
@@ -268,7 +268,7 @@ extern int parse_long_opt(const char *opt, const char **argv,
 extern int git_diff_basic_config(const char *var, const char *value, void *cb);
 extern int git_diff_ui_config(const char *var, const char *value, void *cb);
 extern void diff_setup(struct diff_options *);
-extern int diff_opt_parse(struct diff_options *, const char **, int);
+extern int diff_opt_parse(struct diff_options *, const char **, int, const char *);
 extern void diff_setup_done(struct diff_options *);
 
 #define DIFF_DETECT_RENAME     1
@@ -345,7 +345,7 @@ extern int diff_flush_patch_id(struct diff_options *, unsigned char *);
 
 extern int diff_result_code(struct diff_options *, int);
 
-extern void diff_no_index(struct rev_info *, int, const char **, const char *);
+extern void diff_no_index(struct rev_info *, int, const char **);
 
 extern int index_differs_from(const char *def, int diff_flags);
 
diff --git a/dir.c b/dir.c
index d2a8f06..29aec12 100644 (file)
--- a/dir.c
+++ b/dir.c
@@ -564,9 +564,7 @@ void clear_exclude_list(struct exclude_list *el)
        free(el->excludes);
        free(el->filebuf);
 
-       el->nr = 0;
-       el->excludes = NULL;
-       el->filebuf = NULL;
+       memset(el, 0, sizeof(*el));
 }
 
 static void trim_trailing_spaces(char *buf)
@@ -882,25 +880,6 @@ int match_pathname(const char *pathname, int pathlen,
                 */
                if (!patternlen && !namelen)
                        return 1;
-               /*
-                * This can happen when we ignore some exclude rules
-                * on directories in other to see if negative rules
-                * may match. E.g.
-                *
-                * /abc
-                * !/abc/def/ghi
-                *
-                * The pattern of interest is "/abc". On the first
-                * try, we should match path "abc" with this pattern
-                * in the "if" statement right above, but the caller
-                * ignores it.
-                *
-                * On the second try with paths within "abc",
-                * e.g. "abc/xyz", we come here and try to match it
-                * with "/abc".
-                */
-               if (!patternlen && namelen && *name == '/')
-                       return 1;
        }
 
        return fnmatch_icase_mem(pattern, patternlen,
@@ -908,48 +887,6 @@ int match_pathname(const char *pathname, int pathlen,
                                 WM_PATHNAME) == 0;
 }
 
-/*
- * Return non-zero if pathname is a directory and an ancestor of the
- * literal path in a (negative) pattern. This is used to keep
- * descending in "foo" and "foo/bar" when the pattern is
- * "!foo/bar/.gitignore". "foo/notbar" will not be descended however.
- */
-static int match_neg_path(const char *pathname, int pathlen, int *dtype,
-                         const char *base, int baselen,
-                         const char *pattern, int prefix, int patternlen,
-                         int flags)
-{
-       assert((flags & EXC_FLAG_NEGATIVE) && !(flags & EXC_FLAG_NODIR));
-
-       if (*dtype == DT_UNKNOWN)
-               *dtype = get_dtype(NULL, pathname, pathlen);
-       if (*dtype != DT_DIR)
-               return 0;
-
-       if (*pattern == '/') {
-               pattern++;
-               patternlen--;
-               prefix--;
-       }
-
-       if (baselen) {
-               if (((pathlen < baselen && base[pathlen] == '/') ||
-                    pathlen == baselen) &&
-                   !strncmp_icase(pathname, base, pathlen))
-                       return 1;
-               pathname += baselen + 1;
-               pathlen  -= baselen + 1;
-       }
-
-
-       if (prefix &&
-           ((pathlen < prefix && pattern[pathlen] == '/') &&
-            !strncmp_icase(pathname, pattern, pathlen)))
-               return 1;
-
-       return 0;
-}
-
 /*
  * Scan the given exclude list in reverse to see whether pathname
  * should be ignored.  The first match (i.e. the last on the list), if
@@ -963,7 +900,7 @@ static struct exclude *last_exclude_matching_from_list(const char *pathname,
                                                       struct exclude_list *el)
 {
        struct exclude *exc = NULL; /* undecided */
-       int i, matched_negative_path = 0;
+       int i;
 
        if (!el->nr)
                return NULL;    /* undefined */
@@ -998,18 +935,7 @@ static struct exclude *last_exclude_matching_from_list(const char *pathname,
                        exc = x;
                        break;
                }
-
-               if ((x->flags & EXC_FLAG_NEGATIVE) && !matched_negative_path &&
-                   match_neg_path(pathname, pathlen, dtype, x->base,
-                                  x->baselen ? x->baselen - 1 : 0,
-                                  exclude, prefix, x->patternlen, x->flags))
-                       matched_negative_path = 1;
-       }
-       if (exc &&
-           !(exc->flags & EXC_FLAG_NEGATIVE) &&
-           !(exc->flags & EXC_FLAG_NODIR) &&
-           matched_negative_path)
-               exc = NULL;
+       }
        return exc;
 }
 
index 2da7fe2..1cc4aab 100644 (file)
@@ -235,8 +235,6 @@ void set_git_work_tree(const char *new_work_tree)
        }
        git_work_tree_initialized = 1;
        work_tree = xstrdup(real_path(new_work_tree));
-       if (setenv(GIT_WORK_TREE_ENVIRONMENT, work_tree, 1))
-               die("could not set GIT_WORK_TREE to '%s'", work_tree);
 }
 
 const char *get_git_work_tree(void)
index 2da0a75..693a336 100644 (file)
@@ -253,6 +253,8 @@ struct itimerval {
 #else
 #define basename gitbasename
 extern char *gitbasename(char *);
+#define dirname gitdirname
+extern char *gitdirname(char *);
 #endif
 
 #ifndef NO_ICONV
@@ -335,6 +337,14 @@ static inline int git_has_dos_drive_prefix(const char *path)
 #define has_dos_drive_prefix git_has_dos_drive_prefix
 #endif
 
+#ifndef skip_dos_drive_prefix
+static inline int git_skip_dos_drive_prefix(char **path)
+{
+       return 0;
+}
+#define skip_dos_drive_prefix git_skip_dos_drive_prefix
+#endif
+
 #ifndef is_dir_sep
 static inline int git_is_dir_sep(int c)
 {
@@ -733,6 +743,7 @@ extern int xmkstemp_mode(char *template, int mode);
 extern int odb_mkstemp(char *template, size_t limit, const char *pattern);
 extern int odb_pack_keep(char *name, size_t namesz, const unsigned char *sha1);
 extern char *xgetcwd(void);
+extern FILE *fopen_for_writing(const char *path);
 
 #define REALLOC_ARRAY(x, alloc) (x) = xrealloc((x), (alloc) * sizeof(*(x)))
 
index 95e69b1..02c0445 100755 (executable)
@@ -2664,7 +2664,7 @@ sub argsfromdir
     #   co  # Obtain list directly.
     #   remove # HERE: TEST: MAYBE client does the recursion for us,
     #          # since it only makes sense to remove stuff already in
-    #          # the sandobx?
+    #          # the sandbox?
     #   ci # HERE: Similar to remove...
     #      # Don't try to implement the confusing/weird
     #      # ci -r bug er.."feature".
index 98f1779..86b2ff1 100755 (executable)
@@ -404,7 +404,7 @@ while read commit parents; do
        then
                tree=$(git write-tree)
        else
-               tree="$commit^{tree}"
+               tree=$(git rev-parse "$commit^{tree}")
        fi
        workdir=$workdir @SHELL_PATH@ -c "$filter_commit" "git commit-tree" \
                "$tree" $parentstr < ../message > ../map/$commit ||
index af7ba5f..cf60c43 100755 (executable)
@@ -176,7 +176,7 @@ You can run "git stash pop" or "git stash drop" at any time.
 
 finish_rebase () {
        apply_autostash &&
-       git gc --auto &&
+       { git gc --auto || true; } &&
        rm -rf "$state_dir"
 }
 
index 6caa5b5..d356901 100755 (executable)
@@ -524,8 +524,13 @@ my %parse_alias = (
                if (/^\s*alias\s+(?:-group\s+\S+\s+)*(\S+)\s+(.*)$/) {
                        my ($alias, $addr) = ($1, $2);
                        $addr =~ s/#.*$//; # mutt allows # comments
-                        # commas delimit multiple addresses
-                       $aliases{$alias} = [ split_addrs($addr) ];
+                       # commas delimit multiple addresses
+                       my @addr = split_addrs($addr);
+
+                       # quotes may be escaped in the file,
+                       # unescape them so we do not double-escape them later.
+                       s/\\"/"/g foreach @addr;
+                       $aliases{$alias} = \@addr
                }}},
        mailrc => sub { my $fh = shift; while (<$fh>) {
                if (/^alias\s+(\S+)\s+(.*)$/) {
index 7a5b23a..05d7910 100755 (executable)
@@ -7576,7 +7576,7 @@ sub git_object {
                        git_cmd(), 'cat-file', '-t', $object_id) . ' 2> /dev/null'
                        or die_error(404, "Object does not exist");
                $type = <$fd>;
-               chomp $type;
+               defined $type && chomp $type;
                close $fd
                        or die_error(404, "Object does not exist");
 
index 1ddfbfc..74ea6d5 100644 (file)
@@ -9,8 +9,8 @@ merge_cmd () {
        gvimdiff|vimdiff)
                if $base_present
                then
-                       "$merge_tool_path" -f -d -c 'wincmd J' \
-                               "$MERGED" "$LOCAL" "$BASE" "$REMOTE"
+                       "$merge_tool_path" -f -d -c '4wincmd w | wincmd J' \
+                               "$LOCAL" "$BASE" "$REMOTE" "$MERGED"
                else
                        "$merge_tool_path" -f -d -c 'wincmd l' \
                                "$LOCAL" "$MERGED" "$REMOTE"
diff --git a/path.c b/path.c
index 3cd155e..8b7e168 100644 (file)
--- a/path.c
+++ b/path.c
@@ -782,13 +782,10 @@ const char *relative_path(const char *in, const char *prefix,
        else if (!prefix_len)
                return in;
 
-       if (have_same_root(in, prefix)) {
+       if (have_same_root(in, prefix))
                /* bypass dos_drive, for "c:" is identical to "C:" */
-               if (has_dos_drive_prefix(in)) {
-                       i = 2;
-                       j = 2;
-               }
-       } else {
+               i = j = has_dos_drive_prefix(in);
+       else {
                return in;
        }
 
@@ -943,11 +940,10 @@ const char *remove_leading_path(const char *in, const char *prefix)
 int normalize_path_copy_len(char *dst, const char *src, int *prefix_len)
 {
        char *dst0;
+       int i;
 
-       if (has_dos_drive_prefix(src)) {
+       for (i = has_dos_drive_prefix(src); i > 0; i--)
                *dst++ = *src++;
-               *dst++ = *src++;
-       }
        dst0 = dst;
 
        if (is_dir_sep(*src)) {
index 4a499fc..e764696 100644 (file)
@@ -81,7 +81,6 @@ sub prepare_config_once {
        SVN::_Core::svn_config_ensure($config_dir, undef);
        my ($baton, $callbacks) = SVN::Core::auth_open_helper(_auth_providers);
        my $config = SVN::Core::config_get_config($config_dir);
-       my $dont_store_passwords = 1;
        my $conf_t = $config->{'config'};
 
        no warnings 'once';
@@ -93,9 +92,14 @@ sub prepare_config_once {
            $SVN::_Core::SVN_CONFIG_SECTION_AUTH,
            $SVN::_Core::SVN_CONFIG_OPTION_STORE_PASSWORDS,
            1) == 0) {
+               my $val = '1';
+               if (::compare_svn_version('1.9.0') < 0) { # pre-SVN r1553823
+                       my $dont_store_passwords = 1;
+                       $val = bless \$dont_store_passwords, "_p_void";
+               }
                SVN::_Core::svn_auth_set_parameter($baton,
                    $SVN::_Core::SVN_AUTH_PARAM_DONT_STORE_PASSWORDS,
-                   bless (\$dont_store_passwords, "_p_void"));
+                   $val);
        }
        if (SVN::_Core::svn_config_get_bool($conf_t,
            $SVN::_Core::SVN_CONFIG_SECTION_AUTH,
index 7bef7f8..f097176 100644 (file)
@@ -763,6 +763,29 @@ static inline char *copy_advance(char *dst, const char *src)
        return dst;
 }
 
+static const char *strip_ref_components(const char *refname, const char *nr_arg)
+{
+       char *end;
+       long nr = strtol(nr_arg, &end, 10);
+       long remaining = nr;
+       const char *start = refname;
+
+       if (nr < 1 || *end != '\0')
+               die(":strip= requires a positive integer argument");
+
+       while (remaining) {
+               switch (*start++) {
+               case '\0':
+                       die("ref '%s' does not have %ld components to :strip",
+                           refname, nr);
+               case '/':
+                       remaining--;
+                       break;
+               }
+       }
+       return start;
+}
+
 /*
  * Parse the object referred by ref, and grab needed value.
  */
@@ -909,11 +932,14 @@ static void populate_value(struct ref_array_item *ref)
                formatp = strchr(name, ':');
                if (formatp) {
                        int num_ours, num_theirs;
+                       const char *arg;
 
                        formatp++;
                        if (!strcmp(formatp, "short"))
                                refname = shorten_unambiguous_ref(refname,
                                                      warn_ambiguous_refs);
+                       else if (skip_prefix(formatp, "strip=", &arg))
+                               refname = strip_ref_components(refname, arg);
                        else if (!strcmp(formatp, "track") &&
                                 (starts_with(name, "upstream") ||
                                  starts_with(name, "push"))) {
index 85b8a54..0ebd1da 100644 (file)
@@ -221,6 +221,7 @@ void fake_reflog_parent(struct reflog_walk_info *info, struct commit *commit)
        struct commit_info *commit_info =
                get_commit_info(commit, &info->reflogs, 0);
        struct commit_reflog *commit_reflog;
+       struct object *logobj;
        struct reflog_info *reflog;
 
        info->last_commit_reflog = NULL;
@@ -232,15 +233,20 @@ void fake_reflog_parent(struct reflog_walk_info *info, struct commit *commit)
                commit->parents = NULL;
                return;
        }
-
-       reflog = &commit_reflog->reflogs->items[commit_reflog->recno];
        info->last_commit_reflog = commit_reflog;
-       commit_reflog->recno--;
-       commit_info->commit = (struct commit *)parse_object(reflog->osha1);
-       if (!commit_info->commit) {
+
+       do {
+               reflog = &commit_reflog->reflogs->items[commit_reflog->recno];
+               commit_reflog->recno--;
+               logobj = parse_object(reflog->osha1);
+       } while (commit_reflog->recno && (logobj && logobj->type != OBJ_COMMIT));
+
+       if (!logobj || logobj->type != OBJ_COMMIT) {
+               commit_info->commit = NULL;
                commit->parents = NULL;
                return;
        }
+       commit_info->commit = (struct commit *)logobj;
 
        commit->parents = xcalloc(1, sizeof(struct commit_list));
        commit->parents->item = commit_info->commit;
index c648b5e..3a27f27 100644 (file)
@@ -933,6 +933,10 @@ static void clear_loose_ref_cache(struct ref_cache *refs)
        }
 }
 
+/*
+ * Create a new submodule ref cache and add it to the internal
+ * set of caches.
+ */
 static struct ref_cache *create_ref_cache(const char *submodule)
 {
        int len;
@@ -942,16 +946,12 @@ static struct ref_cache *create_ref_cache(const char *submodule)
        len = strlen(submodule) + 1;
        refs = xcalloc(1, sizeof(struct ref_cache) + len);
        memcpy(refs->name, submodule, len);
+       refs->next = submodule_ref_caches;
+       submodule_ref_caches = refs;
        return refs;
 }
 
-/*
- * Return a pointer to a ref_cache for the specified submodule. For
- * the main repository, use submodule==NULL. The returned structure
- * will be allocated and initialized but not necessarily populated; it
- * should not be freed.
- */
-static struct ref_cache *get_ref_cache(const char *submodule)
+static struct ref_cache *lookup_ref_cache(const char *submodule)
 {
        struct ref_cache *refs;
 
@@ -961,10 +961,20 @@ static struct ref_cache *get_ref_cache(const char *submodule)
        for (refs = submodule_ref_caches; refs; refs = refs->next)
                if (!strcmp(submodule, refs->name))
                        return refs;
+       return NULL;
+}
 
-       refs = create_ref_cache(submodule);
-       refs->next = submodule_ref_caches;
-       submodule_ref_caches = refs;
+/*
+ * Return a pointer to a ref_cache for the specified submodule. For
+ * the main repository, use submodule==NULL. The returned structure
+ * will be allocated and initialized but not necessarily populated; it
+ * should not be freed.
+ */
+static struct ref_cache *get_ref_cache(const char *submodule)
+{
+       struct ref_cache *refs = lookup_ref_cache(submodule);
+       if (!refs)
+               refs = create_ref_cache(submodule);
        return refs;
 }
 
@@ -1336,16 +1346,24 @@ static int resolve_gitlink_ref_recursive(struct ref_cache *refs,
 int resolve_gitlink_ref(const char *path, const char *refname, unsigned char *sha1)
 {
        int len = strlen(path), retval;
-       char *submodule;
+       struct strbuf submodule = STRBUF_INIT;
        struct ref_cache *refs;
 
        while (len && path[len-1] == '/')
                len--;
        if (!len)
                return -1;
-       submodule = xstrndup(path, len);
-       refs = get_ref_cache(submodule);
-       free(submodule);
+
+       strbuf_add(&submodule, path, len);
+       refs = lookup_ref_cache(submodule.buf);
+       if (!refs) {
+               if (!is_nonbare_repository_dir(&submodule)) {
+                       strbuf_release(&submodule);
+                       return -1;
+               }
+               refs = create_ref_cache(submodule.buf);
+       }
+       strbuf_release(&submodule);
 
        retval = resolve_gitlink_ref_recursive(refs, refname, sha1, 0);
        return retval;
index 9d34b5a..3ceac07 100644 (file)
--- a/remote.c
+++ b/remote.c
@@ -1545,11 +1545,8 @@ void set_ref_status_for_push(struct ref *remote_refs, int send_mirror,
                }
 
                /*
-                * Bypass the usual "must fast-forward" check but
-                * replace it with a weaker "the old value must be
-                * this value we observed".  If the remote ref has
-                * moved and is now different from what we expect,
-                * reject any push.
+                * If the remote ref has moved and is now different
+                * from what we expect, reject any push.
                 *
                 * It also is an error if the user told us to check
                 * with the remote-tracking branch to find the value
@@ -1560,10 +1557,14 @@ void set_ref_status_for_push(struct ref *remote_refs, int send_mirror,
                        if (ref->expect_old_no_trackback ||
                            oidcmp(&ref->old_oid, &ref->old_oid_expect))
                                reject_reason = REF_STATUS_REJECT_STALE;
+                       else
+                               /* If the ref isn't stale then force the update. */
+                               force_ref_update = 1;
                }
 
                /*
-                * The usual "must fast-forward" rules.
+                * If the update isn't already rejected then check
+                * the usual "must fast-forward" rules.
                 *
                 * Decide whether an individual refspec A:B can be
                 * pushed.  The push will succeed if any of the
@@ -1582,7 +1583,7 @@ void set_ref_status_for_push(struct ref *remote_refs, int send_mirror,
                 *     passing the --force argument
                 */
 
-               else if (!ref->deletion && !is_null_oid(&ref->old_oid)) {
+               if (!reject_reason && !ref->deletion && !is_null_oid(&ref->old_oid)) {
                        if (starts_with(ref->name, "refs/tags/"))
                                reject_reason = REF_STATUS_REJECT_ALREADY_EXISTS;
                        else if (!has_object_file(&ref->old_oid))
index 0a282f5..14daefb 100644 (file)
@@ -2049,7 +2049,7 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
        } else if (!strcmp(arg, "--ignore-missing")) {
                revs->ignore_missing = 1;
        } else {
-               int opts = diff_opt_parse(&revs->diffopt, argv, argc);
+               int opts = diff_opt_parse(&revs->diffopt, argv, argc, revs->prefix);
                if (!opts)
                        unkv[(*unkc)++] = arg;
                return opts;
diff --git a/setup.c b/setup.c
index d343725..0deb022 100644 (file)
--- a/setup.c
+++ b/setup.c
@@ -312,6 +312,23 @@ done:
        return ret;
 }
 
+int is_nonbare_repository_dir(struct strbuf *path)
+{
+       int ret = 0;
+       int gitfile_error;
+       size_t orig_path_len = path->len;
+       assert(orig_path_len != 0);
+       strbuf_complete(path, '/');
+       strbuf_addstr(path, ".git");
+       if (read_gitfile_gently(path->buf, &gitfile_error) || is_git_directory(path->buf))
+               ret = 1;
+       if (gitfile_error == READ_GITFILE_ERR_OPEN_FAILED ||
+           gitfile_error == READ_GITFILE_ERR_READ_FAILED)
+               ret = 1;
+       strbuf_setlen(path, orig_path_len);
+       return ret;
+}
+
 int is_inside_git_dir(void)
 {
        if (inside_git_dir < 0)
@@ -434,17 +451,6 @@ static int check_repository_format_gently(const char *gitdir, int *nongit_ok)
        return ret;
 }
 
-static void update_linked_gitdir(const char *gitfile, const char *gitdir)
-{
-       struct strbuf path = STRBUF_INIT;
-       struct stat st;
-
-       strbuf_addf(&path, "%s/gitdir", gitdir);
-       if (stat(path.buf, &st) || st.st_mtime + 24 * 3600 < time(NULL))
-               write_file(path.buf, "%s", gitfile);
-       strbuf_release(&path);
-}
-
 /*
  * Try to read the location of the git directory from the .git file,
  * return path to git directory if found.
@@ -514,7 +520,6 @@ const char *read_gitfile_gently(const char *path, int *return_error_code)
                error_code = READ_GITFILE_ERR_NOT_A_REPO;
                goto cleanup_return;
        }
-       update_linked_gitdir(path, dir);
        path = real_path(dir);
 
 cleanup_return:
index ec94cdd..7c1888a 100755 (executable)
@@ -28,4 +28,8 @@ test_perf 'clean many untracked sub dirs, ignore nested git' '
        git clean -n -q -f -f -d 100000_sub_dirs/
 '
 
+test_perf 'ls-files -o' '
+       git ls-files -o
+'
+
 test_done
index 9670e8c..3afe012 100755 (executable)
@@ -99,7 +99,7 @@ test_expect_success 'check rev-list' '
        test "$SHA" = "$(git rev-list HEAD)"
 '
 
-test_expect_success 'setup_git_dir twice in subdir' '
+test_expect_failure 'setup_git_dir twice in subdir' '
        git init sgd &&
        (
                cd sgd &&
index 627ef85..f0152a7 100755 (executable)
@@ -59,6 +59,9 @@ case $(uname -s) in
        ;;
 esac
 
+test_expect_success basename 'test-path-utils basename'
+test_expect_success dirname 'test-path-utils dirname'
+
 norm_path "" ""
 norm_path . ""
 norm_path ./ ""
index b79049f..17a194b 100755 (executable)
@@ -325,4 +325,17 @@ test_expect_success 'parsing reverse reflogs at BUFSIZ boundaries' '
        test_cmp expect actual
 '
 
+test_expect_success 'no segfaults for reflog containing non-commit sha1s' '
+       git update-ref --create-reflog -m "Creating ref" \
+               refs/tests/tree-in-reflog HEAD &&
+       git update-ref -m "Forcing tree" refs/tests/tree-in-reflog HEAD^{tree} &&
+       git update-ref -m "Restoring to commit" refs/tests/tree-in-reflog HEAD &&
+       git reflog refs/tests/tree-in-reflog
+'
+
+test_expect_failure 'reflog with non-commit entries displays all entries' '
+       git reflog refs/tests/tree-in-reflog >actual &&
+       test_line_count = 3 actual
+'
+
 test_done
index 88be904..c525656 100755 (executable)
@@ -65,6 +65,13 @@ test_expect_success '--no-empty-directory hides empty directory' '
        test_cmp expected3 output
 '
 
+test_expect_success 'ls-files --others handles non-submodule .git' '
+       mkdir not-a-submodule &&
+       echo foo >not-a-submodule/.git &&
+       git ls-files -o >output &&
+       test_cmp expected1 output
+'
+
 test_expect_success SYMLINKS 'ls-files --others with symlinked submodule' '
        git init super &&
        git init sub &&
index da257c0..3fc484e 100755 (executable)
@@ -305,29 +305,4 @@ test_expect_success 'ls-files with "**" patterns and no slashes' '
        test_cmp expect actual
 '
 
-test_expect_success 'negative patterns' '
-       git init reinclude &&
-       (
-               cd reinclude &&
-               cat >.gitignore <<-\EOF &&
-               /fooo
-               /foo
-               !foo/bar/bar
-               EOF
-               mkdir fooo &&
-               cat >fooo/.gitignore <<-\EOF &&
-               !/*
-               EOF
-               mkdir -p foo/bar &&
-               touch abc foo/def foo/bar/ghi foo/bar/bar &&
-               git ls-files -o --exclude-standard >../actual &&
-               cat >../expected <<-\EOF &&
-               .gitignore
-               abc
-               foo/bar/bar
-               EOF
-               test_cmp ../expected ../actual
-       )
-'
-
 test_done
index d3913f9..4261403 100755 (executable)
@@ -176,4 +176,12 @@ test_expect_success 'git branch --points-at option' '
        test_cmp expect actual
 '
 
+test_expect_success 'ambiguous branch/tag not marked' '
+       git tag ambiguous &&
+       git branch ambiguous &&
+       echo "  ambiguous" >expect &&
+       git branch --list ambiguous >actual &&
+       test_cmp expect actual
+'
+
 test_done
index c0460bb..43dd474 100755 (executable)
@@ -68,6 +68,12 @@ test_expect_success POSIXPERM,SANITY 'unreadable orderfile' '
        test_must_fail git diff -Ounreadable_file --name-only HEAD^..HEAD
 '
 
+test_expect_success "orderfile using option from subdir with --output" '
+       mkdir subdir &&
+       git -C subdir diff -O../order_file_1 --output ../actual --name-only HEAD^..HEAD &&
+       test_cmp expect_1 actual
+'
+
 for i in 1 2
 do
        test_expect_success "orderfile using option ($i)" '
index 0ba9db0..e3ee4bd 100755 (executable)
@@ -708,4 +708,17 @@ test_expect_success 'fetching a one-level ref works' '
        )
 '
 
+test_expect_success 'fetching with auto-gc does not lock up' '
+       write_script askyesno <<-\EOF &&
+       echo "$*" &&
+       false
+       EOF
+       git clone "file://$D" auto-gc &&
+       test_commit test2 &&
+       cd auto-gc &&
+       git config gc.autoPackLimit 1 &&
+       GIT_ASK_YESNO="$D/askyesno" git fetch >fetch.out 2>&1 &&
+       ! grep "Should I try again" fetch.out
+'
+
 test_done
index c402d8d..c732012 100755 (executable)
@@ -25,7 +25,8 @@ test_expect_success 'push to update (protected)' '
        (
                cd dst &&
                test_commit D &&
-               test_must_fail git push --force-with-lease=master:master origin master
+               test_must_fail git push --force-with-lease=master:master origin master 2>err &&
+               grep "stale info" err
        ) &&
        git ls-remote . refs/heads/master >expect &&
        git ls-remote src refs/heads/master >actual &&
@@ -37,7 +38,8 @@ test_expect_success 'push to update (protected, forced)' '
        (
                cd dst &&
                test_commit D &&
-               git push --force --force-with-lease=master:master origin master
+               git push --force --force-with-lease=master:master origin master 2>err &&
+               grep "forced update" err
        ) &&
        git ls-remote dst refs/heads/master >expect &&
        git ls-remote src refs/heads/master >actual &&
@@ -101,7 +103,8 @@ test_expect_success 'push to update (allowed, tracking)' '
        (
                cd dst &&
                test_commit D &&
-               git push --force-with-lease=master origin master
+               git push --force-with-lease=master origin master 2>err &&
+               ! grep "forced update" err
        ) &&
        git ls-remote dst refs/heads/master >expect &&
        git ls-remote src refs/heads/master >actual &&
@@ -114,7 +117,8 @@ test_expect_success 'push to update (allowed even though no-ff)' '
                cd dst &&
                git reset --hard HEAD^ &&
                test_commit D &&
-               git push --force-with-lease=master origin master
+               git push --force-with-lease=master origin master 2>err &&
+               grep "forced update" err
        ) &&
        git ls-remote dst refs/heads/master >expect &&
        git ls-remote src refs/heads/master >actual &&
@@ -147,7 +151,8 @@ test_expect_success 'push to delete (allowed)' '
        setup_srcdst_basic &&
        (
                cd dst &&
-               git push --force-with-lease=master origin :master
+               git push --force-with-lease=master origin :master 2>err &&
+               grep deleted err
        ) &&
        >expect &&
        git ls-remote src refs/heads/master >actual &&
index 190ee90..20aee43 100755 (executable)
@@ -346,4 +346,17 @@ test_expect_success 'conflict at EOF without LF resolved by --union' \
         printf "line1\nline2\nline3x\nline3y" >expect.txt &&
         test_cmp expect.txt output.txt'
 
+test_expect_success 'conflict sections match existing line endings' '
+       printf "1\\r\\n2\\r\\n3" >crlf-orig.txt &&
+       printf "1\\r\\n2\\r\\n4" >crlf-diff1.txt &&
+       printf "1\\r\\n2\\r\\n5" >crlf-diff2.txt &&
+       test_must_fail git -c core.eol=crlf merge-file -p \
+               crlf-diff1.txt crlf-orig.txt crlf-diff2.txt >crlf.txt &&
+       test $(tr "\015" Q <crlf.txt | grep "^[<=>].*Q$" | wc -l) = 3 &&
+       test $(tr "\015" Q <crlf.txt | grep "[345]Q$" | wc -l) = 3 &&
+       test_must_fail git -c core.eol=crlf merge-file -p \
+               nolf-diff1.txt nolf-orig.txt nolf-diff2.txt >nolf.txt &&
+       test $(tr "\015" Q <nolf.txt | grep "^[<=>].*Q$" | wc -l) = 0
+'
+
 test_done
index 4d5a25e..c630aba 100755 (executable)
@@ -351,11 +351,15 @@ test_expect_success 'test --format long' '
        test_cmp expected actual
 '
 
-test_expect_success 'setup a fake editor' '
-       write_script fakeeditor <<-\EOF
+test_expect_success 'setup fake editors' '
+       write_script fakeeditor <<-\EOF &&
                sed -e "s/A U Thor/A fake Thor/" "$1" >"$1.new"
                mv "$1.new" "$1"
        EOF
+       write_script failingfakeeditor <<-\EOF
+               ./fakeeditor "$@"
+               false
+       EOF
 '
 
 test_expect_success '--edit with and without already replaced object' '
@@ -372,7 +376,7 @@ test_expect_success '--edit with and without already replaced object' '
 test_expect_success '--edit and change nothing or command failed' '
        git replace -d "$PARA3" &&
        test_must_fail env GIT_EDITOR=true git replace --edit "$PARA3" &&
-       test_must_fail env GIT_EDITOR="./fakeeditor;false" git replace --edit "$PARA3" &&
+       test_must_fail env GIT_EDITOR="./failingfakeeditor" git replace --edit "$PARA3" &&
        GIT_EDITOR=./fakeeditor git replace --edit "$PARA3" &&
        git replace -l | grep "$PARA3" &&
        git cat-file commit "$PARA3" | grep "A fake Thor"
index 03873b0..19a2823 100755 (executable)
@@ -49,11 +49,17 @@ test_atom() {
 }
 
 test_atom head refname refs/heads/master
+test_atom head refname:short master
+test_atom head refname:strip=1 heads/master
+test_atom head refname:strip=2 master
 test_atom head upstream refs/remotes/origin/master
+test_atom head upstream:short origin/master
 test_atom head push refs/remotes/myfork/master
+test_atom head push:short myfork/master
 test_atom head objecttype commit
 test_atom head objectsize 171
 test_atom head objectname $(git rev-parse refs/heads/master)
+test_atom head objectname:short $(git rev-parse --short refs/heads/master)
 test_atom head tree $(git rev-parse refs/heads/master^{tree})
 test_atom head parent ''
 test_atom head numparent 0
@@ -86,11 +92,13 @@ test_atom head contents 'Initial
 test_atom head HEAD '*'
 
 test_atom tag refname refs/tags/testtag
+test_atom tag refname:short testtag
 test_atom tag upstream ''
 test_atom tag push ''
 test_atom tag objecttype tag
 test_atom tag objectsize 154
 test_atom tag objectname $(git rev-parse refs/tags/testtag)
+test_atom tag objectname:short $(git rev-parse --short refs/tags/testtag)
 test_atom tag tree ''
 test_atom tag parent ''
 test_atom tag numparent ''
@@ -126,6 +134,16 @@ test_expect_success 'Check invalid atoms names are errors' '
        test_must_fail git for-each-ref --format="%(INVALID)" refs/heads
 '
 
+test_expect_success 'arguments to :strip must be positive integers' '
+       test_must_fail git for-each-ref --format="%(refname:strip=0)" &&
+       test_must_fail git for-each-ref --format="%(refname:strip=-1)" &&
+       test_must_fail git for-each-ref --format="%(refname:strip=foo)"
+'
+
+test_expect_success 'stripping refnames too far gives an error' '
+       test_must_fail git for-each-ref --format="%(refname:strip=3)"
+'
+
 test_expect_success 'Check format specifiers are ignored in naming date atoms' '
        git for-each-ref --format="%(authordate)" refs/heads &&
        git for-each-ref --format="%(authordate:default) %(authordate)" refs/heads &&
@@ -338,47 +356,14 @@ for i in "--perl --shell" "-s --python" "--python --tcl" "--tcl --perl"; do
        "
 done
 
-cat >expected <<\EOF
-master
-testtag
-EOF
-
-test_expect_success 'Check short refname format' '
-       (git for-each-ref --format="%(refname:short)" refs/heads &&
-       git for-each-ref --format="%(refname:short)" refs/tags) >actual &&
-       test_cmp expected actual
-'
-
-cat >expected <<EOF
-origin/master
-EOF
-
-test_expect_success 'Check short upstream format' '
-       git for-each-ref --format="%(upstream:short)" refs/heads >actual &&
-       test_cmp expected actual
-'
-
 test_expect_success 'setup for upstream:track[short]' '
        test_commit two
 '
 
-cat >expected <<EOF
-[ahead 1]
-EOF
-
-test_expect_success 'Check upstream:track format' '
-       git for-each-ref --format="%(upstream:track)" refs/heads >actual &&
-       test_cmp expected actual
-'
-
-cat >expected <<EOF
->
-EOF
-
-test_expect_success 'Check upstream:trackshort format' '
-       git for-each-ref --format="%(upstream:trackshort)" refs/heads >actual &&
-       test_cmp expected actual
-'
+test_atom head upstream:track '[ahead 1]'
+test_atom head upstream:trackshort '>'
+test_atom head push:track '[ahead 1]'
+test_atom head push:trackshort '>'
 
 test_expect_success 'Check that :track[short] cannot be used with other atoms' '
        test_must_fail git for-each-ref --format="%(refname:track)" 2>/dev/null &&
@@ -398,21 +383,6 @@ test_expect_success 'Check that :track[short] works when upstream is invalid' '
        test_cmp expected actual
 '
 
-test_expect_success '%(push) supports tracking specifiers, too' '
-       echo "[ahead 1]" >expected &&
-       git for-each-ref --format="%(push:track)" refs/heads >actual &&
-       test_cmp expected actual
-'
-
-cat >expected <<EOF
-$(git rev-parse --short HEAD)
-EOF
-
-test_expect_success 'Check short objectname format' '
-       git for-each-ref --format="%(objectname:short)" refs/heads >actual &&
-       test_cmp expected actual
-'
-
 test_expect_success 'Check for invalid refname format' '
        test_must_fail git for-each-ref --format="%(refname:INVALID)"
 '
index 869e0bf..edb8341 100755 (executable)
@@ -333,6 +333,14 @@ test_expect_success 'prune empty collapsed merges' '
        test_cmp expect actual
 '
 
+test_expect_success 'prune empty works even without index/tree filters' '
+       git rev-list HEAD >expect &&
+       git commit --allow-empty -m empty &&
+       git filter-branch -f --prune-empty HEAD &&
+       git rev-list HEAD >actual &&
+       test_cmp expect actual
+'
+
 test_expect_success '--remap-to-ancestor with filename filters' '
        git checkout master &&
        git reset --hard A &&
index 3dd2f51..c64579f 100755 (executable)
@@ -1558,4 +1558,12 @@ test_expect_success '--no-merged show unmerged tags' '
        test_cmp expect actual
 '
 
+test_expect_success 'ambiguous branch/tags not marked' '
+       git tag ambiguous &&
+       git branch ambiguous &&
+       echo ambiguous >expect &&
+       git tag -l ambiguous >actual &&
+       test_cmp expect actual
+'
+
 test_done
index 3c49536..834d91a 100755 (executable)
@@ -1527,6 +1527,21 @@ test_expect_success $PREREQ 'cccover adds Cc to all mail' '
        test_cover_addresses "Cc"
 '
 
+test_expect_success $PREREQ 'escaped quotes in sendemail.aliasfiletype=mutt' '
+       clean_fake_sendmail &&
+       echo "alias sbd \\\"Dot U. Sir\\\" <somebody@example.org>" >.mutt &&
+       git config --replace-all sendemail.aliasesfile "$(pwd)/.mutt" &&
+       git config sendemail.aliasfiletype mutt &&
+       git send-email \
+               --from="Example <nobody@example.com>" \
+               --to=sbd \
+               --smtp-server="$(pwd)/fake.sendmail" \
+               outdir/0001-*.patch \
+               2>errors >out &&
+       grep "^!somebody@example\.org!$" commandline1 &&
+       grep -F "To: \"Dot U. Sir\" <somebody@example.org>" out
+'
+
 test_expect_success $PREREQ 'sendemail.aliasfiletype=mailrc' '
        clean_fake_sendmail &&
        echo "alias sbd  somebody@example.org" >.mailrc &&
index 16c4d7b..51e4a88 100644 (file)
@@ -907,9 +907,11 @@ yes () {
                y="$*"
        fi
 
-       while echo "$y"
+       i=0
+       while test $i -lt 99
        do
-               :
+               echo "$y"
+               i=$(($i+1))
        done
 }
 
@@ -1054,20 +1056,28 @@ test_lazy_prereq NOT_ROOT '
        test "$uid" != 0
 '
 
-# On a filesystem that lacks SANITY, a file can be deleted even if
-# the containing directory doesn't have write permissions, or a file
-# can be accessed even if the containing directory doesn't have read
-# or execute permissions, causing our tests that validate that Git
-# works sensibly in such situations.
+# SANITY is about "can you correctly predict what the filesystem would
+# do by only looking at the permission bits of the files and
+# directories?"  A typical example of !SANITY is running the test
+# suite as root, where a test may expect "chmod -r file && cat file"
+# to fail because file is supposed to be unreadable after a successful
+# chmod.  In an environment (i.e. combination of what filesystem is
+# being used and who is running the tests) that lacks SANITY, you may
+# be able to delete or create a file when the containing directory
+# doesn't have write permissions, or access a file even if the
+# containing directory doesn't have read or execute permissions.
+
 test_lazy_prereq SANITY '
        mkdir SANETESTD.1 SANETESTD.2 &&
 
        chmod +w SANETESTD.1 SANETESTD.2 &&
        >SANETESTD.1/x 2>SANETESTD.2/x &&
        chmod -w SANETESTD.1 &&
+       chmod -r SANETESTD.1/x &&
        chmod -rx SANETESTD.2 ||
        error "bug in test sript: cannot prepare SANETESTD"
 
+       ! test -r SANETESTD.1/x &&
        ! rm SANETESTD.1/x && ! test -f SANETESTD.2/x
        status=$?
 
index c67bf65..c3adcd8 100644 (file)
@@ -39,6 +39,130 @@ static void normalize_argv_string(const char **var, const char *input)
                die("Bad value: %s\n", input);
 }
 
+struct test_data {
+       const char *from;  /* input:  transform from this ... */
+       const char *to;    /* output: ... to this.            */
+       const char *alternative; /* output: ... or this.      */
+};
+
+static int test_function(struct test_data *data, char *(*func)(char *input),
+       const char *funcname)
+{
+       int failed = 0, i;
+       char buffer[1024];
+       char *to;
+
+       for (i = 0; data[i].to; i++) {
+               if (!data[i].from)
+                       to = func(NULL);
+               else {
+                       strcpy(buffer, data[i].from);
+                       to = func(buffer);
+               }
+               if (!strcmp(to, data[i].to))
+                       continue;
+               if (!data[i].alternative)
+                       error("FAIL: %s(%s) => '%s' != '%s'\n",
+                               funcname, data[i].from, to, data[i].to);
+               else if (!strcmp(to, data[i].alternative))
+                       continue;
+               else
+                       error("FAIL: %s(%s) => '%s' != '%s', '%s'\n",
+                               funcname, data[i].from, to, data[i].to,
+                               data[i].alternative);
+               failed = 1;
+       }
+       return failed;
+}
+
+static struct test_data basename_data[] = {
+       /* --- POSIX type paths --- */
+       { NULL,              "."    },
+       { "",                "."    },
+       { ".",               "."    },
+       { "..",              ".."   },
+       { "/",               "/"    },
+       { "//",              "/", "//" },
+       { "///",             "/", "//" },
+       { "////",            "/", "//" },
+       { "usr",             "usr"  },
+       { "/usr",            "usr"  },
+       { "/usr/",           "usr"  },
+       { "/usr//",          "usr"  },
+       { "/usr/lib",        "lib"  },
+       { "usr/lib",         "lib"  },
+       { "usr/lib///",      "lib"  },
+
+#if defined(__MINGW32__) || defined(_MSC_VER)
+       /* --- win32 type paths --- */
+       { "\\usr",           "usr"  },
+       { "\\usr\\",         "usr"  },
+       { "\\usr\\\\",       "usr"  },
+       { "\\usr\\lib",      "lib"  },
+       { "usr\\lib",        "lib"  },
+       { "usr\\lib\\\\\\",  "lib"  },
+       { "C:/usr",          "usr"  },
+       { "C:/usr",          "usr"  },
+       { "C:/usr/",         "usr"  },
+       { "C:/usr//",        "usr"  },
+       { "C:/usr/lib",      "lib"  },
+       { "C:usr/lib",       "lib"  },
+       { "C:usr/lib///",    "lib"  },
+       { "C:",              "."    },
+       { "C:a",             "a"    },
+       { "C:/",             "/"    },
+       { "C:///",           "/"    },
+       { "\\",              "\\", "/" },
+       { "\\\\",            "\\", "/" },
+       { "\\\\\\",          "\\", "/" },
+#endif
+       { NULL,              NULL   }
+};
+
+static struct test_data dirname_data[] = {
+       /* --- POSIX type paths --- */
+       { NULL,              "."      },
+       { "",                "."      },
+       { ".",               "."      },
+       { "..",              "."      },
+       { "/",               "/"      },
+       { "//",              "/", "//" },
+       { "///",             "/", "//" },
+       { "////",            "/", "//" },
+       { "usr",             "."      },
+       { "/usr",            "/"      },
+       { "/usr/",           "/"      },
+       { "/usr//",          "/"      },
+       { "/usr/lib",        "/usr"   },
+       { "usr/lib",         "usr"    },
+       { "usr/lib///",      "usr"    },
+
+#if defined(__MINGW32__) || defined(_MSC_VER)
+       /* --- win32 type paths --- */
+       { "\\",              "\\"     },
+       { "\\\\",            "\\\\"   },
+       { "\\usr",           "\\"     },
+       { "\\usr\\",         "\\"     },
+       { "\\usr\\\\",       "\\"     },
+       { "\\usr\\lib",      "\\usr"  },
+       { "usr\\lib",        "usr"    },
+       { "usr\\lib\\\\\\",  "usr"    },
+       { "C:a",             "C:."    },
+       { "C:/",             "C:/"    },
+       { "C:///",           "C:/"    },
+       { "C:/usr",          "C:/"    },
+       { "C:/usr/",         "C:/"    },
+       { "C:/usr//",        "C:/"    },
+       { "C:/usr/lib",      "C:/usr" },
+       { "C:usr/lib",       "C:usr"  },
+       { "C:usr/lib///",    "C:usr"  },
+       { "\\\\\\",          "\\"     },
+       { "\\\\\\\\",        "\\"     },
+       { "C:",              "C:.", "." },
+#endif
+       { NULL,              NULL     }
+};
+
 int main(int argc, char **argv)
 {
        if (argc == 3 && !strcmp(argv[1], "normalize_path_copy")) {
@@ -133,6 +257,12 @@ int main(int argc, char **argv)
                return 0;
        }
 
+       if (argc == 2 && !strcmp(argv[1], "basename"))
+               return test_function(basename_data, basename, argv[1]);
+
+       if (argc == 2 && !strcmp(argv[1], "dirname"))
+               return test_function(dirname_data, dirname, argv[1]);
+
        fprintf(stderr, "%s: unknown function name: %s\n", argv[0],
                argv[1] ? argv[1] : "(there was none)");
        return 1;
index 981f810..6181a66 100644 (file)
@@ -176,10 +176,10 @@ struct worktree **get_worktrees(void)
                        if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
                                continue;
 
-                               if ((linked = get_linked_worktree(d->d_name))) {
-                                       ALLOC_GROW(list, counter + 1, alloc);
-                                       list[counter++] = linked;
-                               }
+                       if ((linked = get_linked_worktree(d->d_name))) {
+                               ALLOC_GROW(list, counter + 1, alloc);
+                               list[counter++] = linked;
+                       }
                }
                closedir(dir);
        }
index c95e290..5200178 100644 (file)
--- a/wrapper.c
+++ b/wrapper.c
@@ -375,6 +375,19 @@ FILE *xfdopen(int fd, const char *mode)
        return stream;
 }
 
+FILE *fopen_for_writing(const char *path)
+{
+       FILE *ret = fopen(path, "w");
+
+       if (!ret && errno == EPERM) {
+               if (!unlink(path))
+                       ret = fopen(path, "w");
+               else
+                       errno = EPERM;
+       }
+       return ret;
+}
+
 int xmkstemp(char *template)
 {
        int fd;
index 625198e..d98f430 100644 (file)
@@ -109,7 +109,7 @@ static int xdl_merge_cmp_lines(xdfenv_t *xe1, int i1, xdfenv_t *xe2, int i2,
        return 0;
 }
 
-static int xdl_recs_copy_0(int use_orig, xdfenv_t *xe, int i, int count, int add_nl, char *dest)
+static int xdl_recs_copy_0(int use_orig, xdfenv_t *xe, int i, int count, int needs_cr, int add_nl, char *dest)
 {
        xrecord_t **recs;
        int size = 0;
@@ -125,6 +125,12 @@ static int xdl_recs_copy_0(int use_orig, xdfenv_t *xe, int i, int count, int add
        if (add_nl) {
                i = recs[count - 1]->size;
                if (i == 0 || recs[count - 1]->ptr[i - 1] != '\n') {
+                       if (needs_cr) {
+                               if (dest)
+                                       dest[size] = '\r';
+                               size++;
+                       }
+
                        if (dest)
                                dest[size] = '\n';
                        size++;
@@ -133,14 +139,58 @@ static int xdl_recs_copy_0(int use_orig, xdfenv_t *xe, int i, int count, int add
        return size;
 }
 
-static int xdl_recs_copy(xdfenv_t *xe, int i, int count, int add_nl, char *dest)
+static int xdl_recs_copy(xdfenv_t *xe, int i, int count, int needs_cr, int add_nl, char *dest)
+{
+       return xdl_recs_copy_0(0, xe, i, count, needs_cr, add_nl, dest);
+}
+
+static int xdl_orig_copy(xdfenv_t *xe, int i, int count, int needs_cr, int add_nl, char *dest)
+{
+       return xdl_recs_copy_0(1, xe, i, count, needs_cr, add_nl, dest);
+}
+
+/*
+ * Returns 1 if the i'th line ends in CR/LF (if it is the last line and
+ * has no eol, the preceding line, if any), 0 if it ends in LF-only, and
+ * -1 if the line ending cannot be determined.
+ */
+static int is_eol_crlf(xdfile_t *file, int i)
 {
-       return xdl_recs_copy_0(0, xe, i, count, add_nl, dest);
+       long size;
+
+       if (i < file->nrec - 1)
+               /* All lines before the last *must* end in LF */
+               return (size = file->recs[i]->size) > 1 &&
+                       file->recs[i]->ptr[size - 2] == '\r';
+       if (!file->nrec)
+               /* Cannot determine eol style from empty file */
+               return -1;
+       if ((size = file->recs[i]->size) &&
+                       file->recs[i]->ptr[size - 1] == '\n')
+               /* Last line; ends in LF; Is it CR/LF? */
+               return size > 1 &&
+                       file->recs[i]->ptr[size - 2] == '\r';
+       if (!i)
+               /* The only line has no eol */
+               return -1;
+       /* Determine eol from second-to-last line */
+       return (size = file->recs[i - 1]->size) > 1 &&
+               file->recs[i - 1]->ptr[size - 2] == '\r';
 }
 
-static int xdl_orig_copy(xdfenv_t *xe, int i, int count, int add_nl, char *dest)
+static int is_cr_needed(xdfenv_t *xe1, xdfenv_t *xe2, xdmerge_t *m)
 {
-       return xdl_recs_copy_0(1, xe, i, count, add_nl, dest);
+       int needs_cr;
+
+       /* Match post-images' preceding, or first, lines' end-of-line style */
+       needs_cr = is_eol_crlf(&xe1->xdf2, m->i1 ? m->i1 - 1 : 0);
+       if (needs_cr)
+               needs_cr = is_eol_crlf(&xe2->xdf2, m->i2 ? m->i2 - 1 : 0);
+       /* Look at pre-image's first line, unless we already settled on LF */
+       if (needs_cr)
+               needs_cr = is_eol_crlf(&xe1->xdf1, 0);
+       /* If still undecided, use LF-only */
+       return needs_cr < 0 ? 0 : needs_cr;
 }
 
 static int fill_conflict_hunk(xdfenv_t *xe1, const char *name1,
@@ -152,16 +202,17 @@ static int fill_conflict_hunk(xdfenv_t *xe1, const char *name1,
        int marker1_size = (name1 ? strlen(name1) + 1 : 0);
        int marker2_size = (name2 ? strlen(name2) + 1 : 0);
        int marker3_size = (name3 ? strlen(name3) + 1 : 0);
+       int needs_cr = is_cr_needed(xe1, xe2, m);
 
        if (marker_size <= 0)
                marker_size = DEFAULT_CONFLICT_MARKER_SIZE;
 
        /* Before conflicting part */
-       size += xdl_recs_copy(xe1, i, m->i1 - i, 0,
+       size += xdl_recs_copy(xe1, i, m->i1 - i, 0, 0,
                              dest ? dest + size : NULL);
 
        if (!dest) {
-               size += marker_size + 1 + marker1_size;
+               size += marker_size + 1 + needs_cr + marker1_size;
        } else {
                memset(dest + size, '<', marker_size);
                size += marker_size;
@@ -170,17 +221,19 @@ static int fill_conflict_hunk(xdfenv_t *xe1, const char *name1,
                        memcpy(dest + size + 1, name1, marker1_size - 1);
                        size += marker1_size;
                }
+               if (needs_cr)
+                       dest[size++] = '\r';
                dest[size++] = '\n';
        }
 
        /* Postimage from side #1 */
-       size += xdl_recs_copy(xe1, m->i1, m->chg1, 1,
+       size += xdl_recs_copy(xe1, m->i1, m->chg1, needs_cr, 1,
                              dest ? dest + size : NULL);
 
        if (style == XDL_MERGE_DIFF3) {
                /* Shared preimage */
                if (!dest) {
-                       size += marker_size + 1 + marker3_size;
+                       size += marker_size + 1 + needs_cr + marker3_size;
                } else {
                        memset(dest + size, '|', marker_size);
                        size += marker_size;
@@ -189,25 +242,29 @@ static int fill_conflict_hunk(xdfenv_t *xe1, const char *name1,
                                memcpy(dest + size + 1, name3, marker3_size - 1);
                                size += marker3_size;
                        }
+                       if (needs_cr)
+                               dest[size++] = '\r';
                        dest[size++] = '\n';
                }
-               size += xdl_orig_copy(xe1, m->i0, m->chg0, 1,
+               size += xdl_orig_copy(xe1, m->i0, m->chg0, needs_cr, 1,
                                      dest ? dest + size : NULL);
        }
 
        if (!dest) {
-               size += marker_size + 1;
+               size += marker_size + 1 + needs_cr;
        } else {
                memset(dest + size, '=', marker_size);
                size += marker_size;
+               if (needs_cr)
+                       dest[size++] = '\r';
                dest[size++] = '\n';
        }
 
        /* Postimage from side #2 */
-       size += xdl_recs_copy(xe2, m->i2, m->chg2, 1,
+       size += xdl_recs_copy(xe2, m->i2, m->chg2, needs_cr, 1,
                              dest ? dest + size : NULL);
        if (!dest) {
-               size += marker_size + 1 + marker2_size;
+               size += marker_size + 1 + needs_cr + marker2_size;
        } else {
                memset(dest + size, '>', marker_size);
                size += marker_size;
@@ -216,6 +273,8 @@ static int fill_conflict_hunk(xdfenv_t *xe1, const char *name1,
                        memcpy(dest + size + 1, name2, marker2_size - 1);
                        size += marker2_size;
                }
+               if (needs_cr)
+                       dest[size++] = '\r';
                dest[size++] = '\n';
        }
        return size;
@@ -241,21 +300,24 @@ static int xdl_fill_merge_buffer(xdfenv_t *xe1, const char *name1,
                                                  marker_size);
                else if (m->mode & 3) {
                        /* Before conflicting part */
-                       size += xdl_recs_copy(xe1, i, m->i1 - i, 0,
+                       size += xdl_recs_copy(xe1, i, m->i1 - i, 0, 0,
                                              dest ? dest + size : NULL);
                        /* Postimage from side #1 */
-                       if (m->mode & 1)
-                               size += xdl_recs_copy(xe1, m->i1, m->chg1, (m->mode & 2),
+                       if (m->mode & 1) {
+                               int needs_cr = is_cr_needed(xe1, xe2, m);
+
+                               size += xdl_recs_copy(xe1, m->i1, m->chg1, needs_cr, (m->mode & 2),
                                                      dest ? dest + size : NULL);
+                       }
                        /* Postimage from side #2 */
                        if (m->mode & 2)
-                               size += xdl_recs_copy(xe2, m->i2, m->chg2, 0,
+                               size += xdl_recs_copy(xe2, m->i2, m->chg2, 0, 0,
                                                      dest ? dest + size : NULL);
                } else
                        continue;
                i = m->i1 + m->chg1;
        }
-       size += xdl_recs_copy(xe1, i, xe1->xdf2.nrec - i, 0,
+       size += xdl_recs_copy(xe1, i, xe1->xdf2.nrec - i, 0, 0,
                              dest ? dest + size : NULL);
        return size;
 }