summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.mailmap1
-rw-r--r--.travis.yml2
-rw-r--r--Documentation/RelNotes/2.15.0.txt6
-rw-r--r--Documentation/RelNotes/2.15.1.txt68
-rw-r--r--Documentation/config.txt17
-rw-r--r--Documentation/diff-heuristic-options.txt5
-rw-r--r--Documentation/diff-options.txt7
-rw-r--r--Documentation/git-annotate.txt1
-rw-r--r--Documentation/git-blame.txt2
-rw-r--r--Documentation/git-check-ref-format.txt9
-rw-r--r--Documentation/git.txt18
-rwxr-xr-xGIT-VERSION-GEN2
-rw-r--r--Makefile3
l---------RelNotes2
-rw-r--r--builtin/check-ref-format.c6
-rw-r--r--builtin/commit.c2
-rw-r--r--builtin/grep.c2
-rw-r--r--builtin/remote.c2
-rwxr-xr-xci/install-dependencies.sh10
-rwxr-xr-xci/lib-travisci.sh8
-rw-r--r--column.c2
-rw-r--r--compat/mingw.c58
-rw-r--r--contrib/completion/git-completion.bash3
-rw-r--r--contrib/credential/libsecret/git-credential-libsecret.c2
-rw-r--r--contrib/credential/wincred/git-credential-wincred.c10
-rw-r--r--diff.c91
-rw-r--r--dir.c2
-rw-r--r--git-rebase--interactive.sh2
-rw-r--r--git.rc4
-rw-r--r--grep.c2
-rw-r--r--grep.h5
-rw-r--r--log-tree.c2
-rw-r--r--sequencer.c7
-rw-r--r--setup.c4
-rw-r--r--sha1_file.c4
-rw-r--r--sha1_name.c5
-rw-r--r--t/helper/test-ref-store.c2
-rwxr-xr-xt/lib-credential.sh19
-rwxr-xr-xt/t0001-init.sh12
-rwxr-xr-xt/t1402-check-ref-format.sh16
-rwxr-xr-xt/t3404-rebase-interactive.sh11
-rwxr-xr-xt/t3426-rebase-submodule.sh17
-rwxr-xr-xt/t3600-rm.sh2
-rwxr-xr-xt/t4015-diff-whitespace.sh213
-rwxr-xr-xt/t5580-clone-push-unc.sh14
-rwxr-xr-xt/t5601-clone.sh2
-rwxr-xr-xt/t7001-mv.sh2
-rwxr-xr-xt/t7006-pager.sh14
-rwxr-xr-xt/t7061-wtstatus-ignore.sh11
-rwxr-xr-xt/t9902-completion.sh4
-rw-r--r--worktree.c3
-rw-r--r--wrapper.c8
-rw-r--r--wt-status.c4
-rw-r--r--xdiff-interface.c12
-rw-r--r--xdiff-interface.h16
55 files changed, 585 insertions, 173 deletions
diff --git a/.mailmap b/.mailmap
index 224db83887..7c71e88ea5 100644
--- a/.mailmap
+++ b/.mailmap
@@ -113,6 +113,7 @@ Junio C Hamano <gitster@pobox.com> <junio@pobox.com>
Junio C Hamano <gitster@pobox.com> <junio@twinsun.com>
Junio C Hamano <gitster@pobox.com> <junkio@cox.net>
Junio C Hamano <gitster@pobox.com> <junkio@twinsun.com>
+Kaartic Sivaraam <kaartic.sivaraam@gmail.com> <kaarticsivaraam91196@gmail.com>
Karl Wiberg <kha@treskal.com> Karl Hasselström
Karl Wiberg <kha@treskal.com> <kha@yoghurt.hemma.treskal.com>
Karsten Blees <blees@dcon.de> <karsten.blees@dcon.de>
diff --git a/.travis.yml b/.travis.yml
index fead995edd..281f101f31 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -71,7 +71,7 @@ matrix:
packages:
- coccinelle
before_install:
- # "before_script" that builds Git is inherited from base job
+ before_script:
script: ci/run-static-analysis.sh
after_failure:
- env: Documentation
diff --git a/Documentation/RelNotes/2.15.0.txt b/Documentation/RelNotes/2.15.0.txt
index 248ba70c3d..cdd761bcc2 100644
--- a/Documentation/RelNotes/2.15.0.txt
+++ b/Documentation/RelNotes/2.15.0.txt
@@ -65,7 +65,7 @@ UI, Workflows & Features
learned to take the 'unfold' and 'only' modifiers to normalize its
output, e.g. "git log --format=%(trailers:only,unfold)".
- * "gitweb" shows a link to visit the 'raw' contents of blbos in the
+ * "gitweb" shows a link to visit the 'raw' contents of blobs in the
history overview page.
* "[gc] rerereResolved = 5.days" used to be invalid, as the variable
@@ -109,13 +109,13 @@ Performance, Internal Implementation, Development Support etc.
* Conversion from uchar[20] to struct object_id continues.
* Start using selected c99 constructs in small, stable and
- essentialpart of the system to catch people who care about
+ essential part of the system to catch people who care about
older compilers that do not grok them.
* The filter-process interface learned to allow a process with long
latency give a "delayed" response.
- * Many uses of comparision callback function the hashmap API uses
+ * Many uses of comparison callback function the hashmap API uses
cast the callback function type when registering it to
hashmap_init(), which defeats the compile time type checking when
the callback interface changes (e.g. gaining more parameters).
diff --git a/Documentation/RelNotes/2.15.1.txt b/Documentation/RelNotes/2.15.1.txt
new file mode 100644
index 0000000000..15b24a0b76
--- /dev/null
+++ b/Documentation/RelNotes/2.15.1.txt
@@ -0,0 +1,68 @@
+Git v2.15.1 Release Notes
+=========================
+
+Fixes since v2.15
+-----------------
+
+ * TravisCI build updates.
+
+ * "auto" as a value for the columnar output configuration ought to
+ judge "is the output consumed by humans?" with the same criteria as
+ "auto" for coloured output configuration, i.e. either the standard
+ output stream is going to tty, or a pager is in use. We forgot the
+ latter, which has been fixed.
+
+ * The experimental "color moved lines differently in diff output"
+ feature was buggy around "ignore whitespace changes" edges, whihch
+ has been corrected.
+
+ * Instead of using custom line comparison and hashing functions to
+ implement "moved lines" coloring in the diff output, use the pair
+ of these functions from lower-layer xdiff/ code.
+
+ * Some codepaths did not check for errors when asking what branch the
+ HEAD points at, which have been fixed.
+
+ * "git commit", after making a commit, did not check for errors when
+ asking on what branch it made the commit, which has been correted.
+
+ * "git status --ignored -u" did not stop at a working tree of a
+ separate project that is embedded in an ignored directory and
+ listed files in that other project, instead of just showing the
+ directory itself as ignored.
+
+ * A broken access to object databases in recent update to "git grep
+ --recurse-submodules" has been fixed.
+
+ * A recent regression in "git rebase -i" that broke execution of git
+ commands from subdirectories via "exec" insn has been fixed.
+
+ * "git check-ref-format --branch @{-1}" bit a "BUG()" when run
+ outside a repository for obvious reasons; clarify the documentation
+ and make sure we do not even try to expand the at-mark magic in
+ such a case, but still call the validation logic for branch names.
+
+ * Command line completion (in contrib/) update.
+
+ * Description of blame.{showroot,blankboundary,showemail,date}
+ configuration variables have been added to "git config --help".
+
+ * After an error from lstat(), diff_populate_filespec() function
+ sometimes still went ahead and used invalid data in struct stat,
+ which has been fixed.
+
+ * UNC paths are also relevant in Cygwin builds and they are now
+ tested just like Mingw builds.
+
+ * Correct start-up sequence so that a repository could be placed
+ immediately under the root directory again (which was broken at
+ around Git 2.13).
+
+ * The credential helper for libsecret (in contrib/) has been improved
+ to allow possibly prompting the end user to unlock secrets that are
+ currently locked (otherwise the secrets may not be loaded).
+
+ * Updates from GfW project.
+
+
+Also contains various documentation updates and code clean-ups.
diff --git a/Documentation/config.txt b/Documentation/config.txt
index 1ac0ae6adb..9593bfabaa 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -949,6 +949,23 @@ apply.whitespace::
Tells 'git apply' how to handle whitespaces, in the same way
as the `--whitespace` option. See linkgit:git-apply[1].
+blame.showRoot::
+ Do not treat root commits as boundaries in linkgit:git-blame[1].
+ This option defaults to false.
+
+blame.blankBoundary::
+ Show blank commit object name for boundary commits in
+ linkgit:git-blame[1]. This option defaults to false.
+
+blame.showEmail::
+ Show the author email instead of author name in linkgit:git-blame[1].
+ This option defaults to false.
+
+blame.date::
+ Specifies the format used to output dates in linkgit:git-blame[1].
+ If unset the iso format is used. For supported values,
+ see the discussion of the `--date` option at linkgit:git-log[1].
+
branch.autoSetupMerge::
Tells 'git branch' and 'git checkout' to set up new branches
so that linkgit:git-pull[1] will appropriately merge from the
diff --git a/Documentation/diff-heuristic-options.txt b/Documentation/diff-heuristic-options.txt
deleted file mode 100644
index d4f3d95505..0000000000
--- a/Documentation/diff-heuristic-options.txt
+++ /dev/null
@@ -1,5 +0,0 @@
---indent-heuristic::
---no-indent-heuristic::
- These are to help debugging and tuning experimental heuristics
- (which are off by default) that shift diff hunk boundaries to
- make patches easier to read.
diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt
index a88c76741e..dd0dba5b1d 100644
--- a/Documentation/diff-options.txt
+++ b/Documentation/diff-options.txt
@@ -63,7 +63,12 @@ ifndef::git-format-patch[]
Synonym for `-p --raw`.
endif::git-format-patch[]
-include::diff-heuristic-options.txt[]
+--indent-heuristic::
+ Enable the heuristic that shift diff hunk boundaries to make patches
+ easier to read. This is the default.
+
+--no-indent-heuristic::
+ Disable the indent heuristic.
--minimal::
Spend extra time to make sure the smallest possible
diff --git a/Documentation/git-annotate.txt b/Documentation/git-annotate.txt
index 94be4b85e0..05fd482b74 100644
--- a/Documentation/git-annotate.txt
+++ b/Documentation/git-annotate.txt
@@ -23,7 +23,6 @@ familiar command name for people coming from other SCM systems.
OPTIONS
-------
include::blame-options.txt[]
-include::diff-heuristic-options.txt[]
SEE ALSO
--------
diff --git a/Documentation/git-blame.txt b/Documentation/git-blame.txt
index fdc3aea30a..16323eb80e 100644
--- a/Documentation/git-blame.txt
+++ b/Documentation/git-blame.txt
@@ -89,8 +89,6 @@ include::blame-options.txt[]
abbreviated object name, use <n>+1 digits. Note that 1 column
is used for a caret to mark the boundary commit.
-include::diff-heuristic-options.txt[]
-
THE PORCELAIN FORMAT
--------------------
diff --git a/Documentation/git-check-ref-format.txt b/Documentation/git-check-ref-format.txt
index 92777cef25..cf0a0b7df2 100644
--- a/Documentation/git-check-ref-format.txt
+++ b/Documentation/git-check-ref-format.txt
@@ -77,7 +77,14 @@ reference name expressions (see linkgit:gitrevisions[7]):
. at-open-brace `@{` is used as a notation to access a reflog entry.
-With the `--branch` option, it expands the ``previous branch syntax''
+With the `--branch` option, the command takes a name and checks if
+it can be used as a valid branch name (e.g. when creating a new
+branch). The rule `git check-ref-format --branch $name` implements
+may be stricter than what `git check-ref-format refs/heads/$name`
+says (e.g. a dash may appear at the beginning of a ref component,
+but it is explicitly forbidden at the beginning of a branch name).
+When run with `--branch` option in a repository, the input is first
+expanded for the ``previous branch syntax''
`@{-n}`. For example, `@{-1}` is a way to refer the last branch you
were on. This option should be used by porcelains to accept this
syntax anywhere a branch name is expected, so they can act as if you
diff --git a/Documentation/git.txt b/Documentation/git.txt
index 7a1d629ca0..463b0eb0f5 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -709,6 +709,24 @@ of clones and fetches.
the background which do not want to cause lock contention with
other operations on the repository. Defaults to `1`.
+`GIT_REDIRECT_STDIN`::
+`GIT_REDIRECT_STDOUT`::
+`GIT_REDIRECT_STDERR`::
+ Windows-only: allow redirecting the standard input/output/error
+ handles to paths specified by the environment variables. This is
+ particularly useful in multi-threaded applications where the
+ canonical way to pass standard handles via `CreateProcess()` is
+ not an option because it would require the handles to be marked
+ inheritable (and consequently *every* spawned process would
+ inherit them, possibly blocking regular Git operations). The
+ primary intended use case is to use named pipes for communication
+ (e.g. `\\.\pipe\my-git-stdin-123`).
++
+Two special values are supported: `off` will simply close the
+corresponding standard handle, and if `GIT_REDIRECT_STDERR` is
+`2>&1`, standard error will be redirected to the same handle as
+standard output.
+
Discussion[[Discussion]]
------------------------
diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN
index a9dbc3f12c..879178c550 100755
--- a/GIT-VERSION-GEN
+++ b/GIT-VERSION-GEN
@@ -1,7 +1,7 @@
#!/bin/sh
GVF=GIT-VERSION-FILE
-DEF_VER=v2.15.0
+DEF_VER=v2.15.1
LF='
'
diff --git a/Makefile b/Makefile
index cd75985991..ee9d5eb11e 100644
--- a/Makefile
+++ b/Makefile
@@ -1940,7 +1940,8 @@ $(SCRIPT_LIB) : % : %.sh GIT-SCRIPT-DEFINES
git.res: git.rc GIT-VERSION-FILE
$(QUIET_RC)$(RC) \
- $(join -DMAJOR= -DMINOR=, $(wordlist 1,2,$(subst -, ,$(subst ., ,$(GIT_VERSION))))) \
+ $(join -DMAJOR= -DMINOR= -DMICRO= -DPATCHLEVEL=, $(wordlist 1, 4, \
+ $(shell echo $(GIT_VERSION) 0 0 0 0 | tr '.a-zA-Z-' ' '))) \
-DGIT_VERSION="\\\"$(GIT_VERSION)\\\"" -i $< -o $@
# This makes sure we depend on the NO_PERL setting itself.
diff --git a/RelNotes b/RelNotes
index 80ae7a3110..0c1dd02073 120000
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes/2.15.0.txt \ No newline at end of file
+Documentation/RelNotes/2.15.1.txt \ No newline at end of file
diff --git a/builtin/check-ref-format.c b/builtin/check-ref-format.c
index 6c40ff110b..bc67d3f0a8 100644
--- a/builtin/check-ref-format.c
+++ b/builtin/check-ref-format.c
@@ -39,12 +39,14 @@ static char *collapse_slashes(const char *refname)
static int check_ref_format_branch(const char *arg)
{
struct strbuf sb = STRBUF_INIT;
+ const char *name;
int nongit;
setup_git_directory_gently(&nongit);
- if (strbuf_check_branch_ref(&sb, arg))
+ if (strbuf_check_branch_ref(&sb, arg) ||
+ !skip_prefix(sb.buf, "refs/heads/", &name))
die("'%s' is not a valid branch name", arg);
- printf("%s\n", sb.buf + 11);
+ printf("%s\n", name);
strbuf_release(&sb);
return 0;
}
diff --git a/builtin/commit.c b/builtin/commit.c
index d75b3805ea..b2a6c7f100 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -1492,6 +1492,8 @@ static void print_summary(const char *prefix, const struct object_id *oid,
diff_setup_done(&rev.diffopt);
head = resolve_ref_unsafe("HEAD", 0, NULL, NULL);
+ if (!head)
+ die_errno(_("unable to resolve HEAD after creating commit"));
if (!strcmp(head, "HEAD"))
head = _("detached HEAD");
else
diff --git a/builtin/grep.c b/builtin/grep.c
index 2d65f27d01..5a6cfe6b45 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -431,7 +431,9 @@ static int grep_submodule(struct grep_opt *opt, struct repository *superproject,
* store is no longer global and instead is a member of the repository
* object.
*/
+ grep_read_lock();
add_to_alternates_memory(submodule.objectdir);
+ grep_read_unlock();
if (oid) {
struct object *object;
diff --git a/builtin/remote.c b/builtin/remote.c
index 4f5cac96b0..bc89623695 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -565,7 +565,7 @@ static int read_remote_branches(const char *refname,
item = string_list_append(rename->remote_branches, xstrdup(refname));
symref = resolve_ref_unsafe(refname, RESOLVE_REF_READING,
NULL, &flag);
- if (flag & REF_ISSYMREF)
+ if (symref && (flag & REF_ISSYMREF))
item->util = xstrdup(symref);
else
item->util = NULL;
diff --git a/ci/install-dependencies.sh b/ci/install-dependencies.sh
index a29246af35..5bd06fe900 100755
--- a/ci/install-dependencies.sh
+++ b/ci/install-dependencies.sh
@@ -12,20 +12,18 @@ case "${TRAVIS_OS_NAME:-linux}" in
linux)
export GIT_TEST_HTTPD=YesPlease
- mkdir --parents custom/p4
- pushd custom/p4
+ mkdir --parents "$P4_PATH"
+ pushd "$P4_PATH"
wget --quiet "$P4WHENCE/bin.linux26x86_64/p4d"
wget --quiet "$P4WHENCE/bin.linux26x86_64/p4"
chmod u+x p4d
chmod u+x p4
- export PATH="$(pwd):$PATH"
popd
- mkdir --parents custom/git-lfs
- pushd custom/git-lfs
+ mkdir --parents "$GIT_LFS_PATH"
+ pushd "$GIT_LFS_PATH"
wget --quiet "$LFSWHENCE/git-lfs-linux-amd64-$LINUX_GIT_LFS_VERSION.tar.gz"
tar --extract --gunzip --file "git-lfs-linux-amd64-$LINUX_GIT_LFS_VERSION.tar.gz"
cp git-lfs-$LINUX_GIT_LFS_VERSION/git-lfs .
- export PATH="$(pwd):$PATH"
popd
;;
osx)
diff --git a/ci/lib-travisci.sh b/ci/lib-travisci.sh
index b3ed0a0dda..ac05f1f469 100755
--- a/ci/lib-travisci.sh
+++ b/ci/lib-travisci.sh
@@ -26,3 +26,11 @@ skip_branch_tip_with_tag () {
set -e
skip_branch_tip_with_tag
+
+case "${TRAVIS_OS_NAME:-linux}" in
+linux)
+ P4_PATH="$(pwd)/custom/p4"
+ GIT_LFS_PATH="$(pwd)/custom/git-lfs"
+ export PATH="$GIT_LFS_PATH:$P4_PATH:$PATH"
+ ;;
+esac
diff --git a/column.c b/column.c
index ff7bdab1a3..49ab85b769 100644
--- a/column.c
+++ b/column.c
@@ -224,7 +224,7 @@ int finalize_colopts(unsigned int *colopts, int stdout_is_tty)
if (stdout_is_tty < 0)
stdout_is_tty = isatty(1);
*colopts &= ~COL_ENABLE_MASK;
- if (stdout_is_tty)
+ if (stdout_is_tty || pager_in_use())
*colopts |= COL_ENABLED;
}
return 0;
diff --git a/compat/mingw.c b/compat/mingw.c
index 8b6fa0db44..2d44d21aca 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -2139,6 +2139,62 @@ static char *wcstoutfdup_startup(char *buffer, const wchar_t *wcs, size_t len)
return memcpy(malloc_startup(len), buffer, len);
}
+static void maybe_redirect_std_handle(const wchar_t *key, DWORD std_id, int fd,
+ DWORD desired_access, DWORD flags)
+{
+ DWORD create_flag = fd ? OPEN_ALWAYS : OPEN_EXISTING;
+ wchar_t buf[MAX_PATH];
+ DWORD max = ARRAY_SIZE(buf);
+ HANDLE handle;
+ DWORD ret = GetEnvironmentVariableW(key, buf, max);
+
+ if (!ret || ret >= max)
+ return;
+
+ /* make sure this does not leak into child processes */
+ SetEnvironmentVariableW(key, NULL);
+ if (!wcscmp(buf, L"off")) {
+ close(fd);
+ handle = GetStdHandle(std_id);
+ if (handle != INVALID_HANDLE_VALUE)
+ CloseHandle(handle);
+ return;
+ }
+ if (std_id == STD_ERROR_HANDLE && !wcscmp(buf, L"2>&1")) {
+ handle = GetStdHandle(STD_OUTPUT_HANDLE);
+ if (handle == INVALID_HANDLE_VALUE) {
+ close(fd);
+ handle = GetStdHandle(std_id);
+ if (handle != INVALID_HANDLE_VALUE)
+ CloseHandle(handle);
+ } else {
+ int new_fd = _open_osfhandle((intptr_t)handle, O_BINARY);
+ SetStdHandle(std_id, handle);
+ dup2(new_fd, fd);
+ /* do *not* close the new_fd: that would close stdout */
+ }
+ return;
+ }
+ handle = CreateFileW(buf, desired_access, 0, NULL, create_flag,
+ flags, NULL);
+ if (handle != INVALID_HANDLE_VALUE) {
+ int new_fd = _open_osfhandle((intptr_t)handle, O_BINARY);
+ SetStdHandle(std_id, handle);
+ dup2(new_fd, fd);
+ close(new_fd);
+ }
+}
+
+static void maybe_redirect_std_handles(void)
+{
+ maybe_redirect_std_handle(L"GIT_REDIRECT_STDIN", STD_INPUT_HANDLE, 0,
+ GENERIC_READ, FILE_ATTRIBUTE_NORMAL);
+ maybe_redirect_std_handle(L"GIT_REDIRECT_STDOUT", STD_OUTPUT_HANDLE, 1,
+ GENERIC_WRITE, FILE_ATTRIBUTE_NORMAL);
+ maybe_redirect_std_handle(L"GIT_REDIRECT_STDERR", STD_ERROR_HANDLE, 2,
+ GENERIC_WRITE, FILE_FLAG_NO_BUFFERING);
+}
+
void mingw_startup(void)
{
int i, maxlen, argc;
@@ -2146,6 +2202,8 @@ void mingw_startup(void)
wchar_t **wenv, **wargv;
_startupinfo si;
+ maybe_redirect_std_handles();
+
/* get wide char arguments and environment */
si.newmode = 0;
if (__wgetmainargs(&argc, &wargv, &wenv, _CRT_glob, &si) < 0)
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index 6934064ee9..a54cc2cef6 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -1249,7 +1249,8 @@ _git_checkout ()
--*)
__gitcomp "
--quiet --ours --theirs --track --no-track --merge
- --conflict= --orphan --patch
+ --conflict= --orphan --patch --detach --ignore-skip-worktree-bits
+ --recurse-submodules --no-recurse-submodules
"
;;
*)
diff --git a/contrib/credential/libsecret/git-credential-libsecret.c b/contrib/credential/libsecret/git-credential-libsecret.c
index cfe295f36b..e6598b6383 100644
--- a/contrib/credential/libsecret/git-credential-libsecret.c
+++ b/contrib/credential/libsecret/git-credential-libsecret.c
@@ -103,7 +103,7 @@ static int keyring_get(struct credential *c)
items = secret_service_search_sync(service,
SECRET_SCHEMA_COMPAT_NETWORK,
attributes,
- SECRET_SEARCH_LOAD_SECRETS,
+ SECRET_SEARCH_LOAD_SECRETS | SECRET_SEARCH_UNLOCK,
NULL,
&error);
g_hash_table_unref(attributes);
diff --git a/contrib/credential/wincred/git-credential-wincred.c b/contrib/credential/wincred/git-credential-wincred.c
index 006134043a..86518cd93d 100644
--- a/contrib/credential/wincred/git-credential-wincred.c
+++ b/contrib/credential/wincred/git-credential-wincred.c
@@ -94,6 +94,12 @@ static WCHAR *wusername, *password, *protocol, *host, *path, target[1024];
static void write_item(const char *what, LPCWSTR wbuf, int wlen)
{
char *buf;
+
+ if (!wbuf || !wlen) {
+ printf("%s=\n", what);
+ return;
+ }
+
int len = WideCharToMultiByte(CP_UTF8, 0, wbuf, wlen, NULL, 0, NULL,
FALSE);
buf = xmalloc(len);
@@ -160,7 +166,7 @@ static int match_part_last(LPCWSTR *ptarget, LPCWSTR want, LPCWSTR delim)
static int match_cred(const CREDENTIALW *cred)
{
LPCWSTR target = cred->TargetName;
- if (wusername && wcscmp(wusername, cred->UserName))
+ if (wusername && wcscmp(wusername, cred->UserName ? cred->UserName : L""))
return 0;
return match_part(&target, L"git", L":") &&
@@ -183,7 +189,7 @@ static void get_credential(void)
for (i = 0; i < num_creds; ++i)
if (match_cred(creds[i])) {
write_item("username", creds[i]->UserName,
- wcslen(creds[i]->UserName));
+ creds[i]->UserName ? wcslen(creds[i]->UserName) : 0);
write_item("password",
(LPCWSTR)creds[i]->CredentialBlob,
creds[i]->CredentialBlobSize / sizeof(WCHAR));
diff --git a/diff.c b/diff.c
index 6fd288420b..1898dd307d 100644
--- a/diff.c
+++ b/diff.c
@@ -707,83 +707,14 @@ struct moved_entry {
struct moved_entry *next_line;
};
-static int next_byte(const char **cp, const char **endp,
- const struct diff_options *diffopt)
-{
- int retval;
-
- if (*cp > *endp)
- return -1;
-
- if (isspace(**cp)) {
- if (DIFF_XDL_TST(diffopt, IGNORE_WHITESPACE_CHANGE)) {
- while (*cp < *endp && isspace(**cp))
- (*cp)++;
- /*
- * After skipping a couple of whitespaces,
- * we still have to account for one space.
- */
- return (int)' ';
- }
-
- if (DIFF_XDL_TST(diffopt, IGNORE_WHITESPACE)) {
- while (*cp < *endp && isspace(**cp))
- (*cp)++;
- /* return the first non-ws character via the usual below */
- }
- }
-
- retval = (unsigned char)(**cp);
- (*cp)++;
- return retval;
-}
-
static int moved_entry_cmp(const struct diff_options *diffopt,
const struct moved_entry *a,
const struct moved_entry *b,
const void *keydata)
{
- const char *ap = a->es->line, *ae = a->es->line + a->es->len;
- const char *bp = b->es->line, *be = b->es->line + b->es->len;
-
- if (!(diffopt->xdl_opts & XDF_WHITESPACE_FLAGS))
- return a->es->len != b->es->len || memcmp(ap, bp, a->es->len);
-
- if (DIFF_XDL_TST(diffopt, IGNORE_WHITESPACE_AT_EOL)) {
- while (ae > ap && isspace(*ae))
- ae--;
- while (be > bp && isspace(*be))
- be--;
- }
-
- while (1) {
- int ca, cb;
- ca = next_byte(&ap, &ae, diffopt);
- cb = next_byte(&bp, &be, diffopt);
- if (ca != cb)
- return 1;
- if (ca < 0)
- return 0;
- }
-}
-
-static unsigned get_string_hash(struct emitted_diff_symbol *es, struct diff_options *o)
-{
- if (o->xdl_opts & XDF_WHITESPACE_FLAGS) {
- static struct strbuf sb = STRBUF_INIT;
- const char *ap = es->line, *ae = es->line + es->len;
- int c;
-
- strbuf_reset(&sb);
- while (ae > ap && isspace(*ae))
- ae--;
- while ((c = next_byte(&ap, &ae, o)) > 0)
- strbuf_addch(&sb, c);
-
- return memhash(sb.buf, sb.len);
- } else {
- return memhash(es->line, es->len);
- }
+ return !xdiff_compare_lines(a->es->line, a->es->len,
+ b->es->line, b->es->len,
+ diffopt->xdl_opts);
}
static struct moved_entry *prepare_entry(struct diff_options *o,
@@ -792,7 +723,7 @@ static struct moved_entry *prepare_entry(struct diff_options *o,
struct moved_entry *ret = xmalloc(sizeof(*ret));
struct emitted_diff_symbol *l = &o->emitted_symbols->buf[line_no];
- ret->ent.hash = get_string_hash(l, o);
+ ret->ent.hash = xdiff_hash_string(l->line, l->len, o->xdl_opts);
ret->es = l;
ret->next_line = NULL;
@@ -3614,14 +3545,12 @@ int diff_populate_filespec(struct diff_filespec *s, unsigned int flags)
int fd;
if (lstat(s->path, &st) < 0) {
- if (errno == ENOENT) {
- err_empty:
- err = -1;
- empty:
- s->data = (char *)"";
- s->size = 0;
- return err;
- }
+ err_empty:
+ err = -1;
+ empty:
+ s->data = (char *)"";
+ s->size = 0;
+ return err;
}
s->size = xsize_t(st.st_size);
if (!s->size)
diff --git a/dir.c b/dir.c
index 1d17b800cf..9987011da5 100644
--- a/dir.c
+++ b/dir.c
@@ -1392,7 +1392,7 @@ static enum path_treatment treat_directory(struct dir_struct *dir,
if (!(dir->flags & DIR_NO_GITLINKS)) {
unsigned char sha1[20];
if (resolve_gitlink_ref(dirname, "HEAD", sha1) == 0)
- return path_untracked;
+ return exclude ? path_excluded : path_untracked;
}
return path_recurse;
}
diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 2563dc52da..437815669f 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -722,7 +722,7 @@ collapse_todo_ids() {
git rebase--helper --shorten-ids
}
-# Add commands after a pick or after a squash/fixup serie
+# Add commands after a pick or after a squash/fixup series
# in the todo list.
add_exec_commands () {
{
diff --git a/git.rc b/git.rc
index 33aafb786c..49002e0d54 100644
--- a/git.rc
+++ b/git.rc
@@ -1,6 +1,6 @@
1 VERSIONINFO
-FILEVERSION MAJOR,MINOR,0,0
-PRODUCTVERSION MAJOR,MINOR,0,0
+FILEVERSION MAJOR,MINOR,MICRO,PATCHLEVEL
+PRODUCTVERSION MAJOR,MINOR,MICRO,PATCHLEVEL
BEGIN
BLOCK "StringFileInfo"
BEGIN
diff --git a/grep.c b/grep.c
index ce6a48e634..d0b9b6cdfa 100644
--- a/grep.c
+++ b/grep.c
@@ -387,7 +387,7 @@ static void compile_pcre1_regexp(struct grep_pat *p, const struct grep_opt *opt)
if (!p->pcre1_regexp)
compile_regexp_failed(p, error);
- p->pcre1_extra_info = pcre_study(p->pcre1_regexp, PCRE_STUDY_JIT_COMPILE, &error);
+ p->pcre1_extra_info = pcre_study(p->pcre1_regexp, GIT_PCRE_STUDY_JIT_COMPILE, &error);
if (!p->pcre1_extra_info && error)
die("%s", error);
diff --git a/grep.h b/grep.h
index 52aecfab6e..399381c908 100644
--- a/grep.h
+++ b/grep.h
@@ -7,11 +7,12 @@
#if PCRE_MAJOR >= 8 && PCRE_MINOR >= 32
#ifndef NO_LIBPCRE1_JIT
#define GIT_PCRE1_USE_JIT
+#define GIT_PCRE_STUDY_JIT_COMPILE PCRE_STUDY_JIT_COMPILE
#endif
#endif
#endif
-#ifndef PCRE_STUDY_JIT_COMPILE
-#define PCRE_STUDY_JIT_COMPILE 0
+#ifndef GIT_PCRE_STUDY_JIT_COMPILE
+#define GIT_PCRE_STUDY_JIT_COMPILE 0
#endif
#if PCRE_MAJOR <= 8 && PCRE_MINOR < 20
typedef int pcre_jit_stack;
diff --git a/log-tree.c b/log-tree.c
index cea056234d..580b3a98a0 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -198,7 +198,7 @@ static const struct name_decoration *current_pointed_by_HEAD(const struct name_d
/* Now resolve and find the matching current branch */
branch_name = resolve_ref_unsafe("HEAD", 0, NULL, &rru_flags);
- if (!(rru_flags & REF_ISSYMREF))
+ if (!branch_name || !(rru_flags & REF_ISSYMREF))
return NULL;
if (!starts_with(branch_name, "refs/"))
diff --git a/sequencer.c b/sequencer.c
index f2a10cc4f2..332a383b03 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -1862,12 +1862,15 @@ static int error_failed_squash(struct commit *commit,
static int do_exec(const char *command_line)
{
+ struct argv_array child_env = ARGV_ARRAY_INIT;
const char *child_argv[] = { NULL, NULL };
int dirty, status;
fprintf(stderr, "Executing: %s\n", command_line);
child_argv[0] = command_line;
- status = run_command_v_opt(child_argv, RUN_USING_SHELL);
+ argv_array_pushf(&child_env, "GIT_DIR=%s", absolute_path(get_git_dir()));
+ status = run_command_v_opt_cd_env(child_argv, RUN_USING_SHELL, NULL,
+ child_env.argv);
/* force re-reading of the cache */
if (discard_cache() < 0 || read_cache() < 0)
@@ -1897,6 +1900,8 @@ static int do_exec(const char *command_line)
status = 1;
}
+ argv_array_clear(&child_env);
+
return status;
}
diff --git a/setup.c b/setup.c
index 03f51e056c..94768512b7 100644
--- a/setup.c
+++ b/setup.c
@@ -312,7 +312,9 @@ int is_git_directory(const char *suspect)
size_t len;
/* Check worktree-related signatures */
- strbuf_addf(&path, "%s/HEAD", suspect);
+ strbuf_addstr(&path, suspect);
+ strbuf_complete(&path, '/');
+ strbuf_addstr(&path, "HEAD");
if (validate_headref(path.buf))
goto done;
diff --git a/sha1_file.c b/sha1_file.c
index 10c3a0083d..36f85455e6 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -404,6 +404,9 @@ static void link_alt_odb_entries(const char *alt, int sep,
struct strbuf objdirbuf = STRBUF_INIT;
struct strbuf entry = STRBUF_INIT;
+ if (!alt || !*alt)
+ return;
+
if (depth > 5) {
error("%s: ignoring alternate object stores, nesting too deep.",
relative_base);
@@ -607,7 +610,6 @@ void prepare_alt_odb(void)
return;
alt = getenv(ALTERNATE_DB_ENVIRONMENT);
- if (!alt) alt = "";
alt_odb_tail = &alt_odb_list;
link_alt_odb_entries(alt, PATH_SEP, NULL, 0);
diff --git a/sha1_name.c b/sha1_name.c
index c7c5ab376c..603e667faa 100644
--- a/sha1_name.c
+++ b/sha1_name.c
@@ -1331,7 +1331,10 @@ void strbuf_branchname(struct strbuf *sb, const char *name, unsigned allowed)
int strbuf_check_branch_ref(struct strbuf *sb, const char *name)
{
- strbuf_branchname(sb, name, INTERPRET_BRANCH_LOCAL);
+ if (startup_info->have_repository)
+ strbuf_branchname(sb, name, INTERPRET_BRANCH_LOCAL);
+ else
+ strbuf_addstr(sb, name);
if (name[0] == '-')
return -1;
strbuf_splice(sb, 0, 0, "refs/heads/", 11);
diff --git a/t/helper/test-ref-store.c b/t/helper/test-ref-store.c
index 05d8c4d8af..6ec2670044 100644
--- a/t/helper/test-ref-store.c
+++ b/t/helper/test-ref-store.c
@@ -135,7 +135,7 @@ static int cmd_resolve_ref(struct ref_store *refs, const char **argv)
ref = refs_resolve_ref_unsafe(refs, refname, resolve_flags,
sha1, &flags);
- printf("%s %s 0x%x\n", sha1_to_hex(sha1), ref, flags);
+ printf("%s %s 0x%x\n", sha1_to_hex(sha1), ref ? ref : "(null)", flags);
return ref ? 0 : 1;
}
diff --git a/t/lib-credential.sh b/t/lib-credential.sh
index d8e41f7ddd..937b831ea6 100755
--- a/t/lib-credential.sh
+++ b/t/lib-credential.sh
@@ -44,6 +44,7 @@ helper_test_clean() {
reject $1 https example.com user2
reject $1 http path.tld user
reject $1 https timeout.tld user
+ reject $1 https sso.tld
}
reject() {
@@ -250,6 +251,24 @@ helper_test() {
password=pass2
EOF
'
+
+ test_expect_success "helper ($HELPER) can store empty username" '
+ check approve $HELPER <<-\EOF &&
+ protocol=https
+ host=sso.tld
+ username=
+ password=
+ EOF
+ check fill $HELPER <<-\EOF
+ protocol=https
+ host=sso.tld
+ --
+ protocol=https
+ host=sso.tld
+ username=
+ password=
+ EOF
+ '
}
helper_test_timeout() {
diff --git a/t/t0001-init.sh b/t/t0001-init.sh
index 86c1a51654..c413bff9cf 100755
--- a/t/t0001-init.sh
+++ b/t/t0001-init.sh
@@ -453,4 +453,16 @@ test_expect_success 're-init from a linked worktree' '
)
'
+test_expect_success MINGW 'redirect std handles' '
+ GIT_REDIRECT_STDOUT=output.txt git rev-parse --git-dir &&
+ test .git = "$(cat output.txt)" &&
+ test -z "$(GIT_REDIRECT_STDOUT=off git rev-parse --git-dir)" &&
+ test_must_fail env \
+ GIT_REDIRECT_STDOUT=output.txt \
+ GIT_REDIRECT_STDERR="2>&1" \
+ git rev-parse --git-dir --verify refs/invalid &&
+ printf ".git\nfatal: Needed a single revision\n" >expect &&
+ test_cmp expect output.txt
+'
+
test_done
diff --git a/t/t1402-check-ref-format.sh b/t/t1402-check-ref-format.sh
index 0790edf60d..98e4a8613b 100755
--- a/t/t1402-check-ref-format.sh
+++ b/t/t1402-check-ref-format.sh
@@ -144,6 +144,11 @@ test_expect_success "check-ref-format --branch @{-1}" '
refname2=$(git check-ref-format --branch @{-2}) &&
test "$refname2" = master'
+test_expect_success 'check-ref-format --branch -naster' '
+ test_must_fail git check-ref-format --branch -naster >actual &&
+ test_must_be_empty actual
+'
+
test_expect_success 'check-ref-format --branch from subdir' '
mkdir subdir &&
@@ -161,6 +166,17 @@ test_expect_success 'check-ref-format --branch from subdir' '
test "$refname" = "$sha1"
'
+test_expect_success 'check-ref-format --branch @{-1} from non-repo' '
+ nongit test_must_fail git check-ref-format --branch @{-1} >actual &&
+ test_must_be_empty actual
+'
+
+test_expect_success 'check-ref-format --branch master from non-repo' '
+ echo master >expect &&
+ nongit git check-ref-format --branch master >actual &&
+ test_cmp expect actual
+'
+
valid_ref_normalized() {
prereq=
case $1 in
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index 3704dbb2ec..6a82d1ed87 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -108,6 +108,17 @@ test_expect_success 'rebase -i with the exec command runs from tree root' '
rm -fr subdir
'
+test_expect_success 'rebase -i with exec allows git commands in subdirs' '
+ test_when_finished "rm -rf subdir" &&
+ test_when_finished "git rebase --abort ||:" &&
+ git checkout master &&
+ mkdir subdir && (cd subdir &&
+ set_fake_editor &&
+ FAKE_LINES="1 exec_cd_subdir_&&_git_rev-parse_--is-inside-work-tree" \
+ git rebase -i HEAD^
+ )
+'
+
test_expect_success 'rebase -i with the exec command checks tree cleanness' '
git checkout master &&
set_fake_editor &&
diff --git a/t/t3426-rebase-submodule.sh b/t/t3426-rebase-submodule.sh
index ebf4f5e4b2..a2bba04ba9 100755
--- a/t/t3426-rebase-submodule.sh
+++ b/t/t3426-rebase-submodule.sh
@@ -40,4 +40,21 @@ git_rebase_interactive () {
test_submodule_switch "git_rebase_interactive"
+test_expect_success 'rebase interactive ignores modified submodules' '
+ test_when_finished "rm -rf super sub" &&
+ git init sub &&
+ git -C sub commit --allow-empty -m "Initial commit" &&
+ git init super &&
+ git -C super submodule add ../sub &&
+ git -C super config submodule.sub.ignore dirty &&
+ >super/foo &&
+ git -C super add foo &&
+ git -C super commit -m "Initial commit" &&
+ test_commit -C super a &&
+ test_commit -C super b &&
+ test_commit -C super/sub c &&
+ set_fake_editor &&
+ git -C super rebase -i HEAD^^
+'
+
test_done
diff --git a/t/t3600-rm.sh b/t/t3600-rm.sh
index f8568f8841..ab5500db44 100755
--- a/t/t3600-rm.sh
+++ b/t/t3600-rm.sh
@@ -688,7 +688,7 @@ test_expect_success 'checking out a commit after submodule removal needs manual
git submodule update &&
git checkout -q HEAD^ &&
git checkout -q master 2>actual &&
- test_i18ngrep "^warning: unable to rmdir submod:" actual &&
+ test_i18ngrep "^warning: unable to rmdir '\''submod'\'':" actual &&
git status -s submod >actual &&
echo "?? submod/" >expected &&
test_cmp expected actual &&
diff --git a/t/t4015-diff-whitespace.sh b/t/t4015-diff-whitespace.sh
index 87083f728f..6c9a93b734 100755
--- a/t/t4015-diff-whitespace.sh
+++ b/t/t4015-diff-whitespace.sh
@@ -1318,30 +1318,38 @@ test_expect_success 'no effect from --color-moved with --word-diff' '
test_cmp expect actual
'
-test_expect_success 'move detection ignoring whitespace ' '
+test_expect_success 'set up whitespace tests' '
git reset --hard &&
- cat <<\EOF >lines.txt &&
-line 1
-line 2
-line 3
-line 4
-long line 5
-long line 6
-long line 7
-EOF
- git add lines.txt &&
- git commit -m "add poetry" &&
- cat <<\EOF >lines.txt &&
- long line 5
+ # Note that these lines have no leading or trailing whitespace.
+ cat <<-\EOF >lines.txt &&
+ line 1
+ line 2
+ line 3
+ line 4
+ line 5
long line 6
long line 7
-line 1
-line 2
-line 3
-line 4
-EOF
- test_config color.diff.oldMoved "magenta" &&
- test_config color.diff.newMoved "cyan" &&
+ long line 8
+ long line 9
+ EOF
+ git add lines.txt &&
+ git commit -m "add poetry" &&
+ git config color.diff.oldMoved "magenta" &&
+ git config color.diff.newMoved "cyan"
+'
+
+test_expect_success 'move detection ignoring whitespace ' '
+ q_to_tab <<-\EOF >lines.txt &&
+ Qlong line 6
+ Qlong line 7
+ Qlong line 8
+ Qchanged long line 9
+ line 1
+ line 2
+ line 3
+ line 4
+ line 5
+ EOF
git diff HEAD --no-renames --color-moved --color |
grep -v "index" |
test_decode_color >actual &&
@@ -1349,17 +1357,20 @@ EOF
<BOLD>diff --git a/lines.txt b/lines.txt<RESET>
<BOLD>--- a/lines.txt<RESET>
<BOLD>+++ b/lines.txt<RESET>
- <CYAN>@@ -1,7 +1,7 @@<RESET>
- <GREEN>+<RESET> <GREEN>long line 5<RESET>
+ <CYAN>@@ -1,9 +1,9 @@<RESET>
<GREEN>+<RESET> <GREEN>long line 6<RESET>
<GREEN>+<RESET> <GREEN>long line 7<RESET>
+ <GREEN>+<RESET> <GREEN>long line 8<RESET>
+ <GREEN>+<RESET> <GREEN>changed long line 9<RESET>
line 1<RESET>
line 2<RESET>
line 3<RESET>
line 4<RESET>
- <RED>-long line 5<RESET>
+ line 5<RESET>
<RED>-long line 6<RESET>
<RED>-long line 7<RESET>
+ <RED>-long line 8<RESET>
+ <RED>-long line 9<RESET>
EOF
test_cmp expected actual &&
@@ -1370,21 +1381,160 @@ EOF
<BOLD>diff --git a/lines.txt b/lines.txt<RESET>
<BOLD>--- a/lines.txt<RESET>
<BOLD>+++ b/lines.txt<RESET>
- <CYAN>@@ -1,7 +1,7 @@<RESET>
- <CYAN>+<RESET> <CYAN>long line 5<RESET>
+ <CYAN>@@ -1,9 +1,9 @@<RESET>
<CYAN>+<RESET> <CYAN>long line 6<RESET>
<CYAN>+<RESET> <CYAN>long line 7<RESET>
+ <CYAN>+<RESET> <CYAN>long line 8<RESET>
+ <GREEN>+<RESET> <GREEN>changed long line 9<RESET>
+ line 1<RESET>
+ line 2<RESET>
+ line 3<RESET>
+ line 4<RESET>
+ line 5<RESET>
+ <MAGENTA>-long line 6<RESET>
+ <MAGENTA>-long line 7<RESET>
+ <MAGENTA>-long line 8<RESET>
+ <RED>-long line 9<RESET>
+ EOF
+ test_cmp expected actual
+'
+
+test_expect_success 'move detection ignoring whitespace changes' '
+ git reset --hard &&
+ # Lines 6-8 have a space change, but 9 is new whitespace
+ q_to_tab <<-\EOF >lines.txt &&
+ longQline 6
+ longQline 7
+ longQline 8
+ long liQne 9
+ line 1
+ line 2
+ line 3
+ line 4
+ line 5
+ EOF
+
+ git diff HEAD --no-renames --color-moved --color |
+ grep -v "index" |
+ test_decode_color >actual &&
+ cat <<-\EOF >expected &&
+ <BOLD>diff --git a/lines.txt b/lines.txt<RESET>
+ <BOLD>--- a/lines.txt<RESET>
+ <BOLD>+++ b/lines.txt<RESET>
+ <CYAN>@@ -1,9 +1,9 @@<RESET>
+ <GREEN>+<RESET><GREEN>long line 6<RESET>
+ <GREEN>+<RESET><GREEN>long line 7<RESET>
+ <GREEN>+<RESET><GREEN>long line 8<RESET>
+ <GREEN>+<RESET><GREEN>long li ne 9<RESET>
+ line 1<RESET>
+ line 2<RESET>
+ line 3<RESET>
+ line 4<RESET>
+ line 5<RESET>
+ <RED>-long line 6<RESET>
+ <RED>-long line 7<RESET>
+ <RED>-long line 8<RESET>
+ <RED>-long line 9<RESET>
+ EOF
+ test_cmp expected actual &&
+
+ git diff HEAD --no-renames -b --color-moved --color |
+ grep -v "index" |
+ test_decode_color >actual &&
+ cat <<-\EOF >expected &&
+ <BOLD>diff --git a/lines.txt b/lines.txt<RESET>
+ <BOLD>--- a/lines.txt<RESET>
+ <BOLD>+++ b/lines.txt<RESET>
+ <CYAN>@@ -1,9 +1,9 @@<RESET>
+ <CYAN>+<RESET><CYAN>long line 6<RESET>
+ <CYAN>+<RESET><CYAN>long line 7<RESET>
+ <CYAN>+<RESET><CYAN>long line 8<RESET>
+ <GREEN>+<RESET><GREEN>long li ne 9<RESET>
+ line 1<RESET>
+ line 2<RESET>
+ line 3<RESET>
+ line 4<RESET>
+ line 5<RESET>
+ <MAGENTA>-long line 6<RESET>
+ <MAGENTA>-long line 7<RESET>
+ <MAGENTA>-long line 8<RESET>
+ <RED>-long line 9<RESET>
+ EOF
+ test_cmp expected actual
+'
+
+test_expect_success 'move detection ignoring whitespace at eol' '
+ git reset --hard &&
+ # Lines 6-9 have new eol whitespace, but 9 also has it in the middle
+ q_to_tab <<-\EOF >lines.txt &&
+ long line 6Q
+ long line 7Q
+ long line 8Q
+ longQline 9Q
+ line 1
+ line 2
+ line 3
+ line 4
+ line 5
+ EOF
+
+ # avoid cluttering the output with complaints about our eol whitespace
+ test_config core.whitespace -blank-at-eol &&
+
+ git diff HEAD --no-renames --color-moved --color |
+ grep -v "index" |
+ test_decode_color >actual &&
+ cat <<-\EOF >expected &&
+ <BOLD>diff --git a/lines.txt b/lines.txt<RESET>
+ <BOLD>--- a/lines.txt<RESET>
+ <BOLD>+++ b/lines.txt<RESET>
+ <CYAN>@@ -1,9 +1,9 @@<RESET>
+ <GREEN>+<RESET><GREEN>long line 6 <RESET>
+ <GREEN>+<RESET><GREEN>long line 7 <RESET>
+ <GREEN>+<RESET><GREEN>long line 8 <RESET>
+ <GREEN>+<RESET><GREEN>long line 9 <RESET>
+ line 1<RESET>
+ line 2<RESET>
+ line 3<RESET>
+ line 4<RESET>
+ line 5<RESET>
+ <RED>-long line 6<RESET>
+ <RED>-long line 7<RESET>
+ <RED>-long line 8<RESET>
+ <RED>-long line 9<RESET>
+ EOF
+ test_cmp expected actual &&
+
+ git diff HEAD --no-renames --ignore-space-at-eol --color-moved --color |
+ grep -v "index" |
+ test_decode_color >actual &&
+ cat <<-\EOF >expected &&
+ <BOLD>diff --git a/lines.txt b/lines.txt<RESET>
+ <BOLD>--- a/lines.txt<RESET>
+ <BOLD>+++ b/lines.txt<RESET>
+ <CYAN>@@ -1,9 +1,9 @@<RESET>
+ <CYAN>+<RESET><CYAN>long line 6 <RESET>
+ <CYAN>+<RESET><CYAN>long line 7 <RESET>
+ <CYAN>+<RESET><CYAN>long line 8 <RESET>
+ <GREEN>+<RESET><GREEN>long line 9 <RESET>
line 1<RESET>
line 2<RESET>
line 3<RESET>
line 4<RESET>
- <MAGENTA>-long line 5<RESET>
+ line 5<RESET>
<MAGENTA>-long line 6<RESET>
<MAGENTA>-long line 7<RESET>
+ <MAGENTA>-long line 8<RESET>
+ <RED>-long line 9<RESET>
EOF
test_cmp expected actual
'
+test_expect_success 'clean up whitespace-test colors' '
+ git config --unset color.diff.oldMoved &&
+ git config --unset color.diff.newMoved
+'
+
test_expect_success '--color-moved block at end of diff output respects MIN_ALNUM_COUNT' '
git reset --hard &&
>bar &&
@@ -1530,13 +1680,4 @@ test_expect_success 'move detection with submodules' '
test_cmp expect decoded_actual
'
-test_expect_success 'move detection with whitespace changes' '
- test_when_finished "git reset --hard" &&
- test_seq 10 >test &&
- git add test &&
- sed s/3/42/ <test >test.tmp &&
- mv test.tmp test &&
- git -c diff.colormoved diff --ignore-space-change -- test
-'
-
test_done
diff --git a/t/t5580-clone-push-unc.sh b/t/t5580-clone-push-unc.sh
index b322c2f722..ba548df4a9 100755
--- a/t/t5580-clone-push-unc.sh
+++ b/t/t5580-clone-push-unc.sh
@@ -3,12 +3,18 @@
test_description='various Windows-only path tests'
. ./test-lib.sh
-if ! test_have_prereq MINGW; then
+if test_have_prereq CYGWIN
+then
+ alias winpwd='cygpath -aw .'
+elif test_have_prereq MINGW
+then
+ alias winpwd=pwd
+else
skip_all='skipping Windows-only path tests'
test_done
fi
-UNCPATH="$(pwd)"
+UNCPATH="$(winpwd)"
case "$UNCPATH" in
[A-Z]:*)
# Use administrative share e.g. \\localhost\C$\git-sdk-64\usr\src\git
@@ -45,8 +51,8 @@ test_expect_success push '
test "$rev" = "$(git rev-parse --verify refs/heads/to-push)"
'
-test_expect_success 'remote nick cannot contain backslashes' '
- BACKSLASHED="$(pwd | tr / \\\\)" &&
+test_expect_success MINGW 'remote nick cannot contain backslashes' '
+ BACKSLASHED="$(winpwd | tr / \\\\)" &&
git ls-remote "$BACKSLASHED" >out 2>err &&
test_i18ngrep ! "unable to access" err
'
diff --git a/t/t5601-clone.sh b/t/t5601-clone.sh
index 9c56f771b6..50e40abb11 100755
--- a/t/t5601-clone.sh
+++ b/t/t5601-clone.sh
@@ -308,6 +308,7 @@ test_expect_success 'clone checking out a tag' '
setup_ssh_wrapper () {
test_expect_success 'setup ssh wrapper' '
+ rm -f "$TRASH_DIRECTORY/ssh-wrapper$X" &&
cp "$GIT_BUILD_DIR/t/helper/test-fake-ssh$X" \
"$TRASH_DIRECTORY/ssh-wrapper$X" &&
GIT_SSH="$TRASH_DIRECTORY/ssh-wrapper$X" &&
@@ -318,6 +319,7 @@ setup_ssh_wrapper () {
}
copy_ssh_wrapper_as () {
+ rm -f "${1%$X}$X" &&
cp "$TRASH_DIRECTORY/ssh-wrapper$X" "${1%$X}$X" &&
GIT_SSH="${1%$X}$X" &&
export GIT_SSH
diff --git a/t/t7001-mv.sh b/t/t7001-mv.sh
index f5929c46f3..6e5031f56f 100755
--- a/t/t7001-mv.sh
+++ b/t/t7001-mv.sh
@@ -452,7 +452,7 @@ test_expect_success 'checking out a commit before submodule moved needs manual u
git mv sub sub2 &&
git commit -m "moved sub to sub2" &&
git checkout -q HEAD^ 2>actual &&
- test_i18ngrep "^warning: unable to rmdir sub2:" actual &&
+ test_i18ngrep "^warning: unable to rmdir '\''sub2'\'':" actual &&
git status -s sub2 >actual &&
echo "?? sub2/" >expected &&
test_cmp expected actual &&
diff --git a/t/t7006-pager.sh b/t/t7006-pager.sh
index f0f1abd1c2..865168ec6a 100755
--- a/t/t7006-pager.sh
+++ b/t/t7006-pager.sh
@@ -570,4 +570,18 @@ test_expect_success 'command with underscores does not complain' '
test_cmp expect actual
'
+test_expect_success TTY 'git tag with auto-columns ' '
+ test_commit one &&
+ test_commit two &&
+ test_commit three &&
+ test_commit four &&
+ test_commit five &&
+ cat >expect <<-\EOF &&
+ initial one two three four five
+ EOF
+ test_terminal env PAGER="cat >actual" COLUMNS=80 \
+ git -c column.ui=auto tag --sort=authordate &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t7061-wtstatus-ignore.sh b/t/t7061-wtstatus-ignore.sh
index fc6013ba3c..0c394cf995 100755
--- a/t/t7061-wtstatus-ignore.sh
+++ b/t/t7061-wtstatus-ignore.sh
@@ -272,4 +272,15 @@ test_expect_success 'status ignored tracked directory with uncommitted file in t
test_cmp expected actual
'
+cat >expected <<\EOF
+!! tracked/submodule/
+EOF
+
+test_expect_success 'status ignores submodule in excluded directory' '
+ git init tracked/submodule &&
+ test_commit -C tracked/submodule initial &&
+ git status --porcelain --ignored -u tracked/submodule >actual &&
+ test_cmp expected actual
+'
+
test_done
diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh
index 2cb999ecfa..fc614dcbfa 100755
--- a/t/t9902-completion.sh
+++ b/t/t9902-completion.sh
@@ -1245,6 +1245,10 @@ test_expect_success 'double dash "git checkout"' '
--conflict=
--orphan Z
--patch Z
+ --detach Z
+ --ignore-skip-worktree-bits Z
+ --recurse-submodules Z
+ --no-recurse-submodules Z
EOF
'
diff --git a/worktree.c b/worktree.c
index 70015629dc..f8c40f2f5f 100644
--- a/worktree.c
+++ b/worktree.c
@@ -327,7 +327,8 @@ const struct worktree *find_shared_symref(const char *symref,
refs = get_worktree_ref_store(wt);
symref_target = refs_resolve_ref_unsafe(refs, symref, 0,
NULL, &flags);
- if ((flags & REF_ISSYMREF) && !strcmp(symref_target, target)) {
+ if ((flags & REF_ISSYMREF) &&
+ symref_target && !strcmp(symref_target, target)) {
existing = wt;
break;
}
diff --git a/wrapper.c b/wrapper.c
index 61aba0b5c1..d20356a776 100644
--- a/wrapper.c
+++ b/wrapper.c
@@ -569,7 +569,7 @@ static int warn_if_unremovable(const char *op, const char *file, int rc)
if (!rc || errno == ENOENT)
return 0;
err = errno;
- warning_errno("unable to %s %s", op, file);
+ warning_errno("unable to %s '%s'", op, file);
errno = err;
return rc;
}
@@ -583,7 +583,7 @@ int unlink_or_msg(const char *file, struct strbuf *err)
if (!rc || errno == ENOENT)
return 0;
- strbuf_addf(err, "unable to unlink %s: %s",
+ strbuf_addf(err, "unable to unlink '%s': %s",
file, strerror(errno));
return -1;
}
@@ -653,9 +653,9 @@ void write_file_buf(const char *path, const char *buf, size_t len)
{
int fd = xopen(path, O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (write_in_full(fd, buf, len) < 0)
- die_errno(_("could not write to %s"), path);
+ die_errno(_("could not write to '%s'"), path);
if (close(fd))
- die_errno(_("could not close %s"), path);
+ die_errno(_("could not close '%s'"), path);
}
void write_file(const char *path, const char *fmt, ...)
diff --git a/wt-status.c b/wt-status.c
index 29bc64cc02..94e5ebaf8b 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -2262,8 +2262,10 @@ int has_unstaged_changes(int ignore_submodules)
int result;
init_revisions(&rev_info, NULL);
- if (ignore_submodules)
+ if (ignore_submodules) {
DIFF_OPT_SET(&rev_info.diffopt, IGNORE_SUBMODULES);
+ DIFF_OPT_SET(&rev_info.diffopt, OVERRIDE_SUBMODULE_CONFIG);
+ }
DIFF_OPT_SET(&rev_info.diffopt, QUICK);
diff_setup_done(&rev_info.diffopt);
result = run_diff_files(&rev_info, 0);
diff --git a/xdiff-interface.c b/xdiff-interface.c
index 018e033089..770e1f7f81 100644
--- a/xdiff-interface.c
+++ b/xdiff-interface.c
@@ -5,6 +5,7 @@
#include "xdiff/xdiffi.h"
#include "xdiff/xemit.h"
#include "xdiff/xmacros.h"
+#include "xdiff/xutils.h"
struct xdiff_emit_state {
xdiff_emit_consume_fn consume;
@@ -296,6 +297,17 @@ void xdiff_clear_find_func(xdemitconf_t *xecfg)
}
}
+unsigned long xdiff_hash_string(const char *s, size_t len, long flags)
+{
+ return xdl_hash_record(&s, s + len, flags);
+}
+
+int xdiff_compare_lines(const char *l1, long s1,
+ const char *l2, long s2, long flags)
+{
+ return xdl_recmatch(l1, s1, l2, s2, flags);
+}
+
int git_xmerge_style = -1;
int git_xmerge_config(const char *var, const char *value, void *cb)
diff --git a/xdiff-interface.h b/xdiff-interface.h
index 6f6ba9095d..135fc05d72 100644
--- a/xdiff-interface.h
+++ b/xdiff-interface.h
@@ -29,4 +29,20 @@ extern void xdiff_clear_find_func(xdemitconf_t *xecfg);
extern int git_xmerge_config(const char *var, const char *value, void *cb);
extern int git_xmerge_style;
+/*
+ * Compare the strings l1 with l2 which are of size s1 and s2 respectively.
+ * Returns 1 if the strings are deemed equal, 0 otherwise.
+ * The `flags` given as XDF_WHITESPACE_FLAGS determine how white spaces
+ * are treated for the comparision.
+ */
+extern int xdiff_compare_lines(const char *l1, long s1,
+ const char *l2, long s2, long flags);
+
+/*
+ * Returns a hash of the string s of length len.
+ * The `flags` given as XDF_WHITESPACE_FLAGS determine how white spaces
+ * are treated for the hash.
+ */
+extern unsigned long xdiff_hash_string(const char *s, size_t len, long flags);
+
#endif