diff --git a/Documentation/RelNotes/2.55.0.adoc b/Documentation/RelNotes/2.55.0.adoc index 63c921d9d0fc8e..82577357a065d9 100644 --- a/Documentation/RelNotes/2.55.0.adoc +++ b/Documentation/RelNotes/2.55.0.adoc @@ -33,6 +33,12 @@ UI, Workflows & Features * Misspelt proxy URL (e.g., httt://...) did not trigger any warning or failure, which has been corrected. + * Document the fact that .git/info/exclude is shared across worktrees + linked to the same repository. + + * The command line parser for "git diff" learned a few options take + only non-negative integers. + Performance, Internal Implementation, Development Support etc. -------------------------------------------------------------- @@ -56,6 +62,8 @@ Performance, Internal Implementation, Development Support etc. integration branches closer to their origin in the contributor PR builds. + * "git merge-base" optimization. + Fixes since v2.54 ----------------- @@ -153,6 +161,17 @@ Fixes since v2.54 time, which has been corrected. (merge 29364f1624 ps/maintenance-daemonize-lockfix later to maint). + * Remove ineffective strbuf presizing that would have computed an + allocation that would not have fit in the available memory anyway, + or too small due to integer wraparound to cause immediate automatic + growing. + (merge a9ce8526dc jk/pretty-no-strbuf-presizing later to maint). + + * The HTTP walker misinterpreted the alternates file that gives an + absolute path when the server URL does not have the final slash + (i.e., "https://example.com" not "https://example.com/"). + (merge b92387cd55 jk/dumb-http-alternate-fix later to maint). + * Other code cleanup, docfix, build fix, etc. (merge 80f4b802e9 ja/doc-difftool-synopsis-style later to maint). (merge b96490241e jc/doc-timestamps-in-stat later to maint). diff --git a/Documentation/git-ls-files.adoc b/Documentation/git-ls-files.adoc index 58c529afbee4c5..2b175388e1c844 100644 --- a/Documentation/git-ls-files.adoc +++ b/Documentation/git-ls-files.adoc @@ -331,7 +331,7 @@ can give `--exclude-per-directory=.gitignore`, and then specify: 1. The file specified by the `core.excludesfile` configuration variable, if exists, or the `$XDG_CONFIG_HOME/git/ignore` file. - 2. The `$GIT_DIR/info/exclude` file. + 2. The `$GIT_COMMON_DIR/info/exclude` file. via the `--exclude-from=` option. diff --git a/Documentation/git-svn.adoc b/Documentation/git-svn.adoc index c26c12bab37abf..2a7fa60465c5fb 100644 --- a/Documentation/git-svn.adoc +++ b/Documentation/git-svn.adoc @@ -439,7 +439,7 @@ Any other arguments are passed directly to 'git log' 'show-ignore':: Recursively finds and lists the svn:ignore and svn:global-ignores properties on directories. The output is suitable for appending to - the $GIT_DIR/info/exclude file. + the $GIT_COMMON_DIR/info/exclude file. 'mkdirs':: Attempts to recreate empty directories that core Git cannot track diff --git a/Documentation/gitformat-index.adoc b/Documentation/gitformat-index.adoc index 145cace1fe9fd3..f6a427cb495990 100644 --- a/Documentation/gitformat-index.adoc +++ b/Documentation/gitformat-index.adoc @@ -291,14 +291,14 @@ Git index format sequence in variable width encoding. Each string describes the environment where the cache can be used. - - Stat data of $GIT_DIR/info/exclude. See "Index entry" section from + - Stat data of $GIT_COMMON_DIR/info/exclude. See "Index entry" section from ctime field until "file size". - Stat data of core.excludesFile - 32-bit dir_flags (see struct dir_struct) - - Hash of $GIT_DIR/info/exclude. A null hash means the file + - Hash of $GIT_COMMON_DIR/info/exclude. A null hash means the file does not exist. - Hash of core.excludesFile. A null hash means the file does diff --git a/Documentation/gitignore.adoc b/Documentation/gitignore.adoc index a3d24e5c34aabc..7979e50f187e23 100644 --- a/Documentation/gitignore.adoc +++ b/Documentation/gitignore.adoc @@ -7,7 +7,7 @@ gitignore - Specifies intentionally untracked files to ignore SYNOPSIS -------- -$XDG_CONFIG_HOME/git/ignore, $GIT_DIR/info/exclude, .gitignore +$XDG_CONFIG_HOME/git/ignore, $GIT_COMMON_DIR/info/exclude, .gitignore DESCRIPTION ----------- @@ -34,7 +34,7 @@ precedence, the last matching pattern decides the outcome): includes such `.gitignore` files in its repository, containing patterns for files generated as part of the project build. - * Patterns read from `$GIT_DIR/info/exclude`. + * Patterns read from `$GIT_COMMON_DIR/info/exclude`. * Patterns read from the file specified by the configuration variable `core.excludesFile`. @@ -50,7 +50,7 @@ be used. specific to a particular repository but which do not need to be shared with other related repositories (e.g., auxiliary files that live inside the repository but are specific to one user's workflow) should go into - the `$GIT_DIR/info/exclude` file. + the `$GIT_COMMON_DIR/info/exclude` file. * Patterns which a user wants Git to ignore in all situations (e.g., backup or temporary files generated by @@ -97,7 +97,7 @@ PATTERN FORMAT match at any level below the `.gitignore` level. - Patterns read from exclude sources that are outside the working tree, - such as $GIT_DIR/info/exclude and core.excludesFile, are treated as if + such as $GIT_COMMON_DIR/info/exclude and core.excludesFile, are treated as if they are specified at the root of the working tree, i.e. a leading "/" in such patterns anchors the match at the root of the repository. @@ -146,8 +146,8 @@ CONFIGURATION The optional configuration variable `core.excludesFile` indicates a path to a file containing patterns of file names to exclude, similar to -`$GIT_DIR/info/exclude`. Patterns in the exclude file are used in addition to -those in `$GIT_DIR/info/exclude`. +`$GIT_COMMON_DIR/info/exclude`. Patterns in the exclude file are used in +addition to those in `$GIT_COMMON_DIR/info/exclude`. NOTES ----- diff --git a/builtin/merge-base.c b/builtin/merge-base.c index c7ee97fa6ac62a..a87011c6cdab46 100644 --- a/builtin/merge-base.c +++ b/builtin/merge-base.c @@ -11,10 +11,12 @@ static int show_merge_base(struct commit **rev, size_t rev_nr, int show_all) { + enum merge_base_flags flags = show_all ? MERGE_BASE_FIND_ALL : 0; struct commit_list *result = NULL, *r; if (repo_get_merge_bases_many_dirty(the_repository, rev[0], - rev_nr - 1, rev + 1, &result) < 0) { + rev_nr - 1, rev + 1, + flags, &result) < 0) { commit_list_free(result); return -1; } diff --git a/commit-reach.c b/commit-reach.c index d3a9b3ed6fe561..5a52be90a66f5a 100644 --- a/commit-reach.c +++ b/commit-reach.c @@ -54,7 +54,7 @@ static int paint_down_to_common(struct repository *r, struct commit *one, int n, struct commit **twos, timestamp_t min_generation, - int ignore_missing_commits, + enum merge_base_flags mb_flags, struct commit_list **result) { struct prio_queue queue = { compare_commits_by_gen_then_commit_date }; @@ -97,6 +97,14 @@ static int paint_down_to_common(struct repository *r, if (!(commit->object.flags & RESULT)) { commit->object.flags |= RESULT; tail = commit_list_append(commit, tail); + /* + * The queue is generation-ordered; no + * remaining common ancestor can be a + * descendant of this one. + */ + if (!(mb_flags & MERGE_BASE_FIND_ALL) && + generation < GENERATION_NUMBER_INFINITY) + break; } /* Mark parents of a found merge stale */ flags |= STALE; @@ -118,7 +126,7 @@ static int paint_down_to_common(struct repository *r, * corrupt commits would already have been * dispatched with a `die()`. */ - if (ignore_missing_commits) + if (mb_flags & MERGE_BASE_IGNORE_MISSING_COMMITS) return 0; return error(_("could not parse commit %s"), oid_to_hex(&p->object.oid)); @@ -136,6 +144,7 @@ static int paint_down_to_common(struct repository *r, static int merge_bases_many(struct repository *r, struct commit *one, int n, struct commit **twos, + enum merge_base_flags mb_flags, struct commit_list **result) { struct commit_list *list = NULL, **tail = result; @@ -165,7 +174,7 @@ static int merge_bases_many(struct repository *r, oid_to_hex(&twos[i]->object.oid)); } - if (paint_down_to_common(r, one, n, twos, 0, 0, &list)) { + if (paint_down_to_common(r, one, n, twos, 0, mb_flags, &list)) { commit_list_free(list); return -1; } @@ -246,7 +255,8 @@ static int remove_redundant_no_gen(struct repository *r, min_generation = curr_generation; } if (paint_down_to_common(r, array[i], filled, - work, min_generation, 0, &common)) { + work, min_generation, + MERGE_BASE_FIND_ALL, &common)) { clear_commit_marks(array[i], all_flags); clear_commit_marks_many(filled, work, all_flags); commit_list_free(common); @@ -425,6 +435,7 @@ static int get_merge_bases_many_0(struct repository *r, size_t n, struct commit **twos, int cleanup, + enum merge_base_flags mb_flags, struct commit_list **result) { struct commit_list *list, **tail = result; @@ -432,7 +443,7 @@ static int get_merge_bases_many_0(struct repository *r, size_t cnt, i; int ret; - if (merge_bases_many(r, one, n, twos, result) < 0) + if (merge_bases_many(r, one, n, twos, mb_flags, result) < 0) return -1; for (i = 0; i < n; i++) { if (one == twos[i]) @@ -475,16 +486,18 @@ int repo_get_merge_bases_many(struct repository *r, struct commit **twos, struct commit_list **result) { - return get_merge_bases_many_0(r, one, n, twos, 1, result); + return get_merge_bases_many_0(r, one, n, twos, 1, + MERGE_BASE_FIND_ALL, result); } int repo_get_merge_bases_many_dirty(struct repository *r, struct commit *one, size_t n, struct commit **twos, + enum merge_base_flags mb_flags, struct commit_list **result) { - return get_merge_bases_many_0(r, one, n, twos, 0, result); + return get_merge_bases_many_0(r, one, n, twos, 0, mb_flags, result); } int repo_get_merge_bases(struct repository *r, @@ -492,7 +505,8 @@ int repo_get_merge_bases(struct repository *r, struct commit *two, struct commit_list **result) { - return get_merge_bases_many_0(r, one, 1, &two, 1, result); + return get_merge_bases_many_0(r, one, 1, &two, 1, + MERGE_BASE_FIND_ALL, result); } /* @@ -537,6 +551,10 @@ int repo_in_merge_bases_many(struct repository *r, struct commit *commit, struct commit_list *bases = NULL; int ret = 0, i; timestamp_t generation, max_generation = GENERATION_NUMBER_ZERO; + enum merge_base_flags mb_flags = MERGE_BASE_FIND_ALL; + + if (ignore_missing_commits) + mb_flags |= MERGE_BASE_IGNORE_MISSING_COMMITS; if (repo_parse_commit(r, commit)) return ignore_missing_commits ? 0 : -1; @@ -555,7 +573,7 @@ int repo_in_merge_bases_many(struct repository *r, struct commit *commit, if (paint_down_to_common(r, commit, nr_reference, reference, - generation, ignore_missing_commits, &bases)) + generation, mb_flags, &bases)) ret = -1; else if (commit->object.flags & PARENT2) ret = 1; diff --git a/commit-reach.h b/commit-reach.h index 6012402dfcfe45..3f3a563d8a5dd1 100644 --- a/commit-reach.h +++ b/commit-reach.h @@ -17,10 +17,20 @@ int repo_get_merge_bases_many(struct repository *r, struct commit *one, size_t n, struct commit **twos, struct commit_list **result); -/* To be used only when object flags after this call no longer matter */ +enum merge_base_flags { + MERGE_BASE_IGNORE_MISSING_COMMITS = (1 << 0), + MERGE_BASE_FIND_ALL = (1 << 1), +}; + +/* + * To be used only when object flags after this call no longer matter. + * Without MERGE_BASE_FIND_ALL and with generation numbers available, + * returns after finding the first merge-base, skipping the STALE drain. + */ int repo_get_merge_bases_many_dirty(struct repository *r, struct commit *one, size_t n, struct commit **twos, + enum merge_base_flags mb_flags, struct commit_list **result); int get_octopus_merge_bases(struct commit_list *in, struct commit_list **result); diff --git a/diff.c b/diff.c index 1a3b19f71f0e30..5a584fa1d569e7 100644 --- a/diff.c +++ b/diff.c @@ -60,8 +60,8 @@ static int diff_suppress_blank_empty; static enum git_colorbool diff_use_color_default = GIT_COLOR_UNKNOWN; static int diff_color_moved_default; static int diff_color_moved_ws_default; -static int diff_context_default = 3; -static int diff_interhunk_context_default; +static unsigned int diff_context_default = 3; +static unsigned int diff_interhunk_context_default; static char *diff_word_regex_cfg; static struct external_diff external_diff_cfg; static char *diff_order_file_cfg; @@ -382,16 +382,17 @@ int git_diff_ui_config(const char *var, const char *value, return 0; } if (!strcmp(var, "diff.context")) { - diff_context_default = git_config_int(var, value, ctx->kvi); - if (diff_context_default < 0) + int val = git_config_int(var, value, ctx->kvi); + if (val < 0) return -1; + diff_context_default = val; return 0; } if (!strcmp(var, "diff.interhunkcontext")) { - diff_interhunk_context_default = git_config_int(var, value, - ctx->kvi); - if (diff_interhunk_context_default < 0) + int val = git_config_int(var, value, ctx->kvi); + if (val < 0) return -1; + diff_interhunk_context_default = val; return 0; } if (!strcmp(var, "diff.renames")) { @@ -5946,9 +5947,12 @@ static int diff_opt_unified(const struct option *opt, BUG_ON_OPT_NEG(unset); if (arg) { - options->context = strtol(arg, &s, 10); + long val = strtol(arg, &s, 10); if (*s) return error(_("%s expects a numerical value"), "--unified"); + if (val < 0) + return error(_("%s expects a non-negative integer"), "--unified"); + options->context = val; } enable_patch_output(&options->output_format); @@ -6133,9 +6137,8 @@ struct option *add_diff_options(const struct option *opts, OPT_CALLBACK_F(0, "default-prefix", options, NULL, N_("use default prefixes a/ and b/"), PARSE_OPT_NONEG | PARSE_OPT_NOARG, diff_opt_default_prefix), - OPT_INTEGER_F(0, "inter-hunk-context", &options->interhunkcontext, - N_("show context between diff hunks up to the specified number of lines"), - PARSE_OPT_NONEG), + OPT_UNSIGNED(0, "inter-hunk-context", &options->interhunkcontext, + N_("show context between diff hunks up to the specified number of lines")), OPT_CALLBACK_F(0, "output-indicator-new", &options->output_indicators[OUTPUT_INDICATOR_NEW], N_(""), diff --git a/diff.h b/diff.h index 7eb84aadf40c41..bb5cddaf3499e9 100644 --- a/diff.h +++ b/diff.h @@ -294,9 +294,9 @@ struct diff_options { enum git_colorbool use_color; /* Number of context lines to generate in patch output. */ - int context; + unsigned int context; - int interhunkcontext; + unsigned int interhunkcontext; /* Affects the way detection logic for complete rewrites, renames and * copies. diff --git a/dir.c b/dir.c index fcb8f6dd2aa969..33c81c256ee925 100644 --- a/dir.c +++ b/dir.c @@ -2985,7 +2985,7 @@ static struct untracked_cache_dir *validate_untracked_cache(struct dir_struct *d return NULL; /* - * We only support $GIT_DIR/info/exclude and core.excludesfile + * We only support $GIT_COMMON_DIR/info/exclude and core.excludesfile * as the global ignore rule files. Any other additions * (e.g. from command line) invalidate the cache. This * condition also catches running setup_standard_excludes() @@ -3078,7 +3078,7 @@ static struct untracked_cache_dir *validate_untracked_cache(struct dir_struct *d istate->cache_changed |= UNTRACKED_CHANGED; } - /* Validate $GIT_DIR/info/exclude and core.excludesfile */ + /* Validate $GIT_COMMON_DIR/info/exclude and core.excludesfile */ root = dir->untracked->root; if (!oideq(&dir->internal.ss_info_exclude.oid, &dir->untracked->ss_info_exclude.oid)) { diff --git a/dir.h b/dir.h index 20d4a078d61ef8..83e0f648a81f36 100644 --- a/dir.h +++ b/dir.h @@ -153,7 +153,7 @@ struct oid_stat { * - The list of files and directories of the directory in question * - The $GIT_DIR/index * - dir_struct flags - * - The content of $GIT_DIR/info/exclude + * - The content of $GIT_COMMON_DIR/info/exclude * - The content of core.excludesfile * - The content (or the lack) of .gitignore of all parent directories * from $GIT_WORK_TREE diff --git a/http-walker.c b/http-walker.c index 1b6d496548373e..f252de089f67a0 100644 --- a/http-walker.c +++ b/http-walker.c @@ -268,7 +268,7 @@ static void process_alternates_response(void *callback_data) */ const char *colon_ss = strstr(base,"://"); if (colon_ss) { - serverlen = (strchr(colon_ss + 3, '/') + serverlen = (strchrnul(colon_ss + 3, '/') - base); okay = 1; } diff --git a/parse-options.h b/parse-options.h index 706de9729f6b3f..0d1f738f8d8671 100644 --- a/parse-options.h +++ b/parse-options.h @@ -117,6 +117,7 @@ typedef int parse_opt_subcommand_fn(int argc, const char **argv, * PARSE_OPT_OPTARG: says that the argument is optional (not for BOOLEANs) * PARSE_OPT_NOARG: says that this option does not take an argument * PARSE_OPT_NONEG: says that this option cannot be negated + * (i.e. rejects "--no-