diff options
89 files changed, 1309 insertions, 560 deletions
@@ -152,6 +152,7 @@ Lars Doelle <lars.doelle@on-line ! de> Lars Doelle <lars.doelle@on-line.de> Lars Noschinski <lars@public.noschinski.de> <lars.noschinski@rwth-aachen.de> Li Hong <leehong@pku.edu.cn> +Linus Arver <linus@ucla.edu> <linusa@google.com> Linus Torvalds <torvalds@linux-foundation.org> <torvalds@evo.osdl.org> Linus Torvalds <torvalds@linux-foundation.org> <torvalds@g5.osdl.org> Linus Torvalds <torvalds@linux-foundation.org> <torvalds@osdl.org> diff --git a/Documentation/CodingGuidelines b/Documentation/CodingGuidelines index ab39509d59..1d92b2da03 100644 --- a/Documentation/CodingGuidelines +++ b/Documentation/CodingGuidelines @@ -188,6 +188,22 @@ For shell scripts specifically (not exhaustive): hopefully nobody starts using "local" before they are reimplemented in C ;-) + - Some versions of shell do not understand "export variable=value", + so we write "variable=value" and then "export variable" on two + separate lines. + + - Some versions of dash have broken variable assignment when prefixed + with "local", "export", and "readonly", in that the value to be + assigned goes through field splitting at $IFS unless quoted. + + (incorrect) + local variable=$value + local variable=$(command args) + + (correct) + local variable="$value" + local variable="$(command args)" + - Use octal escape sequences (e.g. "\302\242"), not hexadecimal (e.g. "\xc2\xa2") in printf format strings, since hexadecimal escape sequences are not portable. diff --git a/Documentation/RelNotes/2.45.0.txt b/Documentation/RelNotes/2.45.0.txt index 1be72e2e5c..15704ff98f 100644 --- a/Documentation/RelNotes/2.45.0.txt +++ b/Documentation/RelNotes/2.45.0.txt @@ -77,8 +77,17 @@ UI, Workflows & Features skip showing the hunk immediately after it has already been shown, and an additional action to explicitly ask to reshow the current hunk. - * "git pack-refs" learned the "--auto" option, which is a useful - addition to be triggered from "git gc --auto". + * "git pack-refs" learned the "--auto" option, which defers the decision of + whether and how to pack to the ref backend. This is used by the reftable + backend to avoid repacking of an already-optimal ref database. The new mode + is triggered from "git gc --auto". + + * "git add -u <pathspec>" and "git commit [-i] <pathspec>" did not + diagnose a pathspec element that did not match any files in certain + situations, unlike "git add <pathspec>" did. + + * The userdiff patterns for C# has been updated. + Performance, Internal Implementation, Development Support etc. @@ -93,7 +102,7 @@ Performance, Internal Implementation, Development Support etc. * The way placeholders are to be marked-up in documentation have been specified; use "_<placeholder>_" to typeset the word inside a pair - of <angle-brakets> emphasized. + of <angle-brackets> emphasized. * "git --no-lazy-fetch cmd" allows to run "cmd" while disabling lazy fetching of objects from the promisor remote, which may be handy @@ -103,9 +112,6 @@ Performance, Internal Implementation, Development Support etc. clean.requireForce has been simplified, together with the documentation. - * The code to iterate over refs with the reftable backend has seen - some optimization. - * Uses of xwrite() helper have been audited and updated for better error checking and simpler code. @@ -161,6 +167,23 @@ Performance, Internal Implementation, Development Support etc. out folks with compilers who have trouble compiling code that uses the feature. + * Windows binary used to decide the use of unix-domain socket at + build time, but it learned to make the decision at runtime instead. + + * The "shared repository" test in the t0610 reftable test failed + under restrictive umask setting (e.g. 007), which has been + corrected. + + * Document and apply workaround for a buggy version of dash that + mishandles "local var=val" construct. + + * The codepaths that reach date_mode_from_type() have been updated to + pass "struct date_mode" by value to make them thread safe. + + * The strategy to compact multiple tables of reftables after many + operations accumulate many entries has been improved to avoid + accumulating too many tables uncollected. + Fixes since v2.44 ----------------- @@ -224,7 +247,7 @@ Fixes since v2.44 This has been corrected. (merge 199f44cb2e ps/remote-helper-repo-initialization-fix later to maint). - * Various parts of upload-pack has been updated to bound the resource + * Various parts of upload-pack have been updated to bound the resource consumption relative to the size of the repository to protect from abusive clients. (merge 6cd05e768b jk/upload-pack-bounded-resources later to maint). @@ -271,11 +294,11 @@ Fixes since v2.44 variable that is no longer used. (merge 72a8d3f027 pw/rebase-i-ignore-cherry-pick-help-environment later to maint). - * The code to find the effective end of log message can fall into an + * The code to find the effective end of log messages can fall into an endless loop, which has been corrected. (merge 2541cba2d6 fs/find-end-of-log-message-fix later to maint). - * Mark-ups used in the documentation has been improved for + * Mark-up used in the documentation has been improved for consistency. (merge 45d5ed3e50 ja/doc-markup-fixes later to maint). @@ -347,6 +370,37 @@ Fixes since v2.44 HEAD state, gave the tracking information for the 'foo' branch, which was pointless. + * "git apply" has been updated to lift the hardcoded pathname length + limit, which in turn allowed a mksnpath() function that is no + longer used. + (merge 708f7e0590 rs/apply-lift-path-length-limit later to maint). + + * A file descriptor leak in an error codepath, used when "git apply + --reject" fails to create the *.rej file, has been corrected. + (merge 2b1f456adf rs/apply-reject-fd-leakfix later to maint). + + * A config parser callback function fell through instead of returning + after recognising and processing a variable, wasting cycles, which + has been corrected. + (merge a816ccd642 ds/fetch-config-parse-microfix later to maint). + + * Fix was added to work around a regression in libcURL 8.7.0 (which has + already been fixed in their tip of the tree). + (merge 92a209bf24 jk/libcurl-8.7-regression-workaround later to maint). + + * The variable that holds the value read from the core.excludefile + configuration variable used to leak, which has been corrected. + (merge 0e0fefb29f jc/unleak-core-excludesfile later to maint). + + * vreportf(), which is used by error() and friends, has been taught + to give the error message printf-format string when its vsnprintf() + call fails, instead of showing nothing useful to identify the + nature of the error. + (merge c63adab961 rs/usage-fallback-to-show-message-format later to maint). + + * Adjust to an upcoming changes to GNU make that breaks our Makefiles. + (merge 227b8fd902 tb/make-indent-conditional-with-non-spaces later to maint). + * Other code cleanup, docfix, build fix, etc. (merge f0e578c69c rs/use-xstrncmpz later to maint). (merge 83e6eb7d7a ba/credential-test-clean-fix later to maint). @@ -373,3 +427,7 @@ Fixes since v2.44 (merge 7c43bdf07b rs/strbuf-expand-bad-format later to maint). (merge 8b68b48d5c ds/typofix-core-config-doc later to maint). (merge 39bb692152 rs/imap-send-use-xsnprintf later to maint). + (merge 8d320cec60 jc/t2104-style-fixes later to maint). + (merge b4454d5a7b pw/t3428-cleanup later to maint). + (merge 84a7c33a4b pf/commitish-committish later to maint). + (merge 8882ee9d68 la/mailmap-entry later to maint). diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN index df788c764b..dabd2b5b89 100755 --- a/GIT-VERSION-GEN +++ b/GIT-VERSION-GEN @@ -1,7 +1,7 @@ #!/bin/sh GVF=GIT-VERSION-FILE -DEF_VER=v2.44.GIT +DEF_VER=v2.45.0-rc0 LF=' ' @@ -139,7 +139,7 @@ Issues of note: not need that functionality, use NO_CURL to build without it. - Git requires version "7.19.5" or later of "libcurl" to build + Git requires version "7.21.3" or later of "libcurl" to build without NO_CURL. This version requirement may be bumped in the future. @@ -1558,23 +1558,23 @@ ifneq (,$(SOCKLEN_T)) endif ifeq ($(uname_S),Darwin) - ifndef NO_FINK - ifeq ($(shell test -d /sw/lib && echo y),y) + ifndef NO_FINK + ifeq ($(shell test -d /sw/lib && echo y),y) BASIC_CFLAGS += -I/sw/include BASIC_LDFLAGS += -L/sw/lib - endif - endif - ifndef NO_DARWIN_PORTS - ifeq ($(shell test -d /opt/local/lib && echo y),y) + endif + endif + ifndef NO_DARWIN_PORTS + ifeq ($(shell test -d /opt/local/lib && echo y),y) BASIC_CFLAGS += -I/opt/local/include BASIC_LDFLAGS += -L/opt/local/lib - endif - endif - ifndef NO_APPLE_COMMON_CRYPTO + endif + endif + ifndef NO_APPLE_COMMON_CRYPTO NO_OPENSSL = YesPlease APPLE_COMMON_CRYPTO = YesPlease COMPAT_CFLAGS += -DAPPLE_COMMON_CRYPTO - endif + endif PTHREAD_LIBS = endif @@ -1613,23 +1613,23 @@ ifdef NO_CURL REMOTE_CURL_NAMES = EXCLUDED_PROGRAMS += git-http-fetch git-http-push else - ifdef CURLDIR + ifdef CURLDIR # Try "-Wl,-rpath=$(CURLDIR)/$(lib)" in such a case. CURL_CFLAGS = -I$(CURLDIR)/include CURL_LIBCURL = $(call libpath_template,$(CURLDIR)/$(lib)) - else + else CURL_CFLAGS = CURL_LIBCURL = - endif + endif - ifndef CURL_LDFLAGS + ifndef CURL_LDFLAGS CURL_LDFLAGS = $(eval CURL_LDFLAGS := $$(shell $$(CURL_CONFIG) --libs))$(CURL_LDFLAGS) - endif + endif CURL_LIBCURL += $(CURL_LDFLAGS) - ifndef CURL_CFLAGS + ifndef CURL_CFLAGS CURL_CFLAGS = $(eval CURL_CFLAGS := $$(shell $$(CURL_CONFIG) --cflags))$(CURL_CFLAGS) - endif + endif BASIC_CFLAGS += $(CURL_CFLAGS) REMOTE_CURL_PRIMARY = git-remote-http$X @@ -1637,29 +1637,29 @@ else REMOTE_CURL_NAMES = $(REMOTE_CURL_PRIMARY) $(REMOTE_CURL_ALIASES) PROGRAM_OBJS += http-fetch.o PROGRAMS += $(REMOTE_CURL_NAMES) - ifndef NO_EXPAT + ifndef NO_EXPAT PROGRAM_OBJS += http-push.o - endif + endif curl_check := $(shell (echo 072200; $(CURL_CONFIG) --vernum | sed -e '/^70[BC]/s/^/0/') 2>/dev/null | sort -r | sed -ne 2p) - ifeq "$(curl_check)" "072200" + ifeq "$(curl_check)" "072200" USE_CURL_FOR_IMAP_SEND = YesPlease - endif - ifdef USE_CURL_FOR_IMAP_SEND + endif + ifdef USE_CURL_FOR_IMAP_SEND BASIC_CFLAGS += -DUSE_CURL_FOR_IMAP_SEND IMAP_SEND_BUILDDEPS = http.o IMAP_SEND_LDFLAGS += $(CURL_LIBCURL) - endif - ifndef NO_EXPAT - ifdef EXPATDIR + endif + ifndef NO_EXPAT + ifdef EXPATDIR BASIC_CFLAGS += -I$(EXPATDIR)/include EXPAT_LIBEXPAT = $(call libpath_template,$(EXPATDIR)/$(lib)) -lexpat - else + else EXPAT_LIBEXPAT = -lexpat - endif - ifdef EXPAT_NEEDS_XMLPARSE_H + endif + ifdef EXPAT_NEEDS_XMLPARSE_H BASIC_CFLAGS += -DEXPAT_NEEDS_XMLPARSE_H - endif - endif + endif + endif endif IMAP_SEND_LDFLAGS += $(OPENSSL_LINK) $(OPENSSL_LIBSSL) $(LIB_4_CRYPTO) @@ -1671,15 +1671,15 @@ EXTLIBS += -lz ifndef NO_OPENSSL OPENSSL_LIBSSL = -lssl - ifdef OPENSSLDIR + ifdef OPENSSLDIR BASIC_CFLAGS += -I$(OPENSSLDIR)/include OPENSSL_LINK = $(call libpath_template,$(OPENSSLDIR)/$(lib)) - else + else OPENSSL_LINK = - endif - ifdef NEEDS_CRYPTO_WITH_SSL + endif + ifdef NEEDS_CRYPTO_WITH_SSL OPENSSL_LIBSSL += -lcrypto - endif + endif else BASIC_CFLAGS += -DNO_OPENSSL OPENSSL_LIBSSL = @@ -1697,18 +1697,18 @@ ifdef APPLE_COMMON_CRYPTO endif endif ifndef NO_ICONV - ifdef NEEDS_LIBICONV - ifdef ICONVDIR + ifdef NEEDS_LIBICONV + ifdef ICONVDIR BASIC_CFLAGS += -I$(ICONVDIR)/include ICONV_LINK = $(call libpath_template,$(ICONVDIR)/$(lib)) - else + else ICONV_LINK = - endif - ifdef NEEDS_LIBINTL_BEFORE_LIBICONV + endif + ifdef NEEDS_LIBINTL_BEFORE_LIBICONV ICONV_LINK += -lintl - endif + endif EXTLIBS += $(ICONV_LINK) -liconv - endif + endif endif ifdef ICONV_OMITS_BOM BASIC_CFLAGS += -DICONV_OMITS_BOM @@ -1829,10 +1829,10 @@ ifdef NO_MMAP COMPAT_CFLAGS += -DNO_MMAP COMPAT_OBJS += compat/mmap.o else - ifdef USE_WIN32_MMAP + ifdef USE_WIN32_MMAP COMPAT_CFLAGS += -DUSE_WIN32_MMAP COMPAT_OBJS += compat/win32mmap.o - endif + endif endif ifdef MMAP_PREVENTS_DELETE BASIC_CFLAGS += -DMMAP_PREVENTS_DELETE @@ -1957,11 +1957,11 @@ else BASIC_CFLAGS += -DSHA1_DC LIB_OBJS += sha1dc_git.o ifdef DC_SHA1_EXTERNAL - ifdef DC_SHA1_SUBMODULE - ifneq ($(DC_SHA1_SUBMODULE),auto) + ifdef DC_SHA1_SUBMODULE + ifneq ($(DC_SHA1_SUBMODULE),auto) $(error Only set DC_SHA1_EXTERNAL or DC_SHA1_SUBMODULE, not both) - endif - endif + endif + endif BASIC_CFLAGS += -DDC_SHA1_EXTERNAL EXTLIBS += -lsha1detectcoll else @@ -4448,6 +4448,7 @@ static int create_one_file(struct apply_state *state, const char *buf, unsigned long size) { + char *newpath = NULL; int res; if (state->cached) @@ -4509,24 +4510,26 @@ static int create_one_file(struct apply_state *state, unsigned int nr = getpid(); for (;;) { - char newpath[PATH_MAX]; - mksnpath(newpath, sizeof(newpath), "%s~%u", path, nr); + newpath = mkpathdup("%s~%u", path, nr); res = try_create_file(state, newpath, mode, buf, size); if (res < 0) - return -1; + goto out; if (!res) { if (!rename(newpath, path)) - return 0; + goto out; unlink_or_warn(newpath); break; } if (errno != EEXIST) break; ++nr; + FREE_AND_NULL(newpath); } } - return error_errno(_("unable to write file '%s' mode %o"), - path, mode); + res = error_errno(_("unable to write file '%s' mode %o"), path, mode); +out: + free(newpath); + return res; } static int add_conflicted_stages_file(struct apply_state *state, @@ -4662,8 +4665,11 @@ static int write_out_one_reject(struct apply_state *state, struct patch *patch) return error_errno(_("cannot open %s"), namebuf); } rej = fdopen(fd, "w"); - if (!rej) - return error_errno(_("cannot open %s"), namebuf); + if (!rej) { + error_errno(_("cannot open %s"), namebuf); + close(fd); + return -1; + } /* Normal git tools never deal with .rej, so do not pretend * this is a git patch by saying --git or giving extended @@ -738,7 +738,7 @@ static int submodule_create_branch(struct repository *r, } void create_branches_recursively(struct repository *r, const char *name, - const char *start_commitish, + const char *start_committish, const char *tracking_name, int force, int reflog, int quiet, enum branch_track track, int dry_run) @@ -748,8 +748,8 @@ void create_branches_recursively(struct repository *r, const char *name, struct object_id super_oid; struct submodule_entry_list submodule_entry_list; - /* Perform dwim on start_commitish to get super_oid and branch_point. */ - dwim_branch_start(r, start_commitish, BRANCH_TRACK_NEVER, + /* Perform dwim on start_committish to get super_oid and branch_point. */ + dwim_branch_start(r, start_committish, BRANCH_TRACK_NEVER, &branch_point, &super_oid); /* @@ -772,7 +772,7 @@ void create_branches_recursively(struct repository *r, const char *name, submodule_entry_list.entries[i].submodule->name); if (advice_enabled(ADVICE_SUBMODULES_NOT_UPDATED)) advise(_("You may try updating the submodules using 'git checkout --no-recurse-submodules %s && git submodule update --init'"), - start_commitish); + start_committish); exit(code); } @@ -787,7 +787,7 @@ void create_branches_recursively(struct repository *r, const char *name, name); } - create_branch(r, name, start_commitish, force, 0, reflog, quiet, + create_branch(r, name, start_committish, force, 0, reflog, quiet, BRANCH_TRACK_NEVER, dry_run); if (dry_run) return; @@ -78,26 +78,26 @@ void create_branch(struct repository *r, * those of create_branch() except for start_name, which is represented * by two different parameters: * - * - start_commitish is the commit-ish, in repository r, that determines + * - start_committish is the commit-ish, in repository r, that determines * which commits the branches will point to. The superproject branch - * will point to the commit of start_commitish and the submodule - * branches will point to the gitlink commit oids in start_commitish's + * will point to the commit of start_committish and the submodule + * branches will point to the gitlink commit oids in start_committish's * tree. * * - tracking_name is the name of the ref, in repository r, that will be * used to set up tracking information. This value is propagated to * all submodules, which will evaluate the ref using their own ref - * stores. If NULL, this defaults to start_commitish. + * stores. If NULL, this defaults to start_committish. * - * When this function is called on the superproject, start_commitish + * When this function is called on the superproject, start_committish * can be any user-provided ref and tracking_name can be NULL (similar * to create_branches()). But when recursing through submodules, - * start_commitish is the plain gitlink commit oid. Since the oid cannot + * start_committish is the plain gitlink commit oid. Since the oid cannot * be used for tracking information, tracking_name is propagated and * used for tracking instead. */ void create_branches_recursively(struct repository *r, const char *name, - const char *start_commitish, + const char *start_committish, const char *tracking_name, int force, int reflog, int quiet, enum branch_track track, int dry_run); diff --git a/builtin/add.c b/builtin/add.c index e97699d6b9..ae723bc85e 100644 --- a/builtin/add.c +++ b/builtin/add.c @@ -368,6 +368,7 @@ int cmd_add(int argc, const char **argv, const char *prefix) int add_new_files; int require_pathspec; char *seen = NULL; + char *ps_matched = NULL; struct lock_file lock_file = LOCK_INIT; git_config(add_config, NULL); @@ -545,12 +546,17 @@ int cmd_add(int argc, const char **argv, const char *prefix) begin_odb_transaction(); + ps_matched = xcalloc(pathspec.nr, 1); if (add_renormalize) exit_status |= renormalize_tracked_files(&pathspec, flags); else exit_status |= add_files_to_cache(the_repository, prefix, - &pathspec, include_sparse, - flags); + &pathspec, ps_matched, + include_sparse, flags); + + if (take_worktree_changes && !add_renormalize && !ignore_add_errors && + report_path_error(ps_matched, &pathspec)) + exit(128); if (add_new_files) exit_status |= add_files(&dir, flags); @@ -564,6 +570,7 @@ finish: COMMIT_LOCK | SKIP_IF_UNCHANGED)) die(_("unable to write new index file")); + free(ps_matched); dir_clear(&dir); clear_pathspec(&pathspec); return exit_status; diff --git a/builtin/blame.c b/builtin/blame.c index db1f56de61..9aa74680a3 100644 --- a/builtin/blame.c +++ b/builtin/blame.c @@ -316,7 +316,7 @@ static const char *format_time(timestamp_t time, const char *tz_str, size_t time_width; int tz; tz = atoi(tz_str); - time_str = show_date(time, tz, &blame_date_mode); + time_str = show_date(time, tz, blame_date_mode); strbuf_addstr(&time_buf, time_str); /* * Add space paddings to time_buf to display a fixed width @@ -1029,7 +1029,7 @@ parse_done: blame_date_width = sizeof("Thu Oct 19 16:00:04 2006 -0700"); break; case DATE_STRFTIME: - blame_date_width = strlen(show_date(0, 0, &blame_date_mode)) + 1; /* add the null */ + blame_date_width = strlen(show_date(0, 0, blame_date_mode)) + 1; /* add the null */ break; } blame_date_width -= 1; /* strip the null */ diff --git a/builtin/checkout.c b/builtin/checkout.c index 947827de1d..71e6036aab 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -882,7 +882,8 @@ static int merge_working_tree(const struct checkout_opts *opts, * entries in the index. */ - add_files_to_cache(the_repository, NULL, NULL, 0, 0); + add_files_to_cache(the_repository, NULL, NULL, NULL, 0, + 0); init_merge_options(&o, the_repository); o.verbosity = 0; work = write_in_core_index_as_tree(the_repository); diff --git a/builtin/commit.c b/builtin/commit.c index 7ba7201cfb..6e1484446b 100644 --- a/builtin/commit.c +++ b/builtin/commit.c @@ -441,16 +441,21 @@ static const char *prepare_index(const char **argv, const char *prefix, * (B) on failure, rollback the real index. */ if (all || (also && pathspec.nr)) { + char *ps_matched = xcalloc(pathspec.nr, 1); repo_hold_locked_index(the_repository, &index_lock, LOCK_DIE_ON_ERROR); add_files_to_cache(the_repository, also ? prefix : NULL, - &pathspec, 0, 0); + &pathspec, ps_matched, 0, 0); + if (!all && report_path_error(ps_matched, &pathspec)) + exit(128); + refresh_cache_or_die(refresh_flags); cache_tree_update(&the_index, WRITE_TREE_SILENT); if (write_locked_index(&the_index, &index_lock, 0)) die(_("unable to write new index file")); commit_style = COMMIT_NORMAL; ret = get_lock_file_path(&index_lock); + free(ps_matched); goto out; } diff --git a/builtin/credential-cache--daemon.c b/builtin/credential-cache--daemon.c index 3a6a750a8e..17f929dede 100644 --- a/builtin/credential-cache--daemon.c +++ b/builtin/credential-cache--daemon.c @@ -294,6 +294,8 @@ int cmd_credential_cache_daemon(int argc, const char **argv, const char *prefix) argc = parse_options(argc, argv, prefix, options, usage, 0); socket_path = argv[0]; + if (!have_unix_sockets()) + die(_("credential-cache--daemon unavailable; no unix socket support")); if (!socket_path) usage_with_options(usage, options); diff --git a/builtin/credential-cache.c b/builtin/credential-cache.c index bba96d4ffd..bef120b537 100644 --- a/builtin/credential-cache.c +++ b/builtin/credential-cache.c @@ -149,6 +149,9 @@ int cmd_credential_cache(int argc, const char **argv, const char *prefix) usage_with_options(usage, options); op = argv[0]; + if (!have_unix_sockets()) + die(_("credential-cache unavailable; no unix socket support")); + if (!socket_path) socket_path = get_socket_path(); if (!socket_path) diff --git a/builtin/fetch.c b/builtin/fetch.c index 46a793411a..5857d860db 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -138,6 +138,7 @@ static int git_fetch_config(const char *k, const char *v, int r = git_config_bool(k, v) ? RECURSE_SUBMODULES_ON : RECURSE_SUBMODULES_OFF; fetch_config->recurse_submodules = r; + return 0; } if (!strcmp(k, "submodule.fetchjobs")) { diff --git a/compat/mingw.c b/compat/mingw.c index 320fb99a90..4876344b5b 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -3158,3 +3158,22 @@ int uname(struct utsname *buf) "%u", (v >> 16) & 0x7fff); return 0; } + +int mingw_have_unix_sockets(void) +{ + SC_HANDLE scm, srvc; + SERVICE_STATUS_PROCESS status; + DWORD bytes; + int ret = 0; + scm = OpenSCManagerA(NULL, NULL, SC_MANAGER_CONNECT); + if (scm) { + srvc = OpenServiceA(scm, "afunix", SERVICE_QUERY_STATUS); + if (srvc) { + if(QueryServiceStatusEx(srvc, SC_STATUS_PROCESS_INFO, (LPBYTE)&status, sizeof(SERVICE_STATUS_PROCESS), &bytes)) + ret = status.dwCurrentState == SERVICE_RUNNING; + CloseServiceHandle(srvc); + } + CloseServiceHandle(scm); + } + return ret; +} diff --git a/compat/mingw.h b/compat/mingw.h index 6aec50e412..27b61284f4 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -631,3 +631,9 @@ void open_in_gdb(void); * Used by Pthread API implementation for Windows */ int err_win_to_posix(DWORD winerr); + +#ifndef NO_UNIX_SOCKETS +int mingw_have_unix_sockets(void); +#undef have_unix_sockets +#define have_unix_sockets mingw_have_unix_sockets +#endif @@ -1584,8 +1584,10 @@ static int git_default_core_config(const char *var, const char *value, if (!strcmp(var, "core.askpass")) return git_config_string(&askpass_program, var, value); - if (!strcmp(var, "core.excludesfile")) + if (!strcmp(var, "core.excludesfile")) { + free((char *)excludes_file); return git_config_pathname(&excludes_file, var, value); + } if (!strcmp(var, "core.whitespace")) { if (!value) diff --git a/config.mak.uname b/config.mak.uname index d0dcca2ec5..a7607a5676 100644 --- a/config.mak.uname +++ b/config.mak.uname @@ -65,9 +65,9 @@ ifeq ($(uname_S),Linux) HAVE_PLATFORM_PROCINFO = YesPlease COMPAT_OBJS += compat/linux/procinfo.o # centos7/rhel7 provides gcc 4.8.5 and zlib 1.2.7. - ifneq ($(findstring .el7.,$(uname_R)),) + ifneq ($(findstring .el7.,$(uname_R)),) BASIC_CFLAGS += -std=c99 - endif + endif endif ifeq ($(uname_S),GNU/kFreeBSD) HAVE_ALLOCA_H = YesPlease @@ -95,13 +95,13 @@ ifeq ($(uname_S),UnixWare) NO_MEMMEM = YesPlease endif ifeq ($(uname_S),SCO_SV) - ifeq ($(uname_R),3.2) + ifeq ($(uname_R),3.2) CFLAGS = -O2 - endif - ifeq ($(uname_R),5) + endif + ifeq ($(uname_R),5) CC = cc BASIC_CFLAGS += -Kthread - endif + endif NEEDS_SOCKET = YesPlease NEEDS_NSL = YesPlease NEEDS_SSL_WITH_CRYPTO = YesPlease @@ -124,19 +124,19 @@ ifeq ($(uname_S),Darwin) # - MacOS 10.0.* and MacOS 10.1.0 = Darwin 1.* # - MacOS 10.x.* = Darwin (x+4).* for (1 <= x) # i.e. "begins with [15678] and a dot" means "10.4.* or older". - ifeq ($(shell expr "$(uname_R)" : '[15678]\.'),2) + ifeq ($(shell expr "$(uname_R)" : '[15678]\.'),2) OLD_ICONV = UnfortunatelyYes NO_APPLE_COMMON_CRYPTO = YesPlease - endif - ifeq ($(shell expr "$(uname_R)" : '[15]\.'),2) + endif + ifeq ($(shell expr "$(uname_R)" : '[15]\.'),2) NO_STRLCPY = YesPlease - endif - ifeq ($(shell test "`expr "$(uname_R)" : '\([0-9][0-9]*\)\.'`" -ge 11 && echo 1),1) + endif + ifeq ($(shell test "`expr "$(uname_R)" : '\([0-9][0-9]*\)\.'`" -ge 11 && echo 1),1) HAVE_GETDELIM = YesPlease - endif - ifeq ($(shell test "`expr "$(uname_R)" : '\([0-9][0-9]*\)\.'`" -ge 20 && echo 1),1) + endif + ifeq ($(shell test "`expr "$(uname_R)" : '\([0-9][0-9]*\)\.'`" -ge 20 && echo 1),1) OPEN_RETURNS_EINTR = UnfortunatelyYes - endif + endif NO_MEMMEM = YesPlease USE_ST_TIMESPEC = YesPlease HAVE_DEV_TTY = YesPlease @@ -152,12 +152,12 @@ ifeq ($(uname_S),Darwin) # Workaround for `gettext` being keg-only and not even being linked via # `brew link --force gettext`, should be obsolete as of # https://github.com/Homebrew/homebrew-core/pull/53489 - ifeq ($(shell test -d /usr/local/opt/gettext/ && echo y),y) + ifeq ($(shell test -d /usr/local/opt/gettext/ && echo y),y) BASIC_CFLAGS += -I/usr/local/include -I/usr/local/opt/gettext/include BASIC_LDFLAGS += -L/usr/local/lib -L/usr/local/opt/gettext/lib - ifeq ($(shell test -x /usr/local/opt/gettext/bin/msgfmt && echo y),y) + ifeq ($(shell test -x /usr/local/opt/gettext/bin/msgfmt && echo y),y) MSGFMT = /usr/local/opt/gettext/bin/msgfmt - endif + endif # On newer ARM-based machines the default installation path has changed to # /opt/homebrew. Include it in our search paths so that the user does not # have to configure this manually. @@ -165,22 +165,22 @@ ifeq ($(uname_S),Darwin) # Note that we do not employ the same workaround as above where we manually # add gettext. The issue was fixed more than three years ago by now, and at # that point there haven't been any ARM-based Macs yet. - else ifeq ($(shell test -d /opt/homebrew/ && echo y),y) + else ifeq ($(shell test -d /opt/homebrew/ && echo y),y) BASIC_CFLAGS += -I/opt/homebrew/include BASIC_LDFLAGS += -L/opt/homebrew/lib - ifeq ($(shell test -x /opt/homebrew/bin/msgfmt && echo y),y) + ifeq ($(shell test -x /opt/homebrew/bin/msgfmt && echo y),y) MSGFMT = /opt/homebrew/bin/msgfmt - endif - endif + endif + endif # The builtin FSMonitor on MacOS builds upon Simple-IPC. Both require # Unix domain sockets and PThreads. - ifndef NO_PTHREADS - ifndef NO_UNIX_SOCKETS + ifndef NO_PTHREADS + ifndef NO_UNIX_SOCKETS FSMONITOR_DAEMON_BACKEND = darwin FSMONITOR_OS_SETTINGS = darwin - endif - endif + endif + endif BASIC_LDFLAGS += -framework CoreServices endif @@ -196,7 +196,7 @@ ifeq ($(uname_S),SunOS) NO_REGEX = YesPlease NO_MSGFMT_EXTENDED_OPTIONS = YesPlease HAVE_DEV_TTY = YesPlease - ifeq ($(uname_R),5.6) + ifeq ($(uname_R),5.6) SOCKLEN_T = int NO_HSTRERROR = YesPlease NO_IPV6 = YesPlease @@ -206,8 +206,8 @@ ifeq ($(uname_S),SunOS) NO_STRLCPY = YesPlease NO_STRTOUMAX = YesPlease GIT_TEST_CMP = cmp - endif - ifeq ($(uname_R),5.7) + endif + ifeq ($(uname_R),5.7) NEEDS_RESOLV = YesPlease NO_IPV6 = YesPlease NO_SOCKADDR_STORAGE = YesPlease @@ -216,25 +216,25 @@ ifeq ($(uname_S),SunOS) NO_STRLCPY = YesPlease NO_STRTOUMAX = YesPlease GIT_TEST_CMP = cmp - endif - ifeq ($(uname_R),5.8) + endif + ifeq ($(uname_R),5.8) NO_UNSETENV = YesPlease NO_SETENV = YesPlease NO_STRTOUMAX = YesPlease GIT_TEST_CMP = cmp - endif - ifeq ($(uname_R),5.9) + endif + ifeq ($(uname_R),5.9) NO_UNSETENV = YesPlease NO_SETENV = YesPlease NO_STRTOUMAX = YesPlease GIT_TEST_CMP = cmp - endif + endif INSTALL = /usr/ucb/install TAR = gtar BASIC_CFLAGS += -D__EXTENSIONS__ -D__sun__ endif ifeq ($(uname_O),Cygwin) - ifeq ($(shell expr "$(uname_R)" : '1\.[1-6]\.'),4) + ifeq ($(shell expr "$(uname_R)" : '1\.[1-6]\.'),4) NO_D_TYPE_IN_DIRENT = YesPlease NO_STRCASESTR = YesPlease NO_MEMMEM = YesPlease @@ -245,9 +245,9 @@ ifeq ($(uname_O),Cygwin) # On some boxes NO_MMAP is needed, and not so elsewhere. # Try commenting this out if you suspect MMAP is more efficient NO_MMAP = YesPlease - else + else NO_REGEX = UnfortunatelyYes - endif + endif HAVE_ALLOCA_H = YesPlease NEEDS_LIBICONV = YesPlease NO_FAST_WORKING_DIRECTORY = UnfortunatelyYes @@ -263,25 +263,25 @@ ifeq ($(uname_S),FreeBSD) NEEDS_LIBICONV = YesPlease # Versions up to 10.1 require OLD_ICONV; 10.2 and beyond don't. # A typical version string looks like "10.2-RELEASE". - ifeq ($(shell expr "$(uname_R)" : '[1-9]\.'),2) + ifeq ($(shell expr "$(uname_R)" : '[1-9]\.'),2) OLD_ICONV = YesPlease - endif - ifeq ($(firstword $(subst -, ,$(uname_R))),10.0) + endif + ifeq ($(firstword $(subst -, ,$(uname_R))),10.0) OLD_ICONV = YesPlease - endif - ifeq ($(firstword $(subst -, ,$(uname_R))),10.1) + endif + ifeq ($(firstword $(subst -, ,$(uname_R))),10.1) OLD_ICONV = YesPlease - endif + endif NO_MEMMEM = YesPlease BASIC_CFLAGS += -I/usr/local/include BASIC_LDFLAGS += -L/usr/local/lib DIR_HAS_BSD_GROUP_SEMANTICS = YesPlease USE_ST_TIMESPEC = YesPlease - ifeq ($(shell expr "$(uname_R)" : '4\.'),2) + ifeq ($(shell expr "$(uname_R)" : '4\.'),2) PTHREAD_LIBS = -pthread NO_UINTMAX_T = YesPlease NO_STRTOUMAX = YesPlease - endif + endif PYTHON_PATH = /usr/local/bin/python PERL_PATH = /usr/local/bin/perl HAVE_PATHS_H = YesPlease @@ -317,9 +317,9 @@ ifeq ($(uname_S),MirBSD) CSPRNG_METHOD = arc4random endif ifeq ($(uname_S),NetBSD) - ifeq ($(shell expr "$(uname_R)" : '[01]\.'),2) + ifeq ($(shell expr "$(uname_R)" : '[01]\.'),2) NEEDS_LIBICONV = YesPlease - endif + endif BASIC_CFLAGS += -I/usr/pkg/include BASIC_LDFLAGS += -L/usr/pkg/lib $(CC_LD_DYNPATH)/usr/pkg/lib USE_ST_TIMESPEC = YesPlease @@ -343,14 +343,14 @@ ifeq ($(uname_S),AIX) BASIC_CFLAGS += -D_LARGE_FILES FILENO_IS_A_MACRO = UnfortunatelyYes NEED_ACCESS_ROOT_HANDLER = UnfortunatelyYes - ifeq ($(shell expr "$(uname_V)" : '[1234]'),1) + ifeq ($(shell expr "$(uname_V)" : '[1234]'),1) NO_PTHREADS = YesPlease - else + else PTHREAD_LIBS = -lpthread - endif - ifeq ($(shell expr "$(uname_V).$(uname_R)" : '5\.1'),3) + endif + ifeq ($(shell expr "$(uname_V).$(uname_R)" : '5\.1'),3) INLINE = '' - endif + endif GIT_TEST_CMP = cmp endif ifeq ($(uname_S),GNU) @@ -410,29 +410,29 @@ ifeq ($(uname_S),HP-UX) NO_SYS_SELECT_H = YesPlease SNPRINTF_RETURNS_BOGUS = YesPlease NO_NSEC = YesPlease - ifeq ($(uname_R),B.11.00) + ifeq ($(uname_R),B.11.00) NO_INET_NTOP = YesPlease NO_INET_PTON = YesPlease - endif - ifeq ($(uname_R),B.10.20) + endif + ifeq ($(uname_R),B.10.20) # Override HP-UX 11.x setting: INLINE = SOCKLEN_T = size_t NO_PREAD = YesPlease NO_INET_NTOP = YesPlease NO_INET_PTON = YesPlease - endif + endif GIT_TEST_CMP = cmp endif ifeq ($(uname_S),Windows) GIT_VERSION := $(GIT_VERSION).MSVC pathsep = ; # Assume that this is built in Git for Windows' SDK - ifeq (MINGW32,$(MSYSTEM)) + ifeq (MINGW32,$(MSYSTEM)) prefix = /mingw32 - else + else prefix = /mingw64 - endif + endif # Prepend MSVC 64-bit tool-chain to PATH. # # A regular Git Bash *does not* have cl.exe in its $PATH. As there is a @@ -447,7 +447,6 @@ ifeq ($(uname_S),Windows) NO_POLL = YesPlease NO_SYMLINK_HEAD = YesPlease NO_IPV6 = YesPlease - NO_UNIX_SOCKETS = YesPlease NO_SETENV = YesPlease NO_STRCASESTR = YesPlease NO_STRLCPY = YesPlease @@ -550,16 +549,16 @@ ifeq ($(uname_S),Interix) NO_MKDTEMP = YesPlease NO_STRTOUMAX = YesPlease NO_NSEC = YesPlease - ifeq ($(uname_R),3.5) + ifeq ($(uname_R),3.5) NO_INET_NTOP = YesPlease NO_INET_PTON = YesPlease NO_SOCKADDR_STORAGE = YesPlease - endif - ifeq ($(uname_R),5.2) + endif + ifeq ($(uname_R),5.2) NO_INET_NTOP = YesPlease NO_INET_PTON = YesPlease NO_SOCKADDR_STORAGE = YesPlease - endif + endif endif ifeq ($(uname_S),Minix) NO_IPV6 = YesPlease @@ -579,12 +578,12 @@ ifeq ($(uname_S),NONSTOP_KERNEL) # still not compile in c89 mode, due to non-const array initializations. CC = cc -c99 # Build down-rev compatible objects that don't use our new getopt_long. - ifeq ($(uname_R).$(uname_V),J06.21) + ifeq ($(uname_R).$(uname_V),J06.21) CC += -WRVU=J06.20 - endif - ifeq ($(uname_R).$(uname_V),L17.02) + endif + ifeq ($(uname_R).$(uname_V),L17.02) CC += -WRVU=L16.05 - endif + endif # Disable all optimization, seems to result in bad code, with -O or -O2 # or even -O1 (default), /usr/local/libexec/git-core/git-pack-objects # abends on "git push". Needs more investigation. @@ -651,9 +650,9 @@ ifeq ($(uname_S),OS/390) NEEDS_MODE_TRANSLATION = YesPlease endif ifeq ($(uname_S),MINGW) - ifeq ($(shell expr "$(uname_R)" : '1\.'),2) + ifeq ($(shell expr "$(uname_R)" : '1\.'),2) $(error "Building with MSys is no longer supported") - endif + endif pathsep = ; HAVE_ALLOCA_H = YesPlease NO_PREAD = YesPlease @@ -661,7 +660,6 @@ ifeq ($(uname_S),MINGW) NO_LIBGEN_H = YesPlease NO_POLL = YesPlease NO_SYMLINK_HEAD = YesPlease - NO_UNIX_SOCKETS = YesPlease NO_SETENV = YesPlease NO_STRCASESTR = YesPlease NO_STRLCPY = YesPlease @@ -712,22 +710,22 @@ ifeq ($(uname_S),MINGW) # Enable DEP BASIC_LDFLAGS += -Wl,--nxcompat # Enable ASLR (unless debugging) - ifneq (,$(findstring -O,$(filter-out -O0 -Og,$(CFLAGS)))) + ifneq (,$(findstring -O,$(filter-out -O0 -Og,$(CFLAGS)))) BASIC_LDFLAGS += -Wl,--dynamicbase - endif - ifeq (MINGW32,$(MSYSTEM)) + endif + ifeq (MINGW32,$(MSYSTEM)) prefix = /mingw32 HOST_CPU = i686 BASIC_LDFLAGS += -Wl,--pic-executable,-e,_mainCRTStartup - endif - ifeq (MINGW64,$(MSYSTEM)) + endif + ifeq (MINGW64,$(MSYSTEM)) prefix = /mingw64 HOST_CPU = x86_64 BASIC_LDFLAGS += -Wl,--pic-executable,-e,mainCRTStartup - else + else COMPAT_CFLAGS += -D_USE_32BIT_TIME_T BASIC_LDFLAGS += -Wl,--large-address-aware - endif + endif CC = gcc COMPAT_CFLAGS += -D__USE_MINGW_ANSI_STDIO=0 -DDETECT_MSYS_TTY \ -fstack-protector-strong @@ -739,11 +737,11 @@ ifeq ($(uname_S),MINGW) USE_GETTEXT_SCHEME = fallthrough USE_LIBPCRE = YesPlease USE_NED_ALLOCATOR = YesPlease - ifeq (/mingw64,$(subst 32,64,$(prefix))) + ifeq (/mingw64,$(subst 32,64,$(prefix))) # Move system config into top-level /etc/ ETC_GITCONFIG = ../etc/gitconfig ETC_GITATTRIBUTES = ../etc/gitattributes - endif + endif endif ifeq ($(uname_S),QNX) COMPAT_CFLAGS += -DSA_RESTART=0 diff --git a/contrib/credential/osxkeychain/Makefile b/contrib/credential/osxkeychain/Makefile index 4b3a08a2ba..238f5f8c36 100644 --- a/contrib/credential/osxkeychain/Makefile +++ b/contrib/credential/osxkeychain/Makefile @@ -8,7 +8,8 @@ CFLAGS = -g -O2 -Wall -include ../../../config.mak git-credential-osxkeychain: git-credential-osxkeychain.o - $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) -Wl,-framework -Wl,Security + $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) \ + -framework Security -framework CoreFoundation git-credential-osxkeychain.o: git-credential-osxkeychain.c $(CC) -c $(CFLAGS) $< diff --git a/contrib/credential/osxkeychain/git-credential-osxkeychain.c b/contrib/credential/osxkeychain/git-credential-osxkeychain.c index 5f2e5f16c8..6a40917b1e 100644 --- a/contrib/credential/osxkeychain/git-credential-osxkeychain.c +++ b/contrib/credential/osxkeychain/git-credential-osxkeychain.c @@ -3,14 +3,51 @@ #include <stdlib.h> #include <Security/Security.h> -static SecProtocolType protocol; -static char *host; -static char *path; -static char *username; -static char *password; -static UInt16 port; - -__attribute__((format (printf, 1, 2))) +#define ENCODING kCFStringEncodingUTF8 +static CFStringRef protocol; /* Stores constant strings - not memory managed */ +static CFStringRef host; +static CFNumberRef port; +static CFStringRef path; +static CFStringRef username; +static CFDataRef password; +static CFDataRef password_expiry_utc; +static CFDataRef oauth_refresh_token; + +static void clear_credential(void) +{ + if (host) { + CFRelease(host); + host = NULL; + } + if (port) { + CFRelease(port); + port = NULL; + } + if (path) { + CFRelease(path); + path = NULL; + } + if (username) { + CFRelease(username); + username = NULL; + } + if (password) { + CFRelease(password); + password = NULL; + } + if (password_expiry_utc) { + CFRelease(password_expiry_utc); + password_expiry_utc = NULL; + } + if (oauth_refresh_token) { + CFRelease(oauth_refresh_token); + oauth_refresh_token = NULL; + } +} + +#define STRING_WITH_LENGTH(s) s, sizeof(s) - 1 + +__attribute__((format (printf, 1, 2), __noreturn__)) static void die(const char *err, ...) { char msg[4096]; @@ -19,70 +56,199 @@ static void die(const char *err, ...) vsnprintf(msg, sizeof(msg), err, params); fprintf(stderr, "%s\n", msg); va_end(params); + clear_credential(); exit(1); } -static void *xstrdup(const char *s1) +static void *xmalloc(size_t len) { - void *ret = strdup(s1); + void *ret = malloc(len); if (!ret) die("Out of memory"); return ret; } -#define KEYCHAIN_ITEM(x) (x ? strlen(x) : 0), x -#define KEYCHAIN_ARGS \ - NULL, /* default keychain */ \ - KEYCHAIN_ITEM(host), \ - 0, NULL, /* account domain */ \ - KEYCHAIN_ITEM(username), \ - KEYCHAIN_ITEM(path), \ - port, \ - protocol, \ - kSecAuthenticationTypeDefault - -static void write_item(const char *what, const char *buf, int len) +static CFDictionaryRef create_dictionary(CFAllocatorRef allocator, ...) +{ + va_list args; + const void *key; + CFMutableDictionaryRef result; + + result = CFDictionaryCreateMutable(allocator, + 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + + + va_start(args, allocator); + while ((key = va_arg(args, const void *)) != NULL) { + const void *value; + value = va_arg(args, const void *); + if (value) + CFDictionarySetValue(result, key, value); + } + va_end(args); + + return result; +} + +#define CREATE_SEC_ATTRIBUTES(...) \ + create_dictionary(kCFAllocatorDefault, \ + kSecClass, kSecClassInternetPassword, \ + kSecAttrServer, host, \ + kSecAttrAccount, username, \ + kSecAttrPath, path, \ + kSecAttrPort, port, \ + kSecAttrProtocol, protocol, \ + kSecAttrAuthenticationType, \ + kSecAttrAuthenticationTypeDefault, \ + __VA_ARGS__); + +static void write_item(const char *what, const char *buf, size_t len) { printf("%s=", what); fwrite(buf, 1, len, stdout); putchar('\n'); } -static void find_username_in_item(SecKeychainItemRef item) +static void find_username_in_item(CFDictionaryRef item) { - SecKeychainAttributeList list; - SecKeychainAttribute attr; + CFStringRef account_ref; + char *username_buf; + CFIndex buffer_len; - list.count = 1; - list.attr = &attr; - attr.tag = kSecAccountItemAttr; + account_ref = CFDictionaryGetValue(item, kSecAttrAccount); + if (!account_ref) + { + write_item("username", "", 0); + return; + } - if (SecKeychainItemCopyContent(item, NULL, &list, NULL, NULL)) + username_buf = (char *)CFStringGetCStringPtr(account_ref, ENCODING); + if (username_buf) + { + write_item("username", username_buf, strlen(username_buf)); return; + } - write_item("username", attr.data, attr.length); - SecKeychainItemFreeContent(&list, NULL); + /* If we can't get a CString pointer then + * we need to allocate our own buffer */ + buffer_len = CFStringGetMaximumSizeForEncoding( + CFStringGetLength(account_ref), ENCODING) + 1; + username_buf = xmalloc(buffer_len); + if (CFStringGetCString(account_ref, + username_buf, + buffer_len, + ENCODING)) { + write_item("username", username_buf, buffer_len - 1); + } + free(username_buf); } -static void find_internet_password(void) +static OSStatus find_internet_password(void) { - void *buf; - UInt32 len; - SecKeychainItemRef item; + CFDictionaryRef attrs; + CFDictionaryRef item; + CFDataRef data; + OSStatus result; - if (SecKeychainFindInternetPassword(KEYCHAIN_ARGS, &len, &buf, &item)) - return; + attrs = CREATE_SEC_ATTRIBUTES(kSecMatchLimit, kSecMatchLimitOne, + kSecReturnAttributes, kCFBooleanTrue, + kSecReturnData, kCFBooleanTrue, + NULL); + result = SecItemCopyMatching(attrs, (CFTypeRef *)&item); + if (result) { + goto out; + } + + data = CFDictionaryGetValue(item, kSecValueData); - write_item("password", buf, len); + write_item("password", + (const char *)CFDataGetBytePtr(data), + CFDataGetLength(data)); if (!username) find_username_in_item(item); - SecKeychainItemFreeContent(NULL, buf); + CFRelease(item); + +out: + CFRelease(attrs); + + /* We consider not found to not be an error */ + if (result == errSecItemNotFound) + result = errSecSuccess; + + return result; +} + +static OSStatus delete_ref(const void *itemRef) +{ + CFArrayRef item_ref_list; + CFDictionaryRef delete_query; + OSStatus result; + + item_ref_list = CFArrayCreate(kCFAllocatorDefault, + &itemRef, + 1, + &kCFTypeArrayCallBacks); + delete_query = create_dictionary(kCFAllocatorDefault, + kSecClass, kSecClassInternetPassword, + kSecMatchItemList, item_ref_list, + NULL); + + if (password) { + /* We only want to delete items with a matching password */ + CFIndex capacity; + CFMutableDictionaryRef query; + CFDataRef data; + + capacity = CFDictionaryGetCount(delete_query) + 1; + query = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, + capacity, + delete_query); + CFDictionarySetValue(query, kSecReturnData, kCFBooleanTrue); + result = SecItemCopyMatching(query, (CFTypeRef *)&data); + if (!result) { + CFDataRef kc_password; + const UInt8 *raw_data; + const UInt8 *line; + + /* Don't match appended metadata */ + raw_data = CFDataGetBytePtr(data); + line = memchr(raw_data, '\n', CFDataGetLength(data)); + if (line) + kc_password = CFDataCreateWithBytesNoCopy( + kCFAllocatorDefault, + raw_data, + line - raw_data, + kCFAllocatorNull); + else + kc_password = data; + + if (CFEqual(kc_password, password)) + result = SecItemDelete(delete_query); + + if (line) + CFRelease(kc_password); + CFRelease(data); + } + + CFRelease(query); + } else { + result = SecItemDelete(delete_query); + } + + CFRelease(delete_query); + CFRelease(item_ref_list); + + return result; } -static void delete_internet_password(void) +static OSStatus delete_internet_password(void) { - SecKeychainItemRef item; + CFDictionaryRef attrs; + CFArrayRef refs; + OSStatus result; /* * Require at least a protocol and host for removal, which is what git @@ -90,25 +256,69 @@ static void delete_internet_password(void) * Keychain manager. */ if (!protocol || !host) - return; + return -1; - if (SecKeychainFindInternetPassword(KEYCHAIN_ARGS, 0, NULL, &item)) - return; + attrs = CREATE_SEC_ATTRIBUTES(kSecMatchLimit, kSecMatchLimitAll, + kSecReturnRef, kCFBooleanTrue, + NULL); + result = SecItemCopyMatching(attrs, (CFTypeRef *)&refs); + CFRelease(attrs); + + if (!result) { + for (CFIndex i = 0; !result && i < CFArrayGetCount(refs); i++) + result = delete_ref(CFArrayGetValueAtIndex(refs, i)); - SecKeychainItemDelete(item); + CFRelease(refs); + } + + /* We consider not found to not be an error */ + if (result == errSecItemNotFound) + result = errSecSuccess; + + return result; } -static void add_internet_password(void) +static OSStatus add_internet_password(void) { + CFMutableDataRef data; + CFDictionaryRef attrs; + OSStatus result; + /* Only store complete credentials */ if (!protocol || !host || !username || !password) - return; + return -1; - if (SecKeychainAddInternetPassword( - KEYCHAIN_ARGS, - KEYCHAIN_ITEM(password), - NULL)) - return; + data = CFDataCreateMutableCopy(kCFAllocatorDefault, 0, password); + if (password_expiry_utc) { + CFDataAppendBytes(data, + (const UInt8 *)STRING_WITH_LENGTH("\npassword_expiry_utc=")); + CFDataAppendBytes(data, + CFDataGetBytePtr(password_expiry_utc), + CFDataGetLength(password_expiry_utc)); + } + if (oauth_refresh_token) { + CFDataAppendBytes(data, + (const UInt8 *)STRING_WITH_LENGTH("\noauth_refresh_token=")); + CFDataAppendBytes(data, + CFDataGetBytePtr(oauth_refresh_token), + CFDataGetLength(oauth_refresh_token)); + } + + attrs = CREATE_SEC_ATTRIBUTES(kSecValueData, data, + NULL); + + result = SecItemAdd(attrs, NULL); + if (result == errSecDuplicateItem) { + CFDictionaryRef query; + query = CREATE_SEC_ATTRIBUTES(NULL); + result = SecItemUpdate(query, attrs); + CFRelease(query); + } + + CFRelease(data); + CFRelease(attrs); + + return result; } static void read_credential(void) @@ -131,36 +341,60 @@ static void read_credential(void) if (!strcmp(buf, "protocol")) { if (!strcmp(v, "imap")) - protocol = kSecProtocolTypeIMAP; + protocol = kSecAttrProtocolIMAP; else if (!strcmp(v, "imaps")) - protocol = kSecProtocolTypeIMAPS; + protocol = kSecAttrProtocolIMAPS; else if (!strcmp(v, "ftp")) - protocol = kSecProtocolTypeFTP; + protocol = kSecAttrProtocolFTP; else if (!strcmp(v, "ftps")) - protocol = kSecProtocolTypeFTPS; + protocol = kSecAttrProtocolFTPS; else if (!strcmp(v, "https")) - protocol = kSecProtocolTypeHTTPS; + protocol = kSecAttrProtocolHTTPS; else if (!strcmp(v, "http")) - protocol = kSecProtocolTypeHTTP; + protocol = kSecAttrProtocolHTTP; else if (!strcmp(v, "smtp")) - protocol = kSecProtocolTypeSMTP; - else /* we don't yet handle other protocols */ + protocol = kSecAttrProtocolSMTP; + else { + /* we don't yet handle other protocols */ + clear_credential(); exit(0); + } } else if (!strcmp(buf, "host")) { char *colon = strchr(v, ':'); if (colon) { + UInt16 port_i; *colon++ = '\0'; - port = atoi(colon); + port_i = atoi(colon); + port = CFNumberCreate(kCFAllocatorDefault, + kCFNumberShortType, + &port_i); } - host = xstrdup(v); + host = CFStringCreateWithCString(kCFAllocatorDefault, + v, + ENCODING); } else if (!strcmp(buf, "path")) - path = xstrdup(v); + path = CFStringCreateWithCString(kCFAllocatorDefault, + v, + ENCODING); else if (!strcmp(buf, "username")) - username = xstrdup(v); + username = CFStringCreateWithCString( + kCFAllocatorDefault, + v, + ENCODING); else if (!strcmp(buf, "password")) - password = xstrdup(v); + password = CFDataCreate(kCFAllocatorDefault, + (UInt8 *)v, + strlen(v)); + else if (!strcmp(buf, "password_expiry_utc")) + password_expiry_utc = CFDataCreate(kCFAllocatorDefault, + (UInt8 *)v, + strlen(v)); + else if (!strcmp(buf, "oauth_refresh_token")) + oauth_refresh_token = CFDataCreate(kCFAllocatorDefault, + (UInt8 *)v, + strlen(v)); /* * Ignore other lines; we don't know what they mean, but * this future-proofs us when later versions of git do @@ -173,6 +407,7 @@ static void read_credential(void) int main(int argc, const char **argv) { + OSStatus result = 0; const char *usage = "usage: git credential-osxkeychain <get|store|erase>"; @@ -182,12 +417,17 @@ int main(int argc, const char **argv) read_credential(); if (!strcmp(argv[1], "get")) - find_internet_password(); + result = find_internet_password(); else if (!strcmp(argv[1], "store")) - add_internet_password(); + result = add_internet_password(); else if (!strcmp(argv[1], "erase")) - delete_internet_password(); + result = delete_internet_password(); /* otherwise, ignore unknown action */ + if (result) + die("failed to %s: %d", argv[1], (int)result); + + clear_credential(); + return 0; } diff --git a/contrib/vscode/init.sh b/contrib/vscode/init.sh index 521d303722..f2d61bb0e6 100755 --- a/contrib/vscode/init.sh +++ b/contrib/vscode/init.sh @@ -92,7 +92,6 @@ cat >.vscode/settings.json.new <<\EOF || "isexe", "iskeychar", "kompare", - "mksnpath", "mktag", "mktree", "mmblob", @@ -207,13 +207,13 @@ void show_date_relative(timestamp_t time, struct strbuf *timebuf) (diff + 183) / 365); } -struct date_mode *date_mode_from_type(enum date_mode_type type) +struct date_mode date_mode_from_type(enum date_mode_type type) { - static struct date_mode mode = DATE_MODE_INIT; + struct date_mode mode = DATE_MODE_INIT; if (type == DATE_STRFTIME) BUG("cannot create anonymous strftime date_mode struct"); mode.type = type; - return &mode; + return mode; } static void show_date_normal(struct strbuf *buf, timestamp_t time, struct tm *tm, int tz, struct tm *human_tm, int human_tz, int local) @@ -283,7 +283,7 @@ static void show_date_normal(struct strbuf *buf, timestamp_t time, struct tm *tm strbuf_addf(buf, " %+05d", tz); } -const char *show_date(timestamp_t time, int tz, const struct date_mode *mode) +const char *show_date(timestamp_t time, int tz, struct date_mode mode) { struct tm *tm; struct tm tmbuf = { 0 }; @@ -291,13 +291,13 @@ const char *show_date(timestamp_t time, int tz, const struct date_mode *mode) int human_tz = -1; static struct strbuf timebuf = STRBUF_INIT; - if (mode->type == DATE_UNIX) { + if (mode.type == DATE_UNIX) { strbuf_reset(&timebuf); strbuf_addf(&timebuf, "%"PRItime, time); return timebuf.buf; } - if (mode->type == DATE_HUMAN) { + if (mode.type == DATE_HUMAN) { struct timeval now; get_time(&now); @@ -306,22 +306,22 @@ const char *show_date(timestamp_t time, int tz, const struct date_mode *mode) human_tz = local_time_tzoffset(now.tv_sec, &human_tm); } - if (mode->local) + if (mode.local) tz = local_tzoffset(time); - if (mode->type == DATE_RAW) { + if (mode.type == DATE_RAW) { strbuf_reset(&timebuf); strbuf_addf(&timebuf, "%"PRItime" %+05d", time, tz); return timebuf.buf; } - if (mode->type == DATE_RELATIVE) { + if (mode.type == DATE_RELATIVE) { strbuf_reset(&timebuf); show_date_relative(time, &timebuf); return timebuf.buf; } - if (mode->local) + if (mode.local) tm = time_to_tm_local(time, &tmbuf); else tm = time_to_tm(time, tz, &tmbuf); @@ -331,17 +331,17 @@ const char *show_date(timestamp_t time, int tz, const struct date_mode *mode) } strbuf_reset(&timebuf); - if (mode->type == DATE_SHORT) + if (mode.type == DATE_SHORT) strbuf_addf(&timebuf, "%04d-%02d-%02d", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday); - else if (mode->type == DATE_ISO8601) + else if (mode.type == DATE_ISO8601) strbuf_addf(&timebuf, "%04d-%02d-%02d %02d:%02d:%02d %+05d", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, tz); - else if (mode->type == DATE_ISO8601_STRICT) { + else if (mode.type == DATE_ISO8601_STRICT) { strbuf_addf(&timebuf, "%04d-%02d-%02dT%02d:%02d:%02d", tm->tm_year + 1900, tm->tm_mon + 1, @@ -354,16 +354,16 @@ const char *show_date(timestamp_t time, int tz, const struct date_mode *mode) tz = abs(tz); strbuf_addf(&timebuf, "%02d:%02d", tz / 100, tz % 100); } - } else if (mode->type == DATE_RFC2822) + } else if (mode.type == DATE_RFC2822) strbuf_addf(&timebuf, "%.3s, %d %.3s %d %02d:%02d:%02d %+05d", weekday_names[tm->tm_wday], tm->tm_mday, month_names[tm->tm_mon], tm->tm_year + 1900, tm->tm_hour, tm->tm_min, tm->tm_sec, tz); - else if (mode->type == DATE_STRFTIME) - strbuf_addftime(&timebuf, mode->strftime_fmt, tm, tz, - !mode->local); + else if (mode.type == DATE_STRFTIME) + strbuf_addftime(&timebuf, mode.strftime_fmt, tm, tz, + !mode.local); else - show_date_normal(&timebuf, time, tm, tz, &human_tm, human_tz, mode->local); + show_date_normal(&timebuf, time, tm, tz, &human_tm, human_tz, mode.local); return timebuf.buf; } @@ -22,8 +22,8 @@ enum date_mode_type { struct date_mode { enum date_mode_type type; - const char *strftime_fmt; int local; + const char *strftime_fmt; }; #define DATE_MODE_INIT { \ @@ -36,14 +36,14 @@ struct date_mode { * show_date(t, tz, DATE_MODE(NORMAL)); */ #define DATE_MODE(t) date_mode_from_type(DATE_##t) -struct date_mode *date_mode_from_type(enum date_mode_type type); +struct date_mode date_mode_from_type(enum date_mode_type type); /** * Format <'time', 'timezone'> into static memory according to 'mode' * and return it. The mode is an initialized "struct date_mode" * (usually from the DATE_MODE() macro). */ -const char *show_date(timestamp_t time, int timezone, const struct date_mode *mode); +const char *show_date(timestamp_t time, int timezone, struct date_mode mode); /** * Parse a date format for later use with show_date(). diff --git a/diff-lib.c b/diff-lib.c index 1cd790a4d2..683f11e509 100644 --- a/diff-lib.c +++ b/diff-lib.c @@ -127,7 +127,16 @@ void run_diff_files(struct rev_info *revs, unsigned int option) if (diff_can_quit_early(&revs->diffopt)) break; - if (!ce_path_match(istate, ce, &revs->prune_data, NULL)) + /* + * NEEDSWORK: + * Here we filter with pathspec but the result is further + * filtered out when --relative is in effect. To end-users, + * a pathspec element that matched only to paths outside the + * current directory is like not matching anything at all; + * the handling of ps_matched[] here may become problematic + * if/when we add the "--error-unmatch" option to "git diff". + */ + if (!ce_path_match(istate, ce, &revs->prune_data, revs->ps_matched)) continue; if (revs->diffopt.prefix && diff --git a/git-compat-util.h b/git-compat-util.h index 7c2a6538e5..044f87454a 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -218,6 +218,18 @@ struct strbuf; #define GIT_WINDOWS_NATIVE #endif +#if defined(NO_UNIX_SOCKETS) || !defined(GIT_WINDOWS_NATIVE) +static inline int _have_unix_sockets(void) +{ +#if defined(NO_UNIX_SOCKETS) + return 0; +#else + return 1; +#endif +} +#define have_unix_sockets _have_unix_sockets +#endif + #include <unistd.h> #include <stdio.h> #include <sys/stat.h> diff --git a/git-curl-compat.h b/git-curl-compat.h index fd96b3cdff..e1d0bdd273 100644 --- a/git-curl-compat.h +++ b/git-curl-compat.h @@ -127,6 +127,15 @@ #endif /** + * Versions before curl 7.66.0 (September 2019) required manually setting the + * transfer-encoding for a streaming POST; after that this is handled + * automatically. + */ +#if LIBCURL_VERSION_NUM < 0x074200 +#define GIT_CURL_NEED_TRANSFER_ENCODING_HEADER +#endif + +/** * CURLOPT_PROTOCOLS_STR and CURLOPT_REDIR_PROTOCOLS_STR were added in 7.85.0, * released in August 2022. */ diff --git a/git-gui/.gitattributes b/git-gui/.gitattributes index 59cd41dbff..118d56cfbd 100644 --- a/git-gui/.gitattributes +++ b/git-gui/.gitattributes @@ -3,3 +3,4 @@ git-gui.sh encoding=UTF-8 /po/*.po encoding=UTF-8 /GIT-VERSION-GEN eol=lf +Makefile whitespace=!indent,trail,space diff --git a/git-gui/Makefile b/git-gui/Makefile index 3f80435436..667c39ed56 100644 --- a/git-gui/Makefile +++ b/git-gui/Makefile @@ -107,12 +107,12 @@ endif ifeq ($(uname_S),Darwin) TKFRAMEWORK = /Library/Frameworks/Tk.framework/Resources/Wish.app - ifeq ($(shell echo "$(uname_R)" | awk -F. '{if ($$1 >= 9) print "y"}')_$(shell test -d $(TKFRAMEWORK) || echo n),y_n) + ifeq ($(shell echo "$(uname_R)" | awk -F. '{if ($$1 >= 9) print "y"}')_$(shell test -d $(TKFRAMEWORK) || echo n),y_n) TKFRAMEWORK = /System/Library/Frameworks/Tk.framework/Resources/Wish.app - ifeq ($(shell test -d $(TKFRAMEWORK) || echo n),n) + ifeq ($(shell test -d $(TKFRAMEWORK) || echo n),n) TKFRAMEWORK = /System/Library/Frameworks/Tk.framework/Resources/Wish\ Shell.app - endif - endif + endif + endif TKEXECUTABLE = $(shell basename "$(TKFRAMEWORK)" .app) endif @@ -143,9 +143,9 @@ ifeq ($(exedir),$(gg_libdir)) endif gg_libdir_sed_in := $(gg_libdir) ifeq ($(uname_S),Darwin) - ifeq ($(shell test -d $(TKFRAMEWORK) && echo y),y) + ifeq ($(shell test -d $(TKFRAMEWORK) && echo y),y) GITGUI_MACOSXAPP := YesPlease - endif + endif endif ifneq (,$(findstring MINGW,$(uname_S))) ifeq ($(shell expr "$(uname_R)" : '1\.'),2) @@ -220,9 +220,9 @@ ifdef NO_MSGFMT MSGFMT ?= $(TCL_PATH) po/po2msg.sh else MSGFMT ?= msgfmt - ifneq ($(shell $(MSGFMT) --tcl -l C -d . /dev/null 2>/dev/null; echo $$?),0) + ifneq ($(shell $(MSGFMT) --tcl -l C -d . /dev/null 2>/dev/null; echo $$?),0) MSGFMT := $(TCL_PATH) po/po2msg.sh - endif + endif endif msgsdir = $(gg_libdir)/msgs diff --git a/gitk-git/Makefile b/gitk-git/Makefile index 5bdd52a6eb..e1f0aff4a1 100644 --- a/gitk-git/Makefile +++ b/gitk-git/Makefile @@ -33,9 +33,9 @@ ifdef NO_MSGFMT MSGFMT ?= $(TCL_PATH) po/po2msg.sh else MSGFMT ?= msgfmt - ifneq ($(shell $(MSGFMT) --tcl -l C -d . /dev/null 2>/dev/null; echo $$?),0) + ifneq ($(shell $(MSGFMT) --tcl -l C -d . /dev/null 2>/dev/null; echo $$?),0) MSGFMT := $(TCL_PATH) po/po2msg.sh - endif + endif endif PO_TEMPLATE = po/gitk.pot diff --git a/gpg-interface.c b/gpg-interface.c index b5993385ff..1ff94266d2 100644 --- a/gpg-interface.c +++ b/gpg-interface.c @@ -483,7 +483,7 @@ static int verify_ssh_signed_buffer(struct signature_check *sigc, if (sigc->payload_timestamp) strbuf_addf(&verify_time, "-Overify-time=%s", - show_date(sigc->payload_timestamp, 0, &verify_date_mode)); + show_date(sigc->payload_timestamp, 0, verify_date_mode)); /* Find the principal from the signers */ strvec_pushl(&ssh_keygen.args, fmt->program, @@ -1452,6 +1452,7 @@ struct active_request_slot *get_active_slot(void) curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, NULL); curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, NULL); curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDS, NULL); + curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDSIZE, -1L); curl_easy_setopt(slot->curl, CURLOPT_UPLOAD, 0); curl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1); curl_easy_setopt(slot->curl, CURLOPT_FAILONERROR, 1); diff --git a/log-tree.c b/log-tree.c index 59eeaef1f7..16031b44e7 100644 --- a/log-tree.c +++ b/log-tree.c @@ -773,7 +773,7 @@ void show_log(struct rev_info *opt) */ show_reflog_message(opt->reflog_info, opt->commit_format == CMIT_FMT_ONELINE, - &opt->date_mode, + opt->date_mode, opt->date_mode_explicit); if (opt->commit_format == CMIT_FMT_ONELINE) return; diff --git a/oss-fuzz/fuzz-date.c b/oss-fuzz/fuzz-date.c index 036378b946..9619dae40e 100644 --- a/oss-fuzz/fuzz-date.c +++ b/oss-fuzz/fuzz-date.c @@ -11,7 +11,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) int16_t tz; timestamp_t ts; enum date_mode_type dmtype; - struct date_mode *dm; + struct date_mode dm; if (size <= 4) /* @@ -40,10 +40,10 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) free(str); dm = date_mode_from_type(dmtype); - dm->local = local; + dm.local = local; show_date(ts, (int)tz, dm); - date_mode_release(dm); + date_mode_release(&dm); return 0; } @@ -28,8 +28,6 @@ static int get_st_mode_bits(const char *path, int *mode) return 0; } -static char bad_path[] = "/bad-path/"; - static struct strbuf *get_pathname(void) { static struct strbuf pathname_array[4] = { @@ -59,21 +57,6 @@ static void strbuf_cleanup_path(struct strbuf *sb) strbuf_remove(sb, 0, path - sb->buf); } -char *mksnpath(char *buf, size_t n, const char *fmt, ...) -{ - va_list args; - unsigned len; - - va_start(args, fmt); - len = vsnprintf(buf, n, fmt, args); - va_end(args); - if (len >= n) { - strlcpy(buf, bad_path, n); - return buf; - } - return (char *)cleanup_path(buf); -} - static int dir_prefix(const char *buf, const char *dir) { int len = strlen(dir); @@ -24,12 +24,6 @@ char *mkpathdup(const char *fmt, ...) __attribute__((format (printf, 1, 2))); /* - * Construct a path and place the result in the provided buffer `buf`. - */ -char *mksnpath(char *buf, size_t n, const char *fmt, ...) - __attribute__((format (printf, 3, 4))); - -/* * The `git_common_path` family of functions will construct a path into a * repository's common git directory, which is shared by all worktrees. */ @@ -20,7 +20,7 @@ # clone | klon(lamak) # # commit (ad) | işleme # # commit (eyl.) | işlemek # -# commitish | işlememsi # +# commit-ish | işlememsi # # conflict | çakışma # # cruft | süprüntü # # dangling object | sallanan nesne # @@ -428,7 +428,7 @@ static void add_rfc2047(struct strbuf *sb, const char *line, size_t len, } const char *show_ident_date(const struct ident_split *ident, - const struct date_mode *mode) + struct date_mode mode) { timestamp_t date = 0; long tz = 0; @@ -592,7 +592,7 @@ void pp_user_info(struct pretty_print_context *pp, switch (pp->fmt) { case CMIT_FMT_MEDIUM: strbuf_addf(sb, "Date: %s\n", - show_ident_date(&ident, &pp->date_mode)); + show_ident_date(&ident, pp->date_mode)); break; case CMIT_FMT_EMAIL: case CMIT_FMT_MBOXRD: @@ -601,7 +601,7 @@ void pp_user_info(struct pretty_print_context *pp, break; case CMIT_FMT_FULLER: strbuf_addf(sb, "%sDate: %s\n", what, - show_ident_date(&ident, &pp->date_mode)); + show_ident_date(&ident, pp->date_mode)); break; default: /* notin' */ @@ -775,7 +775,7 @@ static int mailmap_name(const char **email, size_t *email_len, static size_t format_person_part(struct strbuf *sb, char part, const char *msg, int len, - const struct date_mode *dmode) + struct date_mode dmode) { /* currently all placeholders have same length */ const int placeholder_len = 2; @@ -1034,7 +1034,7 @@ static void rewrap_message_tail(struct strbuf *sb, static int format_reflog_person(struct strbuf *sb, char part, struct reflog_walk_info *log, - const struct date_mode *dmode) + struct date_mode dmode) { const char *ident; @@ -1602,7 +1602,7 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */ if (c->pretty_ctx->reflog_info) get_reflog_selector(sb, c->pretty_ctx->reflog_info, - &c->pretty_ctx->date_mode, + c->pretty_ctx->date_mode, c->pretty_ctx->date_mode_explicit, (placeholder[1] == 'd')); return 2; @@ -1617,7 +1617,7 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */ return format_reflog_person(sb, placeholder[1], c->pretty_ctx->reflog_info, - &c->pretty_ctx->date_mode); + c->pretty_ctx->date_mode); } return 0; /* unknown %g placeholder */ case 'N': @@ -1712,11 +1712,11 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */ case 'a': /* author ... */ return format_person_part(sb, placeholder[1], msg + c->author.off, c->author.len, - &c->pretty_ctx->date_mode); + c->pretty_ctx->date_mode); case 'c': /* committer ... */ return format_person_part(sb, placeholder[1], msg + c->committer.off, c->committer.len, - &c->pretty_ctx->date_mode); + c->pretty_ctx->date_mode); case 'e': /* encoding */ if (c->commit_encoding) strbuf_addstr(sb, c->commit_encoding); @@ -167,7 +167,7 @@ int format_set_trailers_options(struct process_trailer_options *opts, * a well-known sentinel date if they appear bogus. */ const char *show_ident_date(const struct ident_split *id, - const struct date_mode *mode); + struct date_mode mode); #endif /* PRETTY_H */ diff --git a/read-cache-ll.h b/read-cache-ll.h index 2a50a784f0..09414afd04 100644 --- a/read-cache-ll.h +++ b/read-cache-ll.h @@ -480,8 +480,8 @@ extern int verify_ce_order; int cmp_cache_name_compare(const void *a_, const void *b_); int add_files_to_cache(struct repository *repo, const char *prefix, - const struct pathspec *pathspec, int include_sparse, - int flags); + const struct pathspec *pathspec, char *ps_matched, + int include_sparse, int flags); void overlay_tree_on_index(struct index_state *istate, const char *tree_name, const char *prefix); diff --git a/read-cache.c b/read-cache.c index f546cf7875..e1723ad796 100644 --- a/read-cache.c +++ b/read-cache.c @@ -3958,8 +3958,8 @@ static void update_callback(struct diff_queue_struct *q, } int add_files_to_cache(struct repository *repo, const char *prefix, - const struct pathspec *pathspec, int include_sparse, - int flags) + const struct pathspec *pathspec, char *ps_matched, + int include_sparse, int flags) { struct update_callback_data data; struct rev_info rev; @@ -3971,8 +3971,10 @@ int add_files_to_cache(struct repository *repo, const char *prefix, repo_init_revisions(repo, &rev, prefix); setup_revisions(0, NULL, &rev, NULL); - if (pathspec) + if (pathspec) { copy_pathspec(&rev.prune_data, pathspec); + rev.ps_matched = ps_matched; + } rev.diffopt.output_format = DIFF_FORMAT_CALLBACK; rev.diffopt.format_callback = update_callback; rev.diffopt.format_callback_data = &data; diff --git a/ref-filter.c b/ref-filter.c index 03542d0236..59ad6f54dd 100644 --- a/ref-filter.c +++ b/ref-filter.c @@ -1627,7 +1627,7 @@ static void grab_date(const char *buf, struct atom_value *v, const char *atomnam tz = strtol(zone, NULL, 10); if ((tz == LONG_MIN || tz == LONG_MAX) && errno == ERANGE) goto bad; - v->s = xstrdup(show_date(timestamp, tz, &date_mode)); + v->s = xstrdup(show_date(timestamp, tz, date_mode)); v->value = timestamp; date_mode_release(&date_mode); return; diff --git a/reflog-walk.c b/reflog-walk.c index d216f6f966..66484f4f32 100644 --- a/reflog-walk.c +++ b/reflog-walk.c @@ -223,7 +223,7 @@ int add_reflog_for_walk(struct reflog_walk_info *info, void get_reflog_selector(struct strbuf *sb, struct reflog_walk_info *reflog_info, - const struct date_mode *dmode, int force_date, + struct date_mode dmode, int force_date, int shorten) { struct commit_reflog *commit_reflog = reflog_info->last_commit_reflog; @@ -297,7 +297,7 @@ timestamp_t get_reflog_timestamp(struct reflog_walk_info *reflog_info) } void show_reflog_message(struct reflog_walk_info *reflog_info, int oneline, - const struct date_mode *dmode, int force_date) + struct date_mode dmode, int force_date) { if (reflog_info && reflog_info->last_commit_reflog) { struct commit_reflog *commit_reflog = reflog_info->last_commit_reflog; diff --git a/reflog-walk.h b/reflog-walk.h index 4d93a26957..989583dc55 100644 --- a/reflog-walk.h +++ b/reflog-walk.h @@ -10,14 +10,14 @@ void reflog_walk_info_release(struct reflog_walk_info *info); int add_reflog_for_walk(struct reflog_walk_info *info, struct commit *commit, const char *name); void show_reflog_message(struct reflog_walk_info *info, int, - const struct date_mode *, int force_date); + struct date_mode, int force_date); void get_reflog_message(struct strbuf *sb, struct reflog_walk_info *reflog_info); const char *get_reflog_ident(struct reflog_walk_info *reflog_info); timestamp_t get_reflog_timestamp(struct reflog_walk_info *reflog_info); void get_reflog_selector(struct strbuf *sb, struct reflog_walk_info *reflog_info, - const struct date_mode *dmode, int force_date, + struct date_mode dmode, int force_date, int shorten); int reflog_walk_empty(struct reflog_walk_info *walk); diff --git a/refs/reftable-backend.c b/refs/reftable-backend.c index 0bed6d2ab4..1cda48c504 100644 --- a/refs/reftable-backend.c +++ b/refs/reftable-backend.c @@ -18,6 +18,7 @@ #include "../reftable/reftable-merged.h" #include "../setup.h" #include "../strmap.h" +#include "parse.h" #include "refs-internal.h" /* @@ -247,6 +248,8 @@ static struct ref_store *reftable_be_init(struct repository *repo, refs->write_options.block_size = 4096; refs->write_options.hash_id = repo->hash_algo->format_id; refs->write_options.default_permissions = calc_shared_perm(0666 & ~mask); + refs->write_options.disable_auto_compact = + !git_env_bool("GIT_TEST_REFTABLE_AUTOCOMPACTION", 1); /* * Set up the main reftable stack that is hosted in GIT_COMMON_DIR. diff --git a/reftable/reftable-writer.h b/reftable/reftable-writer.h index 7c7cae5f99..155bf0bbe2 100644 --- a/reftable/reftable-writer.h +++ b/reftable/reftable-writer.h @@ -46,6 +46,9 @@ struct reftable_write_options { * is a single line, and add '\n' if missing. */ unsigned exact_log_message : 1; + + /* boolean: Prevent auto-compaction of tables. */ + unsigned disable_auto_compact : 1; }; /* reftable_block_stats holds statistics for a single block type */ diff --git a/reftable/stack.c b/reftable/stack.c index dde50b61d6..80266bcbab 100644 --- a/reftable/stack.c +++ b/reftable/stack.c @@ -680,7 +680,7 @@ int reftable_addition_commit(struct reftable_addition *add) if (err) goto done; - if (!add->stack->disable_auto_compact) { + if (!add->stack->config.disable_auto_compact) { /* * Auto-compact the stack to keep the number of tables in * control. It is possible that a concurrent writer is already @@ -1216,75 +1216,76 @@ static int segment_size(struct segment *s) return s->end - s->start; } -int fastlog2(uint64_t sz) -{ - int l = 0; - if (sz == 0) - return 0; - for (; sz; sz /= 2) { - l++; - } - return l - 1; -} - -struct segment *sizes_to_segments(size_t *seglen, uint64_t *sizes, size_t n) -{ - struct segment *segs = reftable_calloc(n, sizeof(*segs)); - struct segment cur = { 0 }; - size_t next = 0, i; - - if (n == 0) { - *seglen = 0; - return segs; - } - for (i = 0; i < n; i++) { - int log = fastlog2(sizes[i]); - if (cur.log != log && cur.bytes > 0) { - struct segment fresh = { - .start = i, - }; - - segs[next++] = cur; - cur = fresh; - } - - cur.log = log; - cur.end = i + 1; - cur.bytes += sizes[i]; - } - segs[next++] = cur; - *seglen = next; - return segs; -} - struct segment suggest_compaction_segment(uint64_t *sizes, size_t n) { - struct segment min_seg = { - .log = 64, - }; - struct segment *segs; - size_t seglen = 0, i; - - segs = sizes_to_segments(&seglen, sizes, n); - for (i = 0; i < seglen; i++) { - if (segment_size(&segs[i]) == 1) - continue; + struct segment seg = { 0 }; + uint64_t bytes; + size_t i; - if (segs[i].log < min_seg.log) - min_seg = segs[i]; - } + /* + * If there are no tables or only a single one then we don't have to + * compact anything. The sequence is geometric by definition already. + */ + if (n <= 1) + return seg; - while (min_seg.start > 0) { - size_t prev = min_seg.start - 1; - if (fastlog2(min_seg.bytes) < fastlog2(sizes[prev])) + /* + * Find the ending table of the compaction segment needed to restore the + * geometric sequence. Note that the segment end is exclusive. + * + * To do so, we iterate backwards starting from the most recent table + * until a valid segment end is found. If the preceding table is smaller + * than the current table multiplied by the geometric factor (2), the + * compaction segment end has been identified. + * + * Tables after the ending point are not added to the byte count because + * they are already valid members of the geometric sequence. Due to the + * properties of a geometric sequence, it is not possible for the sum of + * these tables to exceed the value of the ending point table. + * + * Example table size sequence requiring no compaction: + * 64, 32, 16, 8, 4, 2, 1 + * + * Example table size sequence where compaction segment end is set to + * the last table. Since the segment end is exclusive, the last table is + * excluded during subsequent compaction and the table with size 3 is + * the final table included: + * 64, 32, 16, 8, 4, 3, 1 + */ + for (i = n - 1; i > 0; i--) { + if (sizes[i - 1] < sizes[i] * 2) { + seg.end = i + 1; + bytes = sizes[i]; break; + } + } - min_seg.start = prev; - min_seg.bytes += sizes[prev]; + /* + * Find the starting table of the compaction segment by iterating + * through the remaining tables and keeping track of the accumulated + * size of all tables seen from the segment end table. The previous + * table is compared to the accumulated size because the tables from the + * segment end are merged backwards recursively. + * + * Note that we keep iterating even after we have found the first + * starting point. This is because there may be tables in the stack + * preceding that first starting point which violate the geometric + * sequence. + * + * Example compaction segment start set to table with size 32: + * 128, 32, 16, 8, 4, 3, 1 + */ + for (; i > 0; i--) { + uint64_t curr = bytes; + bytes += sizes[i - 1]; + + if (sizes[i - 1] < curr * 2) { + seg.start = i - 1; + seg.bytes = bytes; + } } - reftable_free(segs); - return min_seg; + return seg; } static uint64_t *stack_table_sizes_for_compaction(struct reftable_stack *st) diff --git a/reftable/stack.h b/reftable/stack.h index d919455669..d43efa4760 100644 --- a/reftable/stack.h +++ b/reftable/stack.h @@ -19,7 +19,6 @@ struct reftable_stack { int list_fd; char *reftable_dir; - int disable_auto_compact; struct reftable_write_options config; @@ -33,12 +32,9 @@ int read_lines(const char *filename, char ***lines); struct segment { size_t start, end; - int log; uint64_t bytes; }; -int fastlog2(uint64_t sz); -struct segment *sizes_to_segments(size_t *seglen, uint64_t *sizes, size_t n); struct segment suggest_compaction_segment(uint64_t *sizes, size_t n); #endif diff --git a/reftable/stack_test.c b/reftable/stack_test.c index 351e35bd86..1df3ffce52 100644 --- a/reftable/stack_test.c +++ b/reftable/stack_test.c @@ -325,7 +325,7 @@ static void test_reftable_stack_transaction_api_performs_auto_compaction(void) * we can ensure that we indeed honor this setting and have * better control over when exactly auto compaction runs. */ - st->disable_auto_compact = i != n; + st->config.disable_auto_compact = i != n; err = reftable_stack_new_addition(&add, st); EXPECT_ERR(err); @@ -497,6 +497,7 @@ static void test_reftable_stack_add(void) struct reftable_write_options cfg = { .exact_log_message = 1, .default_permissions = 0660, + .disable_auto_compact = 1, }; struct reftable_stack *st = NULL; char *dir = get_tmp_dir(__LINE__); @@ -508,7 +509,6 @@ static void test_reftable_stack_add(void) err = reftable_new_stack(&st, dir, cfg); EXPECT_ERR(err); - st->disable_auto_compact = 1; for (i = 0; i < N; i++) { char buf[256]; @@ -770,59 +770,13 @@ static void test_reftable_stack_hash_id(void) clear_dir(dir); } -static void test_log2(void) -{ - EXPECT(1 == fastlog2(3)); - EXPECT(2 == fastlog2(4)); - EXPECT(2 == fastlog2(5)); -} - -static void test_sizes_to_segments(void) -{ - uint64_t sizes[] = { 2, 3, 4, 5, 7, 9 }; - /* .................0 1 2 3 4 5 */ - - size_t seglen = 0; - struct segment *segs = - sizes_to_segments(&seglen, sizes, ARRAY_SIZE(sizes)); - EXPECT(segs[2].log == 3); - EXPECT(segs[2].start == 5); - EXPECT(segs[2].end == 6); - - EXPECT(segs[1].log == 2); - EXPECT(segs[1].start == 2); - EXPECT(segs[1].end == 5); - reftable_free(segs); -} - -static void test_sizes_to_segments_empty(void) -{ - size_t seglen = 0; - struct segment *segs = sizes_to_segments(&seglen, NULL, 0); - EXPECT(seglen == 0); - reftable_free(segs); -} - -static void test_sizes_to_segments_all_equal(void) -{ - uint64_t sizes[] = { 5, 5 }; - size_t seglen = 0; - struct segment *segs = - sizes_to_segments(&seglen, sizes, ARRAY_SIZE(sizes)); - EXPECT(seglen == 1); - EXPECT(segs[0].start == 0); - EXPECT(segs[0].end == 2); - reftable_free(segs); -} - static void test_suggest_compaction_segment(void) { - uint64_t sizes[] = { 128, 64, 17, 16, 9, 9, 9, 16, 16 }; - /* .................0 1 2 3 4 5 6 */ + uint64_t sizes[] = { 512, 64, 17, 16, 9, 9, 9, 16, 2, 16 }; struct segment min = suggest_compaction_segment(sizes, ARRAY_SIZE(sizes)); - EXPECT(min.start == 2); - EXPECT(min.end == 7); + EXPECT(min.start == 1); + EXPECT(min.end == 10); } static void test_suggest_compaction_segment_nothing(void) @@ -933,9 +887,21 @@ static void test_empty_add(void) reftable_stack_destroy(st2); } +static int fastlog2(uint64_t sz) +{ + int l = 0; + if (sz == 0) + return 0; + for (; sz; sz /= 2) + l++; + return l - 1; +} + static void test_reftable_stack_auto_compaction(void) { - struct reftable_write_options cfg = { 0 }; + struct reftable_write_options cfg = { + .disable_auto_compact = 1, + }; struct reftable_stack *st = NULL; char *dir = get_tmp_dir(__LINE__); @@ -945,7 +911,6 @@ static void test_reftable_stack_auto_compaction(void) err = reftable_new_stack(&st, dir, cfg); EXPECT_ERR(err); - st->disable_auto_compact = 1; /* call manually below for coverage. */ for (i = 0; i < N; i++) { char name[100]; struct reftable_ref_record ref = { @@ -994,7 +959,7 @@ static void test_reftable_stack_add_performs_auto_compaction(void) * we can ensure that we indeed honor this setting and have * better control over when exactly auto compaction runs. */ - st->disable_auto_compact = i != n; + st->config.disable_auto_compact = i != n; strbuf_reset(&refname); strbuf_addf(&refname, "branch-%04d", i); @@ -1121,7 +1086,6 @@ static void test_reftable_stack_compaction_concurrent_clean(void) int stack_test_main(int argc, const char *argv[]) { RUN_TEST(test_empty_add); - RUN_TEST(test_log2); RUN_TEST(test_names_equal); RUN_TEST(test_parse_names); RUN_TEST(test_read_file); @@ -1142,9 +1106,6 @@ int stack_test_main(int argc, const char *argv[]) RUN_TEST(test_reftable_stack_update_index_check); RUN_TEST(test_reftable_stack_uptodate); RUN_TEST(test_reftable_stack_validate_refname); - RUN_TEST(test_sizes_to_segments); - RUN_TEST(test_sizes_to_segments_all_equal); - RUN_TEST(test_sizes_to_segments_empty); RUN_TEST(test_suggest_compaction_segment); RUN_TEST(test_suggest_compaction_segment_nothing); return 0; diff --git a/remote-curl.c b/remote-curl.c index 31b02b8840..0b6d7815fd 100644 --- a/remote-curl.c +++ b/remote-curl.c @@ -1,4 +1,5 @@ #include "git-compat-util.h" +#include "git-curl-compat.h" #include "config.h" #include "environment.h" #include "gettext.h" @@ -955,7 +956,9 @@ retry: /* The request body is large and the size cannot be predicted. * We must use chunked encoding to send it. */ +#ifdef GIT_CURL_NEED_TRANSFER_ENCODING_HEADER headers = curl_slist_append(headers, "Transfer-Encoding: chunked"); +#endif rpc->initial_buffer = 1; curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, rpc_out); curl_easy_setopt(slot->curl, CURLOPT_INFILE, rpc); diff --git a/revision.h b/revision.h index 94c43138bc..0e470d1df1 100644 --- a/revision.h +++ b/revision.h @@ -142,6 +142,7 @@ struct rev_info { /* Basic information */ const char *prefix; const char *def; + char *ps_matched; /* optionally record matches of prune_data */ struct pathspec prune_data; /* diff --git a/t/check-non-portable-shell.pl b/t/check-non-portable-shell.pl index dd8107cd7d..b2b28c2ced 100755 --- a/t/check-non-portable-shell.pl +++ b/t/check-non-portable-shell.pl @@ -47,6 +47,8 @@ while (<>) { /\bgrep\b.*--file\b/ and err 'grep --file FILE is not portable (use grep -f FILE)'; /\b[ef]grep\b/ and err 'egrep/fgrep obsolescent (use grep -E/-F)'; /\bexport\s+[A-Za-z0-9_]*=/ and err '"export FOO=bar" is not portable (use FOO=bar && export FOO)'; + /\blocal\s+[A-Za-z0-9_]*=\$([A-Za-z0-9_{]|[(][^(])/ and + err q(quote "$val" in 'local var=$val'); /^\s*([A-Z0-9_]+=(\w*|(["']).*?\3)\s+)+(\w+)/ and exists($func{$4}) and err '"FOO=bar shell_func" assignment extends beyond "shell_func"'; $line = ''; diff --git a/t/helper/test-date.c b/t/helper/test-date.c index 0683d46574..f25512de9a 100644 --- a/t/helper/test-date.c +++ b/t/helper/test-date.c @@ -52,7 +52,7 @@ static void show_dates(const char **argv, const char *format) arg++; tz = atoi(arg); - printf("%s -> %s\n", *argv, show_date(t, tz, &mode)); + printf("%s -> %s\n", *argv, show_date(t, tz, mode)); } date_mode_release(&mode); diff --git a/t/lib-parallel-checkout.sh b/t/lib-parallel-checkout.sh index acaee9cbb6..8324d6c96d 100644 --- a/t/lib-parallel-checkout.sh +++ b/t/lib-parallel-checkout.sh @@ -20,7 +20,7 @@ test_checkout_workers () { BUG "too few arguments to test_checkout_workers" fi && - local expected_workers=$1 && + local expected_workers="$1" && shift && local trace_file=trace-test-checkout-workers && diff --git a/t/t0301-credential-cache.sh b/t/t0301-credential-cache.sh index 8300faadea..f2c146fa2a 100755 --- a/t/t0301-credential-cache.sh +++ b/t/t0301-credential-cache.sh @@ -8,6 +8,14 @@ test -z "$NO_UNIX_SOCKETS" || { skip_all='skipping credential-cache tests, unix sockets not available' test_done } +if test_have_prereq MINGW +then + service_running=$(sc query afunix | grep "4 RUNNING") + test -z "$service_running" || { + skip_all='skipping credential-cache tests, unix sockets not available' + test_done + } +fi uname_s=$(uname -s) case $uname_s in diff --git a/t/t0610-reftable-basics.sh b/t/t0610-reftable-basics.sh index 931d888bbb..178791e086 100755 --- a/t/t0610-reftable-basics.sh +++ b/t/t0610-reftable-basics.sh @@ -83,7 +83,7 @@ test_expect_success 'init: reinitializing reftable with files backend fails' ' test_expect_perms () { local perms="$1" local file="$2" - local actual=$(ls -l "$file") && + local actual="$(ls -l "$file")" && case "$actual" in $perms*) @@ -96,23 +96,54 @@ test_expect_perms () { esac } -for umask in 002 022 -do - test_expect_success POSIXPERM 'init: honors core.sharedRepository' ' +test_expect_reftable_perms () { + local umask="$1" + local shared="$2" + local expect="$3" + + test_expect_success POSIXPERM "init: honors --shared=$shared with umask $umask" ' test_when_finished "rm -rf repo" && ( umask $umask && - git init --shared=true repo && - test 1 = "$(git -C repo config core.sharedrepository)" + git init --shared=$shared repo ) && - test_expect_perms "-rw-rw-r--" repo/.git/reftable/tables.list && + test_expect_perms "$expect" repo/.git/reftable/tables.list && for table in repo/.git/reftable/*.ref do - test_expect_perms "-rw-rw-r--" "$table" || + test_expect_perms "$expect" "$table" || return 1 done ' -done + + test_expect_success POSIXPERM "pack-refs: honors --shared=$shared with umask $umask" ' + test_when_finished "rm -rf repo" && + ( + umask $umask && + git init --shared=$shared repo && + test_commit -C repo A && + test_line_count = 2 repo/.git/reftable/tables.list && + git -C repo pack-refs + ) && + test_expect_perms "$expect" repo/.git/reftable/tables.list && + for table in repo/.git/reftable/*.ref + do + test_expect_perms "$expect" "$table" || + return 1 + done + ' +} + +test_expect_reftable_perms 002 umask "-rw-rw-r--" +test_expect_reftable_perms 022 umask "-rw-r--r--" +test_expect_reftable_perms 027 umask "-rw-r-----" + +test_expect_reftable_perms 002 group "-rw-rw-r--" +test_expect_reftable_perms 022 group "-rw-rw-r--" +test_expect_reftable_perms 027 group "-rw-rw----" + +test_expect_reftable_perms 002 world "-rw-rw-r--" +test_expect_reftable_perms 022 world "-rw-rw-r--" +test_expect_reftable_perms 027 world "-rw-rw-r--" test_expect_success 'clone: can clone reftable repository' ' test_when_finished "rm -rf repo clone" && @@ -293,12 +324,46 @@ test_expect_success 'ref transaction: writes cause auto-compaction' ' test_line_count = 1 repo/.git/reftable/tables.list && test_commit -C repo --no-tag A && - test_line_count = 2 repo/.git/reftable/tables.list && + test_line_count = 1 repo/.git/reftable/tables.list && test_commit -C repo --no-tag B && test_line_count = 1 repo/.git/reftable/tables.list ' +test_expect_success 'ref transaction: env var disables compaction' ' + test_when_finished "rm -rf repo" && + + git init repo && + test_commit -C repo A && + + start=$(wc -l <repo/.git/reftable/tables.list) && + iterations=5 && + expected=$((start + iterations)) && + + for i in $(test_seq $iterations) + do + GIT_TEST_REFTABLE_AUTOCOMPACTION=false \ + git -C repo update-ref branch-$i HEAD || return 1 + done && + test_line_count = $expected repo/.git/reftable/tables.list && + + git -C repo update-ref foo HEAD && + test_line_count -lt $expected repo/.git/reftable/tables.list +' + +test_expect_success 'ref transaction: alternating table sizes are compacted' ' + test_when_finished "rm -rf repo" && + + git init repo && + test_commit -C repo A && + for i in $(test_seq 5) + do + git -C repo branch -f foo && + git -C repo branch -d foo || return 1 + done && + test_line_count = 2 repo/.git/reftable/tables.list +' + check_fsync_events () { local trace="$1" && shift && @@ -324,7 +389,7 @@ test_expect_success 'ref transaction: writes are synced' ' git -C repo -c core.fsync=reference \ -c core.fsyncMethod=fsync update-ref refs/heads/branch HEAD && check_fsync_events trace2.txt <<-EOF - "name":"hardware-flush","count":2 + "name":"hardware-flush","count":4 EOF ' @@ -356,7 +421,7 @@ test_expect_success 'ref transaction: fails gracefully when auto compaction fail done || exit 1 done && - test_line_count = 13 .git/reftable/tables.list + test_line_count = 10 .git/reftable/tables.list ) ' @@ -366,8 +431,8 @@ test_expect_success 'pack-refs: compacts tables' ' test_commit -C repo A && ls -1 repo/.git/reftable >table-files && - test_line_count = 4 table-files && - test_line_count = 3 repo/.git/reftable/tables.list && + test_line_count = 3 table-files && + test_line_count = 2 repo/.git/reftable/tables.list && git -C repo pack-refs && ls -1 repo/.git/reftable >table-files && @@ -408,7 +473,7 @@ test_expect_success "$command: auto compaction" ' # The tables should have been auto-compacted, and thus auto # compaction should not have to do anything. ls -1 .git/reftable >tables-expect && - test_line_count = 4 tables-expect && + test_line_count = 3 tables-expect && git $command --auto && ls -1 .git/reftable >tables-actual && test_cmp tables-expect tables-actual && @@ -426,7 +491,7 @@ test_expect_success "$command: auto compaction" ' git branch B && git branch C && rm .git/reftable/*.lock && - test_line_count = 5 .git/reftable/tables.list && + test_line_count = 4 .git/reftable/tables.list && git $command --auto && test_line_count = 1 .git/reftable/tables.list @@ -450,26 +515,6 @@ test_expect_success 'pack-refs: does not prune non-table files' ' test_path_is_file repo/.git/reftable/garbage ' -for umask in 002 022 -do - test_expect_success POSIXPERM 'pack-refs: honors core.sharedRepository' ' - test_when_finished "rm -rf repo" && - ( - umask $umask && - git init --shared=true repo && - test_commit -C repo A && - test_line_count = 3 repo/.git/reftable/tables.list - ) && - git -C repo pack-refs && - test_expect_perms "-rw-rw-r--" repo/.git/reftable/tables.list && - for table in repo/.git/reftable/*.ref - do - test_expect_perms "-rw-rw-r--" "$table" || - return 1 - done - ' -done - test_expect_success 'packed-refs: writes are synced' ' test_when_finished "rm -rf repo" && git init repo && @@ -826,12 +871,16 @@ test_expect_success 'worktree: pack-refs in main repo packs main refs' ' test_when_finished "rm -rf repo worktree" && git init repo && test_commit -C repo A && + + GIT_TEST_REFTABLE_AUTOCOMPACTION=false \ git -C repo worktree add ../worktree && + GIT_TEST_REFTABLE_AUTOCOMPACTION=false \ + git -C worktree update-ref refs/worktree/per-worktree HEAD && - test_line_count = 3 repo/.git/worktrees/worktree/reftable/tables.list && - test_line_count = 4 repo/.git/reftable/tables.list && + test_line_count = 4 repo/.git/worktrees/worktree/reftable/tables.list && + test_line_count = 3 repo/.git/reftable/tables.list && git -C repo pack-refs && - test_line_count = 3 repo/.git/worktrees/worktree/reftable/tables.list && + test_line_count = 4 repo/.git/worktrees/worktree/reftable/tables.list && test_line_count = 1 repo/.git/reftable/tables.list ' @@ -839,13 +888,17 @@ test_expect_success 'worktree: pack-refs in worktree packs worktree refs' ' test_when_finished "rm -rf repo worktree" && git init repo && test_commit -C repo A && + + GIT_TEST_REFTABLE_AUTOCOMPACTION=false \ git -C repo worktree add ../worktree && + GIT_TEST_REFTABLE_AUTOCOMPACTION=false \ + git -C worktree update-ref refs/worktree/per-worktree HEAD && - test_line_count = 3 repo/.git/worktrees/worktree/reftable/tables.list && - test_line_count = 4 repo/.git/reftable/tables.list && + test_line_count = 4 repo/.git/worktrees/worktree/reftable/tables.list && + test_line_count = 3 repo/.git/reftable/tables.list && git -C worktree pack-refs && test_line_count = 1 repo/.git/worktrees/worktree/reftable/tables.list && - test_line_count = 4 repo/.git/reftable/tables.list + test_line_count = 3 repo/.git/reftable/tables.list ' test_expect_success 'worktree: creating shared ref updates main stack' ' @@ -859,6 +912,7 @@ test_expect_success 'worktree: creating shared ref updates main stack' ' test_line_count = 1 repo/.git/worktrees/worktree/reftable/tables.list && test_line_count = 1 repo/.git/reftable/tables.list && + GIT_TEST_REFTABLE_AUTOCOMPACTION=false \ git -C worktree update-ref refs/heads/shared HEAD && test_line_count = 1 repo/.git/worktrees/worktree/reftable/tables.list && test_line_count = 2 repo/.git/reftable/tables.list diff --git a/t/t1016-compatObjectFormat.sh b/t/t1016-compatObjectFormat.sh index 8132cd37b8..be3206a16f 100755 --- a/t/t1016-compatObjectFormat.sh +++ b/t/t1016-compatObjectFormat.sh @@ -79,7 +79,7 @@ commit2_oid () { } del_sigcommit () { - local delete=$1 + local delete="$1" if test "$delete" = "sha256" ; then local pattern="gpgsig-sha256" @@ -91,8 +91,8 @@ del_sigcommit () { del_sigtag () { - local storage=$1 - local delete=$2 + local storage="$1" + local delete="$2" if test "$storage" = "$delete" ; then local pattern="trailer" @@ -181,7 +181,7 @@ done cd "$base" compare_oids () { - test "$#" = 5 && { local PREREQ=$1; shift; } || PREREQ= + test "$#" = 5 && { local PREREQ="$1"; shift; } || PREREQ= local type="$1" local name="$2" local sha1_oid="$3" @@ -193,8 +193,8 @@ compare_oids () { git --git-dir=repo-sha1/.git rev-parse --output-object-format=sha256 ${sha1_oid} > ${name}_sha1_sha256_found git --git-dir=repo-sha256/.git rev-parse --output-object-format=sha1 ${sha256_oid} > ${name}_sha256_sha1_found - local sha1_sha256_oid=$(cat ${name}_sha1_sha256_found) - local sha256_sha1_oid=$(cat ${name}_sha256_sha1_found) + local sha1_sha256_oid="$(cat ${name}_sha1_sha256_found)" + local sha256_sha1_oid="$(cat ${name}_sha256_sha1_found)" test_expect_success $PREREQ "Verify ${type} ${name}'s sha1 oid" ' git --git-dir=repo-sha256/.git rev-parse --output-object-format=sha1 ${sha256_oid} > ${name}_sha1 && diff --git a/t/t2200-add-update.sh b/t/t2200-add-update.sh index c01492f33f..df235ac306 100755 --- a/t/t2200-add-update.sh +++ b/t/t2200-add-update.sh @@ -65,6 +65,16 @@ test_expect_success 'update did not touch untracked files' ' test_must_be_empty out ' +test_expect_success 'error out when passing untracked path' ' + git reset --hard && + echo content >>baz && + echo content >>top && + test_must_fail git add -u baz top 2>err && + test_grep -e "error: pathspec .baz. did not match any file(s) known to git" err && + git diff --cached --name-only >actual && + test_must_be_empty actual +' + test_expect_success 'cache tree has not been corrupted' ' git ls-files -s | diff --git a/t/t2400-worktree-add.sh b/t/t2400-worktree-add.sh index c28c04133c..ba320dc417 100755 --- a/t/t2400-worktree-add.sh +++ b/t/t2400-worktree-add.sh @@ -427,7 +427,7 @@ test_expect_success '"add" worktree with orphan branch, lock, and reason' ' # Note: Quoted arguments containing spaces are not supported. test_wt_add_orphan_hint () { local context="$1" && - local use_branch=$2 && + local use_branch="$2" && shift 2 && local opts="$*" && test_expect_success "'worktree add' show orphan hint in bad/orphan HEAD w/ $context" ' diff --git a/t/t3428-rebase-signoff.sh b/t/t3428-rebase-signoff.sh index e1b1e94764..1bebd1ce74 100755 --- a/t/t3428-rebase-signoff.sh +++ b/t/t3428-rebase-signoff.sh @@ -8,47 +8,45 @@ This test runs git rebase --signoff and make sure that it works. TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh -# A simple file to commit -cat >file <<EOF -a -EOF +test_expect_success 'setup' ' + git commit --allow-empty -m "Initial empty commit" && + test_commit first file a && + + ident="$GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>" && -# Expected commit message for initial commit after rebase --signoff -cat >expected-initial-signed <<EOF -Initial empty commit + # Expected commit message for initial commit after rebase --signoff + cat >expected-initial-signed <<-EOF && + Initial empty commit -Signed-off-by: $(git var GIT_COMMITTER_IDENT | sed -e "s/>.*/>/") -EOF + Signed-off-by: $ident + EOF -# Expected commit message after rebase --signoff -cat >expected-signed <<EOF -first + # Expected commit message after rebase --signoff + cat >expected-signed <<-EOF && + first -Signed-off-by: $(git var GIT_COMMITTER_IDENT | sed -e "s/>.*/>/") -EOF + Signed-off-by: $ident + EOF -# Expected commit message after rebase without --signoff (or with --no-signoff) -cat >expected-unsigned <<EOF -first -EOF + # Expected commit message after rebase without --signoff (or with --no-signoff) + cat >expected-unsigned <<-EOF && + first + EOF + git config alias.rbs "rebase --signoff" +' # We configure an alias to do the rebase --signoff so that # on the next subtest we can show that --no-signoff overrides the alias -test_expect_success 'rebase --signoff adds a sign-off line' ' - git commit --allow-empty -m "Initial empty commit" && - git add file && git commit -m first && - git config alias.rbs "rebase --signoff" && - git rbs HEAD^ && - git cat-file commit HEAD | sed -e "1,/^\$/d" > actual && - test_cmp expected-signed actual +test_expect_success 'rebase --apply --signoff adds a sign-off line' ' + git rbs --apply HEAD^ && + test_commit_message HEAD expected-signed ' test_expect_success 'rebase --no-signoff does not add a sign-off line' ' git commit --amend -m "first" && git rbs --no-signoff HEAD^ && - git cat-file commit HEAD | sed -e "1,/^\$/d" > actual && - test_cmp expected-unsigned actual + test_commit_message HEAD expected-unsigned ' test_expect_success 'rebase --exec --signoff adds a sign-off line' ' @@ -56,30 +54,25 @@ test_expect_success 'rebase --exec --signoff adds a sign-off line' ' git commit --amend -m "first" && git rebase --exec "touch exec" --signoff HEAD^ && test_path_is_file exec && - git cat-file commit HEAD | sed -e "1,/^\$/d" >actual && - test_cmp expected-signed actual + test_commit_message HEAD expected-signed ' test_expect_success 'rebase --root --signoff adds a sign-off line' ' git commit --amend -m "first" && git rebase --root --keep-empty --signoff && - git cat-file commit HEAD^ | sed -e "1,/^\$/d" >actual && - test_cmp expected-initial-signed actual && - git cat-file commit HEAD | sed -e "1,/^\$/d" >actual && - test_cmp expected-signed actual + test_commit_message HEAD^ expected-initial-signed && + test_commit_message HEAD expected-signed ' test_expect_success 'rebase -i --signoff fails' ' git commit --amend -m "first" && git rebase -i --signoff HEAD^ && - git cat-file commit HEAD | sed -e "1,/^\$/d" >actual && - test_cmp expected-signed actual + test_commit_message HEAD expected-signed ' test_expect_success 'rebase -m --signoff fails' ' git commit --amend -m "first" && git rebase -m --signoff HEAD^ && - git cat-file commit HEAD | sed -e "1,/^\$/d" >actual && - test_cmp expected-signed actual + test_commit_message HEAD expected-signed ' test_done diff --git a/t/t4011-diff-symlink.sh b/t/t4011-diff-symlink.sh index d7a5f7ae78..bc8ba88719 100755 --- a/t/t4011-diff-symlink.sh +++ b/t/t4011-diff-symlink.sh @@ -13,13 +13,13 @@ TEST_PASSES_SANITIZE_LEAK=true # Print the short OID of a symlink with the given name. symlink_oid () { - local oid=$(printf "%s" "$1" | git hash-object --stdin) && + local oid="$(printf "%s" "$1" | git hash-object --stdin)" && git rev-parse --short "$oid" } # Print the short OID of the given file. short_oid () { - local oid=$(git hash-object "$1") && + local oid="$(git hash-object "$1")" && git rev-parse --short "$oid" } diff --git a/t/t4018/csharp-exclude-assignments b/t/t4018/csharp-exclude-assignments new file mode 100644 index 0000000000..239f312963 --- /dev/null +++ b/t/t4018/csharp-exclude-assignments @@ -0,0 +1,20 @@ +class Example +{ + string Method(int RIGHT) + { + var constantAssignment = "test"; + var methodAssignment = MethodCall(); + var multiLineMethodAssignment = MethodCall( + ); + var multiLine = "first" + + MethodCall() + + + ( MethodCall() + ) + + MethodCall(); + + return "ChangeMe"; + } + + string MethodCall(int a = 0, int b = 0) => "test"; +} diff --git a/t/t4018/csharp-exclude-control-statements b/t/t4018/csharp-exclude-control-statements new file mode 100644 index 0000000000..3a0f404ee1 --- /dev/null +++ b/t/t4018/csharp-exclude-control-statements @@ -0,0 +1,34 @@ +class Example +{ + string Method(int RIGHT) + { + if (false) + { + return "out"; + } + else { } + if (true) MethodCall( + ); + else MethodCall( + ); + switch ("test") + { + case "one": + return MethodCall( + ); + case "two": + break; + } + (int, int) tuple = (1, 4); + switch (tuple) + { + case (1, 4): + MethodCall(); + break; + } + + return "ChangeMe"; + } + + string MethodCall(int a = 0, int b = 0) => "test"; +} diff --git a/t/t4018/csharp-exclude-exceptions b/t/t4018/csharp-exclude-exceptions new file mode 100644 index 0000000000..b1e64256cf --- /dev/null +++ b/t/t4018/csharp-exclude-exceptions @@ -0,0 +1,29 @@ +using System; + +class Example +{ + string Method(int RIGHT) + { + try + { + throw new Exception("fail"); + } + catch (Exception) + { + } + finally + { + } + try { } catch (Exception) {} + try + { + throw GetException( + ); + } + catch (Exception) { } + + return "ChangeMe"; + } + + Exception GetException() => new Exception("fail"); +} diff --git a/t/t4018/csharp-exclude-generic-method-calls b/t/t4018/csharp-exclude-generic-method-calls new file mode 100644 index 0000000000..31af546665 --- /dev/null +++ b/t/t4018/csharp-exclude-generic-method-calls @@ -0,0 +1,12 @@ +class Example +{ + string Method(int RIGHT) + { + GenericMethodCall<int, int>( + ); + + return "ChangeMe"; + } + + string GenericMethodCall<T, T2>() => "test"; +} diff --git a/t/t4018/csharp-exclude-init-dispose b/t/t4018/csharp-exclude-init-dispose new file mode 100644 index 0000000000..2bc8e194e2 --- /dev/null +++ b/t/t4018/csharp-exclude-init-dispose @@ -0,0 +1,22 @@ +using System; + +class Example : IDisposable +{ + string Method(int RIGHT) + { + new Example(); + new Example( + ); + new Example { }; + using (this) + { + } + var def = + this is default( + Example); + + return "ChangeMe"; + } + + public void Dispose() {} +} diff --git a/t/t4018/csharp-exclude-iterations b/t/t4018/csharp-exclude-iterations new file mode 100644 index 0000000000..960aa182ae --- /dev/null +++ b/t/t4018/csharp-exclude-iterations @@ -0,0 +1,26 @@ +using System.Linq; + +class Example +{ + string Method(int RIGHT) + { + do { } while (true); + do MethodCall( + ); while (true); + while (true); + while (true) { + break; + } + for (int i = 0; i < 10; ++i) + { + } + foreach (int i in Enumerable.Range(0, 10)) + { + } + int[] numbers = [5, 4, 1, 3, 9, 8, 6, 7, 2, 0]; + + return "ChangeMe"; + } + + string MethodCall(int a = 0, int b = 0) => "test"; +} diff --git a/t/t4018/csharp-exclude-method-calls b/t/t4018/csharp-exclude-method-calls new file mode 100644 index 0000000000..51e2dc2040 --- /dev/null +++ b/t/t4018/csharp-exclude-method-calls @@ -0,0 +1,20 @@ +class Example +{ + string Method(int RIGHT) + { + MethodCall(); + MethodCall(1, 2); + MethodCall( + 1, 2); + MethodCall( + 1, 2, + 3); + MethodCall( + 1, MethodCall(), + 2); + + return "ChangeMe"; + } + + int MethodCall(int a = 0, int b = 0, int c = 0) => 42; +} diff --git a/t/t4018/csharp-exclude-other b/t/t4018/csharp-exclude-other new file mode 100644 index 0000000000..4d5581cf3e --- /dev/null +++ b/t/t4018/csharp-exclude-other @@ -0,0 +1,18 @@ +class Example +{ + string Method(int RIGHT) + { + lock (this) + { + } + unsafe + { + byte[] bytes = [1, 2, 3]; + fixed (byte* pointerToFirst = bytes) + { + } + } + + return "ChangeMe"; + } +} diff --git a/t/t4018/csharp-method b/t/t4018/csharp-method new file mode 100644 index 0000000000..16b367aca2 --- /dev/null +++ b/t/t4018/csharp-method @@ -0,0 +1,10 @@ +class Example +{ + string Method(int RIGHT) + { + // Filler + // Filler + + return "ChangeMe"; + } +} diff --git a/t/t4018/csharp-method-array b/t/t4018/csharp-method-array new file mode 100644 index 0000000000..1126de8201 --- /dev/null +++ b/t/t4018/csharp-method-array @@ -0,0 +1,10 @@ +class Example +{ + string[] Method(int RIGHT) + { + // Filler + // Filler + + return ["ChangeMe"]; + } +} diff --git a/t/t4018/csharp-method-explicit b/t/t4018/csharp-method-explicit new file mode 100644 index 0000000000..5a710116cc --- /dev/null +++ b/t/t4018/csharp-method-explicit @@ -0,0 +1,12 @@ +using System; + +class Example : IDisposable +{ + void IDisposable.Dispose() // RIGHT + { + // Filler + // Filler + + // ChangeMe + } +} diff --git a/t/t4018/csharp-method-generics b/t/t4018/csharp-method-generics new file mode 100644 index 0000000000..b3216bfb2a --- /dev/null +++ b/t/t4018/csharp-method-generics @@ -0,0 +1,11 @@ +class Example<T1, T2> +{ + Example<int, string> Method<TA, TB>(TA RIGHT, TB b) + { + // Filler + // Filler + + // ChangeMe + return null; + } +} diff --git a/t/t4018/csharp-method-generics-alternate-spaces b/t/t4018/csharp-method-generics-alternate-spaces new file mode 100644 index 0000000000..9583621743 --- /dev/null +++ b/t/t4018/csharp-method-generics-alternate-spaces @@ -0,0 +1,11 @@ +class Example<T1, T2> +{ + Example<int,string> Method<TA ,TB>(TA RIGHT, TB b) + { + // Filler + // Filler + + // ChangeMe + return null; + } +} diff --git a/t/t4018/csharp-method-modifiers b/t/t4018/csharp-method-modifiers new file mode 100644 index 0000000000..caefa8ee99 --- /dev/null +++ b/t/t4018/csharp-method-modifiers @@ -0,0 +1,13 @@ +using System.Threading.Tasks; + +class Example +{ + static internal async Task Method(int RIGHT) + { + // Filler + // Filler + + // ChangeMe + await Task.Delay(1); + } +} diff --git a/t/t4018/csharp-method-multiline b/t/t4018/csharp-method-multiline new file mode 100644 index 0000000000..3983ff42f5 --- /dev/null +++ b/t/t4018/csharp-method-multiline @@ -0,0 +1,10 @@ +class Example +{ + string Method_RIGHT( + int a, + int b, + int c) + { + return "ChangeMe"; + } +} diff --git a/t/t4018/csharp-method-params b/t/t4018/csharp-method-params new file mode 100644 index 0000000000..3f00410ba1 --- /dev/null +++ b/t/t4018/csharp-method-params @@ -0,0 +1,10 @@ +class Example +{ + string Method(int RIGHT, int b, int c = 42) + { + // Filler + // Filler + + return "ChangeMe"; + } +} diff --git a/t/t4018/csharp-method-special-chars b/t/t4018/csharp-method-special-chars new file mode 100644 index 0000000000..e6c7bc01a1 --- /dev/null +++ b/t/t4018/csharp-method-special-chars @@ -0,0 +1,11 @@ +class @Some_Type +{ + @Some_Type @Method_With_Underscore(int RIGHT) + { + // Filler + // Filler + + // ChangeMe + return new @Some_Type(); + } +} diff --git a/t/t4018/csharp-method-with-spacing b/t/t4018/csharp-method-with-spacing new file mode 100644 index 0000000000..233bb976cc --- /dev/null +++ b/t/t4018/csharp-method-with-spacing @@ -0,0 +1,10 @@ +class Example +{ + string Method ( int RIGHT ) + { + // Filler + // Filler + + return "ChangeMe"; + } +} diff --git a/t/t4018/csharp-property b/t/t4018/csharp-property new file mode 100644 index 0000000000..e56dfce34c --- /dev/null +++ b/t/t4018/csharp-property @@ -0,0 +1,11 @@ +class Example +{ + public bool RIGHT + { + get { return true; } + set + { + // ChangeMe + } + } +} diff --git a/t/t4018/csharp-property-braces-same-line b/t/t4018/csharp-property-braces-same-line new file mode 100644 index 0000000000..608131d3d3 --- /dev/null +++ b/t/t4018/csharp-property-braces-same-line @@ -0,0 +1,10 @@ +class Example +{ + public bool RIGHT { + get { return true; } + set + { + // ChangeMe + } + } +} diff --git a/t/t4210-log-i18n.sh b/t/t4210-log-i18n.sh index d2dfcf164e..75216f19ce 100755 --- a/t/t4210-log-i18n.sh +++ b/t/t4210-log-i18n.sh @@ -64,7 +64,7 @@ test_expect_success 'log --grep does not find non-reencoded values (latin1)' ' ' triggers_undefined_behaviour () { - local engine=$1 + local engine="$1" case $engine in fixed) @@ -85,7 +85,7 @@ triggers_undefined_behaviour () { } mismatched_git_log () { - local pattern=$1 + local pattern="$1" LC_ALL=$is_IS_locale git log --encoding=ISO-8859-1 --format=%s \ --grep=$pattern diff --git a/t/t7300-clean.sh b/t/t7300-clean.sh index 1f7201eb60..0aae0dee67 100755 --- a/t/t7300-clean.sh +++ b/t/t7300-clean.sh @@ -5,6 +5,7 @@ test_description='git clean basic tests' +TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh git config clean.requireForce no diff --git a/t/t7501-commit-basic-functionality.sh b/t/t7501-commit-basic-functionality.sh index bced44a0fc..cc12f99f11 100755 --- a/t/t7501-commit-basic-functionality.sh +++ b/t/t7501-commit-basic-functionality.sh @@ -101,22 +101,8 @@ test_expect_success 'fail to commit untracked file (even with --include/--only)' test_must_fail git commit --only -m "baz" baz 2>err && test_grep -e "$error" err && - # TODO: as for --include, the below command will fail because - # nothing is staged. If something was staged, it would not fail - # even though the provided pathspec does not match any tracked - # path. (However, the untracked paths that match the pathspec are - # not committed and only the staged changes get committed.) - # In either cases, no error is returned to stderr like in (--only - # and without --only/--include) cases. In a similar manner, - # "git add -u baz" also does not error out. - # - # Therefore, the below test is just to document the current behavior - # and is not an endorsement to the current behavior, and we may - # want to fix this. And when that happens, this test should be - # updated accordingly. - test_must_fail git commit --include -m "baz" baz 2>err && - test_must_be_empty err + test_grep -e "$error" err ' test_expect_success 'setup: non-initial commit' ' diff --git a/t/t7700-repack.sh b/t/t7700-repack.sh index 94f9f4a1da..127efe99f8 100755 --- a/t/t7700-repack.sh +++ b/t/t7700-repack.sh @@ -629,6 +629,7 @@ test_expect_success '--write-midx with preferred bitmap tips' ' git log --format="create refs/tags/%s/%s %H" HEAD >refs && git update-ref --stdin <refs && + GIT_TEST_MULTI_PACK_INDEX=0 \ git repack --write-midx --write-bitmap-index && test_path_is_file $midx && test_path_is_file $midx-$(midx_checksum $objdir).bitmap && @@ -749,6 +750,7 @@ test_expect_success '--write-midx with --pack-kept-objects' ' keep="$objdir/pack/pack-$one.keep" && touch "$keep" && + GIT_TEST_MULTI_PACK_INDEX=0 \ git repack --write-midx --write-bitmap-index --geometric=2 -d \ --pack-kept-objects && diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh index 2eccf100c0..862d80c974 100644 --- a/t/test-lib-functions.sh +++ b/t/test-lib-functions.sh @@ -385,7 +385,7 @@ test_commit () { shift done && indir=${indir:+"$indir"/} && - local file=${2:-"$1.t"} && + local file="${2:-"$1.t"}" && if test -n "$append" then $echo "${3-$1}" >>"$indir$file" @@ -1748,7 +1748,7 @@ test_oid () { # Insert a slash into an object ID so it can be used to reference a location # under ".git/objects". For example, "deadbeef..." becomes "de/adbeef..". test_oid_to_path () { - local basename=${1#??} + local basename="${1#??}" echo "${1%$basename}/$basename" } @@ -1765,7 +1765,7 @@ test_parse_ls_tree_oids () { # Choose a port number based on the test script's number and store it in # the given variable name, unless that variable already contains a number. test_set_port () { - local var=$1 port + local var="$1" port if test $# -ne 1 || test -z "$var" then @@ -1840,7 +1840,7 @@ test_subcommand () { shift fi - local expr=$(printf '"%s",' "$@") + local expr="$(printf '"%s",' "$@")" expr="${expr%,}" if test -n "$negate" @@ -1930,7 +1930,7 @@ test_readlink () { # An optional increment to the magic timestamp may be specified as second # argument. test_set_magic_mtime () { - local inc=${2:-0} && + local inc="${2:-0}" && local mtime=$((1234567890 + $inc)) && test-tool chmtime =$mtime "$1" && test_is_magic_mtime "$1" $inc @@ -1943,7 +1943,7 @@ test_set_magic_mtime () { # argument. Usually, this should be the same increment which was used for # the associated test_set_magic_mtime. test_is_magic_mtime () { - local inc=${2:-0} && + local inc="${2:-0}" && local mtime=$((1234567890 + $inc)) && echo $mtime >.git/test-mtime-expect && test-tool chmtime --get "$1" >.git/test-mtime-actual && @@ -19,8 +19,11 @@ static void vreportf(const char *prefix, const char *err, va_list params) } memcpy(msg, prefix, prefix_len); p = msg + prefix_len; - if (vsnprintf(p, pend - p, err, params) < 0) + if (vsnprintf(p, pend - p, err, params) < 0) { + fprintf(stderr, _("error: unable to format message: %s\n"), + err); *p = '\0'; /* vsnprintf() failed, clip at prefix */ + } for (; p != pend - 1 && *p; p++) { if (iscntrl(*p) && *p != '\t' && *p != '\n') diff --git a/userdiff.c b/userdiff.c index 92ef649c99..82bc76b910 100644 --- a/userdiff.c +++ b/userdiff.c @@ -90,12 +90,48 @@ PATTERNS("cpp", "|\\.[0-9][0-9]*([Ee][-+]?[0-9]+)?[fFlL]?" "|[-+*/<>%&^|=!]=|--|\\+\\+|<<=?|>>=?|&&|\\|\\||::|->\\*?|\\.\\*|<=>"), PATTERNS("csharp", - /* Keywords */ - "!^[ \t]*(do|while|for|if|else|instanceof|new|return|switch|case|throw|catch|using)\n" - /* Methods and constructors */ - "^[ \t]*(((static|public|internal|private|protected|new|virtual|sealed|override|unsafe|async)[ \t]+)*[][<>@.~_[:alnum:]]+[ \t]+[<>@._[:alnum:]]+[ \t]*\\(.*\\))[ \t]*$\n" - /* Properties */ - "^[ \t]*(((static|public|internal|private|protected|new|virtual|sealed|override|unsafe)[ \t]+)*[][<>@.~_[:alnum:]]+[ \t]+[@._[:alnum:]]+)[ \t]*$\n" + /* + * Jump over reserved keywords which are illegal method names, but which + * can be followed by parentheses without special characters in between, + * making them look like methods. + */ + "!(^|[ \t]+)" /* Start of line or whitespace. */ + "(do|while|for|foreach|if|else|new|default|return|switch|case|throw" + "|catch|using|lock|fixed)" + "([ \t(]+|$)\n" /* Whitespace, "(", or end of line. */ + /* + * Methods/constructors: + * The strategy is to identify a minimum of two groups (any combination + * of keywords/type/name) before the opening parenthesis, and without + * final unexpected characters, normally only used in ordinary statements. + */ + "^[ \t]*" /* Remove leading whitespace. */ + "(" /* Start chunk header capture. */ + "(" /* First group. */ + "[][[:alnum:]@_.]" /* Name. */ + "(<[][[:alnum:]@_, \t<>]+>)?" /* Optional generic parameters. */ + ")+" + "([ \t]+" /* Subsequent groups, prepended with space. */ + "([][[:alnum:]@_.](<[][[:alnum:]@_, \t<>]+>)?)+" + ")+" + "[ \t]*" /* Optional space before parameters start. */ + "\\(" /* Start of method parameters. */ + "[^;]*" /* Allow complex parameters, but exclude statements (;). */ + ")$\n" /* Close chunk header capture. */ + /* + * Properties: + * As with methods, expect a minimum of two groups. But, more trivial than + * methods, the vast majority of properties long enough to be worth + * showing a chunk header for don't include "=:;,()" on the line they are + * defined, since they don't have a parameter list. + */ + "^[ \t]*(" + "([][[:alnum:]@_.](<[][[:alnum:]@_, \t<>]+>)?)+" + "([ \t]+" + "([][[:alnum:]@_.](<[][[:alnum:]@_, \t<>]+>)?)+" + ")+" /* Up to here, same as methods regex. */ + "[^;=:,()]*" /* Compared to methods, no parameter list allowed. */ + ")$\n" /* Type definitions */ "^[ \t]*(((static|public|internal|private|protected|new|unsafe|sealed|abstract|partial)[ \t]+)*(class|enum|interface|struct|record)[ \t]+.*)$\n" /* Namespace */ |