diff options
41 files changed, 370 insertions, 71 deletions
diff --git a/Documentation/RelNotes/2.24.0.txt b/Documentation/RelNotes/2.24.0.txt index 22de0bc497..125169d0da 100644 --- a/Documentation/RelNotes/2.24.0.txt +++ b/Documentation/RelNotes/2.24.0.txt @@ -75,6 +75,9 @@ UI, Workflows & Features submodules, but this did not apply to "git fetch --multiple" that fetches from multiple remote repositories. It now does. + * The installation instruction for zsh completion script (in + contrib/) has been a bit improved. + Performance, Internal Implementation, Development Support etc. @@ -327,6 +330,20 @@ Fixes since v2.23 corrected. (merge 2b6a9b13ca tg/range-diff-output-update later to maint). + * Dev support update. + (merge 4f3c1dc5d6 dl/allow-running-cocci-verbosely later to maint). + + * "git format-patch -o <outdir>" did an equivalent of "mkdir <outdir>" + not "mkdir -p <outdir>", which was corrected. + + * "git stash save" lost local changes to submodules, which has been + corrected. + (merge 556895d0c8 jj/stash-reset-only-toplevel later to maint). + + * The atomic push over smart HTTP transport did not work, which has + been corrected. + (merge 6f1194246a bc/smart-http-atomic-push later to maint). + * Other code cleanup, docfix, build fix, etc. (merge d1387d3895 en/fast-import-merge-doc later to maint). (merge 1c24a54ea4 bm/repository-layout-typofix later to maint). @@ -368,3 +385,13 @@ Fixes since v2.23 (merge d928a8388a am/t0028-utf16-tests later to maint). (merge b05b40930e dl/t0000-skip-test-test later to maint). (merge 03d3b1297c js/xdiffi-comment-updates later to maint). + (merge 57d8f4b4c7 js/doc-stash-save later to maint). + (merge 8c1cfd58e3 ta/t1308-typofix later to maint). + (merge fa364ad790 bb/utf8-wcwidth-cleanup later to maint). + (merge 68b69211b2 bb/compat-util-comment-fix later to maint). + (merge 5cc6a4be11 rs/http-push-simplify later to maint). + (merge a81e42d235 rs/column-use-utf8-strnwidth later to maint). + (merge 062a309d36 rs/remote-curl-use-argv-array later to maint). + (merge 3b3c79f6c9 nr/diff-highlight-indent-fix later to maint). + (merge 3444ec2eb2 wb/fsmonitor-bitmap-fix later to maint). + (merge 10da030ab7 cb/pcre2-chartables-leakfix later to maint). diff --git a/Documentation/config/format.txt b/Documentation/config/format.txt index cb629fa769..40cad9278f 100644 --- a/Documentation/config/format.txt +++ b/Documentation/config/format.txt @@ -81,7 +81,7 @@ format.coverLetter:: format.outputDirectory:: Set a custom directory to store the resulting files instead of the - current working directory. + current working directory. All directory components will be created. format.useAutoBase:: A boolean value which lets you enable the `--base=auto` option of diff --git a/Documentation/git-format-patch.txt b/Documentation/git-format-patch.txt index 0ac56f4b70..2035d4d5d5 100644 --- a/Documentation/git-format-patch.txt +++ b/Documentation/git-format-patch.txt @@ -66,7 +66,8 @@ they are created in the current working directory. The default path can be set with the `format.outputDirectory` configuration option. The `-o` option takes precedence over `format.outputDirectory`. To store patches in the current working directory even when -`format.outputDirectory` points elsewhere, use `-o .`. +`format.outputDirectory` points elsewhere, use `-o .`. All directory +components will be created. By default, the subject of a single patch is "[PATCH] " followed by the concatenation of lines from the commit message up to the first blank diff --git a/Documentation/git-stash.txt b/Documentation/git-stash.txt index 8fbe12c66c..53e1a1205d 100644 --- a/Documentation/git-stash.txt +++ b/Documentation/git-stash.txt @@ -87,8 +87,9 @@ The `--patch` option implies `--keep-index`. You can use save [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q|--quiet] [<message>]:: This option is deprecated in favour of 'git stash push'. It - differs from "stash push" in that it cannot take pathspecs, - and any non-option arguments form the message. + differs from "stash push" in that it cannot take pathspecs. + Instead, all non-option arguments are concatenated to form the stash + message. list [<options>]:: diff --git a/Documentation/gitremote-helpers.txt b/Documentation/gitremote-helpers.txt index a5c3c04371..f48a031dc3 100644 --- a/Documentation/gitremote-helpers.txt +++ b/Documentation/gitremote-helpers.txt @@ -509,6 +509,11 @@ set by Git if the remote helper has the 'option' capability. Indicate that only the objects wanted need to be fetched, not their dependents. +'option atomic' {'true'|'false'}:: + When pushing, request the remote server to update refs in a single atomic + transaction. If successful, all refs will be updated, or none will. If the + remote side does not support this capability, the push will fail. + SEE ALSO -------- linkgit:git-remote[1] diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN index 98f88a28d3..64543ede28 100755 --- a/GIT-VERSION-GEN +++ b/GIT-VERSION-GEN @@ -1,7 +1,7 @@ #!/bin/sh GVF=GIT-VERSION-FILE -DEF_VER=v2.23.GIT +DEF_VER=v2.24.0-rc0 LF=' ' @@ -1885,6 +1885,7 @@ ifndef V QUIET_SP = @echo ' ' SP $<; QUIET_HDR = @echo ' ' HDR $(<:hcc=h); QUIET_RC = @echo ' ' RC $@; + QUIET_SPATCH = @echo ' ' SPATCH $<; QUIET_SUBDIR0 = +@subdir= QUIET_SUBDIR1 = ;$(NO_SUBDIR) echo ' ' SUBDIR $$subdir; \ $(MAKE) $(PRINT_DIR) -C $$subdir @@ -2813,7 +2814,7 @@ FOUND_C_SOURCES = $(filter %.c,$(shell $(FIND_SOURCE_FILES))) COCCI_SOURCES = $(filter-out $(THIRD_PARTY_SOURCES),$(FOUND_C_SOURCES)) %.cocci.patch: %.cocci $(COCCI_SOURCES) - @echo ' ' SPATCH $<; \ + $(QUIET_SPATCH) \ if test $(SPATCH_BATCH_SIZE) = 0; then \ limit=; \ else \ diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 9f099b9529..af2a5ea484 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -157,7 +157,7 @@ jobs: displayName: 'Download git-sdk-64-minimal' - powershell: | & git-sdk-64-minimal\usr\bin\bash.exe -lc @" - make vcxproj + make NDEBUG=1 DEVELOPER=1 vcxproj "@ if (!$?) { exit(1) } displayName: Generate Visual Studio Solution @@ -255,7 +255,7 @@ jobs: cd t && PATH=\"`$PWD/helper:`$PATH\" && - test-tool.exe run-command testsuite -V -x --write-junit-xml \ + test-tool.exe run-command testsuite --jobs=10 -V -x --write-junit-xml \ `$(test-tool.exe path-utils slice-tests \ `$SYSTEM_JOBPOSITIONINPHASE `$SYSTEM_TOTALJOBSINPHASE t[0-9]*.sh) "@ diff --git a/builtin/grep.c b/builtin/grep.c index 69ac053acc..50ce8d9461 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -1147,5 +1147,6 @@ int cmd_grep(int argc, const char **argv, const char *prefix) run_pager(&opt, prefix); clear_pathspec(&pathspec); free_grep_patterns(&opt); + grep_destroy(); return !hit; } diff --git a/builtin/log.c b/builtin/log.c index c4b35fdaf9..89873d2dc2 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -1766,10 +1766,26 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) setup_pager(); if (output_directory) { + int saved; if (rev.diffopt.use_color != GIT_COLOR_ALWAYS) rev.diffopt.use_color = GIT_COLOR_NEVER; if (use_stdout) die(_("standard output, or directory, which one?")); + /* + * We consider <outdir> as 'outside of gitdir', therefore avoid + * applying adjust_shared_perm in s-c-l-d. + */ + saved = get_shared_repository(); + set_shared_repository(0); + switch (safe_create_leading_directories_const(output_directory)) { + case SCLD_OK: + case SCLD_EXISTS: + break; + default: + die(_("could not create leading directories " + "of '%s'"), output_directory); + } + set_shared_repository(saved); if (mkdir(output_directory, 0777) < 0 && errno != EEXIST) die_errno(_("could not create directory '%s'"), output_directory); diff --git a/builtin/stash.c b/builtin/stash.c index bb4f6d8d76..4e806176b0 100644 --- a/builtin/stash.c +++ b/builtin/stash.c @@ -1392,7 +1392,7 @@ static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int q struct child_process cp = CHILD_PROCESS_INIT; cp.git_cmd = 1; argv_array_pushl(&cp.args, "reset", "--hard", "-q", - NULL); + "--no-recurse-submodules", NULL); if (run_command(&cp)) { ret = -1; goto done; diff --git a/ci/install-dependencies.sh b/ci/install-dependencies.sh index b54ccb4b52..4e64a19112 100755 --- a/ci/install-dependencies.sh +++ b/ci/install-dependencies.sh @@ -40,6 +40,11 @@ osx-clang|osx-gcc) test -z "$BREW_INSTALL_PACKAGES" || brew install $BREW_INSTALL_PACKAGES brew link --force gettext + brew cask install perforce || { + # Update the definitions and try again + git -C "$(brew --repository)"/Library/Taps/homebrew/homebrew-cask pull && + brew cask install perforce + } || brew install caskroom/cask/perforce case "$jobname" in osx-gcc) @@ -23,18 +23,7 @@ struct column_data { /* return length of 's' in letters, ANSI escapes stripped */ static int item_length(const char *s) { - int len, i = 0; - struct strbuf str = STRBUF_INIT; - - strbuf_addstr(&str, s); - while ((s = strstr(str.buf + i, "\033[")) != NULL) { - int len = strspn(s + 2, "0123456789;"); - i = s - str.buf; - strbuf_remove(&str, i, len + 3); /* \033[<len><func char> */ - } - len = utf8_strwidth(str.buf); - strbuf_release(&str); - return len; + return utf8_strnwidth(s, -1, 1); } /* diff --git a/compat/win32/pthread.h b/compat/win32/pthread.h index f1cfe73de9..737983d00b 100644 --- a/compat/win32/pthread.h +++ b/compat/win32/pthread.h @@ -51,7 +51,7 @@ typedef struct { } pthread_t; int pthread_create(pthread_t *thread, const void *unused, - void *(*start_routine)(void*), void *arg); + void *(*start_routine)(void*), void *arg); /* * To avoid the need of copying a struct, we use small macro wrapper to pass diff --git a/contrib/completion/git-completion.zsh b/contrib/completion/git-completion.zsh index 886bf95d1f..eef4eff53d 100644 --- a/contrib/completion/git-completion.zsh +++ b/contrib/completion/git-completion.zsh @@ -11,8 +11,9 @@ # # zstyle ':completion:*:*:git:*' script ~/.git-completion.zsh # -# The recommended way to install this script is to copy to '~/.zsh/_git', and -# then add the following to your ~/.zshrc file: +# The recommended way to install this script is to make a copy of it in +# ~/.zsh/ directory as ~/.zsh/git-completion.zsh and then add the following +# to your ~/.zshrc file: # # fpath=(~/.zsh $fpath) diff --git a/contrib/diff-highlight/DiffHighlight.pm b/contrib/diff-highlight/DiffHighlight.pm index 7440aa1c46..e2589922a6 100644 --- a/contrib/diff-highlight/DiffHighlight.pm +++ b/contrib/diff-highlight/DiffHighlight.pm @@ -72,7 +72,7 @@ sub handle_line { (?:$COLOR?\|$COLOR?[ ])* # zero or more trailing "|" [ ]* # trailing whitespace for merges /x) { - my $graph_prefix = $&; + my $graph_prefix = $&; # We must flush before setting graph indent, since the # new commit may be indented differently from what we diff --git a/fsmonitor.c b/fsmonitor.c index 231e83a94d..1f4aa1b150 100644 --- a/fsmonitor.c +++ b/fsmonitor.c @@ -14,8 +14,13 @@ struct trace_key trace_fsmonitor = TRACE_KEY_INIT(FSMONITOR); static void fsmonitor_ewah_callback(size_t pos, void *is) { struct index_state *istate = (struct index_state *)is; - struct cache_entry *ce = istate->cache[pos]; + struct cache_entry *ce; + if (pos >= istate->cache_nr) + BUG("fsmonitor_dirty has more entries than the index (%"PRIuMAX" >= %u)", + (uintmax_t)pos, istate->cache_nr); + + ce = istate->cache[pos]; ce->ce_flags &= ~CE_FSMONITOR_VALID; } @@ -50,17 +55,24 @@ int read_fsmonitor_extension(struct index_state *istate, const void *data, } istate->fsmonitor_dirty = fsmonitor_dirty; + if (istate->fsmonitor_dirty->bit_size > istate->cache_nr) + BUG("fsmonitor_dirty has more entries than the index (%"PRIuMAX" > %u)", + (uintmax_t)istate->fsmonitor_dirty->bit_size, istate->cache_nr); + trace_printf_key(&trace_fsmonitor, "read fsmonitor extension successful"); return 0; } void fill_fsmonitor_bitmap(struct index_state *istate) { - unsigned int i; + unsigned int i, skipped = 0; istate->fsmonitor_dirty = ewah_new(); - for (i = 0; i < istate->cache_nr; i++) - if (!(istate->cache[i]->ce_flags & CE_FSMONITOR_VALID)) - ewah_set(istate->fsmonitor_dirty, i); + for (i = 0; i < istate->cache_nr; i++) { + if (istate->cache[i]->ce_flags & CE_REMOVE) + skipped++; + else if (!(istate->cache[i]->ce_flags & CE_FSMONITOR_VALID)) + ewah_set(istate->fsmonitor_dirty, i - skipped); + } } void write_fsmonitor_extension(struct strbuf *sb, struct index_state *istate) @@ -71,6 +83,10 @@ void write_fsmonitor_extension(struct strbuf *sb, struct index_state *istate) uint32_t ewah_size = 0; int fixup = 0; + if (istate->fsmonitor_dirty->bit_size > istate->cache_nr) + BUG("fsmonitor_dirty has more entries than the index (%"PRIuMAX" > %u)", + (uintmax_t)istate->fsmonitor_dirty->bit_size, istate->cache_nr); + put_be32(&hdr_version, INDEX_EXTENSION_VERSION); strbuf_add(sb, &hdr_version, sizeof(uint32_t)); @@ -236,6 +252,9 @@ void tweak_fsmonitor(struct index_state *istate) } /* Mark all previously saved entries as dirty */ + if (istate->fsmonitor_dirty->bit_size > istate->cache_nr) + BUG("fsmonitor_dirty has more entries than the index (%"PRIuMAX" > %u)", + (uintmax_t)istate->fsmonitor_dirty->bit_size, istate->cache_nr); ewah_each_bit(istate->fsmonitor_dirty, fsmonitor_ewah_callback, istate); /* Now mark the untracked cache for fsmonitor usage */ diff --git a/git-compat-util.h b/git-compat-util.h index 8b8b29a867..607dca7534 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -77,7 +77,7 @@ #endif /* * ARRAY_SIZE - get the number of elements in a visible array - * <at> x: the array whose size you want. + * @x: the array whose size you want. * * This does not work on pointers, or arrays declared as [], or * function parameters. With correct compiler support, such usage diff --git a/git-legacy-stash.sh b/git-legacy-stash.sh index f60e9b3e87..07ad4a5459 100755 --- a/git-legacy-stash.sh +++ b/git-legacy-stash.sh @@ -370,7 +370,7 @@ push_stash () { git diff-index -p --cached --binary HEAD -- "$@" | git apply --index -R else - git reset --hard -q + git reset --hard -q --no-recurse-submodules fi if test "$keep_index" = "t" && test -n "$i_tree" @@ -16,6 +16,20 @@ static int grep_source_is_binary(struct grep_source *gs, static struct grep_opt grep_defaults; +#ifdef USE_LIBPCRE2 +static pcre2_general_context *pcre2_global_context; + +static void *pcre2_malloc(PCRE2_SIZE size, MAYBE_UNUSED void *memory_data) +{ + return malloc(size); +} + +static void pcre2_free(void *pointer, MAYBE_UNUSED void *memory_data) +{ + return free(pointer); +} +#endif + static const char *color_grep_slots[] = { [GREP_COLOR_CONTEXT] = "context", [GREP_COLOR_FILENAME] = "filename", @@ -150,12 +164,28 @@ int grep_config(const char *var, const char *value, void *cb) * Initialize one instance of grep_opt and copy the * default values from the template we read the configuration * information in an earlier call to git_config(grep_config). + * + * If using PCRE, make sure that the library is configured + * to use the same allocator as Git (e.g. nedmalloc on Windows). + * + * Any allocated memory needs to be released in grep_destroy(). */ void grep_init(struct grep_opt *opt, struct repository *repo, const char *prefix) { struct grep_opt *def = &grep_defaults; int i; +#if defined(USE_LIBPCRE2) + if (!pcre2_global_context) + pcre2_global_context = pcre2_general_context_create( + pcre2_malloc, pcre2_free, NULL); +#endif + +#ifdef USE_LIBPCRE1 + pcre_malloc = malloc; + pcre_free = free; +#endif + memset(opt, 0, sizeof(*opt)); opt->repo = repo; opt->prefix = prefix; @@ -178,6 +208,13 @@ void grep_init(struct grep_opt *opt, struct repository *repo, const char *prefix color_set(opt->colors[i], def->colors[i]); } +void grep_destroy(void) +{ +#ifdef USE_LIBPCRE2 + pcre2_general_context_free(pcre2_global_context); +#endif +} + static void grep_set_pattern_type_option(enum grep_pattern_type pattern_type, struct grep_opt *opt) { /* @@ -461,7 +498,6 @@ static void compile_pcre2_pattern(struct grep_pat *p, const struct grep_opt *opt PCRE2_UCHAR errbuf[256]; PCRE2_SIZE erroffset; int options = PCRE2_MULTILINE; - const uint8_t *character_tables = NULL; int jitret; int patinforet; size_t jitsizearg; @@ -470,11 +506,15 @@ static void compile_pcre2_pattern(struct grep_pat *p, const struct grep_opt *opt p->pcre2_compile_context = NULL; + /* pcre2_global_context is initialized in append_grep_pattern */ if (opt->ignore_case) { if (!opt->ignore_locale && has_non_ascii(p->pattern)) { - character_tables = pcre2_maketables(NULL); + if (!pcre2_global_context) + BUG("pcre2_global_context uninitialized"); + p->pcre2_tables = pcre2_maketables(pcre2_global_context); p->pcre2_compile_context = pcre2_compile_context_create(NULL); - pcre2_set_character_tables(p->pcre2_compile_context, character_tables); + pcre2_set_character_tables(p->pcre2_compile_context, + p->pcre2_tables); } options |= PCRE2_CASELESS; } @@ -571,6 +611,7 @@ static void free_pcre2_pattern(struct grep_pat *p) pcre2_compile_context_free(p->pcre2_compile_context); pcre2_code_free(p->pcre2_pattern); pcre2_match_data_free(p->pcre2_match_data); + free((void *)p->pcre2_tables); } #else /* !USE_LIBPCRE2 */ static void compile_pcre2_pattern(struct grep_pat *p, const struct grep_opt *opt) @@ -78,6 +78,7 @@ struct grep_pat { pcre2_code *pcre2_pattern; pcre2_match_data *pcre2_match_data; pcre2_compile_context *pcre2_compile_context; + const uint8_t *pcre2_tables; uint32_t pcre2_jit_on; unsigned fixed:1; unsigned is_fixed:1; @@ -172,6 +173,7 @@ struct grep_opt { void init_grep_defaults(struct repository *); int grep_config(const char *var, const char *value, void *); void grep_init(struct grep_opt *, struct repository *repo, const char *prefix); +void grep_destroy(void); void grep_commit_pattern_type(enum grep_pattern_type, struct grep_opt *opt); void append_grep_pat(struct grep_opt *opt, const char *pat, size_t patlen, const char *origin, int no, enum grep_pat_token t); diff --git a/http-push.c b/http-push.c index 0353f9f514..822f326599 100644 --- a/http-push.c +++ b/http-push.c @@ -501,10 +501,10 @@ static void release_request(struct transfer_request *request) if (request == request_queue_head) { request_queue_head = request->next; } else { - while (entry->next != NULL && entry->next != request) + while (entry && entry->next != request) entry = entry->next; - if (entry->next == request) - entry->next = entry->next->next; + if (entry) + entry->next = request->next; } free(request->url); @@ -981,7 +981,7 @@ static int unlock_remote(struct remote_lock *lock) while (prev && prev->next != lock) prev = prev->next; if (prev) - prev->next = prev->next->next; + prev->next = lock->next; } free(lock->owner); diff --git a/remote-curl.c b/remote-curl.c index 051f26629d..350d92a074 100644 --- a/remote-curl.c +++ b/remote-curl.c @@ -40,7 +40,8 @@ struct options { push_cert : 2, deepen_relative : 1, from_promisor : 1, - no_dependents : 1; + no_dependents : 1, + atomic : 1; }; static struct options options; static struct string_list cas_options = STRING_LIST_INIT_DUP; @@ -148,6 +149,14 @@ static int set_option(const char *name, const char *value) else return -1; return 0; + } else if (!strcmp(name, "atomic")) { + if (!strcmp(value, "true")) + options.atomic = 1; + else if (!strcmp(value, "false")) + options.atomic = 0; + else + return -1; + return 0; } else if (!strcmp(name, "push-option")) { if (*value != '"') string_list_append(&options.push_options, value); @@ -1154,7 +1163,7 @@ static void parse_fetch(struct strbuf *buf) strbuf_reset(buf); } -static int push_dav(int nr_spec, char **specs) +static int push_dav(int nr_spec, const char **specs) { struct child_process child = CHILD_PROCESS_INIT; size_t i; @@ -1175,7 +1184,7 @@ static int push_dav(int nr_spec, char **specs) return 0; } -static int push_git(struct discovery *heads, int nr_spec, char **specs) +static int push_git(struct discovery *heads, int nr_spec, const char **specs) { struct rpc_state rpc; int i, err; @@ -1196,6 +1205,8 @@ static int push_git(struct discovery *heads, int nr_spec, char **specs) argv_array_push(&args, "--signed=yes"); else if (options.push_cert == SEND_PACK_PUSH_CERT_IF_ASKED) argv_array_push(&args, "--signed=if-asked"); + if (options.atomic) + argv_array_push(&args, "--atomic"); if (options.verbosity == 0) argv_array_push(&args, "--quiet"); else if (options.verbosity > 1) @@ -1225,7 +1236,7 @@ static int push_git(struct discovery *heads, int nr_spec, char **specs) return err; } -static int push(int nr_spec, char **specs) +static int push(int nr_spec, const char **specs) { struct discovery *heads = discover_refs("git-receive-pack", 1); int ret; @@ -1240,14 +1251,12 @@ static int push(int nr_spec, char **specs) static void parse_push(struct strbuf *buf) { - char **specs = NULL; - int alloc_spec = 0, nr_spec = 0, i, ret; + struct argv_array specs = ARGV_ARRAY_INIT; + int ret; do { - if (starts_with(buf->buf, "push ")) { - ALLOC_GROW(specs, nr_spec + 1, alloc_spec); - specs[nr_spec++] = xstrdup(buf->buf + 5); - } + if (starts_with(buf->buf, "push ")) + argv_array_push(&specs, buf->buf + 5); else die(_("http transport does not support %s"), buf->buf); @@ -1258,7 +1267,7 @@ static void parse_push(struct strbuf *buf) break; } while (1); - ret = push(nr_spec, specs); + ret = push(specs.argc, specs.argv); printf("\n"); fflush(stdout); @@ -1266,9 +1275,7 @@ static void parse_push(struct strbuf *buf) exit(128); /* error already reported */ free_specs: - for (i = 0; i < nr_spec; i++) - free(specs[i]); - free(specs); + argv_array_clear(&specs); } static int stateless_connect(const char *service_name) diff --git a/repo-settings.c b/repo-settings.c index 05546db98e..a703e407a3 100644 --- a/repo-settings.c +++ b/repo-settings.c @@ -22,7 +22,7 @@ void prepare_repo_settings(struct repository *r) UPDATE_DEFAULT_BOOL(r->settings.core_commit_graph, 1); UPDATE_DEFAULT_BOOL(r->settings.gc_write_commit_graph, 1); - if (!repo_config_get_bool(r, "index.version", &value)) + if (!repo_config_get_int(r, "index.version", &value)) r->settings.index_version = value; if (!repo_config_get_maybe_bool(r, "core.untrackedcache", &value)) { if (value == 0) diff --git a/t/helper/test-progress.c b/t/helper/test-progress.c index 4e9f7fafdf..42b96cb103 100644 --- a/t/helper/test-progress.c +++ b/t/helper/test-progress.c @@ -29,7 +29,7 @@ void progress_test_force_update(void); int cmd__progress(int argc, const char **argv) { - uint64_t total = 0; + int total = 0; const char *title; struct strbuf line = STRBUF_INIT; struct progress *progress; diff --git a/t/t1308-config-set.sh b/t/t1308-config-set.sh index d0a2727b85..7b4e1a63eb 100755 --- a/t/t1308-config-set.sh +++ b/t/t1308-config-set.sh @@ -166,14 +166,14 @@ test_expect_success 'find value with highest priority from a configset' ' ' test_expect_success 'find value_list for a key from a configset' ' - cat >except <<-\EOF && + cat >expect <<-\EOF && + lama + ball sam bat hask - lama - ball EOF - test-tool config configset_get_value case.baz config2 .git/config >actual && + test-tool config configset_get_value_multi case.baz config2 .git/config >actual && test_cmp expect actual ' diff --git a/t/t1600-index.sh b/t/t1600-index.sh index c77721b580..b7c31aa86a 100755 --- a/t/t1600-index.sh +++ b/t/t1600-index.sh @@ -87,6 +87,10 @@ test_index_version () { } test_expect_success 'index version config precedence' ' + test_index_version 0 false 0 2 && + test_index_version 2 false 0 2 && + test_index_version 3 false 0 2 && + test_index_version 4 false 0 4 && test_index_version 2 false 4 4 && test_index_version 2 true 0 2 && test_index_version 0 true 0 4 && diff --git a/t/t3906-stash-submodule.sh b/t/t3906-stash-submodule.sh index d7219d6f8f..b93d1d74da 100755 --- a/t/t3906-stash-submodule.sh +++ b/t/t3906-stash-submodule.sh @@ -1,6 +1,6 @@ #!/bin/sh -test_description='stash apply can handle submodules' +test_description='stash can handle submodules' . ./test-lib.sh . "$TEST_DIRECTORY"/lib-submodule-update.sh @@ -21,4 +21,44 @@ KNOWN_FAILURE_CHERRY_PICK_SEES_EMPTY_COMMIT=1 KNOWN_FAILURE_NOFF_MERGE_DOESNT_CREATE_EMPTY_SUBMODULE_DIR=1 test_submodule_switch "git_stash" +setup_basic () { + test_when_finished "rm -rf main sub" && + git init sub && + ( + cd sub && + test_commit sub_file + ) && + git init main && + ( + cd main && + git submodule add ../sub && + test_commit main_file + ) +} + +test_expect_success 'stash push with submodule.recurse=true preserves dirty submodule worktree' ' + setup_basic && + ( + cd main && + git config submodule.recurse true && + echo "x" >main_file.t && + echo "y" >sub/sub_file.t && + git stash push && + test_must_fail git -C sub diff --quiet + ) +' + +test_expect_success 'stash push and pop with submodule.recurse=true preserves dirty submodule worktree' ' + setup_basic && + ( + cd main && + git config submodule.recurse true && + echo "x" >main_file.t && + echo "y" >sub/sub_file.t && + git stash push && + git stash pop && + test_must_fail git -C sub diff --quiet + ) +' + test_done diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh index 72b09896cf..b8969998b5 100755 --- a/t/t4014-format-patch.sh +++ b/t/t4014-format-patch.sh @@ -1606,6 +1606,32 @@ test_expect_success 'From line has expected format' ' test_cmp from filtered ' +test_expect_success 'format-patch -o with no leading directories' ' + rm -fr patches && + git format-patch -o patches master..side && + count=$(git rev-list --count master..side) && + ls patches >list && + test_line_count = $count list +' + +test_expect_success 'format-patch -o with leading existing directories' ' + rm -rf existing-dir && + mkdir existing-dir && + git format-patch -o existing-dir/patches master..side && + count=$(git rev-list --count master..side) && + ls existing-dir/patches >list && + test_line_count = $count list +' + +test_expect_success 'format-patch -o with leading non-existing directories' ' + rm -rf non-existing-dir && + git format-patch -o non-existing-dir/patches master..side && + count=$(git rev-list --count master..side) && + test_path_is_dir non-existing-dir && + ls non-existing-dir/patches >list && + test_line_count = $count list +' + test_expect_success 'format-patch format.outputDirectory option' ' test_config format.outputDirectory patches && rm -fr patches && diff --git a/t/t4018/dts-nodes-boolean-prop b/t/t4018/dts-nodes-boolean-prop new file mode 100644 index 0000000000..afc6b5b404 --- /dev/null +++ b/t/t4018/dts-nodes-boolean-prop @@ -0,0 +1,9 @@ +/ { + label_1: node1@ff00 { + RIGHT@deadf00,4000 { + boolean-prop1; + + ChangeMe; + }; + }; +}; diff --git a/t/t4018/dts-nodes-multiline-prop b/t/t4018/dts-nodes-multiline-prop new file mode 100644 index 0000000000..072d58b69d --- /dev/null +++ b/t/t4018/dts-nodes-multiline-prop @@ -0,0 +1,13 @@ +/ { + label_1: node1@ff00 { + RIGHT@deadf00,4000 { + multilineprop = <3>, + <4>, + <5>, + <6>, + <7>; + + ChangeMe = <0xffeedd00>; + }; + }; +}; diff --git a/t/t4018/dts-root b/t/t4018/dts-root index 2ef9e6ffaa..4353b8220c 100644 --- a/t/t4018/dts-root +++ b/t/t4018/dts-root @@ -1,4 +1,4 @@ -/RIGHT { /* Technically just supposed to be a slash */ +/ { RIGHT /* Technically just supposed to be a slash and brace */ #size-cells = <1>; ChangeMe = <0xffeedd00>; diff --git a/t/t4018/dts-root-comment b/t/t4018/dts-root-comment new file mode 100644 index 0000000000..333a625c70 --- /dev/null +++ b/t/t4018/dts-root-comment @@ -0,0 +1,8 @@ +/ { RIGHT /* Technically just supposed to be a slash and brace */ + #size-cells = <1>; + + /* This comment should be ignored */ + + some-property = <40+2>; + ChangeMe = <0xffeedd00>; +}; diff --git a/t/t5541-http-push-smart.sh b/t/t5541-http-push-smart.sh index 92bac43257..4c970787b0 100755 --- a/t/t5541-http-push-smart.sh +++ b/t/t5541-http-push-smart.sh @@ -184,11 +184,12 @@ test_expect_success 'push --atomic also prevents branch creation, reports collat test_config -C "$d" http.receivepack true && up="$HTTPD_URL"/smart/atomic-branches.git && - # Tell "$up" about two branches for now + # Tell "$up" about three branches for now test_commit atomic1 && test_commit atomic2 && git branch collateral && - git push "$up" master collateral && + git branch other && + git push "$up" master collateral other && # collateral is a valid push, but should be failed by atomic push git checkout collateral && @@ -226,6 +227,41 @@ test_expect_success 'push --atomic also prevents branch creation, reports collat grep "^ ! .*rejected.* collateral -> collateral .*atomic push failed" output ' +test_expect_success 'push --atomic fails on server-side errors' ' + # Use previously set up repository + d=$HTTPD_DOCUMENT_ROOT_PATH/atomic-branches.git && + test_config -C "$d" http.receivepack true && + up="$HTTPD_URL"/smart/atomic-branches.git && + + # break ref updates for other on the remote site + mkdir "$d/refs/heads/other.lock" && + + # add the new commit to other + git branch -f other collateral && + + # --atomic should cause entire push to be rejected + test_must_fail git push --atomic "$up" atomic other 2>output && + + # the new branch should not have been created upstream + test_must_fail git -C "$d" show-ref --verify refs/heads/atomic && + + # upstream should still reflect atomic2, the last thing we pushed + # successfully + git rev-parse atomic2 >expected && + # ...to other. + git -C "$d" rev-parse refs/heads/other >actual && + test_cmp expected actual && + + # the new branch should not have been created upstream + test_must_fail git -C "$d" show-ref --verify refs/heads/atomic && + + # the failed refs should be indicated to the user + grep "^ ! .*rejected.* other -> other .*atomic transaction failed" output && + + # the collateral failure refs should be indicated to the user + grep "^ ! .*rejected.* atomic -> atomic .*atomic transaction failed" output +' + test_expect_success 'push --all can push to empty repo' ' d=$HTTPD_DOCUMENT_ROOT_PATH/empty-all.git && git init --bare "$d" && diff --git a/t/t7419-submodule-set-branch.sh b/t/t7419-submodule-set-branch.sh index c4b370ea85..fd25f786a3 100755 --- a/t/t7419-submodule-set-branch.sh +++ b/t/t7419-submodule-set-branch.sh @@ -34,7 +34,7 @@ test_expect_success 'submodule config cache setup' ' test_expect_success 'ensure submodule branch is unset' ' (cd super && - test_must_fail grep branch .gitmodules + ! grep branch .gitmodules ) ' @@ -54,7 +54,7 @@ test_expect_success 'test submodule set-branch --branch' ' test_expect_success 'test submodule set-branch --default' ' (cd super && git submodule set-branch --default submodule && - test_must_fail grep branch .gitmodules && + ! grep branch .gitmodules && git submodule update --remote && cat <<-\EOF >expect && a @@ -80,7 +80,7 @@ test_expect_success 'test submodule set-branch -b' ' test_expect_success 'test submodule set-branch -d' ' (cd super && git submodule set-branch -d submodule && - test_must_fail grep branch .gitmodules && + ! grep branch .gitmodules && git submodule update --remote && cat <<-\EOF >expect && a diff --git a/t/t7519-status-fsmonitor.sh b/t/t7519-status-fsmonitor.sh index 81a375fa0f..d8df990972 100755 --- a/t/t7519-status-fsmonitor.sh +++ b/t/t7519-status-fsmonitor.sh @@ -354,4 +354,21 @@ test_expect_success 'discard_index() also discards fsmonitor info' ' test_cmp expect actual ' +# Test staging/unstaging files that appear at the end of the index. Test +# file names begin with 'z' so that they are sorted to the end of the index. +test_expect_success 'status succeeds after staging/unstaging ' ' + test_create_repo fsmonitor-stage-unstage && + ( + cd fsmonitor-stage-unstage && + test_commit initial && + git update-index --fsmonitor && + removed=$(test_seq 1 100 | sed "s/^/z/") && + touch $removed && + git add $removed && + git config core.fsmonitor "$TEST_DIRECTORY/t7519/fsmonitor-env" && + FSMONITOR_LIST="$removed" git restore -S $removed && + FSMONITOR_LIST="$removed" git status + ) +' + test_done diff --git a/t/t7519/fsmonitor-env b/t/t7519/fsmonitor-env new file mode 100755 index 0000000000..8f1f7ab164 --- /dev/null +++ b/t/t7519/fsmonitor-env @@ -0,0 +1,24 @@ +#!/bin/sh +# +# An test hook script to integrate with git to test fsmonitor. +# +# The hook is passed a version (currently 1) and a time in nanoseconds +# formatted as a string and outputs to stdout all files that have been +# modified since the given time. Paths must be relative to the root of +# the working tree and separated by a single NUL. +# +#echo "$0 $*" >&2 + +if test "$#" -ne 2 +then + echo "$0: exactly 2 arguments expected" >&2 + exit 2 +fi + +if test "$1" != 1 +then + echo "Unsupported core.fsmonitor hook version." >&2 + exit 1 +fi + +printf '%s\n' $FSMONITOR_LIST diff --git a/transport-helper.c b/transport-helper.c index 9e1279b928..a9d690297e 100644 --- a/transport-helper.c +++ b/transport-helper.c @@ -854,6 +854,10 @@ static void set_common_push_options(struct transport *transport, die(_("helper %s does not support --signed=if-asked"), name); } + if (flags & TRANSPORT_PUSH_ATOMIC) + if (set_helper_option(transport, TRANS_OPT_ATOMIC, "true") != 0) + die(_("helper %s does not support --atomic"), name); + if (flags & TRANSPORT_PUSH_OPTIONS) { struct string_list_item *item; for_each_string_list_item(item, transport->push_options) diff --git a/transport.h b/transport.h index 0b5f7806f6..e0131daab9 100644 --- a/transport.h +++ b/transport.h @@ -208,6 +208,9 @@ void transport_check_allowed(const char *type); /* Filter objects for partial clone and fetch */ #define TRANS_OPT_LIST_OBJECTS_FILTER "filter" +/* Request atomic (all-or-nothing) updates when pushing */ +#define TRANS_OPT_ATOMIC "atomic" + /** * Returns 0 if the option was used, non-zero otherwise. Prints a * message to stderr if the option is not used. diff --git a/userdiff.c b/userdiff.c index 86e3244e15..e187d356f6 100644 --- a/userdiff.c +++ b/userdiff.c @@ -25,8 +25,9 @@ IPATTERN("ada", "|=>|\\.\\.|\\*\\*|:=|/=|>=|<=|<<|>>|<>"), PATTERNS("dts", "!;\n" + "!=\n" /* lines beginning with a word optionally preceded by '&' or the root */ - "^[ \t]*((/|&?[a-zA-Z_]).*)", + "^[ \t]*((/[ \t]*\\{|&?[a-zA-Z_]).*)", /* -- */ /* Property names and math operators */ "[a-zA-Z0-9,._+?#-]+" @@ -95,13 +95,11 @@ static int git_wcwidth(ucs_char_t ch) return -1; /* binary search in table of non-spacing characters */ - if (bisearch(ch, zero_width, sizeof(zero_width) - / sizeof(struct interval) - 1)) + if (bisearch(ch, zero_width, ARRAY_SIZE(zero_width) - 1)) return 0; /* binary search in table of double width characters */ - if (bisearch(ch, double_width, sizeof(double_width) - / sizeof(struct interval) - 1)) + if (bisearch(ch, double_width, ARRAY_SIZE(double_width) - 1)) return 2; return 1; |