diff --git a/Documentation/config.txt b/Documentation/config.txt
index bf706b950e..7c80473980 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -438,6 +438,8 @@ include::config/reset.txt[]
include::config/sendemail.txt[]
+include::config/sendpack.txt[]
+
include::config/sequencer.txt[]
include::config/showbranch.txt[]
diff --git a/Documentation/config/http.txt b/Documentation/config/http.txt
index 3968fbb697..4d7fef1ba1 100644
--- a/Documentation/config/http.txt
+++ b/Documentation/config/http.txt
@@ -173,11 +173,13 @@ http.sslBackend::
http.schannelCheckRevoke::
Used to enforce or disable certificate revocation checks in cURL
- when http.sslBackend is set to "schannel". Defaults to `true` if
- unset. Only necessary to disable this if Git consistently errors
- and the message is about checking the revocation status of a
- certificate. This option is ignored if cURL lacks support for
- setting the relevant SSL option at runtime.
+ when http.sslBackend is set to "schannel" via "true" and "false",
+ respectively. Another accepted value is "best-effort" (the default)
+ in which case revocation checks are performed, but errors due to
+ revocation list distribution points that are offline are silently
+ ignored, as well as errors due to certificates missing revocation
+ list distribution points. This option is ignored if cURL lacks
+ support for setting the relevant SSL option at runtime.
http.schannelUseSSLCAInfo::
As of cURL v7.60.0, the Secure Channel backend can use the
diff --git a/Documentation/config/sendpack.txt b/Documentation/config/sendpack.txt
new file mode 100644
index 0000000000..e306f657fb
--- /dev/null
+++ b/Documentation/config/sendpack.txt
@@ -0,0 +1,5 @@
+sendpack.sideband::
+ Allows to disable the side-band-64k capability for send-pack even
+ when it is advertised by the server. Makes it possible to work
+ around a limitation in the git for windows implementation together
+ with the dump git protocol. Defaults to true.
diff --git a/Makefile b/Makefile
index 1fb0ec1705..549206da7c 100644
--- a/Makefile
+++ b/Makefile
@@ -2767,6 +2767,11 @@ ifdef GIT_INTEROP_MAKE_OPTS
endif
ifdef GIT_TEST_INDEX_VERSION
@echo GIT_TEST_INDEX_VERSION=\''$(subst ','\'',$(subst ','\'',$(GIT_TEST_INDEX_VERSION)))'\' >>$@+
+endif
+ifdef RUNTIME_PREFIX
+ @echo RUNTIME_PREFIX=\'true\' >>$@+
+else
+ @echo RUNTIME_PREFIX=\'false\' >>$@+
endif
@if cmp $@+ $@ >/dev/null 2>&1; then $(RM) $@+; else mv $@+ $@; fi
diff --git a/abspath.c b/abspath.c
index 6f15a418bb..8a14e61c2c 100644
--- a/abspath.c
+++ b/abspath.c
@@ -95,6 +95,9 @@ char *strbuf_realpath(struct strbuf *resolved, const char *path,
goto error_out;
}
+ if (platform_strbuf_realpath(resolved, path))
+ return resolved->buf;
+
strbuf_addstr(&remaining, path);
get_root_part(resolved, &remaining);
diff --git a/archive-tar.c b/archive-tar.c
index f1a1447ebd..9f2e97f67d 100644
--- a/archive-tar.c
+++ b/archive-tar.c
@@ -17,6 +17,8 @@ static unsigned long offset;
static int tar_umask = 002;
+static gzFile gzip;
+
static int write_tar_filter_archive(const struct archiver *ar,
struct archiver_args *args);
@@ -38,11 +40,21 @@ static int write_tar_filter_archive(const struct archiver *ar,
#define USTAR_MAX_MTIME 077777777777ULL
#endif
+/* writes out the whole block, or dies if fails */
+static void write_block_or_die(const char *block) {
+ if (gzip) {
+ if (gzwrite(gzip, block, (unsigned) BLOCKSIZE) != BLOCKSIZE)
+ die(_("gzwrite failed"));
+ } else {
+ write_or_die(1, block, BLOCKSIZE);
+ }
+}
+
/* writes out the whole block, but only if it is full */
static void write_if_needed(void)
{
if (offset == BLOCKSIZE) {
- write_or_die(1, block, BLOCKSIZE);
+ write_block_or_die(block);
offset = 0;
}
}
@@ -66,7 +78,7 @@ static void do_write_blocked(const void *data, unsigned long size)
write_if_needed();
}
while (size >= BLOCKSIZE) {
- write_or_die(1, buf, BLOCKSIZE);
+ write_block_or_die(buf);
size -= BLOCKSIZE;
buf += BLOCKSIZE;
}
@@ -101,10 +113,10 @@ static void write_trailer(void)
{
int tail = BLOCKSIZE - offset;
memset(block + offset, 0, tail);
- write_or_die(1, block, BLOCKSIZE);
+ write_block_or_die(block);
if (tail < 2 * RECORDSIZE) {
memset(block, 0, offset);
- write_or_die(1, block, BLOCKSIZE);
+ write_block_or_die(block);
}
}
@@ -445,18 +457,34 @@ static int write_tar_filter_archive(const struct archiver *ar,
filter.use_shell = 1;
filter.in = -1;
- if (start_command(&filter) < 0)
- die_errno(_("unable to start '%s' filter"), argv[0]);
- close(1);
- if (dup2(filter.in, 1) < 0)
- die_errno(_("unable to redirect descriptor"));
- close(filter.in);
+ if (!strcmp("gzip -cn", ar->data)) {
+ char outmode[4] = "wb\0";
+
+ if (args->compression_level >= 0 && args->compression_level <= 9)
+ outmode[2] = '0' + args->compression_level;
+
+ gzip = gzdopen(fileno(stdout), outmode);
+ if (!gzip)
+ die(_("Could not gzdopen stdout"));
+ } else {
+ if (start_command(&filter) < 0)
+ die_errno(_("unable to start '%s' filter"), argv[0]);
+ close(1);
+ if (dup2(filter.in, 1) < 0)
+ die_errno(_("unable to redirect descriptor"));
+ close(filter.in);
+ }
r = write_tar_archive(ar, args);
- close(1);
- if (finish_command(&filter) != 0)
- die(_("'%s' filter reported error"), argv[0]);
+ if (gzip) {
+ if (gzclose(gzip) != Z_OK)
+ die(_("gzclose failed"));
+ } else {
+ close(1);
+ if (finish_command(&filter) != 0)
+ die(_("'%s' filter reported error"), argv[0]);
+ }
strbuf_release(&cmd);
return r;
diff --git a/builtin/clean.c b/builtin/clean.c
index 687ab473c2..230c6700df 100644
--- a/builtin/clean.c
+++ b/builtin/clean.c
@@ -34,6 +34,10 @@ static const char *msg_remove = N_("Removing %s\n");
static const char *msg_would_remove = N_("Would remove %s\n");
static const char *msg_skip_git_dir = N_("Skipping repository %s\n");
static const char *msg_would_skip_git_dir = N_("Would skip repository %s\n");
+#ifndef CAN_UNLINK_MOUNT_POINTS
+static const char *msg_skip_mount_point = N_("Skipping mount point %s\n");
+static const char *msg_would_skip_mount_point = N_("Would skip mount point %s\n");
+#endif
static const char *msg_warn_remove_failed = N_("failed to remove %s");
static const char *msg_warn_lstat_failed = N_("could not lstat %s\n");
@@ -171,6 +175,29 @@ static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag,
goto out;
}
+ if (is_mount_point(path)) {
+#ifndef CAN_UNLINK_MOUNT_POINTS
+ if (!quiet) {
+ quote_path(path->buf, prefix, "ed, 0);
+ printf(dry_run ?
+ _(msg_would_skip_mount_point) :
+ _(msg_skip_mount_point), quoted.buf);
+ }
+ *dir_gone = 0;
+#else
+ if (!dry_run && unlink(path->buf)) {
+ int saved_errno = errno;
+ quote_path(path->buf, prefix, "ed, 0);
+ errno = saved_errno;
+ warning_errno(_(msg_warn_remove_failed), quoted.buf);
+ *dir_gone = 0;
+ ret = -1;
+ }
+#endif
+
+ goto out;
+ }
+
dir = opendir(path->buf);
if (!dir) {
/* an empty dir could be removed even if it is unreadble */
diff --git a/builtin/clone.c b/builtin/clone.c
index 391aa41075..25500b4a3d 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -1254,7 +1254,9 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
}
if (!is_local && !complete_refs_before_fetch)
- transport_fetch_refs(transport, mapped_refs);
+ if (transport_fetch_refs(transport, mapped_refs))
+ die(_("could not fetch refs from %s"),
+ transport->url);
remote_head = find_ref_by_name(refs, "HEAD");
remote_head_points_at =
diff --git a/cache.h b/cache.h
index c0072d43b1..3e979666c8 100644
--- a/cache.h
+++ b/cache.h
@@ -1329,6 +1329,7 @@ int normalize_path_copy_len(char *dst, const char *src, int *prefix_len);
int normalize_path_copy(char *dst, const char *src);
int longest_ancestor_length(const char *path, struct string_list *prefixes);
char *strip_path_suffix(const char *path, const char *suffix);
+int is_mount_point_via_stat(struct strbuf *path);
int daemon_avoid_alias(const char *path);
/*
diff --git a/compat/mingw.c b/compat/mingw.c
index a00f331230..47bc71a0f0 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1005,11 +1005,19 @@ unsigned int sleep (unsigned int seconds)
char *mingw_mktemp(char *template)
{
wchar_t wtemplate[MAX_PATH];
+ int offset = 0;
+
if (xutftowcs_path(wtemplate, template) < 0)
return NULL;
+
+ if (is_dir_sep(template[0]) && !is_dir_sep(template[1]) &&
+ iswalpha(wtemplate[0]) && wtemplate[1] == L':') {
+ /* We have an absolute path missing the drive prefix */
+ offset = 2;
+ }
if (!_wmktemp(wtemplate))
return NULL;
- if (xwcstoutf(template, wtemplate, strlen(template) + 1) < 0)
+ if (xwcstoutf(template, wtemplate + offset, strlen(template) + 1) < 0)
return NULL;
return template;
}
@@ -1072,33 +1080,97 @@ struct tm *localtime_r(const time_t *timep, struct tm *result)
return NULL;
}
+char *mingw_strbuf_realpath(struct strbuf *resolved, const char *path)
+{
+ wchar_t wpath[MAX_PATH];
+ HANDLE h;
+ DWORD ret;
+ int len;
+ const char *last_component = NULL;
+
+ if (xutftowcs_path(wpath, path) < 0)
+ return NULL;
+
+ h = CreateFileW(wpath, 0,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
+ OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+
+ /*
+ * strbuf_realpath() allows the last path component to not exist. If
+ * that is the case, now it's time to try without last component.
+ */
+ if (h == INVALID_HANDLE_VALUE &&
+ GetLastError() == ERROR_FILE_NOT_FOUND) {
+ /* cut last component off of `wpath` */
+ wchar_t *p = wpath + wcslen(wpath);
+
+ while (p != wpath)
+ if (*(--p) == L'/' || *p == L'\\')
+ break; /* found start of last component */
+
+ if (p != wpath && (last_component = find_last_dir_sep(path))) {
+ last_component++; /* skip directory separator */
+ *p = L'\0';
+ h = CreateFileW(wpath, 0, FILE_SHARE_READ |
+ FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ NULL, OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS, NULL);
+ }
+ }
+
+ if (h == INVALID_HANDLE_VALUE)
+ return NULL;
+
+ ret = GetFinalPathNameByHandleW(h, wpath, ARRAY_SIZE(wpath), 0);
+ CloseHandle(h);
+ if (!ret || ret >= ARRAY_SIZE(wpath))
+ return NULL;
+
+ len = wcslen(wpath) * 3;
+ strbuf_grow(resolved, len);
+ len = xwcstoutf(resolved->buf, normalize_ntpath(wpath), len);
+ if (len < 0)
+ return NULL;
+ resolved->len = len;
+
+ if (last_component) {
+ /* Use forward-slash, like `normalize_ntpath()` */
+ strbuf_addch(resolved, '/');
+ strbuf_addstr(resolved, last_component);
+ }
+
+ return resolved->buf;
+
+}
+
char *mingw_getcwd(char *pointer, int len)
{
wchar_t cwd[MAX_PATH], wpointer[MAX_PATH];
DWORD ret = GetCurrentDirectoryW(ARRAY_SIZE(cwd), cwd);
+ HANDLE hnd;
if (!ret || ret >= ARRAY_SIZE(cwd)) {
errno = ret ? ENAMETOOLONG : err_win_to_posix(GetLastError());
return NULL;
}
- ret = GetLongPathNameW(cwd, wpointer, ARRAY_SIZE(wpointer));
- if (!ret && GetLastError() == ERROR_ACCESS_DENIED) {
- HANDLE hnd = CreateFileW(cwd, 0,
- FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
- OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
- if (hnd == INVALID_HANDLE_VALUE)
- return NULL;
+ hnd = CreateFileW(cwd, 0,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
+ OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+ if (hnd != INVALID_HANDLE_VALUE) {
ret = GetFinalPathNameByHandleW(hnd, wpointer, ARRAY_SIZE(wpointer), 0);
CloseHandle(hnd);
- if (!ret || ret >= ARRAY_SIZE(wpointer))
- return NULL;
+ if (!ret || ret >= ARRAY_SIZE(wpointer)) {
+ ret = GetLongPathNameW(cwd, wpointer, ARRAY_SIZE(wpointer));
+ if (!ret || ret >= ARRAY_SIZE(wpointer)) {
+ errno = ret ? ENAMETOOLONG : err_win_to_posix(GetLastError());
+ return NULL;
+ }
+ }
if (xwcstoutf(pointer, normalize_ntpath(wpointer), len) < 0)
return NULL;
return pointer;
}
- if (!ret || ret >= ARRAY_SIZE(wpointer))
- return NULL;
- if (xwcstoutf(pointer, wpointer, len) < 0)
+ if (xwcstoutf(pointer, cwd, len) < 0)
return NULL;
convert_slashes(pointer);
return pointer;
@@ -1971,18 +2043,150 @@ static void ensure_socket_initialization(void)
initialized = 1;
}
+static int winsock_error_to_errno(DWORD err)
+{
+ switch (err) {
+ case WSAEINTR: return EINTR;
+ case WSAEBADF: return EBADF;
+ case WSAEACCES: return EACCES;
+ case WSAEFAULT: return EFAULT;
+ case WSAEINVAL: return EINVAL;
+ case WSAEMFILE: return EMFILE;
+ case WSAEWOULDBLOCK: return EWOULDBLOCK;
+ case WSAEINPROGRESS: return EINPROGRESS;
+ case WSAEALREADY: return EALREADY;
+ case WSAENOTSOCK: return ENOTSOCK;
+ case WSAEDESTADDRREQ: return EDESTADDRREQ;
+ case WSAEMSGSIZE: return EMSGSIZE;
+ case WSAEPROTOTYPE: return EPROTOTYPE;
+ case WSAENOPROTOOPT: return ENOPROTOOPT;
+ case WSAEPROTONOSUPPORT: return EPROTONOSUPPORT;
+ case WSAEOPNOTSUPP: return EOPNOTSUPP;
+ case WSAEAFNOSUPPORT: return EAFNOSUPPORT;
+ case WSAEADDRINUSE: return EADDRINUSE;
+ case WSAEADDRNOTAVAIL: return EADDRNOTAVAIL;
+ case WSAENETDOWN: return ENETDOWN;
+ case WSAENETUNREACH: return ENETUNREACH;
+ case WSAENETRESET: return ENETRESET;
+ case WSAECONNABORTED: return ECONNABORTED;
+ case WSAECONNRESET: return ECONNRESET;
+ case WSAENOBUFS: return ENOBUFS;
+ case WSAEISCONN: return EISCONN;
+ case WSAENOTCONN: return ENOTCONN;
+ case WSAETIMEDOUT: return ETIMEDOUT;
+ case WSAECONNREFUSED: return ECONNREFUSED;
+ case WSAELOOP: return ELOOP;
+ case WSAENAMETOOLONG: return ENAMETOOLONG;
+ case WSAEHOSTUNREACH: return EHOSTUNREACH;
+ case WSAENOTEMPTY: return ENOTEMPTY;
+ /* No errno equivalent; default to EIO */
+ case WSAESOCKTNOSUPPORT:
+ case WSAEPFNOSUPPORT:
+ case WSAESHUTDOWN:
+ case WSAETOOMANYREFS:
+ case WSAEHOSTDOWN:
+ case WSAEPROCLIM:
+ case WSAEUSERS:
+ case WSAEDQUOT:
+ case WSAESTALE:
+ case WSAEREMOTE:
+ case WSASYSNOTREADY:
+ case WSAVERNOTSUPPORTED:
+ case WSANOTINITIALISED:
+ case WSAEDISCON:
+ case WSAENOMORE:
+ case WSAECANCELLED:
+ case WSAEINVALIDPROCTABLE:
+ case WSAEINVALIDPROVIDER:
+ case WSAEPROVIDERFAILEDINIT:
+ case WSASYSCALLFAILURE:
+ case WSASERVICE_NOT_FOUND:
+ case WSATYPE_NOT_FOUND:
+ case WSA_E_NO_MORE:
+ case WSA_E_CANCELLED:
+ case WSAEREFUSED:
+ case WSAHOST_NOT_FOUND:
+ case WSATRY_AGAIN:
+ case WSANO_RECOVERY:
+ case WSANO_DATA:
+ case WSA_QOS_RECEIVERS:
+ case WSA_QOS_SENDERS:
+ case WSA_QOS_NO_SENDERS:
+ case WSA_QOS_NO_RECEIVERS:
+ case WSA_QOS_REQUEST_CONFIRMED:
+ case WSA_QOS_ADMISSION_FAILURE:
+ case WSA_QOS_POLICY_FAILURE:
+ case WSA_QOS_BAD_STYLE:
+ case WSA_QOS_BAD_OBJECT:
+ case WSA_QOS_TRAFFIC_CTRL_ERROR:
+ case WSA_QOS_GENERIC_ERROR:
+ case WSA_QOS_ESERVICETYPE:
+ case WSA_QOS_EFLOWSPEC:
+ case WSA_QOS_EPROVSPECBUF:
+ case WSA_QOS_EFILTERSTYLE:
+ case WSA_QOS_EFILTERTYPE:
+ case WSA_QOS_EFILTERCOUNT:
+ case WSA_QOS_EOBJLENGTH:
+ case WSA_QOS_EFLOWCOUNT:
+#ifndef _MSC_VER
+ case WSA_QOS_EUNKNOWNPSOBJ:
+#endif
+ case WSA_QOS_EPOLICYOBJ:
+ case WSA_QOS_EFLOWDESC:
+ case WSA_QOS_EPSFLOWSPEC:
+ case WSA_QOS_EPSFILTERSPEC:
+ case WSA_QOS_ESDMODEOBJ:
+ case WSA_QOS_ESHAPERATEOBJ:
+ case WSA_QOS_RESERVED_PETYPE:
+ default: return EIO;
+ }
+}
+
+/*
+ * On Windows, `errno` is a global macro to a function call.
+ * This makes it difficult to debug and single-step our mappings.
+ */
+static inline void set_wsa_errno(void)
+{
+ DWORD wsa = WSAGetLastError();
+ int e = winsock_error_to_errno(wsa);
+ errno = e;
+
+#ifdef DEBUG_WSA_ERRNO
+ fprintf(stderr, "winsock error: %d -> %d\n", wsa, e);
+ fflush(stderr);
+#endif
+}
+
+static inline int winsock_return(int ret)
+{
+ if (ret < 0)
+ set_wsa_errno();
+
+ return ret;
+}
+
+#define WINSOCK_RETURN(x) do { return winsock_return(x); } while (0)
+
#undef gethostname
int mingw_gethostname(char *name, int namelen)
{
- ensure_socket_initialization();
- return gethostname(name, namelen);
+ ensure_socket_initialization();
+ WINSOCK_RETURN(gethostname(name, namelen));
}
#undef gethostbyname
struct hostent *mingw_gethostbyname(const char *host)
{
+ struct hostent *ret;
+
ensure_socket_initialization();
- return gethostbyname(host);
+
+ ret = gethostbyname(host);
+ if (!ret)
+ set_wsa_errno();
+
+ return ret;
}
#undef getaddrinfo
@@ -1990,7 +2194,7 @@ int mingw_getaddrinfo(const char *node, const char *service,
const struct addrinfo *hints, struct addrinfo **res)
{
ensure_socket_initialization();
- return getaddrinfo(node, service, hints, res);
+ WINSOCK_RETURN(getaddrinfo(node, service, hints, res));
}
int mingw_socket(int domain, int type, int protocol)
@@ -2010,7 +2214,7 @@ int mingw_socket(int domain, int type, int protocol)
* in errno so that _if_ someone looks up the code somewhere,
* then it is at least the number that are usually listed.
*/
- errno = WSAGetLastError();
+ set_wsa_errno();
return -1;
}
/* convert into a file descriptor */
@@ -2026,35 +2230,35 @@ int mingw_socket(int domain, int type, int protocol)
int mingw_connect(int sockfd, struct sockaddr *sa, size_t sz)
{
SOCKET s = (SOCKET)_get_osfhandle(sockfd);
- return connect(s, sa, sz);
+ WINSOCK_RETURN(connect(s, sa, sz));
}
#undef bind
int mingw_bind(int sockfd, struct sockaddr *sa, size_t sz)
{
SOCKET s = (SOCKET)_get_osfhandle(sockfd);
- return bind(s, sa, sz);
+ WINSOCK_RETURN(bind(s, sa, sz));
}
#undef setsockopt
int mingw_setsockopt(int sockfd, int lvl, int optname, void *optval, int optlen)
{
SOCKET s = (SOCKET)_get_osfhandle(sockfd);
- return setsockopt(s, lvl, optname, (const char*)optval, optlen);
+ WINSOCK_RETURN(setsockopt(s, lvl, optname, (const char*)optval, optlen));
}
#undef shutdown
int mingw_shutdown(int sockfd, int how)
{
SOCKET s = (SOCKET)_get_osfhandle(sockfd);
- return shutdown(s, how);
+ WINSOCK_RETURN(shutdown(s, how));
}
#undef listen
int mingw_listen(int sockfd, int backlog)
{
SOCKET s = (SOCKET)_get_osfhandle(sockfd);
- return listen(s, backlog);
+ WINSOCK_RETURN(listen(s, backlog));
}
#undef accept
@@ -2065,6 +2269,11 @@ int mingw_accept(int sockfd1, struct sockaddr *sa, socklen_t *sz)
SOCKET s1 = (SOCKET)_get_osfhandle(sockfd1);
SOCKET s2 = accept(s1, sa, sz);
+ if (s2 == INVALID_SOCKET) {
+ set_wsa_errno();
+ return -1;
+ }
+
/* convert into a file descriptor */
if ((sockfd2 = _open_osfhandle(s2, O_RDWR|O_BINARY)) < 0) {
int err = errno;
@@ -2459,6 +2668,28 @@ pid_t waitpid(pid_t pid, int *status, int options)
return -1;
}
+int mingw_is_mount_point(struct strbuf *path)
+{
+ WIN32_FIND_DATAW findbuf = { 0 };
+ HANDLE handle;
+ wchar_t wfilename[MAX_PATH];
+ int wlen = xutftowcs_path(wfilename, path->buf);
+ if (wlen < 0)
+ die(_("could not get long path for '%s'"), path->buf);
+
+ /* remove trailing slash, if any */
+ if (wlen > 0 && wfilename[wlen - 1] == L'/')
+ wfilename[--wlen] = L'\0';
+
+ handle = FindFirstFileW(wfilename, &findbuf);
+ if (handle == INVALID_HANDLE_VALUE)
+ return 0;
+ FindClose(handle);
+
+ return (findbuf.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
+ (findbuf.dwReserved0 == IO_REPARSE_TAG_MOUNT_POINT);
+}
+
int xutftowcsn(wchar_t *wcs, const char *utfs, size_t wcslen, int utflen)
{
int upos = 0, wpos = 0;
@@ -2544,6 +2775,59 @@ int xwcstoutf(char *utf, const wchar_t *wcs, size_t utflen)
return -1;
}
+#ifdef ENSURE_MSYSTEM_IS_SET
+static size_t append_system_bin_dirs(char *path, size_t size)
+{
+#if !defined(RUNTIME_PREFIX) || !defined(HAVE_WPGMPTR)
+ return 0;
+#else
+ char prefix[32768];
+ const char *slash;
+ size_t len = xwcstoutf(prefix, _wpgmptr, sizeof(prefix)), off = 0;
+
+ if (len == 0 || len >= sizeof(prefix) ||
+ !(slash = find_last_dir_sep(prefix)))
+ return 0;
+ /* strip trailing `git.exe` */
+ len = slash - prefix;
+
+ /* strip trailing `cmd` or `mingw64\bin` or `mingw32\bin` or `bin` or `libexec\git-core` */
+ if (strip_suffix_mem(prefix, &len, "\\mingw64\\libexec\\git-core") ||
+ strip_suffix_mem(prefix, &len, "\\mingw64\\bin"))
+ off += xsnprintf(path + off, size - off,
+ "%.*s\\mingw64\\bin;", (int)len, prefix);
+ else if (strip_suffix_mem(prefix, &len, "\\mingw32\\libexec\\git-core") ||
+ strip_suffix_mem(prefix, &len, "\\mingw32\\bin"))
+ off += xsnprintf(path + off, size - off,
+ "%.*s\\mingw32\\bin;", (int)len, prefix);
+ else if (strip_suffix_mem(prefix, &len, "\\cmd") ||
+ strip_suffix_mem(prefix, &len, "\\bin") ||
+ strip_suffix_mem(prefix, &len, "\\libexec\\git-core"))
+ off += xsnprintf(path + off, size - off,
+ "%.*s\\mingw%d\\bin;", (int)len, prefix,
+ (int)(sizeof(void *) * 8));
+ else
+ return 0;
+
+ off += xsnprintf(path + off, size - off,
+ "%.*s\\usr\\bin;", (int)len, prefix);
+ return off;
+#endif
+}
+#endif
+
+static int is_system32_path(const char *path)
+{
+ WCHAR system32[MAX_LONG_PATH], wpath[MAX_LONG_PATH];
+
+ if (xutftowcs_long_path(wpath, path) < 0 ||
+ !GetSystemDirectoryW(system32, ARRAY_SIZE(system32)) ||
+ _wcsicmp(system32, wpath))
+ return 0;
+
+ return 1;
+}
+
static void setup_windows_environment(void)
{
char *tmp = getenv("TMPDIR");
@@ -2584,7 +2868,8 @@ static void setup_windows_environment(void)
strbuf_addstr(&buf, tmp);
if ((tmp = getenv("HOMEPATH"))) {
strbuf_addstr(&buf, tmp);
- if (is_directory(buf.buf))
+ if (!is_system32_path(buf.buf) &&
+ is_directory(buf.buf))
setenv("HOME", buf.buf, 1);
else
tmp = NULL; /* use $USERPROFILE */
@@ -2595,6 +2880,37 @@ static void setup_windows_environment(void)
if (!tmp && (tmp = getenv("USERPROFILE")))
setenv("HOME", tmp, 1);
}
+
+ if (!getenv("PLINK_PROTOCOL"))
+ setenv("PLINK_PROTOCOL", "ssh", 0);
+
+#ifdef ENSURE_MSYSTEM_IS_SET
+ if (!(tmp = getenv("MSYSTEM")) || !tmp[0]) {
+ const char *home = getenv("HOME"), *path = getenv("PATH");
+ char buf[32768];
+ size_t off = 0;
+
+ xsnprintf(buf, sizeof(buf),
+ "MINGW%d", (int)(sizeof(void *) * 8));
+ setenv("MSYSTEM", buf, 1);
+
+ if (home)
+ off += xsnprintf(buf + off, sizeof(buf) - off,
+ "%s\\bin;", home);
+ off += append_system_bin_dirs(buf + off, sizeof(buf) - off);
+ if (path)
+ off += xsnprintf(buf + off, sizeof(buf) - off,
+ "%s", path);
+ else if (off > 0)
+ buf[off - 1] = '\0';
+ else
+ buf[0] = '\0';
+ setenv("PATH", buf, 1);
+ }
+#endif
+
+ if (!getenv("LC_ALL") && !getenv("LC_CTYPE") && !getenv("LANG"))
+ setenv("LC_CTYPE", "C.UTF-8", 1);
}
int is_valid_win32_path(const char *path, int allow_literal_nul)
@@ -2839,6 +3155,7 @@ int wmain(int argc, const wchar_t **wargv)
#endif
maybe_redirect_std_handles();
+ fsync_object_files = 1;
/* determine size of argv and environ conversion buffer */
maxlen = wcslen(wargv[0]);
diff --git a/compat/mingw.h b/compat/mingw.h
index af8eddd73e..a974ee8e85 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -442,9 +442,15 @@ static inline void convert_slashes(char *path)
if (*path == '\\')
*path = '/';
}
+struct strbuf;
+int mingw_is_mount_point(struct strbuf *path);
+#define is_mount_point mingw_is_mount_point
+#define CAN_UNLINK_MOUNT_POINTS 1
#define PATH_SEP ';'
char *mingw_query_user_email(void);
#define query_user_email mingw_query_user_email
+char *mingw_strbuf_realpath(struct strbuf *resolved, const char *path);
+#define platform_strbuf_realpath mingw_strbuf_realpath
#if !defined(__MINGW64_VERSION_MAJOR) && (!defined(_MSC_VER) || _MSC_VER < 1800)
#define PRIuMAX "I64u"
#define PRId64 "I64d"
diff --git a/compat/vcbuild/scripts/clink.pl b/compat/vcbuild/scripts/clink.pl
index df167d1e1a..7fd7c5b7b2 100755
--- a/compat/vcbuild/scripts/clink.pl
+++ b/compat/vcbuild/scripts/clink.pl
@@ -56,7 +56,8 @@ while (@ARGV) {
# need to use that instead?
foreach my $flag (@lflags) {
if ($flag =~ /^-LIBPATH:(.*)/) {
- foreach my $l ("libcurl_imp.lib", "libcurl.lib") {
+ my $libcurl = $is_debug ? "libcurl-d.lib" : "libcurl.lib";
+ foreach my $l ("libcurl_imp.lib", $libcurl) {
if (-f "$1/$l") {
$lib = $l;
last;
diff --git a/compat/vcbuild/vcpkg_install.bat b/compat/vcbuild/vcpkg_install.bat
index ebd0bad242..8330d8120f 100644
--- a/compat/vcbuild/vcpkg_install.bat
+++ b/compat/vcbuild/vcpkg_install.bat
@@ -36,6 +36,13 @@ REM ================================================================
dir vcpkg\vcpkg.exe >nul 2>nul && GOTO :install_libraries
+ git.exe version 2>nul
+ IF ERRORLEVEL 1 (
+ echo "***"
+ echo "Git not found. Please adjust your CMD path or Git install option."
+ echo "***"
+ EXIT /B 1 )
+
echo Fetching vcpkg in %cwd%vcpkg
git.exe clone https://github.com/Microsoft/vcpkg vcpkg
IF ERRORLEVEL 1 ( EXIT /B 1 )
@@ -73,6 +80,12 @@ REM ================================================================
:sub__install_one
echo Installing package %1...
+ REM vcpkg may not be reliable on slow, intermittent or proxy
+ REM connections, see e.g.
+ REM https://social.msdn.microsoft.com/Forums/windowsdesktop/en-US/4a8f7be5-5e15-4213-a7bb-ddf424a954e6/winhttpsendrequest-ends-with-12002-errorhttptimeout-after-21-seconds-no-matter-what-timeout?forum=windowssdk
+ REM which explains the hidden 21 second timeout
+ REM (last post by Dave : Microsoft - Windows Networking team)
+
.\vcpkg.exe install %1:%arch%
IF ERRORLEVEL 1 ( EXIT /B 1 )
diff --git a/config.c b/config.c
index 2bdff4457b..bf87d02603 100644
--- a/config.c
+++ b/config.c
@@ -1678,9 +1678,11 @@ static int git_config_from_blob_ref(config_fn_t fn,
const char *git_etc_gitconfig(void)
{
- static const char *system_wide;
- if (!system_wide)
+ static char *system_wide;
+ if (!system_wide) {
system_wide = system_path(ETC_GITCONFIG);
+ normalize_path_copy(system_wide, system_wide);
+ }
return system_wide;
}
diff --git a/config.mak.uname b/config.mak.uname
index c7eba69e54..188281c5ff 100644
--- a/config.mak.uname
+++ b/config.mak.uname
@@ -433,6 +433,11 @@ ifeq ($(uname_S),Windows)
NO_POSIX_GOODIES = UnfortunatelyYes
NATIVE_CRLF = YesPlease
DEFAULT_HELP_FORMAT = html
+ifeq (/mingw64,$(subst 32,64,$(prefix)))
+ # Move system config into top-level /etc/
+ ETC_GITCONFIG = ../etc/gitconfig
+ ETC_GITATTRIBUTES = ../etc/gitattributes
+endif
CC = compat/vcbuild/scripts/clink.pl
AR = compat/vcbuild/scripts/lib.pl
@@ -443,7 +448,7 @@ ifeq ($(uname_S),Windows)
compat/win32/pthread.o compat/win32/syslog.o \
compat/win32/trace2_win32_process_info.o \
compat/win32/dirent.o
- COMPAT_CFLAGS = -D__USE_MINGW_ACCESS -DDETECT_MSYS_TTY -DNOGDI -DHAVE_STRING_H -Icompat -Icompat/regex -Icompat/win32 -DSTRIP_EXTENSION=\".exe\"
+ COMPAT_CFLAGS = -D__USE_MINGW_ACCESS -DDETECT_MSYS_TTY -DENSURE_MSYSTEM_IS_SET -DNOGDI -DHAVE_STRING_H -Icompat -Icompat/regex -Icompat/win32 -DSTRIP_EXTENSION=\".exe\"
BASIC_LDFLAGS = -IGNORE:4217 -IGNORE:4049 -NOLOGO -ENTRY:wmainCRTStartup -SUBSYSTEM:CONSOLE
# invalidcontinue.obj allows Git's source code to close the same file
# handle twice, or to access the osfhandle of an already-closed stdout
@@ -666,7 +671,7 @@ else
endif
CC = gcc
COMPAT_CFLAGS += -D__USE_MINGW_ANSI_STDIO=0 -DDETECT_MSYS_TTY \
- -fstack-protector-strong
+ -DENSURE_MSYSTEM_IS_SET -fstack-protector-strong
EXTLIBS += -lntdll
INSTALL = /bin/install
NO_R_TO_GCC_LINKER = YesPlease
@@ -674,10 +679,15 @@ else
HAVE_LIBCHARSET_H = YesPlease
NO_GETTEXT =
USE_GETTEXT_SCHEME = fallthrough
- USE_LIBPCRE= YesPlease
- NO_LIBPCRE1_JIT = UnfortunatelyYes
+ USE_LIBPCRE = YesPlease
NO_CURL =
USE_NED_ALLOCATOR = YesPlease
+ NO_PYTHON =
+ ifeq (/mingw64,$(subst 32,64,$(prefix)))
+ # Move system config into top-level /etc/
+ ETC_GITCONFIG = ../etc/gitconfig
+ ETC_GITATTRIBUTES = ../etc/gitattributes
+ endif
else
COMPAT_CFLAGS += -D__USE_MINGW_ANSI_STDIO
NO_CURL = YesPlease
@@ -709,7 +719,7 @@ vcxproj:
# Make .vcxproj files and add them
unset QUIET_GEN QUIET_BUILT_IN; \
perl contrib/buildsystems/generate -g Vcxproj
- git add -f git.sln {*,*/lib,t/helper/*}/*.vcxproj
+ git add -f git.sln {*,*/lib.proj,t/helper/*}/*.vcxproj
# Generate the LinkOrCopyBuiltins.targets and LinkOrCopyRemoteHttp.targets file
(echo '' && \
@@ -719,7 +729,7 @@ vcxproj:
echo ' '; \
done && \
echo ' ' && \
- echo '') >git/LinkOrCopyBuiltins.targets
+ echo '') >git.proj/LinkOrCopyBuiltins.targets
(echo '' && \
echo ' ' && \
for name in $(REMOTE_CURL_ALIASES); \
@@ -727,8 +737,8 @@ vcxproj:
echo ' '; \
done && \
echo ' ' && \
- echo '') >git-remote-http/LinkOrCopyRemoteHttp.targets
- git add -f git/LinkOrCopyBuiltins.targets git-remote-http/LinkOrCopyRemoteHttp.targets
+ echo '') >git-remote-http.proj/LinkOrCopyRemoteHttp.targets
+ git add -f git.proj/LinkOrCopyBuiltins.targets git-remote-http.proj/LinkOrCopyRemoteHttp.targets
# Add command-list.h and config-list.h
$(MAKE) MSVC=1 SKIP_VCPKG=1 prefix=/mingw64 config-list.h command-list.h
diff --git a/contrib/buildsystems/Generators/Vcxproj.pm b/contrib/buildsystems/Generators/Vcxproj.pm
index d2584450ba..dd1a20e91b 100644
--- a/contrib/buildsystems/Generators/Vcxproj.pm
+++ b/contrib/buildsystems/Generators/Vcxproj.pm
@@ -58,8 +58,8 @@ sub createProject {
my $uuid = generate_guid($name);
$$build_structure{"$prefix${target}_GUID"} = $uuid;
my $vcxproj = $target;
- $vcxproj =~ s/(.*\/)?(.*)/$&\/$2.vcxproj/;
- $vcxproj =~ s/([^\/]*)(\/lib)\/(lib.vcxproj)/$1$2\/$1_$3/;
+ $vcxproj =~ s/(.*\/)?(.*)/$&.proj\/$2.vcxproj/;
+ $vcxproj =~ s/([^\/]*)(\/lib\.proj)\/(lib.vcxproj)/$1$2\/$1_$3/;
$$build_structure{"$prefix${target}_VCXPROJ"} = $vcxproj;
my @srcs = sort(map("$rel_dir\\$_", @{$$build_structure{"$prefix${name}_SOURCES"}}));
@@ -89,7 +89,9 @@ sub createProject {
$defines =~ s/>/>/g;
$defines =~ s/\'//g;
- die "Could not create the directory $target for $label project!\n" unless (-d "$target" || mkdir "$target");
+ my $dir = $vcxproj;
+ $dir =~ s/\/[^\/]*$//;
+ die "Could not create the directory $dir for $label project!\n" unless (-d "$dir" || mkdir "$dir");
open F, ">$vcxproj" or die "Could not open $vcxproj for writing!\n";
binmode F, ":crlf :utf8";
@@ -236,14 +238,14 @@ EOM
print F << "EOM";
-
+
$uuid_libgit
false
EOM
if (!($name =~ 'xdiff')) {
print F << "EOM";
-
+
$uuid_xdiff_lib
false
@@ -252,7 +254,7 @@ EOM
if ($name =~ /(test-(line-buffer|svn-fe)|^git-remote-testsvn)\.exe$/) {
my $uuid_vcs_svn_lib = $$build_structure{"LIBS_vcs-svn/lib_GUID"};
print F << "EOM";
-
+
$uuid_vcs_svn_lib
false
@@ -329,7 +331,7 @@ sub createGlueProject {
my $vcxproj = $build_structure{"APPS_${appname}_VCXPROJ"};
$vcxproj =~ s/\//\\/g;
$appname =~ s/.*\///;
- print F "\"${appname}\", \"${vcxproj}\", \"${uuid}\"";
+ print F "\"${appname}.proj\", \"${vcxproj}\", \"${uuid}\"";
print F "$SLN_POST";
}
foreach (@libs) {
@@ -339,7 +341,7 @@ sub createGlueProject {
my $vcxproj = $build_structure{"LIBS_${libname}_VCXPROJ"};
$vcxproj =~ s/\//\\/g;
$libname =~ s/\//_/g;
- print F "\"${libname}\", \"${vcxproj}\", \"${uuid}\"";
+ print F "\"${libname}.proj\", \"${vcxproj}\", \"${uuid}\"";
print F "$SLN_POST";
}
diff --git a/contrib/completion/git-prompt.sh b/contrib/completion/git-prompt.sh
index 16260bab73..2d2fb00f97 100644
--- a/contrib/completion/git-prompt.sh
+++ b/contrib/completion/git-prompt.sh
@@ -431,8 +431,8 @@ __git_ps1 ()
fi
local sparse=""
- if [ -z "${GIT_PS1_COMPRESSSPARSESTATE}" ] &&
- [ -z "${GIT_PS1_OMITSPARSESTATE}" ] &&
+ if [ -z "${GIT_PS1_COMPRESSSPARSESTATE-}" ] &&
+ [ -z "${GIT_PS1_OMITSPARSESTATE-}" ] &&
[ "$(git config --bool core.sparseCheckout)" = "true" ]; then
sparse="|SPARSE"
fi
@@ -541,7 +541,7 @@ __git_ps1 ()
u="%${ZSH_VERSION+%}"
fi
- if [ -n "${GIT_PS1_COMPRESSSPARSESTATE}" ] &&
+ if [ -n "${GIT_PS1_COMPRESSSPARSESTATE-}" ] &&
[ "$(git config --bool core.sparseCheckout)" = "true" ]; then
h="?"
fi
diff --git a/diffcore-rename.c b/diffcore-rename.c
index 99e63e90f8..7b12f42a7a 100644
--- a/diffcore-rename.c
+++ b/diffcore-rename.c
@@ -84,6 +84,18 @@ static struct diff_rename_src *register_rename_src(struct diff_filepair *p)
first = 0;
last = rename_src_nr;
+
+ if (last > 0) {
+ struct diff_rename_src *src = &(rename_src[last-1]);
+ int cmp = strcmp(one->path, src->p->one->path);
+ if (!cmp)
+ return src;
+ if (cmp > 0) {
+ first = last;
+ goto append_it;
+ }
+ }
+
while (last > first) {
int next = first + ((last - first) >> 1);
struct diff_rename_src *src = &(rename_src[next]);
@@ -97,6 +109,7 @@ static struct diff_rename_src *register_rename_src(struct diff_filepair *p)
first = next+1;
}
+append_it:
/* insert to make it at "first" */
ALLOC_GROW(rename_src, rename_src_nr + 1, rename_src_alloc);
rename_src_nr++;
diff --git a/git-add--interactive.perl b/git-add--interactive.perl
index 8a72018712..77322dec34 100755
--- a/git-add--interactive.perl
+++ b/git-add--interactive.perl
@@ -174,6 +174,24 @@ sub run_cmd_pipe {
die "$^O does not support: @invalid\n" if @invalid;
my @args = map { m/ /o ? "\"$_\"": $_ } @_;
return qx{@args};
+ } elsif (($^O eq 'MSWin32' || $^O eq 'msys') && (scalar @_ > 200) &&
+ grep $_ eq '--', @_) {
+ use File::Temp qw(tempfile);
+ my ($fhargs, $filename) =
+ tempfile('git-args-XXXXXX', UNLINK => 1);
+
+ my $cmd = 'cat '.$filename.' | xargs -0 -s 20000 ';
+ while ($_[0] ne '--') {
+ $cmd = $cmd . shift(@_) . ' ';
+ }
+
+ shift(@_);
+ print $fhargs join("\0", @_);
+ close($fhargs);
+
+ my $fh = undef;
+ open($fh, '-|', $cmd) or die;
+ return <$fh>;
} else {
my $fh = undef;
open($fh, '-|', @_) or die;
diff --git a/git-compat-util.h b/git-compat-util.h
index 7a0fb7a045..71d931ade5 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -401,10 +401,18 @@ static inline int git_has_dir_sep(const char *path)
#define has_dir_sep(path) git_has_dir_sep(path)
#endif
+#ifndef is_mount_point
+#define is_mount_point is_mount_point_via_stat
+#endif
+
#ifndef query_user_email
#define query_user_email() NULL
#endif
+#ifndef platform_strbuf_realpath
+#define platform_strbuf_realpath(resolved, path) NULL
+#endif
+
#ifdef __TANDEM
#include
#include
diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index 867b8cea46..2ea45e1173 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -2083,6 +2083,7 @@ set all_icons(U$ui_index) file_merge
set all_icons(T$ui_index) file_statechange
set all_icons(_$ui_workdir) file_plain
+set all_icons(A$ui_workdir) file_plain
set all_icons(M$ui_workdir) file_mod
set all_icons(D$ui_workdir) file_question
set all_icons(U$ui_workdir) file_merge
@@ -2109,6 +2110,7 @@ foreach i {
{A_ {mc "Staged for commit"}}
{AM {mc "Portions staged for commit"}}
{AD {mc "Staged for commit, missing"}}
+ {AA {mc "Intended to be added"}}
{_D {mc "Missing"}}
{D_ {mc "Staged for removal"}}
diff --git a/git-gui/lib/diff.tcl b/git-gui/lib/diff.tcl
index 871ad488c2..36d3715f7b 100644
--- a/git-gui/lib/diff.tcl
+++ b/git-gui/lib/diff.tcl
@@ -582,7 +582,8 @@ proc apply_or_revert_hunk {x y revert} {
if {$current_diff_side eq $ui_index} {
set failed_msg [mc "Failed to unstage selected hunk."]
lappend apply_cmd --reverse --cached
- if {[string index $mi 0] ne {M}} {
+ set file_state [string index $mi 0]
+ if {$file_state ne {M} && $file_state ne {A}} {
unlock_index
return
}
@@ -595,7 +596,8 @@ proc apply_or_revert_hunk {x y revert} {
lappend apply_cmd --cached
}
- if {[string index $mi 1] ne {M}} {
+ set file_state [string index $mi 1]
+ if {$file_state ne {M} && $file_state ne {A}} {
unlock_index
return
}
@@ -687,7 +689,8 @@ proc apply_or_revert_range_or_line {x y revert} {
set failed_msg [mc "Failed to unstage selected line."]
set to_context {+}
lappend apply_cmd --reverse --cached
- if {[string index $mi 0] ne {M}} {
+ set file_state [string index $mi 0]
+ if {$file_state ne {M} && $file_state ne {A}} {
unlock_index
return
}
@@ -702,7 +705,8 @@ proc apply_or_revert_range_or_line {x y revert} {
lappend apply_cmd --cached
}
- if {[string index $mi 1] ne {M}} {
+ set file_state [string index $mi 1]
+ if {$file_state ne {M} && $file_state ne {A}} {
unlock_index
return
}
diff --git a/gitk-git/gitk b/gitk-git/gitk
index 23d9dd1fe0..64678c0aa7 100755
--- a/gitk-git/gitk
+++ b/gitk-git/gitk
@@ -353,6 +353,16 @@ proc parseviewrevs {view revs} {
return $ret
}
+# Escapes a list of filter paths to be passed to git log via stdin. Note that
+# paths must not be quoted.
+proc escape_filter_paths {paths} {
+ set escaped [list]
+ foreach path $paths {
+ lappend escaped [string map {\\ \\\\ "\ " "\\\ "} $path]
+ }
+ return $escaped
+}
+
# Start off a git log process and arrange to read its output
proc start_rev_list {view} {
global startmsecs commitidx viewcomplete curview
@@ -405,14 +415,17 @@ proc start_rev_list {view} {
if {$revs eq {}} {
return 0
}
- set args [concat $vflags($view) $revs]
+ set args $vflags($view)
} else {
+ set revs {}
set args $vorigargs($view)
}
if {[catch {
set fd [open [concat | git log --no-color -z --pretty=raw $show_notes \
- --parents --boundary $args "--" $files] r]
+ --parents --boundary $args --stdin \
+ "<<[join [concat $revs "--" \
+ [escape_filter_paths $files]] "\\n"]"] r]
} err]} {
error_popup "[mc "Error executing git log:"] $err"
return 0
@@ -554,13 +567,20 @@ proc updatecommits {} {
set revs $newrevs
set vposids($view) [lsort -unique [concat $oldpos $vposids($view)]]
}
- set args [concat $vflags($view) $revs --not $oldpos]
+ set args $vflags($view)
+ foreach r $oldpos {
+ lappend revs "^$r"
+ }
} else {
+ set revs {}
set args $vorigargs($view)
}
if {[catch {
set fd [open [concat | git log --no-color -z --pretty=raw $show_notes \
- --parents --boundary $args "--" $vfilelimit($view)] r]
+ --parents --boundary $args --stdin \
+ "<<[join [concat $revs "--" \
+ [escape_filter_paths \
+ $vfilelimit($view)]] "\\n"]"] r]
} err]} {
error_popup "[mc "Error executing git log:"] $err"
return
@@ -10228,10 +10248,16 @@ proc getallcommits {} {
foreach id $seeds {
lappend ids "^$id"
}
+ lappend ids "--"
}
}
if {$ids ne {}} {
- set fd [open [concat $cmd $ids] r]
+ if {$ids eq "--all"} {
+ set cmd [concat $cmd "--all"]
+ } else {
+ set cmd [concat $cmd --stdin "<<[join $ids "\\n"]"]
+ }
+ set fd [open $cmd r]
fconfigure $fd -blocking 0
incr allcommits
nowbusy allcommits
diff --git a/http.c b/http.c
index 8b23a546af..2dd616aab6 100644
--- a/http.c
+++ b/http.c
@@ -165,7 +165,13 @@ static char *cached_accept_language;
static char *http_ssl_backend;
-static int http_schannel_check_revoke = 1;
+static int http_schannel_check_revoke_mode =
+#ifdef CURLSSLOPT_REVOKE_BEST_EFFORT
+ CURLSSLOPT_REVOKE_BEST_EFFORT;
+#else
+ CURLSSLOPT_NO_REVOKE;
+#endif
+
/*
* With the backend being set to `schannel`, setting sslCAinfo would override
* the Certificate Store in cURL v7.60.0 and later, which is not what we want
@@ -330,7 +336,19 @@ static int http_options(const char *var, const char *value, void *cb)
}
if (!strcmp("http.schannelcheckrevoke", var)) {
- http_schannel_check_revoke = git_config_bool(var, value);
+ if (value && !strcmp(value, "best-effort")) {
+ http_schannel_check_revoke_mode =
+#ifdef CURLSSLOPT_REVOKE_BEST_EFFORT
+ CURLSSLOPT_REVOKE_BEST_EFFORT;
+#else
+ CURLSSLOPT_NO_REVOKE;
+ warning(_("%s=%s unsupported by current cURL"),
+ var, value);
+#endif
+ } else
+ http_schannel_check_revoke_mode =
+ (git_config_bool(var, value) ?
+ 0 : CURLSSLOPT_NO_REVOKE);
return 0;
}
@@ -903,9 +921,9 @@ static CURL *get_curl_handle(void)
#endif
if (http_ssl_backend && !strcmp("schannel", http_ssl_backend) &&
- !http_schannel_check_revoke) {
+ http_schannel_check_revoke_mode) {
#if LIBCURL_VERSION_NUM >= 0x072c00
- curl_easy_setopt(result, CURLOPT_SSL_OPTIONS, CURLSSLOPT_NO_REVOKE);
+ curl_easy_setopt(result, CURLOPT_SSL_OPTIONS, http_schannel_check_revoke_mode);
#else
warning(_("CURLSSLOPT_NO_REVOKE not supported with cURL < 7.44.0"));
#endif
diff --git a/path.c b/path.c
index 7b385e5eb2..a8de4cb150 100644
--- a/path.c
+++ b/path.c
@@ -12,6 +12,7 @@
#include "packfile.h"
#include "object-store.h"
#include "lockfile.h"
+#include "exec-cmd.h"
static int get_st_mode_bits(const char *path, int *mode)
{
@@ -732,6 +733,10 @@ char *expand_user_path(const char *path, int real_home)
if (path == NULL)
goto return_null;
+#ifdef __MINGW32__
+ if (path[0] == '/')
+ return system_path(path + 1);
+#endif
if (path[0] == '~') {
const char *first_slash = strchrnul(path, '/');
const char *username = path + 1;
@@ -1289,6 +1294,45 @@ char *strip_path_suffix(const char *path, const char *suffix)
return offset == -1 ? NULL : xstrndup(path, offset);
}
+int is_mount_point_via_stat(struct strbuf *path)
+{
+ size_t len = path->len;
+ unsigned int current_dev;
+ struct stat st;
+
+ if (!strcmp("/", path->buf))
+ return 1;
+
+ strbuf_addstr(path, "/.");
+ if (lstat(path->buf, &st)) {
+ /*
+ * If we cannot access the current directory, we cannot say
+ * that it is a bind mount.
+ */
+ strbuf_setlen(path, len);
+ return 0;
+ }
+ current_dev = st.st_dev;
+
+ /* Now look at the parent directory */
+ strbuf_addch(path, '.');
+ if (lstat(path->buf, &st)) {
+ /*
+ * If we cannot access the parent directory, we cannot say
+ * that it is a bind mount.
+ */
+ strbuf_setlen(path, len);
+ return 0;
+ }
+ strbuf_setlen(path, len);
+
+ /*
+ * If the device ID differs between current and parent directory,
+ * then it is a bind mount.
+ */
+ return current_dev != st.st_dev;
+}
+
int daemon_avoid_alias(const char *p)
{
int sl, ndot;
diff --git a/pkt-line.c b/pkt-line.c
index 844c253ccd..657a702927 100644
--- a/pkt-line.c
+++ b/pkt-line.c
@@ -471,6 +471,9 @@ int recv_sideband(const char *me, int in_stream, int out)
write_or_die(out, buf + 1, len - 1);
break;
default: /* errors: message already written */
+ if (scratch.len > 0)
+ BUG("unhandled incomplete sideband: '%s'",
+ scratch.buf);
return sideband_type;
}
}
diff --git a/prompt.c b/prompt.c
index 5ded21a017..460661dbfb 100644
--- a/prompt.c
+++ b/prompt.c
@@ -80,7 +80,7 @@ int git_read_line_interactively(struct strbuf *line)
int ret;
fflush(stdout);
- ret = strbuf_getline_lf(line, stdin);
+ ret = strbuf_getline(line, stdin);
if (ret != EOF)
strbuf_trim_trailing_newline(line);
diff --git a/send-pack.c b/send-pack.c
index c9698070fc..041712e629 100644
--- a/send-pack.c
+++ b/send-pack.c
@@ -39,6 +39,16 @@ int option_parse_push_signed(const struct option *opt,
die("bad %s argument: %s", opt->long_name, arg);
}
+static int config_use_sideband = 1;
+
+static int send_pack_config(const char *var, const char *value, void *unused)
+{
+ if (!strcmp("sendpack.sideband", var))
+ config_use_sideband = git_config_bool(var, value);
+
+ return 0;
+}
+
static void feed_object(const struct object_id *oid, FILE *fh, int negative)
{
if (negative &&
@@ -434,6 +444,8 @@ int send_pack(struct send_pack_args *args,
const char *push_cert_nonce = NULL;
struct packet_reader reader;
+ git_config(send_pack_config, NULL);
+
/* Does the other end support the reporting? */
if (server_supports("report-status-v2"))
status_report = 2;
@@ -443,7 +455,7 @@ int send_pack(struct send_pack_args *args,
allow_deleting_refs = 1;
if (server_supports("ofs-delta"))
args->use_ofs_delta = 1;
- if (server_supports("side-band-64k"))
+ if (config_use_sideband && server_supports("side-band-64k"))
use_sideband = 1;
if (server_supports("quiet"))
quiet_supported = 1;
diff --git a/sideband.c b/sideband.c
index 0a60662fa6..a5405b9aaa 100644
--- a/sideband.c
+++ b/sideband.c
@@ -190,7 +190,7 @@ int demultiplex_sideband(const char *me, char *buf, int len,
return 0;
case 1:
*sideband_type = SIDEBAND_PRIMARY;
- break;
+ return 1;
default:
strbuf_addf(scratch, "%s%s: protocol error: bad band #%d",
scratch->len ? "\n" : "", me, band);
diff --git a/t/helper/test-pkt-line.c b/t/helper/test-pkt-line.c
index 69152958e5..5e638f0b97 100644
--- a/t/helper/test-pkt-line.c
+++ b/t/helper/test-pkt-line.c
@@ -84,6 +84,25 @@ static void unpack_sideband(void)
}
}
+static int send_split_sideband(void)
+{
+ const char *part1 = "Hello,";
+ const char *primary = "\001primary: regular output\n";
+ const char *part2 = " world!\n";
+
+ send_sideband(1, 2, part1, strlen(part1), LARGE_PACKET_MAX);
+ packet_write(1, primary, strlen(primary));
+ send_sideband(1, 2, part2, strlen(part2), LARGE_PACKET_MAX);
+ packet_response_end(1);
+
+ return 0;
+}
+
+static int receive_sideband(void)
+{
+ return recv_sideband("sideband", 0, 1);
+}
+
int cmd__pkt_line(int argc, const char **argv)
{
if (argc < 2)
@@ -95,6 +114,10 @@ int cmd__pkt_line(int argc, const char **argv)
unpack();
else if (!strcmp(argv[1], "unpack-sideband"))
unpack_sideband();
+ else if (!strcmp(argv[1], "send-split-sideband"))
+ send_split_sideband();
+ else if (!strcmp(argv[1], "receive-sideband"))
+ receive_sideband();
else
die("invalid argument '%s'", argv[1]);
diff --git a/t/t0014-alias.sh b/t/t0014-alias.sh
index 8d3d9144c0..288e08299a 100755
--- a/t/t0014-alias.sh
+++ b/t/t0014-alias.sh
@@ -38,10 +38,10 @@ test_expect_success 'looping aliases - internal execution' '
#'
test_expect_success 'run-command formats empty args properly' '
- test_must_fail env GIT_TRACE=1 git frotz a "" b " " c 2>actual.raw &&
- sed -ne "/run_command:/s/.*trace: run_command: //p" actual.raw >actual &&
- echo "git-frotz a '\'''\'' b '\'' '\'' c" >expect &&
- test_cmp expect actual
+ test_must_fail env GIT_TRACE=1 git frotz a "" b " " c 2>actual.raw &&
+ sed -ne "/run_command:/s/.*trace: run_command: //p" actual.raw >actual &&
+ echo "git-frotz a '\'''\'' b '\'' '\'' c" >expect &&
+ test_cmp expect actual
'
test_done
diff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh
index 56db5c8aba..ada3e5b72d 100755
--- a/t/t0060-path-utils.sh
+++ b/t/t0060-path-utils.sh
@@ -495,4 +495,42 @@ test_expect_success MINGW 'is_valid_path() on Windows' '
"PRN./abc"
'
+test_expect_success MINGW 'MSYSTEM/PATH is adjusted if necessary' '
+ mkdir -p "$HOME"/bin pretend/mingw64/bin \
+ pretend/mingw64/libexec/git-core pretend/usr/bin &&
+ cp "$GIT_EXEC_PATH"/git.exe pretend/mingw64/bin/ &&
+ cp "$GIT_EXEC_PATH"/git.exe pretend/mingw64/libexec/git-core/ &&
+ echo "env | grep MSYSTEM=" | write_script "$HOME"/bin/git-test-home &&
+ echo "echo mingw64" | write_script pretend/mingw64/bin/git-test-bin &&
+ echo "echo usr" | write_script pretend/usr/bin/git-test-bin2 &&
+
+ (
+ MSYSTEM= &&
+ GIT_EXEC_PATH= &&
+ pretend/mingw64/libexec/git-core/git.exe test-home >actual &&
+ pretend/mingw64/libexec/git-core/git.exe test-bin >>actual &&
+ pretend/mingw64/bin/git.exe test-bin2 >>actual
+ ) &&
+ test_write_lines MSYSTEM=$MSYSTEM mingw64 usr >expect &&
+ test_cmp expect actual
+'
+
+test_lazy_prereq RUNTIME_PREFIX '
+ test true = "$RUNTIME_PREFIX"
+'
+
+test_lazy_prereq CAN_EXEC_IN_PWD '
+ cp "$GIT_EXEC_PATH"/git$X ./ &&
+ ./git rev-parse
+'
+
+test_expect_success RUNTIME_PREFIX,CAN_EXEC_IN_PWD 'RUNTIME_PREFIX works' '
+ mkdir -p pretend/git pretend/libexec/git-core &&
+ echo "echo HERE" | write_script pretend/libexec/git-core/git-here &&
+ cp "$GIT_EXEC_PATH"/git$X pretend/git/ &&
+ GIT_EXEC_PATH= ./pretend/git/git here >actual &&
+ echo HERE >expect &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t0070-fundamental.sh b/t/t0070-fundamental.sh
index 7b111a56fd..357201640a 100755
--- a/t/t0070-fundamental.sh
+++ b/t/t0070-fundamental.sh
@@ -34,4 +34,10 @@ test_expect_success 'check for a bug in the regex routines' '
test-tool regex --bug
'
+test_expect_success 'incomplete sideband messages are reassembled' '
+ test-tool pkt-line send-split-sideband >split-sideband &&
+ test-tool pkt-line receive-sideband err &&
+ grep "Hello, world" err
+'
+
test_done
diff --git a/t/t3700-add.sh b/t/t3700-add.sh
index b7d4ba608c..d12aebd233 100755
--- a/t/t3700-add.sh
+++ b/t/t3700-add.sh
@@ -423,4 +423,15 @@ test_expect_success CASE_INSENSITIVE_FS 'path is case-insensitive' '
git add "$downcased"
'
+test_expect_success MINGW 'can add files via NTFS junctions' '
+ test_when_finished "cmd //c rmdir junction && rm -rf target" &&
+ test_create_repo target &&
+ cmd //c "mklink /j junction target" &&
+ >target/via-junction &&
+ git -C junction add "$(pwd)/junction/via-junction" &&
+ echo via-junction >expect &&
+ git -C target diff --cached --name-only >actual &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t3701-add-interactive.sh b/t/t3701-add-interactive.sh
index ca04fac417..ade4010ef4 100755
--- a/t/t3701-add-interactive.sh
+++ b/t/t3701-add-interactive.sh
@@ -860,6 +860,27 @@ test_expect_success 'checkout -p patch editing of added file' '
)
'
+test_expect_success EXPENSIVE 'add -i with a lot of files' '
+ git reset --hard &&
+ x160=0123456789012345678901234567890123456789 &&
+ x160=$x160$x160$x160$x160 &&
+ y= &&
+ i=0 &&
+ while test $i -le 200
+ do
+ name=$(printf "%s%03d" $x160 $i) &&
+ echo $name >$name &&
+ git add -N $name &&
+ y="${y}y$LF" &&
+ i=$(($i+1)) ||
+ break
+ done &&
+ echo "$y" | git add -p -- . &&
+ git diff --cached >staged &&
+ test_line_count = 1407 staged &&
+ git reset --hard
+'
+
test_expect_success 'show help from add--helper' '
git reset --hard &&
cat >expect <<-EOF &&
diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh
index 8d62edd98b..5cbf6aa21a 100755
--- a/t/t5505-remote.sh
+++ b/t/t5505-remote.sh
@@ -721,8 +721,8 @@ test_expect_success '"remote show" does not show symbolic refs' '
(
cd three &&
git remote show origin >output &&
- ! grep "^ *HEAD$" < output &&
- ! grep -i stale < output
+ ! grep "^ *HEAD$"