Imported Upstream version 2.25.2 upstream/2.25.2
authorDongHun Kwak <dh0128.kwak@samsung.com>
Wed, 3 Mar 2021 06:17:11 +0000 (15:17 +0900)
committerDongHun Kwak <dh0128.kwak@samsung.com>
Wed, 3 Mar 2021 06:17:11 +0000 (15:17 +0900)
56 files changed:
Documentation/RelNotes/2.25.2.txt [new file with mode: 0644]
Documentation/config/push.txt
Documentation/doc-diff
Documentation/git-check-ignore.txt
Documentation/git-ls-remote.txt
Documentation/gitcli.txt
Documentation/gitcredentials.txt
GIT-VERSION-GEN
RelNotes
add-interactive.c
azure-pipelines.yml
builtin/check-ignore.c
builtin/fetch.c
builtin/fmt-merge-msg.c
builtin/index-pack.c
ci/install-dependencies.sh
compat/mingw.c
compat/mingw.h
compat/obstack.h
compat/poll/poll.c
credential.h
gpg-interface.c
gpg-interface.h
log-tree.c
merge-recursive.c
notes.c
pathspec.c
rebase-interactive.c
run-command.h
sequencer.c
setup.c
submodule.c
t/lib-httpd.sh
t/lib-httpd/apache.conf
t/lib-httpd/apply-one-time-perl.sh [new file with mode: 0644]
t/lib-httpd/apply-one-time-sed.sh [deleted file]
t/t0008-ignores.sh
t/t2405-worktree-submodule.sh [new file with mode: 0755]
t/t3305-notes-fanout.sh
t/t3404-rebase-interactive.sh
t/t3433-rebase-across-mode-change.sh [new file with mode: 0755]
t/t3600-rm.sh
t/t3701-add-interactive.sh
t/t4202-log.sh
t/t5309-pack-delta-cycles.sh
t/t5537-fetch-shallow.sh
t/t5580-unc-paths.sh [moved from t/t5580-clone-push-unc.sh with 89% similarity]
t/t5616-partial-clone.sh
t/t5702-protocol-v2.sh
t/t5703-upload-pack-ref-in-want.sh
t/t6136-pathspec-in-bare.sh [new file with mode: 0755]
t/t7410-submodule-checkout-to.sh [deleted file]
t/test-lib.sh
unicode-width.h
unpack-trees.c
xdiff-interface.c

diff --git a/Documentation/RelNotes/2.25.2.txt b/Documentation/RelNotes/2.25.2.txt
new file mode 100644 (file)
index 0000000..303c53a
--- /dev/null
@@ -0,0 +1,60 @@
+Git 2.25.2 Release Notes
+========================
+
+Fixes since v2.25.1
+-------------------
+
+ * Minor bugfixes to "git add -i" that has recently been rewritten in C.
+
+ * An earlier update to show the location of working tree in the error
+   message did not consider the possibility that a git command may be
+   run in a bare repository, which has been corrected.
+
+ * The "--recurse-submodules" option of various subcommands did not
+   work well when run in an alternate worktree, which has been
+   corrected.
+
+ * Running "git rm" on a submodule failed unnecessarily when
+   .gitmodules is only cache-dirty, which has been corrected.
+
+ * "git rebase -i" identifies existing commits in its todo file with
+   their abbreviated object name, which could become ambigous as it
+   goes to create new commits, and has a mechanism to avoid ambiguity
+   in the main part of its execution.  A few other cases however were
+   not covered by the protection against ambiguity, which has been
+   corrected.
+
+ * The index-pack code now diagnoses a bad input packstream that
+   records the same object twice when it is used as delta base; the
+   code used to declare a software bug when encountering such an
+   input, but it is an input error.
+
+ * The code to automatically shrink the fan-out in the notes tree had
+   an off-by-one bug, which has been killed.
+
+ * "git check-ignore" did not work when the given path is explicitly
+   marked as not ignored with a negative entry in the .gitignore file.
+
+ * The merge-recursive machinery failed to refresh the cache entry for
+   a merge result in a couple of places, resulting in an unnecessary
+   merge failure, which has been fixed.
+
+ * Fix for a bug revealed by a recent change to make the protocol v2
+   the default.
+
+ * "git merge signed-tag" while lacking the public key started to say
+   "No signature", which was utterly wrong.  This regression has been
+   reverted.
+
+ * MinGW's poll() emulation has been improved.
+
+ * "git show" and others gave an object name in raw format in its
+   error output, which has been corrected to give it in hex.
+
+ * Both "git ls-remote -h" and "git grep -h" give short usage help,
+   like any other Git subcommand, but it is not unreasonable to expect
+   that the former would behave the same as "git ls-remote --head"
+   (there is no other sensible behaviour for the latter).  The
+   documentation has been updated in an attempt to clarify this.
+
+Also contains various documentation updates, code clean-ups and minor fixups.
index 0a0e000..dffd4d5 100644 (file)
@@ -79,7 +79,7 @@ higher priority configuration file (e.g. `.git/config` in a
 repository) to clear the values inherited from a lower priority
 configuration files (e.g. `$HOME/.gitconfig`).
 +
---
+----
 
 Example:
 
@@ -96,7 +96,7 @@ repo/.git/config
 
 This will result in only b (a and c are cleared).
 
---
+----
 
 push.recurseSubmodules::
        Make sure all submodule commits used by the revisions to be pushed
index 88a9b20..1694300 100755 (executable)
@@ -127,7 +127,7 @@ generate_render_makefile () {
        while read src
        do
                dst=$2/${src#$1/}
-               printf 'all:: %s\n' "$dst"
+               printf 'all: %s\n' "$dst"
                printf '%s: %s\n' "$dst" "$src"
                printf '\t@echo >&2 "  RENDER $(notdir $@)" && \\\n'
                printf '\tmkdir -p $(dir $@) && \\\n'
index 8b2d49c..0c3924a 100644 (file)
@@ -30,9 +30,15 @@ OPTIONS
        valid with a single pathname.
 
 -v, --verbose::
-       Also output details about the matching pattern (if any)
-       for each given pathname. For precedence rules within and
-       between exclude sources, see linkgit:gitignore[5].
+       Instead of printing the paths that are excluded, for each path
+       that matches an exclude pattern, print the exclude pattern
+       together with the path.  (Matching an exclude pattern usually
+       means the path is excluded, but if the pattern begins with '!'
+       then it is a negated pattern and matching it means the path is
+       NOT excluded.)
++
+For precedence rules within and between exclude sources, see
+linkgit:gitignore[5].
 
 --stdin::
        Read pathnames from the standard input, one per line,
index a2ea1fd..0a5c8b7 100644 (file)
@@ -28,7 +28,9 @@ OPTIONS
        Limit to only refs/heads and refs/tags, respectively.
        These options are _not_ mutually exclusive; when given
        both, references stored in refs/heads and refs/tags are
-       displayed.
+       displayed.  Note that `git ls-remote -h` used without
+       anything else on the command line gives help, consistent
+       with other git subcommands.
 
 --refs::
        Do not show peeled tags or pseudorefs like `HEAD` in the output.
index 373cfa2..92e4ba6 100644 (file)
@@ -126,6 +126,11 @@ usage: git describe [<options>] <commit-ish>*
     --long                always use long format
     --abbrev[=<n>]        use <n> digits to display SHA-1s
 ---------------------------------------------
++
+Note that some subcommand (e.g. `git grep`) may behave differently
+when there are things on the command line other than `-h`, but `git
+subcmd -h` without anything else on the command line is meant to
+consistently give the usage.
 
 --help-all::
        Some Git commands take options that are only used for plumbing or that
index ea759fd..5b9d14f 100644 (file)
@@ -186,7 +186,94 @@ CUSTOM HELPERS
 --------------
 
 You can write your own custom helpers to interface with any system in
-which you keep credentials. See credential.h for details.
+which you keep credentials.
+
+Credential helpers are programs executed by Git to fetch or save
+credentials from and to long-term storage (where "long-term" is simply
+longer than a single Git process; e.g., credentials may be stored
+in-memory for a few minutes, or indefinitely on disk).
+
+Each helper is specified by a single string in the configuration
+variable `credential.helper` (and others, see linkgit:git-config[1]).
+The string is transformed by Git into a command to be executed using
+these rules:
+
+  1. If the helper string begins with "!", it is considered a shell
+     snippet, and everything after the "!" becomes the command.
+
+  2. Otherwise, if the helper string begins with an absolute path, the
+     verbatim helper string becomes the command.
+
+  3. Otherwise, the string "git credential-" is prepended to the helper
+     string, and the result becomes the command.
+
+The resulting command then has an "operation" argument appended to it
+(see below for details), and the result is executed by the shell.
+
+Here are some example specifications:
+
+----------------------------------------------------
+# run "git credential-foo"
+foo
+
+# same as above, but pass an argument to the helper
+foo --bar=baz
+
+# the arguments are parsed by the shell, so use shell
+# quoting if necessary
+foo --bar="whitespace arg"
+
+# you can also use an absolute path, which will not use the git wrapper
+/path/to/my/helper --with-arguments
+
+# or you can specify your own shell snippet
+!f() { echo "password=`cat $HOME/.secret`"; }; f
+----------------------------------------------------
+
+Generally speaking, rule (3) above is the simplest for users to specify.
+Authors of credential helpers should make an effort to assist their
+users by naming their program "git-credential-$NAME", and putting it in
+the `$PATH` or `$GIT_EXEC_PATH` during installation, which will allow a
+user to enable it with `git config credential.helper $NAME`.
+
+When a helper is executed, it will have one "operation" argument
+appended to its command line, which is one of:
+
+`get`::
+
+       Return a matching credential, if any exists.
+
+`store`::
+
+       Store the credential, if applicable to the helper.
+
+`erase`::
+
+       Remove a matching credential, if any, from the helper's storage.
+
+The details of the credential will be provided on the helper's stdin
+stream. The exact format is the same as the input/output format of the
+`git credential` plumbing command (see the section `INPUT/OUTPUT
+FORMAT` in linkgit:git-credential[1] for a detailed specification).
+
+For a `get` operation, the helper should produce a list of attributes on
+stdout in the same format (see linkgit:git-credential[1] for common
+attributes). A helper is free to produce a subset, or even no values at
+all if it has nothing useful to provide. Any provided attributes will
+overwrite those already known about by Git.  If a helper outputs a
+`quit` attribute with a value of `true` or `1`, no further helpers will
+be consulted, nor will the user be prompted (if no credential has been
+provided, the operation will then fail).
+
+For a `store` or `erase` operation, the helper's output is ignored.
+If it fails to perform the requested operation, it may complain to
+stderr to inform the user. If it does not support the requested
+operation (e.g., a read-only store), it should silently ignore the
+request.
+
+If a helper receives any other operation, it should silently ignore the
+request. This leaves room for future operations to be added (older
+helpers will just ignore the new requests).
 
 GIT
 ---
index 2a8e709..61023f4 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 GVF=GIT-VERSION-FILE
-DEF_VER=v2.25.1
+DEF_VER=v2.25.2
 
 LF='
 '
index c63ee7d..19e8340 120000 (symlink)
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes/2.25.1.txt
\ No newline at end of file
+Documentation/RelNotes/2.25.2.txt
\ No newline at end of file
index 6a5048c..143e694 100644 (file)
@@ -326,7 +326,10 @@ static ssize_t list_and_choose(struct add_i_state *s,
                                if (endp == p + sep)
                                        to = from + 1;
                                else if (*endp == '-') {
-                                       to = strtoul(++endp, &endp, 10);
+                                       if (isdigit(*(++endp)))
+                                               to = strtoul(endp, &endp, 10);
+                                       else
+                                               to = items->items.nr;
                                        /* extra characters after the range? */
                                        if (endp != p + sep)
                                                from = -1;
@@ -913,7 +916,7 @@ static int run_patch(struct add_i_state *s, const struct pathspec *ps,
 
        opts->prompt = N_("Patch update");
        count = list_and_choose(s, files, opts);
-       if (count >= 0) {
+       if (count > 0) {
                struct argv_array args = ARGV_ARRAY_INIT;
                struct pathspec ps_selected = { 0 };
 
@@ -954,7 +957,7 @@ static int run_diff(struct add_i_state *s, const struct pathspec *ps,
        opts->flags = IMMEDIATE;
        count = list_and_choose(s, files, opts);
        opts->flags = 0;
-       if (count >= 0) {
+       if (count > 0) {
                struct argv_array args = ARGV_ARRAY_INIT;
 
                argv_array_pushl(&args, "git", "diff", "-p", "--cached",
index af2a5ea..675c3a4 100644 (file)
@@ -5,7 +5,8 @@ jobs:
 - job: windows_build
   displayName: Windows Build
   condition: succeeded()
-  pool: Hosted
+  pool:
+    vmImage: windows-latest
   timeoutInMinutes: 240
   steps:
   - powershell: |
@@ -61,7 +62,8 @@ jobs:
   displayName: Windows Test
   dependsOn: windows_build
   condition: succeeded()
-  pool: Hosted
+  pool:
+    vmImage: windows-latest
   timeoutInMinutes: 240
   strategy:
     parallel: 10
@@ -133,7 +135,8 @@ jobs:
 - job: vs_build
   displayName: Visual Studio Build
   condition: succeeded()
-  pool: Hosted VS2017
+  pool:
+    vmImage: windows-latest
   timeoutInMinutes: 240
   steps:
   - powershell: |
@@ -181,6 +184,7 @@ jobs:
       platform: x64
       configuration: Release
       maximumCpuCount: 4
+      msbuildArguments: /p:PlatformToolset=v142
   - powershell: |
       & compat\vcbuild\vcpkg_copy_dlls.bat release
       if (!$?) { exit(1) }
@@ -224,7 +228,8 @@ jobs:
   displayName: Visual Studio Test
   dependsOn: vs_build
   condition: succeeded()
-  pool: Hosted
+  pool:
+    vmImage: windows-latest
   timeoutInMinutes: 240
   strategy:
     parallel: 10
@@ -292,7 +297,8 @@ jobs:
 - job: linux_clang
   displayName: linux-clang
   condition: succeeded()
-  pool: Hosted Ubuntu 1604
+  pool:
+    vmImage: ubuntu-latest
   steps:
   - bash: |
        test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || ci/mount-fileshare.sh //gitfileshare.file.core.windows.net/test-cache gitfileshare "$GITFILESHAREPWD" "$HOME/test-cache" || exit 1
@@ -330,7 +336,8 @@ jobs:
 - job: linux_gcc
   displayName: linux-gcc
   condition: succeeded()
-  pool: Hosted Ubuntu 1604
+  pool:
+    vmImage: ubuntu-latest
   steps:
   - bash: |
        test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || ci/mount-fileshare.sh //gitfileshare.file.core.windows.net/test-cache gitfileshare "$GITFILESHAREPWD" "$HOME/test-cache" || exit 1
@@ -367,7 +374,8 @@ jobs:
 - job: osx_clang
   displayName: osx-clang
   condition: succeeded()
-  pool: Hosted macOS
+  pool:
+    vmImage: macOS-latest
   steps:
   - bash: |
        test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || ci/mount-fileshare.sh //gitfileshare.file.core.windows.net/test-cache gitfileshare "$GITFILESHAREPWD" "$HOME/test-cache" || exit 1
@@ -402,7 +410,8 @@ jobs:
 - job: osx_gcc
   displayName: osx-gcc
   condition: succeeded()
-  pool: Hosted macOS
+  pool:
+    vmImage: macOS-latest
   steps:
   - bash: |
        test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || ci/mount-fileshare.sh //gitfileshare.file.core.windows.net/test-cache gitfileshare "$GITFILESHAREPWD" "$HOME/test-cache" || exit 1
@@ -435,7 +444,8 @@ jobs:
 - job: gettext_poison
   displayName: GETTEXT_POISON
   condition: succeeded()
-  pool: Hosted Ubuntu 1604
+  pool:
+    vmImage: ubuntu-latest
   steps:
   - bash: |
        test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || ci/mount-fileshare.sh //gitfileshare.file.core.windows.net/test-cache gitfileshare "$GITFILESHAREPWD" "$HOME/test-cache" || exit 1
@@ -472,7 +482,8 @@ jobs:
 - job: linux32
   displayName: Linux32
   condition: succeeded()
-  pool: Hosted Ubuntu 1604
+  pool:
+    vmImage: ubuntu-latest
   steps:
   - bash: |
        test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || ci/mount-fileshare.sh //gitfileshare.file.core.windows.net/test-cache gitfileshare "$GITFILESHAREPWD" "$HOME/test-cache" || exit 1
@@ -506,7 +517,8 @@ jobs:
 - job: static_analysis
   displayName: StaticAnalysis
   condition: succeeded()
-  pool: Hosted Ubuntu 1604
+  pool:
+    vmImage: ubuntu-latest
   steps:
   - bash: |
        test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || ci/mount-fileshare.sh //gitfileshare.file.core.windows.net/test-cache gitfileshare "$GITFILESHAREPWD" "$HOME/test-cache" || exit 1
@@ -526,7 +538,8 @@ jobs:
 - job: documentation
   displayName: Documentation
   condition: succeeded()
-  pool: Hosted Ubuntu 1604
+  pool:
+    vmImage: ubuntu-latest
   steps:
   - bash: |
        test "$GITFILESHAREPWD" = '$(gitfileshare.pwd)' || ci/mount-fileshare.sh //gitfileshare.file.core.windows.net/test-cache gitfileshare "$GITFILESHAREPWD" "$HOME/test-cache" || exit 1
index 5a4f923..ea5d0ae 100644 (file)
@@ -108,6 +108,9 @@ static int check_ignore(struct dir_struct *dir,
                        int dtype = DT_UNKNOWN;
                        pattern = last_matching_pattern(dir, &the_index,
                                                        full_path, &dtype);
+                       if (!verbose && pattern &&
+                           pattern->flags & PATTERN_FLAG_NEGATIVE)
+                               pattern = NULL;
                }
                if (!quiet && (pattern || show_non_matching))
                        output_pattern(pathspec.items[i].original, pattern);
index b4c6d92..fd69c4f 100644 (file)
@@ -335,6 +335,7 @@ static void find_non_local_tags(const struct ref *refs,
        struct string_list_item *remote_ref_item;
        const struct ref *ref;
        struct refname_hash_entry *item = NULL;
+       const int quick_flags = OBJECT_INFO_QUICK | OBJECT_INFO_SKIP_FETCH_OBJECT;
 
        refname_hash_init(&existing_refs);
        refname_hash_init(&remote_refs);
@@ -353,10 +354,9 @@ static void find_non_local_tags(const struct ref *refs,
                 */
                if (ends_with(ref->name, "^{}")) {
                        if (item &&
-                           !has_object_file_with_flags(&ref->old_oid,
-                                                       OBJECT_INFO_QUICK) &&
+                           !has_object_file_with_flags(&ref->old_oid, quick_flags) &&
                            !oidset_contains(&fetch_oids, &ref->old_oid) &&
-                           !has_object_file_with_flags(&item->oid, OBJECT_INFO_QUICK) &&
+                           !has_object_file_with_flags(&item->oid, quick_flags) &&
                            !oidset_contains(&fetch_oids, &item->oid))
                                clear_item(item);
                        item = NULL;
@@ -370,7 +370,7 @@ static void find_non_local_tags(const struct ref *refs,
                 * fetch.
                 */
                if (item &&
-                   !has_object_file_with_flags(&item->oid, OBJECT_INFO_QUICK) &&
+                   !has_object_file_with_flags(&item->oid, quick_flags) &&
                    !oidset_contains(&fetch_oids, &item->oid))
                        clear_item(item);
 
@@ -391,7 +391,7 @@ static void find_non_local_tags(const struct ref *refs,
         * checked to see if it needs fetching.
         */
        if (item &&
-           !has_object_file_with_flags(&item->oid, OBJECT_INFO_QUICK) &&
+           !has_object_file_with_flags(&item->oid, quick_flags) &&
            !oidset_contains(&fetch_oids, &item->oid))
                clear_item(item);
 
index 05a92c5..736f666 100644 (file)
@@ -494,7 +494,6 @@ static void fmt_merge_msg_sigs(struct strbuf *out)
                enum object_type type;
                unsigned long size, len;
                char *buf = read_object_file(oid, &type, &size);
-               struct signature_check sigc = { 0 };
                struct strbuf sig = STRBUF_INIT;
 
                if (!buf || type != OBJ_TAG)
@@ -503,12 +502,10 @@ static void fmt_merge_msg_sigs(struct strbuf *out)
 
                if (size == len)
                        ; /* merely annotated */
-               else if (!check_signature(buf, len, buf + len, size - len,
-                                         &sigc)) {
-                       strbuf_addstr(&sig, sigc.gpg_output);
-                       signature_check_clear(&sigc);
-               } else
-                       strbuf_addstr(&sig, "gpg verification failed.\n");
+               else if (verify_signed_buffer(buf, len, buf + len, size - len, &sig, NULL)) {
+                       if (!sig.len)
+                               strbuf_addstr(&sig, "gpg verification failed.\n");
+               }
 
                if (!tag_number++) {
                        fmt_tag_signature(&tagbuf, &sig, buf, len);
index 60a5591..41a7c11 100644 (file)
@@ -1003,7 +1003,9 @@ static struct base_data *find_unresolved_deltas_1(struct base_data *base,
 
                if (!compare_and_swap_type(&child->real_type, OBJ_REF_DELTA,
                                           base->obj->real_type))
-                       BUG("child->real_type != OBJ_REF_DELTA");
+                       die("REF_DELTA at offset %"PRIuMAX" already resolved (duplicate base %s?)",
+                           (uintmax_t)child->idx.offset,
+                           oid_to_hex(&base->obj->idx.oid));
 
                resolve_delta(child, base, result);
                if (base->ref_first == base->ref_last && base->ofs_last == -1)
index cd59855..497fd32 100755 (executable)
@@ -40,11 +40,11 @@ osx-clang|osx-gcc)
        test -z "$BREW_INSTALL_PACKAGES" ||
        brew install $BREW_INSTALL_PACKAGES
        brew link --force gettext
-       brew cask install perforce || {
+       brew cask install --no-quarantine perforce || {
                # Update the definitions and try again
                cask_repo="$(brew --repository)"/Library/Taps/homebrew/homebrew-cask &&
                git -C "$cask_repo" pull --no-stat &&
-               brew cask install perforce
+               brew cask install --no-quarantine perforce
        } ||
        brew install caskroom/cask/perforce
        case "$jobname" in
index 402c1ad..b523014 100644 (file)
 
 static const int delay[] = { 0, 1, 10, 20, 40 };
 
+void open_in_gdb(void)
+{
+       static struct child_process cp = CHILD_PROCESS_INIT;
+       extern char *_pgmptr;
+
+       argv_array_pushl(&cp.args, "mintty", "gdb", NULL);
+       argv_array_pushf(&cp.args, "--pid=%d", getpid());
+       cp.clean_on_exit = 1;
+       if (start_command(&cp) < 0)
+               die_errno("Could not start gdb");
+       sleep(1);
+}
+
 int err_win_to_posix(DWORD winerr)
 {
        int error = ENOSYS;
index 714bc1d..e6fe810 100644 (file)
@@ -599,6 +599,16 @@ int wmain(int argc, const wchar_t **w_argv);
 int main(int argc, const char **argv);
 
 /*
+ * For debugging: if a problem occurs, say, in a Git process that is spawned
+ * from another Git process which in turn is spawned from yet another Git
+ * process, it can be quite daunting to figure out what is going on.
+ *
+ * Call this function to open a new MinTTY (this assumes you are in Git for
+ * Windows' SDK) with a GDB that attaches to the current process right away.
+ */
+extern void open_in_gdb(void);
+
+/*
  * Used by Pthread API implementation for Windows
  */
 int err_win_to_posix(DWORD winerr);
index 01e7c81..f90a46d 100644 (file)
@@ -135,8 +135,10 @@ extern "C" {
    alignment relative to 0.  */
 
 #define __PTR_ALIGN(B, P, A)                                               \
-  __BPTR_ALIGN (sizeof (PTR_INT_TYPE) < sizeof (void *) ? (B) : (char *) 0, \
-               P, A)
+  (sizeof (PTR_INT_TYPE) < sizeof(void *) ?                                 \
+   __BPTR_ALIGN((B), (P), (A)) :                                            \
+   (void *)__BPTR_ALIGN((PTR_INT_TYPE)(void *)0, (PTR_INT_TYPE)(P), (A))            \
+  )
 
 #include <string.h>
 
index 0e95dd4..afa6d24 100644 (file)
@@ -139,22 +139,10 @@ win32_compute_revents (HANDLE h, int *p_sought)
   INPUT_RECORD *irbuffer;
   DWORD avail, nbuffer;
   BOOL bRet;
-  IO_STATUS_BLOCK iosb;
-  FILE_PIPE_LOCAL_INFORMATION fpli;
-  static PNtQueryInformationFile NtQueryInformationFile;
-  static BOOL once_only;
 
   switch (GetFileType (h))
     {
     case FILE_TYPE_PIPE:
-      if (!once_only)
-       {
-         NtQueryInformationFile = (PNtQueryInformationFile)(void (*)(void))
-           GetProcAddress (GetModuleHandleW (L"ntdll.dll"),
-                           "NtQueryInformationFile");
-         once_only = TRUE;
-       }
-
       happened = 0;
       if (PeekNamedPipe (h, NULL, 0, NULL, &avail, NULL) != 0)
        {
@@ -166,22 +154,9 @@ win32_compute_revents (HANDLE h, int *p_sought)
 
       else
        {
-         /* It was the write-end of the pipe.  Check if it is writable.
-            If NtQueryInformationFile fails, optimistically assume the pipe is
-            writable.  This could happen on Win9x, where NtQueryInformationFile
-            is not available, or if we inherit a pipe that doesn't permit
-            FILE_READ_ATTRIBUTES access on the write end (I think this should
-            not happen since WinXP SP2; WINE seems fine too).  Otherwise,
-            ensure that enough space is available for atomic writes.  */
-         memset (&iosb, 0, sizeof (iosb));
-         memset (&fpli, 0, sizeof (fpli));
-
-         if (!NtQueryInformationFile
-             || NtQueryInformationFile (h, &iosb, &fpli, sizeof (fpli),
-                                        FilePipeLocalInformation)
-             || fpli.WriteQuotaAvailable >= PIPE_BUF
-             || (fpli.OutboundQuota < PIPE_BUF &&
-                 fpli.WriteQuotaAvailable == fpli.OutboundQuota))
+         /* It was the write-end of the pipe. Unfortunately there is no
+            reliable way of knowing if it can be written without blocking.
+            Just say that it's all good. */
            happened |= *p_sought & (POLLOUT | POLLWRNORM | POLLWRBAND);
        }
       return happened;
index 5772d50..a5a3ee9 100644 (file)
  * return status;
  * }
  * -----------------------------------------------------------------------
- *
- * Credential Helpers
- * ------------------
- *
- * Credential helpers are programs executed by Git to fetch or save
- * credentials from and to long-term storage (where "long-term" is simply
- * longer than a single Git process; e.g., credentials may be stored
- * in-memory for a few minutes, or indefinitely on disk).
- *
- * Each helper is specified by a single string in the configuration
- * variable `credential.helper` (and others, see Documentation/git-config.txt).
- * The string is transformed by Git into a command to be executed using
- * these rules:
- *
- *   1. If the helper string begins with "!", it is considered a shell
- *      snippet, and everything after the "!" becomes the command.
- *
- *   2. Otherwise, if the helper string begins with an absolute path, the
- *      verbatim helper string becomes the command.
- *
- *   3. Otherwise, the string "git credential-" is prepended to the helper
- *      string, and the result becomes the command.
- *
- * The resulting command then has an "operation" argument appended to it
- * (see below for details), and the result is executed by the shell.
- *
- * Here are some example specifications:
- *
- * ----------------------------------------------------
- * # run "git credential-foo"
- * foo
- *
- * # same as above, but pass an argument to the helper
- * foo --bar=baz
- *
- * # the arguments are parsed by the shell, so use shell
- * # quoting if necessary
- * foo --bar="whitespace arg"
- *
- * # you can also use an absolute path, which will not use the git wrapper
- * /path/to/my/helper --with-arguments
- *
- * # or you can specify your own shell snippet
- * !f() { echo "password=`cat $HOME/.secret`"; }; f
- * ----------------------------------------------------
- *
- * Generally speaking, rule (3) above is the simplest for users to specify.
- * Authors of credential helpers should make an effort to assist their
- * users by naming their program "git-credential-$NAME", and putting it in
- * the $PATH or $GIT_EXEC_PATH during installation, which will allow a user
- * to enable it with `git config credential.helper $NAME`.
- *
- * When a helper is executed, it will have one "operation" argument
- * appended to its command line, which is one of:
- *
- * `get`::
- *
- *     Return a matching credential, if any exists.
- *
- * `store`::
- *
- *     Store the credential, if applicable to the helper.
- *
- * `erase`::
- *
- *     Remove a matching credential, if any, from the helper's storage.
- *
- * The details of the credential will be provided on the helper's stdin
- * stream. The exact format is the same as the input/output format of the
- * `git credential` plumbing command (see the section `INPUT/OUTPUT
- * FORMAT` in Documentation/git-credential.txt for a detailed specification).
- *
- * For a `get` operation, the helper should produce a list of attributes
- * on stdout in the same format. A helper is free to produce a subset, or
- * even no values at all if it has nothing useful to provide. Any provided
- * attributes will overwrite those already known about by Git.  If a helper
- * outputs a `quit` attribute with a value of `true` or `1`, no further
- * helpers will be consulted, nor will the user be prompted (if no
- * credential has been provided, the operation will then fail).
- *
- * For a `store` or `erase` operation, the helper's output is ignored.
- * If it fails to perform the requested operation, it may complain to
- * stderr to inform the user. If it does not support the requested
- * operation (e.g., a read-only store), it should silently ignore the
- * request.
- *
- * If a helper receives any other operation, it should silently ignore the
- * request. This leaves room for future operations to be added (older
- * helpers will just ignore the new requests).
- *
  */
 
 
index 5134ce2..131e7d5 100644 (file)
@@ -207,55 +207,6 @@ found_duplicate_status:
        FREE_AND_NULL(sigc->key);
 }
 
-static int verify_signed_buffer(const char *payload, size_t payload_size,
-                               const char *signature, size_t signature_size,
-                               struct strbuf *gpg_output,
-                               struct strbuf *gpg_status)
-{
-       struct child_process gpg = CHILD_PROCESS_INIT;
-       struct gpg_format *fmt;
-       struct tempfile *temp;
-       int ret;
-       struct strbuf buf = STRBUF_INIT;
-
-       temp = mks_tempfile_t(".git_vtag_tmpXXXXXX");
-       if (!temp)
-               return error_errno(_("could not create temporary file"));
-       if (write_in_full(temp->fd, signature, signature_size) < 0 ||
-           close_tempfile_gently(temp) < 0) {
-               error_errno(_("failed writing detached signature to '%s'"),
-                           temp->filename.buf);
-               delete_tempfile(&temp);
-               return -1;
-       }
-
-       fmt = get_format_by_sig(signature);
-       if (!fmt)
-               BUG("bad signature '%s'", signature);
-
-       argv_array_push(&gpg.args, fmt->program);
-       argv_array_pushv(&gpg.args, fmt->verify_args);
-       argv_array_pushl(&gpg.args,
-                        "--status-fd=1",
-                        "--verify", temp->filename.buf, "-",
-                        NULL);
-
-       if (!gpg_status)
-               gpg_status = &buf;
-
-       sigchain_push(SIGPIPE, SIG_IGN);
-       ret = pipe_command(&gpg, payload, payload_size,
-                          gpg_status, 0, gpg_output, 0);
-       sigchain_pop(SIGPIPE);
-
-       delete_tempfile(&temp);
-
-       ret |= !strstr(gpg_status->buf, "\n[GNUPG:] GOODSIG ");
-       strbuf_release(&buf); /* no matter it was used or not */
-
-       return ret;
-}
-
 int check_signature(const char *payload, size_t plen, const char *signature,
        size_t slen, struct signature_check *sigc)
 {
@@ -400,3 +351,51 @@ int sign_buffer(struct strbuf *buffer, struct strbuf *signature, const char *sig
 
        return 0;
 }
+
+int verify_signed_buffer(const char *payload, size_t payload_size,
+                        const char *signature, size_t signature_size,
+                        struct strbuf *gpg_output, struct strbuf *gpg_status)
+{
+       struct child_process gpg = CHILD_PROCESS_INIT;
+       struct gpg_format *fmt;
+       struct tempfile *temp;
+       int ret;
+       struct strbuf buf = STRBUF_INIT;
+
+       temp = mks_tempfile_t(".git_vtag_tmpXXXXXX");
+       if (!temp)
+               return error_errno(_("could not create temporary file"));
+       if (write_in_full(temp->fd, signature, signature_size) < 0 ||
+           close_tempfile_gently(temp) < 0) {
+               error_errno(_("failed writing detached signature to '%s'"),
+                           temp->filename.buf);
+               delete_tempfile(&temp);
+               return -1;
+       }
+
+       fmt = get_format_by_sig(signature);
+       if (!fmt)
+               BUG("bad signature '%s'", signature);
+
+       argv_array_push(&gpg.args, fmt->program);
+       argv_array_pushv(&gpg.args, fmt->verify_args);
+       argv_array_pushl(&gpg.args,
+                        "--status-fd=1",
+                        "--verify", temp->filename.buf, "-",
+                        NULL);
+
+       if (!gpg_status)
+               gpg_status = &buf;
+
+       sigchain_push(SIGPIPE, SIG_IGN);
+       ret = pipe_command(&gpg, payload, payload_size,
+                          gpg_status, 0, gpg_output, 0);
+       sigchain_pop(SIGPIPE);
+
+       delete_tempfile(&temp);
+
+       ret |= !strstr(gpg_status->buf, "\n[GNUPG:] GOODSIG ");
+       strbuf_release(&buf); /* no matter it was used or not */
+
+       return ret;
+}
index 93cc3af..3e624ec 100644 (file)
@@ -46,6 +46,15 @@ size_t parse_signature(const char *buf, size_t size);
 int sign_buffer(struct strbuf *buffer, struct strbuf *signature,
                const char *signing_key);
 
+/*
+ * Run "gpg" to see if the payload matches the detached signature.
+ * gpg_output, when set, receives the diagnostic output from GPG.
+ * gpg_status, when set, receives the status output from GPG.
+ */
+int verify_signed_buffer(const char *payload, size_t payload_size,
+                        const char *signature, size_t signature_size,
+                        struct strbuf *gpg_output, struct strbuf *gpg_status);
+
 int git_gpg_config(const char *, const char *, void *);
 void set_signing_key(const char *);
 const char *get_signing_key(void);
index 4e32638..32d17c9 100644 (file)
@@ -449,22 +449,22 @@ static void show_signature(struct rev_info *opt, struct commit *commit)
 {
        struct strbuf payload = STRBUF_INIT;
        struct strbuf signature = STRBUF_INIT;
-       struct signature_check sigc = { 0 };
+       struct strbuf gpg_output = STRBUF_INIT;
        int status;
 
        if (parse_signed_commit(commit, &payload, &signature) <= 0)
                goto out;
 
-       status = check_signature(payload.buf, payload.len, signature.buf,
-                                signature.len, &sigc);
-       if (status && sigc.result == 'N')
-               show_sig_lines(opt, status, "No signature\n");
-       else {
-               show_sig_lines(opt, status, sigc.gpg_output);
-               signature_check_clear(&sigc);
-       }
+       status = verify_signed_buffer(payload.buf, payload.len,
+                                     signature.buf, signature.len,
+                                     &gpg_output, NULL);
+       if (status && !gpg_output.len)
+               strbuf_addstr(&gpg_output, "No signature\n");
+
+       show_sig_lines(opt, status, gpg_output.buf);
 
  out:
+       strbuf_release(&gpg_output);
        strbuf_release(&payload);
        strbuf_release(&signature);
 }
@@ -497,7 +497,6 @@ static int show_one_mergetag(struct commit *commit,
        struct object_id oid;
        struct tag *tag;
        struct strbuf verify_message;
-       struct signature_check sigc = { 0 };
        int status, nth;
        size_t payload_size, gpg_message_offset;
 
@@ -516,7 +515,7 @@ static int show_one_mergetag(struct commit *commit,
                            "merged tag '%s'\n", tag->tag);
        else if ((nth = which_parent(&tag->tagged->oid, commit)) < 0)
                strbuf_addf(&verify_message, "tag %s names a non-parent %s\n",
-                                   tag->tag, tag->tagged->oid.hash);
+                                   tag->tag, oid_to_hex(&tag->tagged->oid));
        else
                strbuf_addf(&verify_message,
                            "parent #%d, tagged '%s'\n", nth + 1, tag->tag);
@@ -526,13 +525,12 @@ static int show_one_mergetag(struct commit *commit,
        status = -1;
        if (extra->len > payload_size) {
                /* could have a good signature */
-               if (!check_signature(extra->value, payload_size,
-                                    extra->value + payload_size,
-                                    extra->len - payload_size, &sigc)) {
-                       strbuf_addstr(&verify_message, sigc.gpg_output);
-                       signature_check_clear(&sigc);
+               if (!verify_signed_buffer(extra->value, payload_size,
+                                         extra->value + payload_size,
+                                         extra->len - payload_size,
+                                         &verify_message, NULL))
                        status = 0; /* good */
-               else if (verify_message.len <= gpg_message_offset)
+               else if (verify_message.len <= gpg_message_offset)
                        strbuf_addstr(&verify_message, "No signature\n");
                /* otherwise we couldn't verify, which is shown as bad */
        }
index 10dca56..e6f943c 100644 (file)
@@ -998,10 +998,13 @@ static int update_file_flags(struct merge_options *opt,
                free(buf);
        }
 update_index:
-       if (!ret && update_cache)
-               if (add_cacheinfo(opt, contents, path, 0, update_wd,
+       if (!ret && update_cache) {
+               int refresh = (!opt->priv->call_depth &&
+                              contents->mode != S_IFGITLINK);
+               if (add_cacheinfo(opt, contents, path, 0, refresh,
                                  ADD_CACHE_OK_TO_ADD))
                        return -1;
+       }
        return ret;
 }
 
@@ -1712,6 +1715,14 @@ static char *find_path_for_conflict(struct merge_options *opt,
        return new_path;
 }
 
+/*
+ * Toggle the stage number between "ours" and "theirs" (2 and 3).
+ */
+static inline int flip_stage(int stage)
+{
+       return (2 + 3) - stage;
+}
+
 static int handle_rename_rename_1to2(struct merge_options *opt,
                                     struct rename_conflict_info *ci)
 {
@@ -1756,14 +1767,14 @@ static int handle_rename_rename_1to2(struct merge_options *opt,
                 * such cases, we should keep the added file around,
                 * resolving the conflict at that path in its favor.
                 */
-               add = &ci->ren1->dst_entry->stages[2 ^ 1];
+               add = &ci->ren1->dst_entry->stages[flip_stage(2)];
                if (is_valid(add)) {
                        if (update_file(opt, 0, add, a->path))
                                return -1;
                }
                else
                        remove_file_from_index(opt->repo->index, a->path);
-               add = &ci->ren2->dst_entry->stages[3 ^ 1];
+               add = &ci->ren2->dst_entry->stages[flip_stage(3)];
                if (is_valid(add)) {
                        if (update_file(opt, 0, add, b->path))
                                return -1;
@@ -1776,7 +1787,7 @@ static int handle_rename_rename_1to2(struct merge_options *opt,
                 * rename/add collision.  If not, we can write the file out
                 * to the specified location.
                 */
-               add = &ci->ren1->dst_entry->stages[2 ^ 1];
+               add = &ci->ren1->dst_entry->stages[flip_stage(2)];
                if (is_valid(add)) {
                        add->path = mfi.blob.path = a->path;
                        if (handle_file_collision(opt, a->path,
@@ -1797,7 +1808,7 @@ static int handle_rename_rename_1to2(struct merge_options *opt,
                                return -1;
                }
 
-               add = &ci->ren2->dst_entry->stages[3 ^ 1];
+               add = &ci->ren2->dst_entry->stages[flip_stage(3)];
                if (is_valid(add)) {
                        add->path = mfi.blob.path = b->path;
                        if (handle_file_collision(opt, b->path,
@@ -1846,7 +1857,7 @@ static int handle_rename_rename_2to1(struct merge_options *opt,
        path_side_1_desc = xstrfmt("version of %s from %s", path, a->path);
        path_side_2_desc = xstrfmt("version of %s from %s", path, b->path);
        ostage1 = ci->ren1->branch == opt->branch1 ? 3 : 2;
-       ostage2 = ostage1 ^ 1;
+       ostage2 = flip_stage(ostage1);
        ci->ren1->src_entry->stages[ostage1].path = a->path;
        ci->ren2->src_entry->stages[ostage2].path = b->path;
        if (merge_mode_and_contents(opt, a, c1,
diff --git a/notes.c b/notes.c
index 0c79964..2de7f4b 100644 (file)
--- a/notes.c
+++ b/notes.c
@@ -576,16 +576,16 @@ redo:
                         * the note tree that have not yet been explored. There
                         * is a direct relationship between subtree entries at
                         * level 'n' in the tree, and the 'fanout' variable:
-                        * Subtree entries at level 'n <= 2 * fanout' should be
+                        * Subtree entries at level 'n < 2 * fanout' should be
                         * preserved, since they correspond exactly to a fanout
                         * directory in the on-disk structure. However, subtree
-                        * entries at level 'n > 2 * fanout' should NOT be
+                        * entries at level 'n >= 2 * fanout' should NOT be
                         * preserved, but rather consolidated into the above
                         * notes tree level. We achieve this by unconditionally
                         * unpacking subtree entries that exist below the
                         * threshold level at 'n = 2 * fanout'.
                         */
-                       if (n <= 2 * fanout &&
+                       if (n < 2 * fanout &&
                            flags & FOR_EACH_NOTE_YIELD_SUBTREES) {
                                /* invoke callback with subtree */
                                unsigned int path_len =
@@ -602,7 +602,7 @@ redo:
                                         path,
                                         cb_data);
                        }
-                       if (n > fanout * 2 ||
+                       if (n >= 2 * fanout ||
                            !(flags & FOR_EACH_NOTE_DONT_UNPACK_SUBTREES)) {
                                /* unpack subtree and resume traversal */
                                tree->a[i] = NULL;
@@ -723,13 +723,15 @@ static int write_each_note_helper(struct tree_write_stack *tws,
 
 struct write_each_note_data {
        struct tree_write_stack *root;
-       struct non_note *next_non_note;
+       struct non_note **nn_list;
+       struct non_note *nn_prev;
 };
 
 static int write_each_non_note_until(const char *note_path,
                struct write_each_note_data *d)
 {
-       struct non_note *n = d->next_non_note;
+       struct non_note *p = d->nn_prev;
+       struct non_note *n = p ? p->next : *d->nn_list;
        int cmp = 0, ret;
        while (n && (!note_path || (cmp = strcmp(n->path, note_path)) <= 0)) {
                if (note_path && cmp == 0)
@@ -740,9 +742,10 @@ static int write_each_non_note_until(const char *note_path,
                        if (ret)
                                return ret;
                }
+               p = n;
                n = n->next;
        }
-       d->next_non_note = n;
+       d->nn_prev = p;
        return 0;
 }
 
@@ -1177,7 +1180,8 @@ int write_notes_tree(struct notes_tree *t, struct object_id *result)
        strbuf_init(&root.buf, 256 * (32 + the_hash_algo->hexsz)); /* assume 256 entries */
        root.path[0] = root.path[1] = '\0';
        cb_data.root = &root;
-       cb_data.next_non_note = t->first_non_note;
+       cb_data.nn_list = &(t->first_non_note);
+       cb_data.nn_prev = NULL;
 
        /* Write tree objects representing current notes tree */
        flags = FOR_EACH_NOTE_DONT_UNPACK_SUBTREES |
index 128f27f..8243e06 100644 (file)
@@ -438,8 +438,13 @@ static void init_pathspec_item(struct pathspec_item *item, unsigned flags,
        } else {
                match = prefix_path_gently(prefix, prefixlen,
                                           &prefixlen, copyfrom);
-               if (!match)
-                       die(_("%s: '%s' is outside repository"), elt, copyfrom);
+               if (!match) {
+                       const char *hint_path = get_git_work_tree();
+                       if (!hint_path)
+                               hint_path = get_git_dir();
+                       die(_("%s: '%s' is outside repository at '%s'"), elt,
+                           copyfrom, absolute_path(hint_path));
+               }
        }
 
        item->match = match;
index aa18ae8..1259adc 100644 (file)
@@ -104,9 +104,11 @@ int edit_todo_list(struct repository *r, struct todo_list *todo_list,
                                    -1, flags | TODO_LIST_SHORTEN_IDS | TODO_LIST_APPEND_TODO_HELP))
                return error_errno(_("could not write '%s'"), todo_file);
 
-       if (initial && copy_file(rebase_path_todo_backup(), todo_file, 0666))
-               return error(_("could not copy '%s' to '%s'."), todo_file,
-                            rebase_path_todo_backup());
+       if (initial &&
+           todo_list_write_to_file(r, todo_list, rebase_path_todo_backup(),
+                                   shortrevisions, shortonto, -1,
+                                   (flags | TODO_LIST_APPEND_TODO_HELP) & ~TODO_LIST_SHORTEN_IDS) < 0)
+               return error(_("could not write '%s'."), rebase_path_todo_backup());
 
        if (launch_sequence_editor(todo_file, &new_todo->buf, NULL))
                return -2;
index 592d9dc..0f3cc73 100644 (file)
@@ -116,7 +116,7 @@ struct child_process {
        unsigned no_stdin:1;
        unsigned no_stdout:1;
        unsigned no_stderr:1;
-    unsigned git_cmd:1; /* if this is to be git sub-command */
+       unsigned git_cmd:1; /* if this is to be git sub-command */
 
        /**
         * If the program cannot be found, the functions return -1 and set
index b9dbf1a..df6d18f 100644 (file)
@@ -588,7 +588,7 @@ static int do_recursive_merge(struct repository *r,
        struct merge_options o;
        struct tree *next_tree, *base_tree, *head_tree;
        int clean;
-       char **xopt;
+       int i;
        struct lock_file index_lock = LOCK_INIT;
 
        if (repo_hold_locked_index(r, &index_lock, LOCK_REPORT_ON_ERROR) < 0)
@@ -608,8 +608,8 @@ static int do_recursive_merge(struct repository *r,
        next_tree = next ? get_commit_tree(next) : empty_tree(r);
        base_tree = base ? get_commit_tree(base) : empty_tree(r);
 
-       for (xopt = opts->xopts; xopt != opts->xopts + opts->xopts_nr; xopt++)
-               parse_merge_opt(&o, *xopt);
+       for (i = 0; i < opts->xopts_nr; i++)
+               parse_merge_opt(&o, opts->xopts[i]);
 
        clean = merge_trees(&o,
                            head_tree,
@@ -2118,6 +2118,8 @@ static int parse_insn_line(struct repository *r, struct todo_item *item,
        saved = *end_of_object_name;
        *end_of_object_name = '\0';
        status = get_oid(bol, &commit_oid);
+       if (status < 0)
+               error(_("could not parse '%s'"), bol); /* return later */
        *end_of_object_name = saved;
 
        bol = end_of_object_name + strspn(end_of_object_name, " \t");
@@ -2125,11 +2127,10 @@ static int parse_insn_line(struct repository *r, struct todo_item *item,
        item->arg_len = (int)(eol - bol);
 
        if (status < 0)
-               return error(_("could not parse '%.*s'"),
-                            (int)(end_of_object_name - bol), bol);
+               return status;
 
        item->commit = lookup_commit_reference(r, &commit_oid);
-       return !item->commit;
+       return item->commit ? 0 : -1;
 }
 
 int sequencer_get_last_command(struct repository *r, enum replay_action *action)
@@ -5075,7 +5076,7 @@ int complete_action(struct repository *r, struct replay_opts *opts, unsigned fla
 {
        const char *shortonto, *todo_file = rebase_path_todo();
        struct todo_list new_todo = TODO_LIST_INIT;
-       struct strbuf *buf = &todo_list->buf;
+       struct strbuf *buf = &todo_list->buf, buf2 = STRBUF_INIT;
        struct object_id oid = onto->object.oid;
        int res;
 
@@ -5127,6 +5128,15 @@ int complete_action(struct repository *r, struct replay_opts *opts, unsigned fla
                return -1;
        }
 
+       /* Expand the commit IDs */
+       todo_list_to_strbuf(r, &new_todo, &buf2, -1, 0);
+       strbuf_swap(&new_todo.buf, &buf2);
+       strbuf_release(&buf2);
+       new_todo.total_nr -= new_todo.nr;
+       if (todo_list_parse_insn_buffer(r, new_todo.buf.buf, &new_todo) < 0)
+               BUG("invalid todo list after expanding IDs:\n%s",
+                   new_todo.buf.buf);
+
        if (opts->allow_ff && skip_unnecessary_picks(r, &new_todo, &oid)) {
                todo_list_release(&new_todo);
                return error(_("could not skip unnecessary pick commands"));
diff --git a/setup.c b/setup.c
index e2a479a..f489728 100644 (file)
--- a/setup.c
+++ b/setup.c
@@ -120,8 +120,13 @@ char *prefix_path_gently(const char *prefix, int len,
 char *prefix_path(const char *prefix, int len, const char *path)
 {
        char *r = prefix_path_gently(prefix, len, NULL, path);
-       if (!r)
-               die(_("'%s' is outside repository"), path);
+       if (!r) {
+               const char *hint_path = get_git_work_tree();
+               if (!hint_path)
+                       hint_path = get_git_dir();
+               die(_("'%s' is outside repository at '%s'"), path,
+                   absolute_path(hint_path));
+       }
        return r;
 }
 
index 6b86744..9f4c4c0 100644 (file)
@@ -82,7 +82,7 @@ int is_staging_gitmodules_ok(struct index_state *istate)
        if ((pos >= 0) && (pos < istate->cache_nr)) {
                struct stat st;
                if (lstat(GITMODULES_FILE, &st) == 0 &&
-                   ie_match_stat(istate, istate->cache[pos], &st, 0) & DATA_CHANGED)
+                   ie_modified(istate, istate->cache[pos], &st, 0) & DATA_CHANGED)
                        return 0;
        }
 
@@ -1811,7 +1811,7 @@ out:
 void submodule_unset_core_worktree(const struct submodule *sub)
 {
        char *config_path = xstrfmt("%s/modules/%s/config",
-                                   get_git_common_dir(), sub->name);
+                                   get_git_dir(), sub->name);
 
        if (git_config_set_in_file_gently(config_path, "core.worktree", NULL))
                warning(_("Could not unset core.worktree setting in submodule '%s'"),
@@ -1914,7 +1914,7 @@ int submodule_move_head(const char *path,
                                        ABSORB_GITDIR_RECURSE_SUBMODULES);
                } else {
                        char *gitdir = xstrfmt("%s/modules/%s",
-                                   get_git_common_dir(), sub->name);
+                                   get_git_dir(), sub->name);
                        connect_work_tree_and_git_dir(path, gitdir, 0);
                        free(gitdir);
 
@@ -1924,7 +1924,7 @@ int submodule_move_head(const char *path,
 
                if (old_head && (flags & SUBMODULE_MOVE_HEAD_FORCE)) {
                        char *gitdir = xstrfmt("%s/modules/%s",
-                                   get_git_common_dir(), sub->name);
+                                   get_git_dir(), sub->name);
                        connect_work_tree_and_git_dir(path, gitdir, 1);
                        free(gitdir);
                }
index 656997b..1449ee9 100644 (file)
@@ -132,7 +132,7 @@ prepare_httpd() {
        install_script broken-smart-http.sh
        install_script error-smart-http.sh
        install_script error.sh
-       install_script apply-one-time-sed.sh
+       install_script apply-one-time-perl.sh
 
        ln -s "$LIB_HTTPD_MODULE_PATH" "$HTTPD_ROOT_PATH/modules"
 
index 5c1c86c..994e529 100644 (file)
@@ -113,7 +113,7 @@ Alias /auth/dumb/ www/auth/dumb/
        SetEnv GIT_EXEC_PATH ${GIT_EXEC_PATH}
        SetEnv GIT_HTTP_EXPORT_ALL
 </LocationMatch>
-<LocationMatch /one_time_sed/>
+<LocationMatch /one_time_perl/>
        SetEnv GIT_EXEC_PATH ${GIT_EXEC_PATH}
        SetEnv GIT_HTTP_EXPORT_ALL
 </LocationMatch>
@@ -122,7 +122,7 @@ ScriptAliasMatch /smart_*[^/]*/(.*) ${GIT_EXEC_PATH}/git-http-backend/$1
 ScriptAlias /broken_smart/ broken-smart-http.sh/
 ScriptAlias /error_smart/ error-smart-http.sh/
 ScriptAlias /error/ error.sh/
-ScriptAliasMatch /one_time_sed/(.*) apply-one-time-sed.sh/$1
+ScriptAliasMatch /one_time_perl/(.*) apply-one-time-perl.sh/$1
 <Directory ${GIT_EXEC_PATH}>
        Options FollowSymlinks
 </Directory>
@@ -135,7 +135,7 @@ ScriptAliasMatch /one_time_sed/(.*) apply-one-time-sed.sh/$1
 <Files error.sh>
   Options ExecCGI
 </Files>
-<Files apply-one-time-sed.sh>
+<Files apply-one-time-perl.sh>
        Options ExecCGI
 </Files>
 <Files ${GIT_EXEC_PATH}/git-http-backend>
diff --git a/t/lib-httpd/apply-one-time-perl.sh b/t/lib-httpd/apply-one-time-perl.sh
new file mode 100644 (file)
index 0000000..09a0abd
--- /dev/null
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+# If "one-time-perl" exists in $HTTPD_ROOT_PATH, run perl on the HTTP response,
+# using the contents of "one-time-perl" as the perl command to be run. If the
+# response was modified as a result, delete "one-time-perl" so that subsequent
+# HTTP responses are no longer modified.
+#
+# This can be used to simulate the effects of the repository changing in
+# between HTTP request-response pairs.
+if test -f one-time-perl
+then
+       LC_ALL=C
+       export LC_ALL
+
+       "$GIT_EXEC_PATH/git-http-backend" >out
+       perl -pe "$(cat one-time-perl)" out >out_modified
+
+       if cmp -s out out_modified
+       then
+               cat out
+       else
+               cat out_modified
+               rm one-time-perl
+       fi
+else
+       "$GIT_EXEC_PATH/git-http-backend"
+fi
diff --git a/t/lib-httpd/apply-one-time-sed.sh b/t/lib-httpd/apply-one-time-sed.sh
deleted file mode 100644 (file)
index bf7689d..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-#!/bin/sh
-
-# If "one-time-sed" exists in $HTTPD_ROOT_PATH, run sed on the HTTP response,
-# using the contents of "one-time-sed" as the sed command to be run. If the
-# response was modified as a result, delete "one-time-sed" so that subsequent
-# HTTP responses are no longer modified.
-#
-# This can be used to simulate the effects of the repository changing in
-# between HTTP request-response pairs.
-if test -f one-time-sed
-then
-       "$GIT_EXEC_PATH/git-http-backend" >out
-       sed "$(cat one-time-sed)" out >out_modified
-
-       if cmp -s out out_modified
-       then
-               cat out
-       else
-               cat out_modified
-               rm one-time-sed
-       fi
-else
-       "$GIT_EXEC_PATH/git-http-backend"
-fi
index 1744cee..370a389 100755 (executable)
@@ -424,9 +424,24 @@ test_expect_success 'local ignore inside a sub-directory with --verbose' '
        )
 '
 
-test_expect_success_multi 'nested include' \
-       'a/b/.gitignore:8:!on*  a/b/one' '
-       test_check_ignore "a/b/one"
+test_expect_success 'nested include of negated pattern' '
+       expect "" &&
+       test_check_ignore "a/b/one" 1
+'
+
+test_expect_success 'nested include of negated pattern with -q' '
+       expect "" &&
+       test_check_ignore "-q a/b/one" 1
+'
+
+test_expect_success 'nested include of negated pattern with -v' '
+       expect "a/b/.gitignore:8:!on*   a/b/one" &&
+       test_check_ignore "-v a/b/one" 0
+'
+
+test_expect_success 'nested include of negated pattern with -v -n' '
+       expect "a/b/.gitignore:8:!on*   a/b/one" &&
+       test_check_ignore "-v -n a/b/one" 0
 '
 
 ############################################################################
@@ -460,7 +475,6 @@ test_expect_success 'cd to ignored sub-directory' '
        expect_from_stdin <<-\EOF &&
                foo
                twoooo
-               ../one
                seven
                ../../one
        EOF
@@ -543,7 +557,6 @@ test_expect_success 'global ignore' '
                globalthree
                a/globalthree
                a/per-repo
-               globaltwo
        EOF
        test_check_ignore "globalone per-repo globalthree a/globalthree a/per-repo not-ignored globaltwo"
 '
@@ -586,17 +599,7 @@ EOF
 cat <<-\EOF >expected-default
        one
        a/one
-       a/b/on
-       a/b/one
-       a/b/one one
-       a/b/one two
-       "a/b/one\"three"
-       a/b/two
        a/b/twooo
-       globaltwo
-       a/globaltwo
-       a/b/globaltwo
-       b/globaltwo
 EOF
 cat <<-EOF >expected-verbose
        .gitignore:1:one        one
@@ -696,8 +699,12 @@ cat <<-EOF >expected-all
        $global_excludes:2:!globaltwo   ../b/globaltwo
        ::      c/not-ignored
 EOF
+cat <<-EOF >expected-default
+../one
+one
+b/twooo
+EOF
 grep -v '^::   ' expected-all >expected-verbose
-sed -e 's/.*   //' expected-verbose >expected-default
 
 broken_c_unquote stdin >stdin0
 
diff --git a/t/t2405-worktree-submodule.sh b/t/t2405-worktree-submodule.sh
new file mode 100755 (executable)
index 0000000..e1b2bfd
--- /dev/null
@@ -0,0 +1,90 @@
+#!/bin/sh
+
+test_description='Combination of submodules and multiple worktrees'
+
+. ./test-lib.sh
+
+base_path=$(pwd -P)
+
+test_expect_success 'setup: create origin repos'  '
+       git init origin/sub &&
+       test_commit -C origin/sub file1 &&
+       git init origin/main &&
+       test_commit -C origin/main first &&
+       git -C origin/main submodule add ../sub &&
+       git -C origin/main commit -m "add sub" &&
+       test_commit -C origin/sub "file1 updated" file1 file1updated file1updated &&
+       git -C origin/main/sub pull &&
+       git -C origin/main add sub &&
+       git -C origin/main commit -m "sub updated"
+'
+
+test_expect_success 'setup: clone superproject to create main worktree' '
+       git clone --recursive "$base_path/origin/main" main
+'
+
+rev1_hash_main=$(git --git-dir=origin/main/.git show --pretty=format:%h -q "HEAD~1")
+rev1_hash_sub=$(git --git-dir=origin/sub/.git show --pretty=format:%h -q "HEAD~1")
+
+test_expect_success 'add superproject worktree' '
+       git -C main worktree add "$base_path/worktree" "$rev1_hash_main"
+'
+
+test_expect_failure 'submodule is checked out just after worktree add' '
+       git -C worktree diff --submodule master"^!" >out &&
+       grep "file1 updated" out
+'
+
+test_expect_success 'add superproject worktree and initialize submodules' '
+       git -C main worktree add "$base_path/worktree-submodule-update" "$rev1_hash_main" &&
+       git -C worktree-submodule-update submodule update
+'
+
+test_expect_success 'submodule is checked out just after submodule update in linked worktree' '
+       git -C worktree-submodule-update diff --submodule master"^!" >out &&
+       grep "file1 updated" out
+'
+
+test_expect_success 'add superproject worktree and manually add submodule worktree' '
+       git -C main worktree add "$base_path/linked_submodule" "$rev1_hash_main" &&
+       git -C main/sub worktree add "$base_path/linked_submodule/sub" "$rev1_hash_sub"
+'
+
+test_expect_success 'submodule is checked out after manually adding submodule worktree' '
+       git -C linked_submodule diff --submodule master"^!" >out &&
+       grep "file1 updated" out
+'
+
+test_expect_success 'checkout --recurse-submodules uses $GIT_DIR for submodules in a linked worktree' '
+       git -C main worktree add "$base_path/checkout-recurse" --detach  &&
+       git -C checkout-recurse submodule update --init &&
+       echo "gitdir: ../../main/.git/worktrees/checkout-recurse/modules/sub" >expect-gitfile &&
+       cat checkout-recurse/sub/.git >actual-gitfile &&
+       test_cmp expect-gitfile actual-gitfile &&
+       git -C main/sub rev-parse HEAD >expect-head-main &&
+       git -C checkout-recurse checkout --recurse-submodules HEAD~1 &&
+       cat checkout-recurse/sub/.git >actual-gitfile &&
+       git -C main/sub rev-parse HEAD >actual-head-main &&
+       test_cmp expect-gitfile actual-gitfile &&
+       test_cmp expect-head-main actual-head-main
+'
+
+test_expect_success 'core.worktree is removed in $GIT_DIR/modules/<name>/config, not in $GIT_COMMON_DIR/modules/<name>/config' '
+       echo "../../../sub" >expect-main &&
+       git -C main/sub config --get core.worktree >actual-main &&
+       test_cmp expect-main actual-main &&
+       echo "../../../../../../checkout-recurse/sub" >expect-linked &&
+       git -C checkout-recurse/sub config --get core.worktree >actual-linked &&
+       test_cmp expect-linked actual-linked &&
+       git -C checkout-recurse checkout --recurse-submodules first &&
+       test_expect_code 1 git -C main/.git/worktrees/checkout-recurse/modules/sub config --get core.worktree >linked-config &&
+       test_must_be_empty linked-config &&
+       git -C main/sub config --get core.worktree >actual-main &&
+       test_cmp expect-main actual-main
+'
+
+test_expect_success 'unsetting core.worktree does not prevent running commands directly against the submodule repository' '
+       git -C main/.git/worktrees/checkout-recurse/modules/sub log
+'
+
+test_done
index 831f83d..3b4753e 100755 (executable)
@@ -4,6 +4,38 @@ test_description='Test that adding/removing many notes triggers automatic fanout
 
 . ./test-lib.sh
 
+path_has_fanout() {
+       path=$1 &&
+       fanout=$2 &&
+       after_last_slash=$((40 - $fanout * 2)) &&
+       echo $path | grep -q "^\([0-9a-f]\{2\}/\)\{$fanout\}[0-9a-f]\{$after_last_slash\}$"
+}
+
+touched_one_note_with_fanout() {
+       notes_commit=$1 &&
+       modification=$2 &&  # 'A' for addition, 'D' for deletion
+       fanout=$3 &&
+       diff=$(git diff-tree --no-commit-id --name-status --root -r $notes_commit) &&
+       path=$(echo $diff | sed -e "s/^$modification[\t ]//") &&
+       path_has_fanout "$path" $fanout;
+}
+
+all_notes_have_fanout() {
+       notes_commit=$1 &&
+       fanout=$2 &&
+       git ls-tree -r --name-only $notes_commit 2>/dev/null |
+       while read path
+       do
+               path_has_fanout $path $fanout || return 1
+       done
+}
+
+test_expect_success 'tweak test environment' '
+       git checkout -b nondeterminism &&
+       test_commit A &&
+       git checkout --orphan with_notes;
+'
+
 test_expect_success 'creating many notes with git-notes' '
        num_notes=300 &&
        i=0 &&
@@ -20,7 +52,7 @@ test_expect_success 'creating many notes with git-notes' '
 
 test_expect_success 'many notes created correctly with git-notes' '
        git log | grep "^    " > output &&
-       i=300 &&
+       i=$num_notes &&
        while test $i -gt 0
        do
                echo "    commit #$i" &&
@@ -30,34 +62,46 @@ test_expect_success 'many notes created correctly with git-notes' '
        test_cmp expect output
 '
 
-test_expect_success 'many notes created with git-notes triggers fanout' '
-       # Expect entire notes tree to have a fanout == 1
-       git ls-tree -r --name-only refs/notes/commits |
-       while read path
+test_expect_success 'stable fanout 0 is followed by stable fanout 1' '
+       i=$num_notes &&
+       fanout=0 &&
+       while test $i -gt 0
        do
-               echo $path | grep "^../[0-9a-f]*$" || {
-                       echo "Invalid path \"$path\"" &&
-                       return 1;
-               }
-       done
+               i=$(($i - 1)) &&
+               if touched_one_note_with_fanout refs/notes/commits~$i A $fanout
+               then
+                       continue
+               elif test $fanout -eq 0
+               then
+                       fanout=1 &&
+                       if all_notes_have_fanout refs/notes/commits~$i $fanout
+                       then
+                               echo "Fanout 0 -> 1 at refs/notes/commits~$i" &&
+                               continue
+                       fi
+               fi &&
+               echo "Failed fanout=$fanout check at refs/notes/commits~$i" &&
+               git ls-tree -r --name-only refs/notes/commits~$i &&
+               return 1
+       done &&
+       all_notes_have_fanout refs/notes/commits 1
 '
 
 test_expect_success 'deleting most notes with git-notes' '
-       num_notes=250 &&
+       remove_notes=285 &&
        i=0 &&
        git rev-list HEAD |
-       while test $i -lt $num_notes && read sha1
+       while test $i -lt $remove_notes && read sha1
        do
                i=$(($i + 1)) &&
                test_tick &&
-               git notes remove "$sha1" ||
-               exit 1
+               git notes remove "$sha1" 2>/dev/null || return 1
        done
 '
 
 test_expect_success 'most notes deleted correctly with git-notes' '
-       git log HEAD~250 | grep "^    " > output &&
-       i=50 &&
+       git log HEAD~$remove_notes | grep "^    " > output &&
+       i=$(($num_notes - $remove_notes)) &&
        while test $i -gt 0
        do
                echo "    commit #$i" &&
@@ -67,16 +111,29 @@ test_expect_success 'most notes deleted correctly with git-notes' '
        test_cmp expect output
 '
 
-test_expect_success 'deleting most notes triggers fanout consolidation' '
-       # Expect entire notes tree to have a fanout == 0
-       git ls-tree -r --name-only refs/notes/commits |
-       while read path
+test_expect_success 'stable fanout 1 is followed by stable fanout 0' '
+       i=$remove_notes &&
+       fanout=1 &&
+       while test $i -gt 0
        do
-               echo $path | grep -v "^../.*" || {
-                       echo "Invalid path \"$path\"" &&
-                       return 1;
-               }
-       done
+               i=$(($i - 1)) &&
+               if touched_one_note_with_fanout refs/notes/commits~$i D $fanout
+               then
+                       continue
+               elif test $fanout -eq 1
+               then
+                       fanout=0 &&
+                       if all_notes_have_fanout refs/notes/commits~$i $fanout
+                       then
+                               echo "Fanout 1 -> 0 at refs/notes/commits~$i" &&
+                               continue
+                       fi
+               fi &&
+               echo "Failed fanout=$fanout check at refs/notes/commits~$i" &&
+               git ls-tree -r --name-only refs/notes/commits~$i &&
+               return 1
+       done &&
+       all_notes_have_fanout refs/notes/commits 0
 '
 
 test_done
index ae6e55c..b90ea0f 100755 (executable)
@@ -1264,13 +1264,26 @@ test_expect_success SHA1 'short SHA-1 setup' '
 test_expect_success SHA1 'short SHA-1 collide' '
        test_when_finished "reset_rebase && git checkout master" &&
        git checkout collide &&
+       colliding_sha1=6bcda37 &&
+       test $colliding_sha1 = "$(git rev-parse HEAD | cut -c 1-7)" &&
        (
                unset test_tick &&
                test_tick &&
                set_fake_editor &&
                FAKE_COMMIT_MESSAGE="collide2 ac4f2ee" \
-               FAKE_LINES="reword 1 2" git rebase -i HEAD~2
-       )
+               FAKE_LINES="reword 1 break 2" git rebase -i HEAD~2 &&
+               test $colliding_sha1 = "$(git rev-parse HEAD | cut -c 1-7)" &&
+               grep "^pick $colliding_sha1 " \
+                       .git/rebase-merge/git-rebase-todo.tmp &&
+               grep "^pick [0-9a-f]\{40\}" \
+                       .git/rebase-merge/git-rebase-todo &&
+               grep "^pick [0-9a-f]\{40\}" \
+                       .git/rebase-merge/git-rebase-todo.backup &&
+               git rebase --continue
+       ) &&
+       collide2="$(git rev-parse HEAD~1 | cut -c 1-4)" &&
+       collide3="$(git rev-parse collide3 | cut -c 1-4)" &&
+       test "$collide2" = "$collide3"
 '
 
 test_expect_success 'respect core.abbrev' '
diff --git a/t/t3433-rebase-across-mode-change.sh b/t/t3433-rebase-across-mode-change.sh
new file mode 100755 (executable)
index 0000000..05df964
--- /dev/null
@@ -0,0 +1,48 @@
+#!/bin/sh
+
+test_description='git rebase across mode change'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+       mkdir DS &&
+       >DS/whatever &&
+       git add DS &&
+       git commit -m base &&
+
+       git branch side1 &&
+       git branch side2 &&
+
+       git checkout side1 &&
+       git rm -rf DS &&
+       test_ln_s_add unrelated DS &&
+       git commit -m side1 &&
+
+       git checkout side2 &&
+       >unrelated &&
+       git add unrelated &&
+       git commit -m commit1 &&
+
+       echo >>unrelated &&
+       git commit -am commit2
+'
+
+test_expect_success 'rebase changes with the apply backend' '
+       test_when_finished "git rebase --abort || true" &&
+       git checkout -b apply-backend side2 &&
+       git rebase side1
+'
+
+test_expect_success 'rebase changes with the merge backend' '
+       test_when_finished "git rebase --abort || true" &&
+       git checkout -b merge-backend side2 &&
+       git rebase -m side1
+'
+
+test_expect_success 'rebase changes with the merge backend with a delay' '
+       test_when_finished "git rebase --abort || true" &&
+       git checkout -b merge-delay-backend side2 &&
+       git rebase -m --exec "sleep 1" side1
+'
+
+test_done
index 0ea858d..f2c0168 100755 (executable)
@@ -425,6 +425,13 @@ test_expect_success 'rm will error out on a modified .gitmodules file unless sta
        git status -s -uno >actual &&
        test_cmp expect actual
 '
+test_expect_success 'rm will not error out on .gitmodules file with zero stat data' '
+       git reset --hard &&
+       git submodule update &&
+       git read-tree HEAD &&
+       git rm submod &&
+       test_path_is_missing submod
+'
 
 test_expect_success 'rm issues a warning when section is not found in .gitmodules' '
        git reset --hard &&
index 12ee321..2182b1c 100755 (executable)
@@ -68,6 +68,15 @@ test_expect_success 'revert works (initial)' '
        ! grep . output
 '
 
+test_expect_success 'add untracked (multiple)' '
+       test_when_finished "git reset && rm [1-9]" &&
+       touch $(test_seq 9) &&
+       test_write_lines a "2-5 8-" | git add -i -- [1-9] &&
+       test_write_lines 2 3 4 5 8 9 >expected &&
+       git ls-files [1-9] >output &&
+       test_cmp expected output
+'
+
 test_expect_success 'setup (commit)' '
        echo baseline >file &&
        git add file &&
index 2c94894..c9c10ca 100755 (executable)
@@ -1631,6 +1631,26 @@ test_expect_success GPG 'log --graph --show-signature for merged tag' '
        grep "^| | gpg: Good signature" actual
 '
 
+test_expect_success GPG 'log --graph --show-signature for merged tag in shallow clone' '
+       test_when_finished "git reset --hard && git checkout master" &&
+       git checkout -b plain-shallow master &&
+       echo aaa >bar &&
+       git add bar &&
+       git commit -m bar_commit &&
+       git checkout --detach master &&
+       echo bbb >baz &&
+       git add baz &&
+       git commit -m baz_commit &&
+       git tag -s -m signed_tag_msg signed_tag_shallow &&
+       hash=$(git rev-parse HEAD) &&
+       git checkout plain-shallow &&
+       git merge --no-ff -m msg signed_tag_shallow &&
+       git clone --depth 1 --no-local . shallow &&
+       test_when_finished "rm -rf shallow" &&
+       git -C shallow log --graph --show-signature -n1 plain-shallow >actual &&
+       grep "tag signed_tag_shallow names a non-parent $hash" actual
+'
+
 test_expect_success GPGSM 'log --graph --show-signature for merged tag x509' '
        test_when_finished "git reset --hard && git checkout master" &&
        test_config gpg.format x509 &&
index 491556d..6c209ad 100755 (executable)
@@ -62,13 +62,13 @@ test_expect_success 'index-pack detects REF_DELTA cycles' '
        test_must_fail git index-pack --fix-thin --stdin <cycle.pack
 '
 
-test_expect_failure 'failover to an object in another pack' '
+test_expect_success 'failover to an object in another pack' '
        clear_packs &&
        git index-pack --stdin <ab.pack &&
-       git index-pack --stdin --fix-thin <cycle.pack
+       test_must_fail git index-pack --stdin --fix-thin <cycle.pack
 '
 
-test_expect_failure 'failover to a duplicate object in the same pack' '
+test_expect_success 'failover to a duplicate object in the same pack' '
        clear_packs &&
        {
                pack_header 3 &&
@@ -77,7 +77,7 @@ test_expect_failure 'failover to a duplicate object in the same pack' '
                pack_obj $A
        } >recoverable.pack &&
        pack_trailer recoverable.pack &&
-       git index-pack --fix-thin --stdin <recoverable.pack
+       test_must_fail git index-pack --fix-thin --stdin <recoverable.pack
 '
 
 test_done
index 97a6772..dd9cd4b 100755 (executable)
@@ -233,7 +233,7 @@ test_expect_success 'shallow fetches check connectivity before writing shallow f
        git -C "$REPO" config protocol.version 2 &&
        git -C client config protocol.version 2 &&
 
-       git -C client fetch --depth=2 "$HTTPD_URL/one_time_sed/repo" master:a_branch &&
+       git -C client fetch --depth=2 "$HTTPD_URL/one_time_perl/repo" master:a_branch &&
 
        # Craft a situation in which the server sends back an unshallow request
        # with an empty packfile. This is done by refetching with a shorter
@@ -242,13 +242,13 @@ test_expect_success 'shallow fetches check connectivity before writing shallow f
        printf "s/0034shallow %s/0036unshallow %s/" \
               "$(git -C "$REPO" rev-parse HEAD)" \
               "$(git -C "$REPO" rev-parse HEAD^)" \
-              >"$HTTPD_ROOT_PATH/one-time-sed" &&
+              >"$HTTPD_ROOT_PATH/one-time-perl" &&
        test_must_fail env GIT_TEST_SIDEBAND_ALL=0 git -C client \
-               fetch --depth=1 "$HTTPD_URL/one_time_sed/repo" \
+               fetch --depth=1 "$HTTPD_URL/one_time_perl/repo" \
                master:a_branch &&
 
-       # Ensure that the one-time-sed script was used.
-       ! test -e "$HTTPD_ROOT_PATH/one-time-sed" &&
+       # Ensure that the one-time-perl script was used.
+       ! test -e "$HTTPD_ROOT_PATH/one-time-perl" &&
 
        # Ensure that the resulting repo is consistent, despite our failure to
        # fetch.
similarity index 89%
rename from t/t5580-clone-push-unc.sh
rename to t/t5580-unc-paths.sh
index 01b52c1..cf768b3 100755 (executable)
@@ -40,11 +40,23 @@ test_expect_success clone '
        git clone "file://$UNCPATH" clone
 '
 
+test_expect_success 'clone without file://' '
+       git clone "$UNCPATH" clone-without-file
+'
+
 test_expect_success 'clone with backslashed path' '
        BACKSLASHED="$(echo "$UNCPATH" | tr / \\\\)" &&
        git clone "$BACKSLASHED" backslashed
 '
 
+test_expect_success fetch '
+       git init to-fetch &&
+       (
+               cd to-fetch &&
+               git fetch "$UNCPATH" master
+       )
+'
+
 test_expect_success push '
        (
                cd clone &&
index 9a9178f..77bb91e 100755 (executable)
@@ -384,6 +384,37 @@ test_expect_success 'fetch lazy-fetches only to resolve deltas, protocol v2' '
        grep "want $(cat hash)" trace
 '
 
+# The following two tests must be in this order, or else
+# the first will not fail. It is important that the srv.bare
+# repository did not have tags during clone, but has tags
+# in the fetch.
+
+test_expect_failure 'verify fetch succeeds when asking for new tags' '
+       git clone --filter=blob:none "file://$(pwd)/srv.bare" tag-test &&
+       for i in I J K
+       do
+               test_commit -C src $i &&
+               git -C src branch $i || return 1
+       done &&
+       git -C srv.bare fetch --tags origin +refs/heads/*:refs/heads/* &&
+       git -C tag-test -c protocol.version=2 fetch --tags origin
+'
+
+test_expect_success 'verify fetch downloads only one pack when updating refs' '
+       git clone --filter=blob:none "file://$(pwd)/srv.bare" pack-test &&
+       ls pack-test/.git/objects/pack/*pack >pack-list &&
+       test_line_count = 2 pack-list &&
+       for i in A B C
+       do
+               test_commit -C src $i &&
+               git -C src branch $i || return 1
+       done &&
+       git -C srv.bare fetch origin +refs/heads/*:refs/heads/* &&
+       git -C pack-test fetch origin &&
+       ls pack-test/.git/objects/pack/*pack >pack-list &&
+       test_line_count = 3 pack-list
+'
+
 . "$TEST_DIRECTORY"/lib-httpd.sh
 start_httpd
 
@@ -398,14 +429,18 @@ intersperse () {
        sed 's/\(..\)/'$1'\1/g'
 }
 
-# Create a one-time-sed command to replace the existing packfile with $1.
+# Create a one-time-perl command to replace the existing packfile with $1.
 replace_packfile () {
        # The protocol requires that the packfile be sent in sideband 1, hence
        # the extra \x01 byte at the beginning.
-       printf "1,/packfile/!c %04x\\\\x01%s0000" \
-               "$(($(wc -c <$1) + 5))" \
-               "$(hex_unpack <$1 | intersperse '\\x')" \
-               >"$HTTPD_ROOT_PATH/one-time-sed"
+       cp $1 "$HTTPD_ROOT_PATH/one-time-pack" &&
+       echo 'if (/packfile/) {
+               print;
+               my $length = -s "one-time-pack";
+               printf "%04x\x01", $length + 5;
+               print `cat one-time-pack` . "0000";
+               last
+       }' >"$HTTPD_ROOT_PATH/one-time-perl"
 }
 
 test_expect_success 'upon cloning, check that all refs point to objects' '
@@ -429,16 +464,16 @@ test_expect_success 'upon cloning, check that all refs point to objects' '
        # \x01 byte at the beginning.
        replace_packfile incomplete.pack &&
 
-       # Use protocol v2 because the sed command looks for the "packfile"
+       # Use protocol v2 because the perl command looks for the "packfile"
        # section header.
        test_config -C "$SERVER" protocol.version 2 &&
        test_must_fail git -c protocol.version=2 clone \
-               --filter=blob:none $HTTPD_URL/one_time_sed/server repo 2>err &&
+               --filter=blob:none $HTTPD_URL/one_time_perl/server repo 2>err &&
 
        test_i18ngrep "did not send all necessary objects" err &&
 
-       # Ensure that the one-time-sed script was used.
-       ! test -e "$HTTPD_ROOT_PATH/one-time-sed"
+       # Ensure that the one-time-perl script was used.
+       ! test -e "$HTTPD_ROOT_PATH/one-time-perl"
 '
 
 test_expect_success 'when partial cloning, tolerate server not sending target of tag' '
@@ -469,17 +504,17 @@ test_expect_success 'when partial cloning, tolerate server not sending target of
        # \x01 byte at the beginning.
        replace_packfile incomplete.pack &&
 
-       # Use protocol v2 because the sed command looks for the "packfile"
+       # Use protocol v2 because the perl command looks for the "packfile"
        # section header.
        test_config -C "$SERVER" protocol.version 2 &&
 
        # Exercise to make sure it works.
        git -c protocol.version=2 clone \
-               --filter=blob:none $HTTPD_URL/one_time_sed/server repo 2> err &&
+               --filter=blob:none $HTTPD_URL/one_time_perl/server repo 2> err &&
        ! grep "missing object referenced by" err &&
 
-       # Ensure that the one-time-sed script was used.
-       ! test -e "$HTTPD_ROOT_PATH/one-time-sed"
+       # Ensure that the one-time-perl script was used.
+       ! test -e "$HTTPD_ROOT_PATH/one-time-perl"
 '
 
 test_expect_success 'tolerate server sending REF_DELTA against missing promisor objects' '
@@ -502,7 +537,7 @@ test_expect_success 'tolerate server sending REF_DELTA against missing promisor
 
        # Clone. The client has deltabase_have but not deltabase_missing.
        git -c protocol.version=2 clone --no-checkout \
-               --filter=blob:none $HTTPD_URL/one_time_sed/server repo &&
+               --filter=blob:none $HTTPD_URL/one_time_perl/server repo &&
        git -C repo hash-object -w -- "$SERVER/have.txt" &&
 
        # Sanity check to ensure that the client does not have
@@ -543,7 +578,7 @@ test_expect_success 'tolerate server sending REF_DELTA against missing promisor
 
        replace_packfile thin.pack &&
 
-       # Use protocol v2 because the sed command looks for the "packfile"
+       # Use protocol v2 because the perl command looks for the "packfile"
        # section header.
        test_config -C "$SERVER" protocol.version 2 &&
 
@@ -556,8 +591,8 @@ test_expect_success 'tolerate server sending REF_DELTA against missing promisor
        grep "want $(cat deltabase_missing)" trace &&
        ! grep "want $(cat deltabase_have)" trace &&
 
-       # Ensure that the one-time-sed script was used.
-       ! test -e "$HTTPD_ROOT_PATH/one-time-sed"
+       # Ensure that the one-time-perl script was used.
+       ! test -e "$HTTPD_ROOT_PATH/one-time-perl"
 '
 
 # DO NOT add non-httpd-specific tests here, because the last part of this
index 7fd7102..5039e66 100755 (executable)
@@ -712,11 +712,11 @@ test_expect_success 'when server sends "ready", expect DELIM' '
 
        # After "ready" in the acknowledgments section, pretend that a FLUSH
        # (0000) was sent instead of a DELIM (0001).
-       printf "/ready/,$ s/0001/0000/" \
-               >"$HTTPD_ROOT_PATH/one-time-sed" &&
+       printf "\$ready = 1 if /ready/; \$ready && s/0001/0000/" \
+               >"$HTTPD_ROOT_PATH/one-time-perl" &&
 
        test_must_fail git -C http_child -c protocol.version=2 \
-               fetch "$HTTPD_URL/one_time_sed/http_parent" 2> err &&
+               fetch "$HTTPD_URL/one_time_perl/http_parent" 2> err &&
        test_i18ngrep "expected packfile to be sent after .ready." err
 '
 
@@ -737,12 +737,12 @@ test_expect_success 'when server does not send "ready", expect FLUSH' '
 
        # After the acknowledgments section, pretend that a DELIM
        # (0001) was sent instead of a FLUSH (0000).
-       printf "/acknowledgments/,$ s/0000/0001/" \
-               >"$HTTPD_ROOT_PATH/one-time-sed" &&
+       printf "\$ack = 1 if /acknowledgments/; \$ack && s/0000/0001/" \
+               >"$HTTPD_ROOT_PATH/one-time-perl" &&
 
        test_must_fail env GIT_TRACE_PACKET="$(pwd)/log" git -C http_child \
                -c protocol.version=2 \
-               fetch "$HTTPD_URL/one_time_sed/http_parent" 2> err &&
+               fetch "$HTTPD_URL/one_time_perl/http_parent" 2> err &&
        grep "fetch< .*acknowledgments" log &&
        ! grep "fetch< .*ready" log &&
        test_i18ngrep "expected no other sections to be sent after no .ready." err
index 1424fab..e1eec7d 100755 (executable)
@@ -313,7 +313,7 @@ test_expect_success 'setup repos for change-while-negotiating test' '
                test_commit m3 &&
                git tag -d m2 m3
        ) &&
-       git -C "$LOCAL_PRISTINE" remote set-url origin "http://127.0.0.1:$LIB_HTTPD_PORT/one_time_sed/repo" &&
+       git -C "$LOCAL_PRISTINE" remote set-url origin "http://127.0.0.1:$LIB_HTTPD_PORT/one_time_perl/repo" &&
        git -C "$LOCAL_PRISTINE" config protocol.version 2
 '
 
@@ -326,7 +326,7 @@ inconsistency () {
        # RPCs during a single negotiation.
        oid1=$(git -C "$REPO" rev-parse $1) &&
        oid2=$(git -C "$REPO" rev-parse $2) &&
-       echo "s/$oid1/$oid2/" >"$HTTPD_ROOT_PATH/one-time-sed"
+       echo "s/$oid1/$oid2/" >"$HTTPD_ROOT_PATH/one-time-perl"
 }
 
 test_expect_success 'server is initially ahead - no ref in want' '
@@ -378,7 +378,7 @@ test_expect_success 'server loses a ref - ref in want' '
        git -C "$REPO" config uploadpack.allowRefInWant true &&
        rm -rf local &&
        cp -r "$LOCAL_PRISTINE" local &&
-       echo "s/master/raster/" >"$HTTPD_ROOT_PATH/one-time-sed" &&
+       echo "s/master/raster/" >"$HTTPD_ROOT_PATH/one-time-perl" &&
        test_must_fail git -C local fetch 2>err &&
 
        test_i18ngrep "fatal: remote error: unknown ref refs/heads/raster" err
diff --git a/t/t6136-pathspec-in-bare.sh b/t/t6136-pathspec-in-bare.sh
new file mode 100755 (executable)
index 0000000..b117251
--- /dev/null
@@ -0,0 +1,38 @@
+#!/bin/sh
+
+test_description='diagnosing out-of-scope pathspec'
+
+. ./test-lib.sh
+
+test_expect_success 'setup a bare and non-bare repository' '
+       test_commit file1 &&
+       git clone --bare . bare
+'
+
+test_expect_success 'log and ls-files in a bare repository' '
+       (
+               cd bare &&
+               test_must_fail git log -- .. >out 2>err &&
+               test_must_be_empty out &&
+               test_i18ngrep "outside repository" err &&
+
+               test_must_fail git ls-files -- .. >out 2>err &&
+               test_must_be_empty out &&
+               test_i18ngrep "outside repository" err
+       )
+'
+
+test_expect_success 'log and ls-files in .git directory' '
+       (
+               cd .git &&
+               test_must_fail git log -- .. >out 2>err &&
+               test_must_be_empty out &&
+               test_i18ngrep "outside repository" err &&
+
+               test_must_fail git ls-files -- .. >out 2>err &&
+               test_must_be_empty out &&
+               test_i18ngrep "outside repository" err
+       )
+'
+
+test_done
diff --git a/t/t7410-submodule-checkout-to.sh b/t/t7410-submodule-checkout-to.sh
deleted file mode 100755 (executable)
index f1b492e..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-#!/bin/sh
-
-test_description='Combination of submodules and multiple workdirs'
-
-. ./test-lib.sh
-
-base_path=$(pwd -P)
-
-test_expect_success 'setup: make origin'  '
-       mkdir -p origin/sub &&
-       (
-               cd origin/sub && git init &&
-               echo file1 >file1 &&
-               git add file1 &&
-               git commit -m file1
-       ) &&
-       mkdir -p origin/main &&
-       (
-               cd origin/main && git init &&
-               git submodule add ../sub &&
-               git commit -m "add sub"
-       ) &&
-       (
-               cd origin/sub &&
-               echo file1updated >file1 &&
-               git add file1 &&
-               git commit -m "file1 updated"
-       ) &&
-       git -C origin/main/sub pull &&
-       (
-               cd origin/main &&
-               git add sub &&
-               git commit -m "sub updated"
-       )
-'
-
-test_expect_success 'setup: clone' '
-       mkdir clone &&
-       git -C clone clone --recursive "$base_path/origin/main"
-'
-
-rev1_hash_main=$(git --git-dir=origin/main/.git show --pretty=format:%h -q "HEAD~1")
-rev1_hash_sub=$(git --git-dir=origin/sub/.git show --pretty=format:%h -q "HEAD~1")
-
-test_expect_success 'checkout main' '
-       mkdir default_checkout &&
-       git -C clone/main worktree add "$base_path/default_checkout/main" "$rev1_hash_main"
-'
-
-test_expect_failure 'can see submodule diffs just after checkout' '
-       git -C default_checkout/main diff --submodule master"^!" >out &&
-       grep "file1 updated" out
-'
-
-test_expect_success 'checkout main and initialize independent clones' '
-       mkdir fully_cloned_submodule &&
-       git -C clone/main worktree add "$base_path/fully_cloned_submodule/main" "$rev1_hash_main" &&
-       git -C fully_cloned_submodule/main submodule update
-'
-
-test_expect_success 'can see submodule diffs after independent cloning' '
-       git -C fully_cloned_submodule/main diff --submodule master"^!" >out &&
-       grep "file1 updated" out
-'
-
-test_expect_success 'checkout sub manually' '
-       mkdir linked_submodule &&
-       git -C clone/main worktree add "$base_path/linked_submodule/main" "$rev1_hash_main" &&
-       git -C clone/main/sub worktree add "$base_path/linked_submodule/main/sub" "$rev1_hash_sub"
-'
-
-test_expect_success 'can see submodule diffs after manual checkout of linked submodule' '
-       git -C linked_submodule/main diff --submodule master"^!" >out &&
-       grep "file1 updated" out
-'
-
-test_done
index 44df51b..0ea1e5a 100644 (file)
@@ -1083,7 +1083,8 @@ finalize_junit_xml () {
 
                # adjust the overall time
                junit_time=$(test-tool date getnanos $junit_suite_start)
-               sed "s/<testsuite [^>]*/& time=\"$junit_time\"/" \
+               sed -e "s/\(<testsuite.*\) time=\"[^\"]*\"/\1/" \
+                       -e "s/<testsuite [^>]*/& time=\"$junit_time\"/" \
                        <"$junit_xml_path" >"$junit_xml_path.new"
                mv "$junit_xml_path.new" "$junit_xml_path"
 
index c9d0276..b50e686 100644 (file)
@@ -59,7 +59,7 @@ static const struct interval zero_width[] = {
 { 0x0B3F, 0x0B3F },
 { 0x0B41, 0x0B44 },
 { 0x0B4D, 0x0B4D },
-{ 0x0B56, 0x0B56 },
+{ 0x0B55, 0x0B56 },
 { 0x0B62, 0x0B63 },
 { 0x0B82, 0x0B82 },
 { 0x0BC0, 0x0BC0 },
@@ -82,6 +82,7 @@ static const struct interval zero_width[] = {
 { 0x0D41, 0x0D44 },
 { 0x0D4D, 0x0D4D },
 { 0x0D62, 0x0D63 },
+{ 0x0D81, 0x0D81 },
 { 0x0DCA, 0x0DCA },
 { 0x0DD2, 0x0DD4 },
 { 0x0DD6, 0x0DD6 },
@@ -139,7 +140,7 @@ static const struct interval zero_width[] = {
 { 0x1A65, 0x1A6C },
 { 0x1A73, 0x1A7C },
 { 0x1A7F, 0x1A7F },
-{ 0x1AB0, 0x1ABE },
+{ 0x1AB0, 0x1AC0 },
 { 0x1B00, 0x1B03 },
 { 0x1B34, 0x1B34 },
 { 0x1B36, 0x1B3A },
@@ -182,6 +183,7 @@ static const struct interval zero_width[] = {
 { 0xA806, 0xA806 },
 { 0xA80B, 0xA80B },
 { 0xA825, 0xA826 },
+{ 0xA82C, 0xA82C },
 { 0xA8C4, 0xA8C5 },
 { 0xA8E0, 0xA8F1 },
 { 0xA8FF, 0xA8FF },
@@ -223,6 +225,7 @@ static const struct interval zero_width[] = {
 { 0x10A3F, 0x10A3F },
 { 0x10AE5, 0x10AE6 },
 { 0x10D24, 0x10D27 },
+{ 0x10EAB, 0x10EAC },
 { 0x10F46, 0x10F50 },
 { 0x11001, 0x11001 },
 { 0x11038, 0x11046 },
@@ -238,6 +241,7 @@ static const struct interval zero_width[] = {
 { 0x11180, 0x11181 },
 { 0x111B6, 0x111BE },
 { 0x111C9, 0x111CC },
+{ 0x111CF, 0x111CF },
 { 0x1122F, 0x11231 },
 { 0x11234, 0x11234 },
 { 0x11236, 0x11237 },
@@ -273,6 +277,9 @@ static const struct interval zero_width[] = {
 { 0x11727, 0x1172B },
 { 0x1182F, 0x11837 },
 { 0x11839, 0x1183A },
+{ 0x1193B, 0x1193C },
+{ 0x1193E, 0x1193E },
+{ 0x11943, 0x11943 },
 { 0x119D4, 0x119D7 },
 { 0x119DA, 0x119DB },
 { 0x119E0, 0x119E0 },
@@ -305,6 +312,7 @@ static const struct interval zero_width[] = {
 { 0x16B30, 0x16B36 },
 { 0x16F4F, 0x16F4F },
 { 0x16F8F, 0x16F92 },
+{ 0x16FE4, 0x16FE4 },
 { 0x1BC9D, 0x1BC9E },
 { 0x1BCA0, 0x1BCA3 },
 { 0x1D167, 0x1D169 },
@@ -376,8 +384,7 @@ static const struct interval double_width[] = {
 { 0x3099, 0x30FF },
 { 0x3105, 0x312F },
 { 0x3131, 0x318E },
-{ 0x3190, 0x31BA },
-{ 0x31C0, 0x31E3 },
+{ 0x3190, 0x31E3 },
 { 0x31F0, 0x321E },
 { 0x3220, 0x3247 },
 { 0x3250, 0x4DBF },
@@ -392,9 +399,11 @@ static const struct interval double_width[] = {
 { 0xFE68, 0xFE6B },
 { 0xFF01, 0xFF60 },
 { 0xFFE0, 0xFFE6 },
-{ 0x16FE0, 0x16FE3 },
+{ 0x16FE0, 0x16FE4 },
+{ 0x16FF0, 0x16FF1 },
 { 0x17000, 0x187F7 },
-{ 0x18800, 0x18AF2 },
+{ 0x18800, 0x18CD5 },
+{ 0x18D00, 0x18D08 },
 { 0x1B000, 0x1B11E },
 { 0x1B150, 0x1B152 },
 { 0x1B164, 0x1B167 },
@@ -429,20 +438,22 @@ static const struct interval double_width[] = {
 { 0x1F680, 0x1F6C5 },
 { 0x1F6CC, 0x1F6CC },
 { 0x1F6D0, 0x1F6D2 },
-{ 0x1F6D5, 0x1F6D5 },
+{ 0x1F6D5, 0x1F6D7 },
 { 0x1F6EB, 0x1F6EC },
-{ 0x1F6F4, 0x1F6FA },
+{ 0x1F6F4, 0x1F6FC },
 { 0x1F7E0, 0x1F7EB },
-{ 0x1F90D, 0x1F971 },
-{ 0x1F973, 0x1F976 },
-{ 0x1F97A, 0x1F9A2 },
-{ 0x1F9A5, 0x1F9AA },
-{ 0x1F9AE, 0x1F9CA },
+{ 0x1F90C, 0x1F93A },
+{ 0x1F93C, 0x1F945 },
+{ 0x1F947, 0x1F978 },
+{ 0x1F97A, 0x1F9CB },
 { 0x1F9CD, 0x1F9FF },
-{ 0x1FA70, 0x1FA73 },
+{ 0x1FA70, 0x1FA74 },
 { 0x1FA78, 0x1FA7A },
-{ 0x1FA80, 0x1FA82 },
-{ 0x1FA90, 0x1FA95 },
+{ 0x1FA80, 0x1FA86 },
+{ 0x1FA90, 0x1FAA8 },
+{ 0x1FAB0, 0x1FAB6 },
+{ 0x1FAC0, 0x1FAC2 },
+{ 0x1FAD0, 0x1FAD6 },
 { 0x20000, 0x2FFFD },
 { 0x30000, 0x3FFFD }
 };
index 191e738..da4d6d4 100644 (file)
@@ -372,15 +372,20 @@ static int check_updates(struct unpack_trees_options *o)
        state.refresh_cache = 1;
        state.istate = index;
 
+       if (!o->update || o->dry_run) {
+               remove_marked_cache_entries(index, 0);
+               trace_performance_leave("check_updates");
+               return 0;
+       }
+
        if (o->clone)
                setup_collided_checkout_detection(&state, index);
 
        progress = get_progress(o);
 
-       if (o->update)
-               git_attr_set_direction(GIT_ATTR_CHECKOUT);
+       git_attr_set_direction(GIT_ATTR_CHECKOUT);
 
-       if (should_update_submodules() && o->update && !o->dry_run)
+       if (should_update_submodules())
                load_gitmodules_file(index, NULL);
 
        for (i = 0; i < index->cache_nr; i++) {
@@ -388,18 +393,18 @@ static int check_updates(struct unpack_trees_options *o)
 
                if (ce->ce_flags & CE_WT_REMOVE) {
                        display_progress(progress, ++cnt);
-                       if (o->update && !o->dry_run)
-                               unlink_entry(ce);
+                       unlink_entry(ce);
                }
        }
+
        remove_marked_cache_entries(index, 0);
        remove_scheduled_dirs();
 
-       if (should_update_submodules() && o->update && !o->dry_run)
+       if (should_update_submodules())
                load_gitmodules_file(index, &state);
 
        enable_delayed_checkout(&state);
-       if (has_promisor_remote() && o->update && !o->dry_run) {
+       if (has_promisor_remote()) {
                /*
                 * Prefetch the objects that are to be checked out in the loop
                 * below.
@@ -431,15 +436,12 @@ static int check_updates(struct unpack_trees_options *o)
                                    ce->name);
                        display_progress(progress, ++cnt);
                        ce->ce_flags &= ~CE_UPDATE;
-                       if (o->update && !o->dry_run) {
-                               errs |= checkout_entry(ce, &state, NULL, NULL);
-                       }
+                       errs |= checkout_entry(ce, &state, NULL, NULL);
                }
        }
        stop_progress(&progress);
        errs |= finish_delayed_checkout(&state, NULL);
-       if (o->update)
-               git_attr_set_direction(GIT_ATTR_CHECKIN);
+       git_attr_set_direction(GIT_ATTR_CHECKIN);
 
        if (o->clone)
                report_collided_checkout(index);
@@ -1350,7 +1352,7 @@ static int clear_ce_flags_1(struct index_state *istate,
                            enum pattern_match_result default_match,
                            int progress_nr)
 {
-       struct cache_entry **cache_end = cache + nr;
+       struct cache_entry **cache_end = nr ? cache + nr : cache;
 
        /*
         * Process all entries that have the given prefix and meet
index 8509f9e..4d20069 100644 (file)
@@ -84,8 +84,8 @@ static void trim_common_tail(mmfile_t *a, mmfile_t *b)
 {
        const int blk = 1024;
        long trimmed = 0, recovered = 0;
-       char *ap = a->ptr + a->size;
-       char *bp = b->ptr + b->size;
+       char *ap = a->size ? a->ptr + a->size : a->ptr;
+       char *bp = b->size ? b->ptr + b->size : b->ptr;
        long smaller = (a->size < b->size) ? a->size : b->size;
 
        while (blk + trimmed <= smaller && !memcmp(ap - blk, bp - blk, blk)) {
@@ -250,9 +250,13 @@ void xdiff_set_find_func(xdemitconf_t *xecfg, const char *value, int cflags)
        ALLOC_ARRAY(regs->array, regs->nr);
        for (i = 0; i < regs->nr; i++) {
                struct ff_reg *reg = regs->array + i;
-               const char *ep = strchr(value, '\n'), *expression;
+               const char *ep, *expression;
                char *buffer = NULL;
 
+               if (!value)
+                       BUG("mismatch between line count and parsing");
+               ep = strchr(value, '\n');
+
                reg->negate = (*value == '!');
                if (reg->negate && i == regs->nr - 1)
                        die("Last expression must not be negated: %s", value);
@@ -265,7 +269,7 @@ void xdiff_set_find_func(xdemitconf_t *xecfg, const char *value, int cflags)
                if (regcomp(&reg->re, expression, cflags))
                        die("Invalid regexp to look for hunk header: %s", expression);
                free(buffer);
-               value = ep + 1;
+               value = ep ? ep + 1 : NULL;
        }
 }