summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/RelNotes/2.24.0.txt52
-rw-r--r--Documentation/config.txt2
-rw-r--r--Documentation/config/core.txt6
-rw-r--r--Documentation/config/diff.txt2
-rw-r--r--Documentation/config/feature.txt29
-rw-r--r--Documentation/config/fetch.txt3
-rw-r--r--Documentation/config/gc.txt2
-rw-r--r--Documentation/config/index.txt1
-rw-r--r--Documentation/config/pack.txt3
-rw-r--r--Documentation/fetch-options.txt7
-rw-r--r--Documentation/git-fast-import.txt2
-rw-r--r--Documentation/gitcli.txt6
-rw-r--r--Documentation/gitrepository-layout.txt2
-rw-r--r--Documentation/technical/api-tree-walking.txt8
-rwxr-xr-xGIT-VERSION-GEN2
-rw-r--r--Makefile1
l---------RelNotes2
-rw-r--r--archive-tar.c14
-rw-r--r--builtin/checkout.c8
-rw-r--r--builtin/commit-graph.c10
-rw-r--r--builtin/fetch.c51
-rw-r--r--builtin/gc.c12
-rw-r--r--builtin/grep.c10
-rw-r--r--builtin/merge-tree.c5
-rw-r--r--builtin/pack-objects.c8
-rw-r--r--builtin/pull.c6
-rw-r--r--builtin/update-index.c6
-rw-r--r--builtin/worktree.c2
-rw-r--r--cache-tree.c2
-rw-r--r--commit-graph.c46
-rw-r--r--commit-graph.h15
-rw-r--r--common-main.c8
-rw-r--r--compat/nedmalloc/malloc.c.h6
-rw-r--r--config.c26
-rw-r--r--diff.c1
-rw-r--r--fetch-negotiator.c25
-rw-r--r--fetch-negotiator.h5
-rw-r--r--fetch-pack.c11
-rwxr-xr-xgit-gui/git-gui.sh19
-rw-r--r--packfile.h2
-rw-r--r--parse-options.c3
-rw-r--r--parse-options.h18
-rw-r--r--read-cache.c30
-rw-r--r--refs/packed-backend.c23
-rw-r--r--repo-settings.c64
-rw-r--r--repository.h30
-rw-r--r--revision.c8
-rw-r--r--sha1-name.c9
-rwxr-xr-xt/perf/p5601-clone-reference.sh (renamed from t/perf/p5600-clone-reference.sh)0
-rwxr-xr-xt/t0000-basic.sh20
-rwxr-xr-xt/t0040-parse-options.sh7
-rwxr-xr-xt/t0410-partial-clone.sh5
-rwxr-xr-xt/t1309-early-config.sh7
-rwxr-xr-xt/t1600-index.sh31
-rwxr-xr-xt/t2022-checkout-paths.sh11
-rwxr-xr-xt/t2070-restore.sh11
-rwxr-xr-xt/t4067-diff-partial-clone.sh31
-rwxr-xr-xt/t4202-log.sh7
-rwxr-xr-xt/t5004-archive-corner-cases.sh19
-rwxr-xr-xt/t5307-pack-missing-commit.sh4
-rwxr-xr-xt/t5318-commit-graph.sh14
-rwxr-xr-xt/t5324-split-commit-graph.sh2
-rwxr-xr-xt/t5500-fetch-pack.sh3
-rwxr-xr-xt/t5510-fetch.sh47
-rwxr-xr-xt/t5537-fetch-shallow.sh3
-rwxr-xr-xt/t5545-push-options.sh3
-rwxr-xr-xt/t5552-skipping-fetch-negotiator.sh23
-rwxr-xr-xt/t5553-set-upstream.sh178
-rwxr-xr-xt/t5601-clone.sh3
-rwxr-xr-xt/t5616-partial-clone.sh3
-rwxr-xr-xt/t5700-protocol-v1.sh3
-rwxr-xr-xt/t5702-protocol-v2.sh3
-rwxr-xr-xt/t5703-upload-pack-ref-in-want.sh204
-rwxr-xr-xt/t6000-rev-list-misc.sh8
-rwxr-xr-xt/t6011-rev-list-with-bad-commit.sh2
-rwxr-xr-xt/t6501-freshen-objects.sh6
-rwxr-xr-xt/t7814-grep-recurse-submodules.sh21
-rw-r--r--t/test-lib-functions.sh4
-rw-r--r--t/test-lib.sh2
-rw-r--r--tree-walk.c64
-rw-r--r--tree-walk.h18
-rw-r--r--unpack-trees.c74
82 files changed, 1050 insertions, 404 deletions
diff --git a/Documentation/RelNotes/2.24.0.txt b/Documentation/RelNotes/2.24.0.txt
new file mode 100644
index 0000000000..a95a8b0084
--- /dev/null
+++ b/Documentation/RelNotes/2.24.0.txt
@@ -0,0 +1,52 @@
+Git 2.24 Release Notes
+======================
+
+Updates since v2.23
+-------------------
+
+Backward compatibility note
+
+ * (no entry yet so far)
+
+
+UI, Workflows & Features
+
+ * (no entry yet so far)
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * The code to write commit-graph over given commit object names has
+ been made a bit more robust.
+
+ * The first line of verbose output from each test piece now carries
+ the test name and number to help scanning with eyeballs.
+
+
+Fixes since v2.23
+-----------------
+
+ * "git grep --recurse-submodules" that looks at the working tree
+ files looked at the contents in the index in submodules, instead of
+ files in the working tree.
+ (merge 6a289d45c0 mt/grep-submodules-working-tree later to maint).
+
+ * Codepaths to walk tree objects have been audited for integer
+ overflows and hardened.
+ (merge 5aa02f9868 jk/tree-walk-overflow later to maint).
+
+ * "git pack-refs" can lose refs that are created while running, which
+ is getting corrected.
+ (merge a613d4f817 sc/pack-refs-deletion-racefix later to maint).
+
+ * "git checkout" and "git restore" to re-populate the index from a
+ tree-ish (typically HEAD) did not work correctly for a path that
+ was removed and then added again with the intent-to-add bit, when
+ the corresponding working tree file was empty. This has been
+ corrected.
+
+ * Compilation fix.
+ (merge 70597e8386 rs/nedalloc-fixlets later to maint).
+
+ * Other code cleanup, docfix, build fix, etc.
+ (merge d1387d3895 en/fast-import-merge-doc later to maint).
diff --git a/Documentation/config.txt b/Documentation/config.txt
index e3f5bc3396..77f3b1486b 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -345,6 +345,8 @@ include::config/difftool.txt[]
include::config/fastimport.txt[]
+include::config/feature.txt[]
+
include::config/fetch.txt[]
include::config/format.txt[]
diff --git a/Documentation/config/core.txt b/Documentation/config/core.txt
index 75538d27e7..852d2ba37a 100644
--- a/Documentation/config/core.txt
+++ b/Documentation/config/core.txt
@@ -86,7 +86,9 @@ core.untrackedCache::
it will automatically be removed, if set to `false`. Before
setting it to `true`, you should check that mtime is working
properly on your system.
- See linkgit:git-update-index[1]. `keep` by default.
+ See linkgit:git-update-index[1]. `keep` by default, unless
+ `feature.manyFiles` is enabled which sets this setting to
+ `true` by default.
core.checkStat::
When missing or is set to `default`, many fields in the stat
@@ -577,7 +579,7 @@ the `GIT_NOTES_REF` environment variable. See linkgit:git-notes[1].
core.commitGraph::
If true, then git will read the commit-graph file (if it exists)
- to parse the graph structure of commits. Defaults to false. See
+ to parse the graph structure of commits. Defaults to true. See
linkgit:git-commit-graph[1] for more information.
core.useReplaceRefs::
diff --git a/Documentation/config/diff.txt b/Documentation/config/diff.txt
index 5afb5a2cbc..ff09f1cf73 100644
--- a/Documentation/config/diff.txt
+++ b/Documentation/config/diff.txt
@@ -189,7 +189,7 @@ diff.guitool::
include::../mergetools-diff.txt[]
diff.indentHeuristic::
- Set this option to `true` to enable experimental heuristics
+ Set this option to `false` to disable the default heuristics
that shift diff hunk boundaries to make patches easier to read.
diff.algorithm::
diff --git a/Documentation/config/feature.txt b/Documentation/config/feature.txt
new file mode 100644
index 0000000000..545522f306
--- /dev/null
+++ b/Documentation/config/feature.txt
@@ -0,0 +1,29 @@
+feature.*::
+ The config settings that start with `feature.` modify the defaults of
+ a group of other config settings. These groups are created by the Git
+ developer community as recommended defaults and are subject to change.
+ In particular, new config options may be added with different defaults.
+
+feature.experimental::
+ Enable config options that are new to Git, and are being considered for
+ future defaults. Config settings included here may be added or removed
+ with each release, including minor version updates. These settings may
+ have unintended interactions since they are so new. Please enable this
+ setting if you are interested in providing feedback on experimental
+ features. The new default values are:
++
+* `pack.useSparse=true` uses a new algorithm when constructing a pack-file
+which can improve `git push` performance in repos with many files.
++
+* `fetch.negotiationAlgorithm=skipping` may improve fetch negotiation times by
+skipping more commits at a time, reducing the number of round trips.
+
+feature.manyFiles::
+ Enable config options that optimize for repos with many files in the
+ working directory. With many files, commands such as `git status` and
+ `git checkout` may be slow and these new defaults improve performance:
++
+* `index.version=4` enables path-prefix compression in the index.
++
+* `core.untrackedCache=true` enables the untracked cache. This setting assumes
+that mtime is working on your machine.
diff --git a/Documentation/config/fetch.txt b/Documentation/config/fetch.txt
index ba890b5884..d402110638 100644
--- a/Documentation/config/fetch.txt
+++ b/Documentation/config/fetch.txt
@@ -59,7 +59,8 @@ fetch.negotiationAlgorithm::
effort to converge faster, but may result in a larger-than-necessary
packfile; The default is "default" which instructs Git to use the default algorithm
that never skips commits (unless the server has acknowledged it or one
- of its descendants).
+ of its descendants). If `feature.experimental` is enabled, then this
+ setting defaults to "skipping".
Unknown values will cause 'git fetch' to error out.
+
See also the `--negotiation-tip` option for linkgit:git-fetch[1].
diff --git a/Documentation/config/gc.txt b/Documentation/config/gc.txt
index 02b92b18b5..00ea0a678e 100644
--- a/Documentation/config/gc.txt
+++ b/Documentation/config/gc.txt
@@ -63,7 +63,7 @@ gc.writeCommitGraph::
If true, then gc will rewrite the commit-graph file when
linkgit:git-gc[1] is run. When using `git gc --auto`
the commit-graph will be updated if housekeeping is
- required. Default is false. See linkgit:git-commit-graph[1]
+ required. Default is true. See linkgit:git-commit-graph[1]
for details.
gc.logExpiry::
diff --git a/Documentation/config/index.txt b/Documentation/config/index.txt
index f181503041..7cb50b37e9 100644
--- a/Documentation/config/index.txt
+++ b/Documentation/config/index.txt
@@ -24,3 +24,4 @@ index.threads::
index.version::
Specify the version with which new index files should be
initialized. This does not affect existing repositories.
+ If `feature.manyFiles` is enabled, then the default is 4.
diff --git a/Documentation/config/pack.txt b/Documentation/config/pack.txt
index 9cdcfa7324..1d66f0c992 100644
--- a/Documentation/config/pack.txt
+++ b/Documentation/config/pack.txt
@@ -112,7 +112,8 @@ pack.useSparse::
objects. This can have significant performance benefits when
computing a pack to send a small change. However, it is possible
that extra objects are added to the pack-file if the included
- commits contain certain types of direct renames.
+ commits contain certain types of direct renames. Default is `false`
+ unless `feature.experimental` is enabled.
pack.writeBitmaps (deprecated)::
This is a deprecated synonym for `repack.writeBitmaps`.
diff --git a/Documentation/fetch-options.txt b/Documentation/fetch-options.txt
index 3c9b4f9e09..99df1f3d4e 100644
--- a/Documentation/fetch-options.txt
+++ b/Documentation/fetch-options.txt
@@ -169,6 +169,13 @@ ifndef::git-pull[]
Disable recursive fetching of submodules (this has the same effect as
using the `--recurse-submodules=no` option).
+--set-upstream::
+ If the remote is fetched successfully, pull and add upstream
+ (tracking) reference, used by argument-less
+ linkgit:git-pull[1] and other commands. For more information,
+ see `branch.<name>.merge` and `branch.<name>.remote` in
+ linkgit:git-config[1].
+
--submodule-prefix=<path>::
Prepend <path> to paths printed in informative messages
such as "Fetching submodule foo". This option is used
diff --git a/Documentation/git-fast-import.txt b/Documentation/git-fast-import.txt
index fad327aecc..0bb276269e 100644
--- a/Documentation/git-fast-import.txt
+++ b/Documentation/git-fast-import.txt
@@ -391,7 +391,7 @@ change to the project.
('encoding' SP <encoding>)?
data
('from' SP <commit-ish> LF)?
- ('merge' SP <commit-ish> LF)?
+ ('merge' SP <commit-ish> LF)*
(filemodify | filedelete | filecopy | filerename | filedeleteall | notemodify)*
LF?
....
diff --git a/Documentation/gitcli.txt b/Documentation/gitcli.txt
index 1ed3ca33b7..4b32876b6e 100644
--- a/Documentation/gitcli.txt
+++ b/Documentation/gitcli.txt
@@ -37,6 +37,12 @@ arguments. Here are the rules:
file called HEAD in your work tree, `git diff HEAD` is ambiguous, and
you have to say either `git diff HEAD --` or `git diff -- HEAD` to
disambiguate.
+
+ * Because `--` disambiguates revisions and paths in some commands, it
+ cannot be used for those commands to separate options and revisions.
+ You can use `--end-of-options` for this (it also works for commands
+ that do not distinguish between revisions in paths, in which case it
+ is simply an alias for `--`).
+
When writing a script that is expected to handle random user-input, it is
a good practice to make it explicit which arguments are which by placing
diff --git a/Documentation/gitrepository-layout.txt b/Documentation/gitrepository-layout.txt
index 216b11ee88..d6388f10bb 100644
--- a/Documentation/gitrepository-layout.txt
+++ b/Documentation/gitrepository-layout.txt
@@ -59,7 +59,7 @@ objects/[0-9a-f][0-9a-f]::
here are often called 'unpacked' (or 'loose') objects.
objects/pack::
- Packs (files that store many object in compressed form,
+ Packs (files that store many objects in compressed form,
along with index files to allow them to be randomly
accessed) are found in this directory.
diff --git a/Documentation/technical/api-tree-walking.txt b/Documentation/technical/api-tree-walking.txt
index bde18622a8..7962e32854 100644
--- a/Documentation/technical/api-tree-walking.txt
+++ b/Documentation/technical/api-tree-walking.txt
@@ -62,9 +62,7 @@ Initializing
`setup_traverse_info`::
Initialize a `traverse_info` given the pathname of the tree to start
- traversing from. The `base` argument is assumed to be the `path`
- member of the `name_entry` being recursed into unless the tree is a
- top-level tree in which case the empty string ("") is used.
+ traversing from.
Walking
-------
@@ -140,6 +138,10 @@ same in the next callback invocation.
This utilizes the memory structure of a tree entry to avoid the
overhead of using a generic strlen().
+`strbuf_make_traverse_path`::
+
+ Convenience wrapper to `make_traverse_path` into a strbuf.
+
Authors
-------
diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN
index a1539a7ce6..98f88a28d3 100755
--- a/GIT-VERSION-GEN
+++ b/GIT-VERSION-GEN
@@ -1,7 +1,7 @@
#!/bin/sh
GVF=GIT-VERSION-FILE
-DEF_VER=v2.23.0
+DEF_VER=v2.23.GIT
LF='
'
diff --git a/Makefile b/Makefile
index f9255344ae..ad71ae1219 100644
--- a/Makefile
+++ b/Makefile
@@ -965,6 +965,7 @@ LIB_OBJS += refspec.o
LIB_OBJS += ref-filter.o
LIB_OBJS += remote.o
LIB_OBJS += replace-object.o
+LIB_OBJS += repo-settings.o
LIB_OBJS += repository.o
LIB_OBJS += rerere.o
LIB_OBJS += resolve-undo.o
diff --git a/RelNotes b/RelNotes
index 248d137c43..fc657e7d2f 120000
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes/2.23.0.txt \ No newline at end of file
+Documentation/RelNotes/2.24.0.txt \ No newline at end of file
diff --git a/archive-tar.c b/archive-tar.c
index 3e53aac1e6..e16d3f756d 100644
--- a/archive-tar.c
+++ b/archive-tar.c
@@ -142,19 +142,25 @@ static int stream_blocked(const struct object_id *oid)
* string and appends it to a struct strbuf.
*/
static void strbuf_append_ext_header(struct strbuf *sb, const char *keyword,
- const char *value, unsigned int valuelen)
+ const char *value, size_t valuelen)
{
- int len, tmp;
+ size_t orig_len = sb->len;
+ size_t len, tmp;
/* "%u %s=%s\n" */
len = 1 + 1 + strlen(keyword) + 1 + valuelen + 1;
- for (tmp = len; tmp > 9; tmp /= 10)
+ for (tmp = 1; len / 10 >= tmp; tmp *= 10)
len++;
strbuf_grow(sb, len);
- strbuf_addf(sb, "%u %s=", len, keyword);
+ strbuf_addf(sb, "%"PRIuMAX" %s=", (uintmax_t)len, keyword);
strbuf_add(sb, value, valuelen);
strbuf_addch(sb, '\n');
+
+ if (len != sb->len - orig_len)
+ BUG("pax extended header length miscalculated as %"PRIuMAX
+ ", should be %"PRIuMAX,
+ (uintmax_t)len, (uintmax_t)(sb->len - orig_len));
}
/*
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 6123f732a2..0a3679eb77 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -126,6 +126,7 @@ static int update_some(const struct object_id *oid, struct strbuf *base,
if (pos >= 0) {
struct cache_entry *old = active_cache[pos];
if (ce->ce_mode == old->ce_mode &&
+ !ce_intent_to_add(old) &&
oideq(&ce->oid, &old->oid)) {
old->ce_flags |= CE_UPDATE;
discard_cache_entry(ce);
@@ -730,13 +731,6 @@ static int merge_working_tree(const struct checkout_opts *opts,
"the following files:\n%s"), sb.buf);
strbuf_release(&sb);
- if (repo_index_has_changes(the_repository,
- get_commit_tree(old_branch_info->commit),
- &sb))
- warning(_("staged changes in the following files may be lost: %s"),
- sb.buf);
- strbuf_release(&sb);
-
/* Do more real merge */
/*
diff --git a/builtin/commit-graph.c b/builtin/commit-graph.c
index 38027b83d9..57863619b7 100644
--- a/builtin/commit-graph.c
+++ b/builtin/commit-graph.c
@@ -154,7 +154,7 @@ static int graph_write(int argc, const char **argv)
struct string_list *commit_hex = NULL;
struct string_list lines;
int result = 0;
- unsigned int flags = COMMIT_GRAPH_PROGRESS;
+ enum commit_graph_write_flags flags = COMMIT_GRAPH_WRITE_PROGRESS;
static struct option builtin_commit_graph_write_options[] = {
OPT_STRING(0, "object-dir", &opts.obj_dir,
@@ -192,9 +192,9 @@ static int graph_write(int argc, const char **argv)
if (!opts.obj_dir)
opts.obj_dir = get_object_directory();
if (opts.append)
- flags |= COMMIT_GRAPH_APPEND;
+ flags |= COMMIT_GRAPH_WRITE_APPEND;
if (opts.split)
- flags |= COMMIT_GRAPH_SPLIT;
+ flags |= COMMIT_GRAPH_WRITE_SPLIT;
read_replace_refs = 0;
@@ -213,8 +213,10 @@ static int graph_write(int argc, const char **argv)
if (opts.stdin_packs)
pack_indexes = &lines;
- if (opts.stdin_commits)
+ if (opts.stdin_commits) {
commit_hex = &lines;
+ flags |= COMMIT_GRAPH_WRITE_CHECK_OIDS;
+ }
UNLEAK(buf);
}
diff --git a/builtin/fetch.c b/builtin/fetch.c
index 717dd14e89..54d6b01892 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -23,6 +23,7 @@
#include "packfile.h"
#include "list-objects-filter-options.h"
#include "commit-reach.h"
+#include "branch.h"
#define FORCED_UPDATES_DELAY_WARNING_IN_MS (10 * 1000)
@@ -50,7 +51,8 @@ static int fetch_prune_tags_config = -1; /* unspecified */
static int prune_tags = -1; /* unspecified */
#define PRUNE_TAGS_BY_DEFAULT 0 /* do we prune tags by default? */
-static int all, append, dry_run, force, keep, multiple, update_head_ok, verbosity, deepen_relative;
+static int all, append, dry_run, force, keep, multiple, update_head_ok;
+static int verbosity, deepen_relative, set_upstream;
static int progress = -1;
static int enable_auto_gc = 1;
static int tags = TAGS_DEFAULT, unshallow, update_shallow, deepen;
@@ -123,6 +125,8 @@ static struct option builtin_fetch_options[] = {
OPT__VERBOSITY(&verbosity),
OPT_BOOL(0, "all", &all,
N_("fetch from all remotes")),
+ OPT_BOOL(0, "set-upstream", &set_upstream,
+ N_("set upstream for git pull/fetch")),
OPT_BOOL('a', "append", &append,
N_("append to .git/FETCH_HEAD instead of overwriting")),
OPT_STRING(0, "upload-pack", &upload_pack, N_("path"),
@@ -1367,6 +1371,51 @@ static int do_fetch(struct transport *transport,
retcode = 1;
goto cleanup;
}
+
+ if (set_upstream) {
+ struct branch *branch = branch_get("HEAD");
+ struct ref *rm;
+ struct ref *source_ref = NULL;
+
+ /*
+ * We're setting the upstream configuration for the
+ * current branch. The relevent upstream is the
+ * fetched branch that is meant to be merged with the
+ * current one, i.e. the one fetched to FETCH_HEAD.
+ *
+ * When there are several such branches, consider the
+ * request ambiguous and err on the safe side by doing
+ * nothing and just emit a warning.
+ */
+ for (rm = ref_map; rm; rm = rm->next) {
+ if (!rm->peer_ref) {
+ if (source_ref) {
+ warning(_("multiple branch detected, incompatible with --set-upstream"));
+ goto skip;
+ } else {
+ source_ref = rm;
+ }
+ }
+ }
+ if (source_ref) {
+ if (!strcmp(source_ref->name, "HEAD") ||
+ starts_with(source_ref->name, "refs/heads/"))
+ install_branch_config(0,
+ branch->name,
+ transport->remote->name,
+ source_ref->name);
+ else if (starts_with(source_ref->name, "refs/remotes/"))
+ warning(_("not setting upstream for a remote remote-tracking branch"));
+ else if (starts_with(source_ref->name, "refs/tags/"))
+ warning(_("not setting upstream for a remote tag"));
+ else
+ warning(_("unknown branch type"));
+ } else {
+ warning(_("no source branch found.\n"
+ "you need to specify exactly one branch with the --set-upstream option."));
+ }
+ }
+ skip:
free_refs(ref_map);
/* if neither --no-tags nor --tags was specified, do automated tag
diff --git a/builtin/gc.c b/builtin/gc.c
index c18efadda5..a22b6ff683 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -41,7 +41,6 @@ static int aggressive_depth = 50;
static int aggressive_window = 250;
static int gc_auto_threshold = 6700;
static int gc_auto_pack_limit = 50;
-static int gc_write_commit_graph;
static int detach_auto = 1;
static timestamp_t gc_log_expire_time;
static const char *gc_log_expire = "1.day.ago";
@@ -148,7 +147,6 @@ static void gc_config(void)
git_config_get_int("gc.aggressivedepth", &aggressive_depth);
git_config_get_int("gc.auto", &gc_auto_threshold);
git_config_get_int("gc.autopacklimit", &gc_auto_pack_limit);
- git_config_get_bool("gc.writecommitgraph", &gc_write_commit_graph);
git_config_get_bool("gc.autodetach", &detach_auto);
git_config_get_expiry("gc.pruneexpire", &prune_expire);
git_config_get_expiry("gc.worktreepruneexpire", &prune_worktrees_expire);
@@ -685,11 +683,11 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
clean_pack_garbage();
}
- if (gc_write_commit_graph &&
- write_commit_graph_reachable(get_object_directory(),
- !quiet && !daemonized ? COMMIT_GRAPH_PROGRESS : 0,
- NULL))
- return 1;
+ prepare_repo_settings(the_repository);
+ if (the_repository->settings.gc_write_commit_graph == 1)
+ write_commit_graph_reachable(get_object_directory(),
+ !quiet && !daemonized ? COMMIT_GRAPH_WRITE_PROGRESS : 0,
+ NULL);
if (auto_gc && too_many_loose_objects())
warning(_("There are too many unreachable loose objects; "
diff --git a/builtin/grep.c b/builtin/grep.c
index 560051784e..2699001fbd 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -403,7 +403,7 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
static int grep_submodule(struct grep_opt *opt,
const struct pathspec *pathspec,
const struct object_id *oid,
- const char *filename, const char *path)
+ const char *filename, const char *path, int cached)
{
struct repository subrepo;
struct repository *superproject = opt->repo;
@@ -475,7 +475,7 @@ static int grep_submodule(struct grep_opt *opt,
strbuf_release(&base);
free(data);
} else {
- hit = grep_cache(&subopt, pathspec, 1);
+ hit = grep_cache(&subopt, pathspec, cached);
}
repo_clear(&subrepo);
@@ -523,7 +523,8 @@ static int grep_cache(struct grep_opt *opt,
}
} else if (recurse_submodules && S_ISGITLINK(ce->ce_mode) &&
submodule_path_match(repo->index, pathspec, name.buf, NULL)) {
- hit |= grep_submodule(opt, pathspec, NULL, ce->name, ce->name);
+ hit |= grep_submodule(opt, pathspec, NULL, ce->name,
+ ce->name, cached);
} else {
continue;
}
@@ -598,7 +599,8 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
free(data);
} else if (recurse_submodules && S_ISGITLINK(entry.mode)) {
hit |= grep_submodule(opt, pathspec, &entry.oid,
- base->buf, base->buf + tn_len);
+ base->buf, base->buf + tn_len,
+ 1); /* ignored */
}
strbuf_setlen(base, old_baselen);
diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c
index 97b54caeb9..e72714a5a8 100644
--- a/builtin/merge-tree.c
+++ b/builtin/merge-tree.c
@@ -180,8 +180,9 @@ static struct merge_list *create_entry(unsigned stage, unsigned mode, const stru
static char *traverse_path(const struct traverse_info *info, const struct name_entry *n)
{
- char *path = xmallocz(traverse_path_len(info, n) + the_hash_algo->rawsz);
- return make_traverse_path(path, info, n);
+ struct strbuf buf = STRBUF_INIT;
+ strbuf_make_traverse_path(&buf, info, n->path, n->pathlen);
+ return strbuf_detach(&buf, NULL);
}
static void resolve(const struct traverse_info *info, struct name_entry *ours, struct name_entry *result)
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index 76ce906946..b410801edb 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -2715,10 +2715,6 @@ static int git_pack_config(const char *k, const char *v, void *cb)
use_bitmap_index_default = git_config_bool(k, v);
return 0;
}
- if (!strcmp(k, "pack.usesparse")) {
- sparse = git_config_bool(k, v);
- return 0;
- }
if (!strcmp(k, "pack.threads")) {
delta_search_threads = git_config_int(k, v);
if (delta_search_threads < 0)
@@ -3343,6 +3339,10 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
read_replace_refs = 0;
sparse = git_env_bool("GIT_TEST_PACK_SPARSE", 0);
+ prepare_repo_settings(the_repository);
+ if (!sparse && the_repository->settings.pack_use_sparse != -1)
+ sparse = the_repository->settings.pack_use_sparse;
+
reset_pack_idx_option(&pack_idx_opts);
git_config(git_pack_config, NULL);
diff --git a/builtin/pull.c b/builtin/pull.c
index f1eaf6e6ed..d25ff13a60 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -129,6 +129,7 @@ static char *opt_refmap;
static char *opt_ipv4;
static char *opt_ipv6;
static int opt_show_forced_updates = -1;
+static char *set_upstream;
static struct option pull_options[] = {
/* Shared options */
@@ -243,6 +244,9 @@ static struct option pull_options[] = {
PARSE_OPT_NOARG),
OPT_BOOL(0, "show-forced-updates", &opt_show_forced_updates,
N_("check for forced-updates on all updated branches")),
+ OPT_PASSTHRU(0, "set-upstream", &set_upstream, NULL,
+ N_("set upstream for git pull/fetch"),
+ PARSE_OPT_NOARG),
OPT_END()
};
@@ -556,6 +560,8 @@ static int run_fetch(const char *repo, const char **refspecs)
argv_array_push(&args, "--show-forced-updates");
else if (opt_show_forced_updates == 0)
argv_array_push(&args, "--no-show-forced-updates");
+ if (set_upstream)
+ argv_array_push(&args, set_upstream);
if (repo) {
argv_array_push(&args, repo);
diff --git a/builtin/update-index.c b/builtin/update-index.c
index dff2f4b837..49302d98c5 100644
--- a/builtin/update-index.c
+++ b/builtin/update-index.c
@@ -966,6 +966,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
struct parse_opt_ctx_t ctx;
strbuf_getline_fn getline_fn;
int parseopt_state = PARSE_OPT_UNKNOWN;
+ struct repository *r = the_repository;
struct option options[] = {
OPT_BIT('q', NULL, &refresh_args.flags,
N_("continue refresh even when index needs update"),
@@ -1180,11 +1181,12 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
remove_split_index(&the_index);
}
+ prepare_repo_settings(r);
switch (untracked_cache) {
case UC_UNSPECIFIED:
break;
case UC_DISABLE:
- if (git_config_get_untracked_cache() == 1)
+ if (r->settings.core_untracked_cache == UNTRACKED_CACHE_WRITE)
warning(_("core.untrackedCache is set to true; "
"remove or change it, if you really want to "
"disable the untracked cache"));
@@ -1196,7 +1198,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
return !test_if_untracked_cache_is_supported();
case UC_ENABLE:
case UC_FORCE:
- if (git_config_get_untracked_cache() == 0)
+ if (r->settings.core_untracked_cache == UNTRACKED_CACHE_REMOVE)
warning(_("core.untrackedCache is set to false; "
"remove or change it, if you really want to "
"enable the untracked cache"));
diff --git a/builtin/worktree.c b/builtin/worktree.c
index a5bb02b207..7f094f8170 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -880,7 +880,7 @@ static void check_clean_worktree(struct worktree *wt,
original_path);
ret = xread(cp.out, buf, sizeof(buf));
if (ret)
- die(_("'%s' is dirty, use --force to delete it"),
+ die(_("'%s' contains modified or untracked files, use --force to delete it"),
original_path);
close(cp.out);
ret = finish_command(&cp);
diff --git a/cache-tree.c b/cache-tree.c
index 706ffcf188..c22161f987 100644
--- a/cache-tree.c
+++ b/cache-tree.c
@@ -713,7 +713,7 @@ static struct cache_tree *find_cache_tree_from_traversal(struct cache_tree *root
if (!info->prev)
return root;
our_parent = find_cache_tree_from_traversal(root, info->prev);
- return cache_tree_find(our_parent, info->name.path);
+ return cache_tree_find(our_parent, info->name);
}
int cache_tree_matches_traversal(struct cache_tree *root,
diff --git a/commit-graph.c b/commit-graph.c
index fe954ab5f8..9b02d2c426 100644
--- a/commit-graph.c
+++ b/commit-graph.c
@@ -467,7 +467,6 @@ static void prepare_commit_graph_one(struct repository *r, const char *obj_dir)
static int prepare_commit_graph(struct repository *r)
{
struct object_directory *odb;
- int config_value;
if (git_env_bool(GIT_TEST_COMMIT_GRAPH_DIE_ON_LOAD, 0))
die("dying as requested by the '%s' variable on commit-graph load!",
@@ -477,9 +476,10 @@ static int prepare_commit_graph(struct repository *r)
return !!r->objects->commit_graph;
r->objects->commit_graph_attempted = 1;
+ prepare_repo_settings(r);
+
if (!git_env_bool(GIT_TEST_COMMIT_GRAPH, 0) &&
- (repo_config_get_bool(r, "core.commitgraph", &config_value) ||
- !config_value))
+ r->settings.core_commit_graph != 1)
/*
* This repository is not configured to use commit graphs, so
* do not load one. (But report commit_graph_attempted anyway
@@ -783,7 +783,8 @@ struct write_commit_graph_context {
unsigned append:1,
report_progress:1,
- split:1;
+ split:1,
+ check_oids:1;
const struct split_commit_graph_opts *split_opts;
};
@@ -1134,7 +1135,8 @@ static int add_ref_to_list(const char *refname,
return 0;
}
-int write_commit_graph_reachable(const char *obj_dir, unsigned int flags,
+int write_commit_graph_reachable(const char *obj_dir,
+ enum commit_graph_write_flags flags,
const struct split_commit_graph_opts *split_opts)
{
struct string_list list = STRING_LIST_INIT_DUP;
@@ -1193,8 +1195,8 @@ static int fill_oids_from_packs(struct write_commit_graph_context *ctx,
return 0;
}
-static void fill_oids_from_commit_hex(struct write_commit_graph_context *ctx,
- struct string_list *commit_hex)
+static int fill_oids_from_commit_hex(struct write_commit_graph_context *ctx,
+ struct string_list *commit_hex)
{
uint32_t i;
struct strbuf progress_title = STRBUF_INIT;
@@ -1215,20 +1217,21 @@ static void fill_oids_from_commit_hex(struct write_commit_graph_context *ctx,
struct commit *result;
display_progress(ctx->progress, i + 1);
- if (commit_hex->items[i].string &&
- parse_oid_hex(commit_hex->items[i].string, &oid, &end))
- continue;
-
- result = lookup_commit_reference_gently(ctx->r, &oid, 1);
-
- if (result) {
+ if (!parse_oid_hex(commit_hex->items[i].string, &oid, &end) &&
+ (result = lookup_commit_reference_gently(ctx->r, &oid, 1))) {
ALLOC_GROW(ctx->oids.list, ctx->oids.nr + 1, ctx->oids.alloc);
oidcpy(&ctx->oids.list[ctx->oids.nr], &(result->object.oid));
ctx->oids.nr++;
+ } else if (ctx->check_oids) {
+ error(_("invalid commit object id: %s"),
+ commit_hex->items[i].string);
+ return -1;
}
}
stop_progress(&ctx->progress);
strbuf_release(&progress_title);
+
+ return 0;
}
static void fill_oids_from_all_packs(struct write_commit_graph_context *ctx)
@@ -1752,7 +1755,7 @@ out:
int write_commit_graph(const char *obj_dir,
struct string_list *pack_indexes,
struct string_list *commit_hex,
- unsigned int flags,
+ enum commit_graph_write_flags flags,
const struct split_commit_graph_opts *split_opts)
{
struct write_commit_graph_context *ctx;
@@ -1773,9 +1776,10 @@ int write_commit_graph(const char *obj_dir,
if (len && ctx->obj_dir[len - 1] == '/')
ctx->obj_dir[len - 1] = 0;
- ctx->append = flags & COMMIT_GRAPH_APPEND ? 1 : 0;
- ctx->report_progress = flags & COMMIT_GRAPH_PROGRESS ? 1 : 0;
- ctx->split = flags & COMMIT_GRAPH_SPLIT ? 1 : 0;
+ ctx->append = flags & COMMIT_GRAPH_WRITE_APPEND ? 1 : 0;
+ ctx->report_progress = flags & COMMIT_GRAPH_WRITE_PROGRESS ? 1 : 0;
+ ctx->split = flags & COMMIT_GRAPH_WRITE_SPLIT ? 1 : 0;
+ ctx->check_oids = flags & COMMIT_GRAPH_WRITE_CHECK_OIDS ? 1 : 0;
ctx->split_opts = split_opts;
if (ctx->split) {
@@ -1830,8 +1834,10 @@ int write_commit_graph(const char *obj_dir,
goto cleanup;
}
- if (commit_hex)
- fill_oids_from_commit_hex(ctx, commit_hex);
+ if (commit_hex) {
+ if ((res = fill_oids_from_commit_hex(ctx, commit_hex)))
+ goto cleanup;
+ }
if (!pack_indexes && !commit_hex)
fill_oids_from_all_packs(ctx);
diff --git a/commit-graph.h b/commit-graph.h
index df9a3b20e4..486e64e591 100644
--- a/commit-graph.h
+++ b/commit-graph.h
@@ -71,9 +71,13 @@ struct commit_graph *parse_commit_graph(void *graph_map, int fd,
*/
int generation_numbers_enabled(struct repository *r);
-#define COMMIT_GRAPH_APPEND (1 << 0)
-#define COMMIT_GRAPH_PROGRESS (1 << 1)
-#define COMMIT_GRAPH_SPLIT (1 << 2)
+enum commit_graph_write_flags {
+ COMMIT_GRAPH_WRITE_APPEND = (1 << 0),
+ COMMIT_GRAPH_WRITE_PROGRESS = (1 << 1),
+ COMMIT_GRAPH_WRITE_SPLIT = (1 << 2),
+ /* Make sure that each OID in the input is a valid commit OID. */
+ COMMIT_GRAPH_WRITE_CHECK_OIDS = (1 << 3)
+};
struct split_commit_graph_opts {
int size_multiple;
@@ -87,12 +91,13 @@ struct split_commit_graph_opts {
* is not compatible with the commit-graph feature, then the
* methods will return 0 without writing a commit-graph.
*/
-int write_commit_graph_reachable(const char *obj_dir, unsigned int flags,
+int write_commit_graph_reachable(const char *obj_dir,
+ enum commit_graph_write_flags flags,
const struct split_commit_graph_opts *split_opts);
int write_commit_graph(const char *obj_dir,
struct string_list *pack_indexes,
struct string_list *commit_hex,
- unsigned int flags,
+ enum commit_graph_write_flags flags,
const struct split_commit_graph_opts *split_opts);
#define COMMIT_GRAPH_VERIFY_SHALLOW (1 << 0)
diff --git a/common-main.c b/common-main.c
index 582a7b1886..71e21dd20a 100644
--- a/common-main.c
+++ b/common-main.c
@@ -39,16 +39,16 @@ int main(int argc, const char **argv)
git_resolve_executable_dir(argv[0]);
- trace2_initialize();
- trace2_cmd_start(argv);
- trace2_collect_process_info(TRACE2_PROCESS_INFO_STARTUP);
-
git_setup_gettext();
initialize_the_repository();
attr_start();
+ trace2_initialize();
+ trace2_cmd_start(argv);
+ trace2_collect_process_info(TRACE2_PROCESS_INFO_STARTUP);
+
result = cmd_main(argc, argv);
trace2_cmd_exit(result);
diff --git a/compat/nedmalloc/malloc.c.h b/compat/nedmalloc/malloc.c.h
index b833ff9225..9134349590 100644
--- a/compat/nedmalloc/malloc.c.h
+++ b/compat/nedmalloc/malloc.c.h
@@ -1755,10 +1755,10 @@ static FORCEINLINE void pthread_release_lock (MLOCK_T *sl) {
assert(sl->l != 0);
assert(sl->threadid == CURRENT_THREAD);
if (--sl->c == 0) {
- sl->threadid = 0;
volatile unsigned int* lp = &sl->l;
int prev = 0;
int ret;
+ sl->threadid = 0;
__asm__ __volatile__ ("lock; xchgl %0, %1"
: "=r" (ret)
: "m" (*(lp)), "0"(prev)
@@ -3066,7 +3066,7 @@ static int init_mparams(void) {
#if !ONLY_MSPACES
/* Set up lock for main malloc area */
gm->mflags = mparams.default_mflags;
- INITIAL_LOCK(&gm->mutex);
+ (void)INITIAL_LOCK(&gm->mutex);
#endif
#if (FOOTERS && !INSECURE)
@@ -5017,7 +5017,7 @@ static mstate init_user_mstate(char* tbase, size_t tsize) {
mchunkptr msp = align_as_chunk(tbase);
mstate m = (mstate)(chunk2mem(msp));
memset(m, 0, msize);
- INITIAL_LOCK(&m->mutex);
+ (void)INITIAL_LOCK(&m->mutex);
msp->head = (msize|PINUSE_BIT|CINUSE_BIT);
m->seg.base = m->least_addr = tbase;
m->seg.size = m->footprint = m->max_footprint = tsize;
diff --git a/config.c b/config.c
index 3900e4947b..b61c258d6d 100644
--- a/config.c
+++ b/config.c
@@ -275,7 +275,7 @@ static int include_by_branch(const char *cond, size_t cond_len)
int flags;
int ret;
struct strbuf pattern = STRBUF_INIT;
- const char *refname = !the_repository || !the_repository->gitdir ?
+ const char *refname = !the_repository->gitdir ?
NULL : resolve_ref_unsafe("HEAD", 0, NULL, &flags);
const char *shortname;
@@ -2288,30 +2288,6 @@ int git_config_get_expiry_in_days(const char *key, timestamp_t *expiry, timestam
return -1; /* thing exists but cannot be parsed */
}
-int git_config_get_untracked_cache(void)
-{
- int val = -1;
- const char *v;
-
- /* Hack for test programs like test-dump-untracked-cache */
- if (ignore_untracked_cache_config)
- return -1;
-
- if (!git_config_get_maybe_bool("core.untrackedcache", &val))
- return val;
-
- if (!git_config_get_value("core.untrackedcache", &v)) {
- if (!strcasecmp(v, "keep"))
- return -1;
-
- error(_("unknown core.untrackedCache value '%s'; "
- "using 'keep' default value"), v);
- return -1;
- }
-
- return -1; /* default value */
-}
-
int git_config_get_split_index(void)
{
int val;
diff --git a/diff.c b/diff.c
index efe42b341a..e28b463f57 100644
--- a/diff.c
+++ b/diff.c
@@ -6512,6 +6512,7 @@ static void add_if_missing(struct repository *r,
const struct diff_filespec *filespec)
{
if (filespec && filespec->oid_valid &&
+ !S_ISGITLINK(filespec->mode) &&
oid_object_info_extended(r, &filespec->oid, NULL,
OBJECT_INFO_FOR_PREFETCH))
oid_array_append(to_fetch, &filespec->oid);
diff --git a/fetch-negotiator.c b/fetch-negotiator.c
index d6d685cba0..0a1357dc9d 100644
--- a/fetch-negotiator.c
+++ b/fetch-negotiator.c
@@ -2,19 +2,20 @@
#include "fetch-negotiator.h"
#include "negotiator/default.h"
#include "negotiator/skipping.h"
+#include "repository.h"
-void fetch_negotiator_init(struct fetch_negotiator *negotiator,
- const char *algorithm)
+void fetch_negotiator_init(struct repository *r,
+ struct fetch_negotiator *negotiator)
{
- if (algorithm) {
- if (!strcmp(algorithm, "skipping")) {
- skipping_negotiator_init(negotiator);
- return;
- } else if (!strcmp(algorithm, "default")) {
- /* Fall through to default initialization */
- } else {
- die("unknown fetch negotiation algorithm '%s'", algorithm);
- }
+ prepare_repo_settings(r);
+ switch(r->settings.fetch_negotiation_algorithm) {
+ case FETCH_NEGOTIATION_SKIPPING:
+ skipping_negotiator_init(negotiator);
+ return;
+
+ case FETCH_NEGOTIATION_DEFAULT:
+ default:
+ default_negotiator_init(negotiator);
+ return;
}
- default_negotiator_init(negotiator);
}
diff --git a/fetch-negotiator.h b/fetch-negotiator.h
index 9e3967ce66..ea78868504 100644
--- a/fetch-negotiator.h
+++ b/fetch-negotiator.h
@@ -2,6 +2,7 @@
#define FETCH_NEGOTIATOR_H
struct commit;
+struct repository;
/*
* An object that supplies the information needed to negotiate the contents of
@@ -52,7 +53,7 @@ struct fetch_negotiator {
void *data;
};
-void fetch_negotiator_init(struct fetch_negotiator *negotiator,
- const char *algorithm);
+void fetch_negotiator_init(struct repository *r,
+ struct fetch_negotiator *negotiator);
#endif
diff --git a/fetch-pack.c b/fetch-pack.c
index 65be043f2a..d81f47c07b 100644
--- a/fetch-pack.c
+++ b/fetch-pack.c
@@ -36,7 +36,6 @@ static int agent_supported;
static int server_supports_filtering;
static struct lock_file shallow_lock;
static const char *alternate_shallow_file;
-static char *negotiation_algorithm;
static struct strbuf fsck_msg_types = STRBUF_INIT;
/* Remember to update object flag allocation in object.h */
@@ -892,12 +891,13 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
struct shallow_info *si,
char **pack_lockfile)
{
+ struct repository *r = the_repository;
struct ref *ref = copy_ref_list(orig_ref);
struct object_id oid;
const char *agent_feature;
int agent_len;
struct fetch_negotiator negotiator;
- fetch_negotiator_init(&negotiator, negotiation_algorithm);
+ fetch_negotiator_init(r, &negotiator);
sort_ref_list(&ref, ref_compare_name);
QSORT(sought, nr_sought, cmp_ref_by_name);
@@ -911,7 +911,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
if (server_supports("shallow"))
print_verbose(args, _("Server supports %s"), "shallow");
- else if (args->depth > 0 || is_repository_shallow(the_repository))
+ else if (args->depth > 0 || is_repository_shallow(r))
die(_("Server does not support shallow clients"));
if (args->depth > 0 || args->deepen_since || args->deepen_not)
args->deepen = 1;
@@ -1379,6 +1379,7 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
struct shallow_info *si,
char **pack_lockfile)
{
+ struct repository *r = the_repository;
struct ref *ref = copy_ref_list(orig_ref);
enum fetch_state state = FETCH_CHECK_LOCAL;
struct oidset common = OIDSET_INIT;
@@ -1386,7 +1387,7 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
int in_vain = 0;
int haves_to_send = INITIAL_FLUSH;
struct fetch_negotiator negotiator;
- fetch_negotiator_init(&negotiator, negotiation_algorithm);
+ fetch_negotiator_init(r, &negotiator);
packet_reader_init(&reader, fd[0], NULL, 0,
PACKET_READ_CHOMP_NEWLINE |
PACKET_READ_DIE_ON_ERR_PACKET);
@@ -1505,8 +1506,6 @@ static void fetch_pack_config(void)
git_config_get_bool("repack.usedeltabaseoffset", &prefer_ofs_delta);
git_config_get_bool("fetch.fsckobjects", &fetch_fsck_objects);
git_config_get_bool("transfer.fsckobjects", &transfer_fsck_objects);
- git_config_get_string("fetch.negotiationalgorithm",
- &negotiation_algorithm);
git_config(fetch_pack_config_cb, NULL);
}
diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index 6de74ce639..6ec562d5da 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -3030,8 +3030,23 @@ unset doc_path doc_url
wm protocol . WM_DELETE_WINDOW do_quit
bind all <$M1B-Key-q> do_quit
bind all <$M1B-Key-Q> do_quit
-bind all <$M1B-Key-w> {destroy [winfo toplevel %W]}
-bind all <$M1B-Key-W> {destroy [winfo toplevel %W]}
+
+set m1b_w_script {
+ set toplvl_win [winfo toplevel %W]
+
+ # If we are destroying the main window, we should call do_quit to take
+ # care of cleanup before exiting the program.
+ if {$toplvl_win eq "."} {
+ do_quit
+ } else {
+ destroy $toplvl_win
+ }
+}
+
+bind all <$M1B-Key-w> $m1b_w_script
+bind all <$M1B-Key-W> $m1b_w_script
+
+unset m1b_w_script
set subcommand_args {}
proc usage {} {
diff --git a/packfile.h b/packfile.h
index 3e98910bdd..fc7904ec81 100644
--- a/packfile.h
+++ b/packfile.h
@@ -100,7 +100,7 @@ struct packed_git *add_packed_git(const char *path, size_t path_len, int local);
* Does not unlink if 'force_delete' is false and the pack-file is
* marked as ".keep".
*/
-extern void unlink_pack_path(const char *pack_name, int force_delete);
+void unlink_pack_path(const char *pack_name, int force_delete);
/*
* Make sure that a pointer access into an mmap'd index file is within bounds,
diff --git a/parse-options.c b/parse-options.c
index 87b26a1d92..b42f54d48b 100644
--- a/parse-options.c
+++ b/parse-options.c
@@ -780,7 +780,8 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,
continue;
}
- if (!arg[2]) { /* "--" */
+ if (!arg[2] /* "--" */ ||
+ !strcmp(arg + 2, "end-of-options")) {
if (!(ctx->flags & PARSE_OPT_KEEP_DASHDASH)) {
ctx->argc--;
ctx->argv++;
diff --git a/parse-options.h b/parse-options.h
index a4bd40bb6a..38a33a087e 100644
--- a/parse-options.h
+++ b/parse-options.h
@@ -46,6 +46,15 @@ enum parse_opt_option_flags {
PARSE_OPT_COMP_ARG = 1024
};
+enum parse_opt_result {
+ PARSE_OPT_COMPLETE = -3,
+ PARSE_OPT_HELP = -2,
+ PARSE_OPT_ERROR = -1, /* must be the same as error() */
+ PARSE_OPT_DONE = 0, /* fixed so that "return 0" works */
+ PARSE_OPT_NON_OPTION,
+ PARSE_OPT_UNKNOWN
+};
+
struct option;
typedef int parse_opt_cb(const struct option *, const char *arg, int unset);
@@ -241,15 +250,6 @@ const char *optname(const struct option *opt, int flags);
/*----- incremental advanced APIs -----*/
-enum parse_opt_result {
- PARSE_OPT_COMPLETE = -3,
- PARSE_OPT_HELP = -2,
- PARSE_OPT_ERROR = -1, /* must be the same as error() */
- PARSE_OPT_DONE = 0, /* fixed so that "return 0" works */
- PARSE_OPT_NON_OPTION,
- PARSE_OPT_UNKNOWN
-};
-
/*
* It's okay for the caller to consume argv/argc in the usual way.
* Other fields of that structure are private to parse-options and should not
diff --git a/read-cache.c b/read-cache.c
index 52ffa8a313..cff1280975 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -1599,16 +1599,17 @@ struct cache_entry *refresh_cache_entry(struct index_state *istate,
#define INDEX_FORMAT_DEFAULT 3
-static unsigned int get_index_format_default(void)
+static unsigned int get_index_format_default(struct repository *r)
{
char *envversion = getenv("GIT_INDEX_VERSION");
char *endp;
- int value;
unsigned int version = INDEX_FORMAT_DEFAULT;
if (!envversion) {
- if (!git_config_get_int("index.version", &value))
- version = value;
+ prepare_repo_settings(r);
+
+ if (r->settings.index_version >= 0)
+ version = r->settings.index_version;
if (version < INDEX_FORMAT_LB || INDEX_FORMAT_UB < version) {
warning(_("index.version set, but the value is invalid.\n"
"Using version %i"), INDEX_FORMAT_DEFAULT);
@@ -1844,18 +1845,17 @@ static void check_ce_order(struct index_state *istate)
static void tweak_untracked_cache(struct index_state *istate)
{
- switch (git_config_get_untracked_cache()) {
- case -1: /* keep: do nothing */
- break;
- case 0: /* false */
+ struct repository *r = the_repository;
+
+ prepare_repo_settings(r);
+
+ if (r->settings.core_untracked_cache == UNTRACKED_CACHE_REMOVE) {
remove_untracked_cache(istate);
- break;
- case 1: /* true */
- add_untracked_cache(istate);
- break;
- default: /* unknown value: do nothing */
- break;
+ return;
}
+
+ if (r->settings.core_untracked_cache == UNTRACKED_CACHE_WRITE)
+ add_untracked_cache(istate);
}
static void tweak_split_index(struct index_state *istate)
@@ -2765,7 +2765,7 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
}
if (!istate->version) {
- istate->version = get_index_format_default();
+ istate->version = get_index_format_default(the_repository);
if (git_env_bool("GIT_TEST_SPLIT_INDEX", 0))
init_split_index(istate);
}
diff --git a/refs/packed-backend.c b/refs/packed-backend.c
index c01c7f5901..4458a0f69c 100644
--- a/refs/packed-backend.c
+++ b/refs/packed-backend.c
@@ -1012,14 +1012,23 @@ int packed_refs_lock(struct ref_store *ref_store, int flags, struct strbuf *err)
}
/*
- * Now that we hold the `packed-refs` lock, make sure that our
- * snapshot matches the current version of the file. Normally
- * `get_snapshot()` does that for us, but that function
- * assumes that when the file is locked, any existing snapshot
- * is still valid. We've just locked the file, but it might
- * have changed the moment *before* we locked it.
+ * There is a stat-validity problem might cause `update-ref -d`
+ * lost the newly commit of a ref, because a new `packed-refs`
+ * file might has the same on-disk file attributes such as
+ * timestamp, file size and inode value, but has a changed
+ * ref value.
+ *
+ * This could happen with a very small chance when
+ * `update-ref -d` is called and at the same time another
+ * `pack-refs --all` process is running.
+ *
+ * Now that we hold the `packed-refs` lock, it is important
+ * to make sure we could read the latest version of
+ * `packed-refs` file no matter we have just mmap it or not.
+ * So what need to do is clear the snapshot if we hold it
+ * already.
*/
- validate_snapshot(refs);
+ clear_snapshot(refs);
/*
* Now make sure that the packed-refs file as it exists in the
diff --git a/repo-settings.c b/repo-settings.c
new file mode 100644
index 0000000000..3779b85c17
--- /dev/null
+++ b/repo-settings.c
@@ -0,0 +1,64 @@
+#include "cache.h"
+#include "config.h"
+#include "repository.h"
+
+#define UPDATE_DEFAULT_BOOL(s,v) do { if (s == -1) { s = v; } } while(0)
+
+void prepare_repo_settings(struct repository *r)
+{
+ int value;
+ char *strval;
+
+ if (r->settings.initialized)
+ return;
+
+ /* Defaults */
+ memset(&r->settings, -1, sizeof(r->settings));
+
+ if (!repo_config_get_bool(r, "core.commitgraph", &value))
+ r->settings.core_commit_graph = value;
+ if (!repo_config_get_bool(r, "gc.writecommitgraph", &value))
+ r->settings.gc_write_commit_graph = value;
+ 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))
+ r->settings.index_version = value;
+ if (!repo_config_get_maybe_bool(r, "core.untrackedcache", &value)) {
+ if (value == 0)
+ r->settings.core_untracked_cache = UNTRACKED_CACHE_REMOVE;
+ else
+ r->settings.core_untracked_cache = UNTRACKED_CACHE_WRITE;
+ } else if (!repo_config_get_string(r, "core.untrackedcache", &strval)) {
+ if (!strcasecmp(strval, "keep"))
+ r->settings.core_untracked_cache = UNTRACKED_CACHE_KEEP;
+
+ free(strval);
+ }
+
+ if (!repo_config_get_string(r, "fetch.negotiationalgorithm", &strval)) {
+ if (!strcasecmp(strval, "skipping"))
+ r->settings.fetch_negotiation_algorithm = FETCH_NEGOTIATION_SKIPPING;
+ else
+ r->settings.fetch_negotiation_algorithm = FETCH_NEGOTIATION_DEFAULT;
+ }
+
+ if (!repo_config_get_bool(r, "pack.usesparse", &value))
+ r->settings.pack_use_sparse = value;
+ if (!repo_config_get_bool(r, "feature.manyfiles", &value) && value) {
+ UPDATE_DEFAULT_BOOL(r->settings.index_version, 4);
+ UPDATE_DEFAULT_BOOL(r->settings.core_untracked_cache, UNTRACKED_CACHE_WRITE);
+ }
+ if (!repo_config_get_bool(r, "feature.experimental", &value) && value) {
+ UPDATE_DEFAULT_BOOL(r->settings.pack_use_sparse, 1);
+ UPDATE_DEFAULT_BOOL(r->settings.fetch_negotiation_algorithm, FETCH_NEGOTIATION_SKIPPING);
+ }
+
+ /* Hack for test programs like test-dump-untracked-cache */
+ if (ignore_untracked_cache_config)
+ r->settings.core_untracked_cache = UNTRACKED_CACHE_KEEP;
+ else
+ UPDATE_DEFAULT_BOOL(r->settings.core_untracked_cache, UNTRACKED_CACHE_KEEP);
+
+ UPDATE_DEFAULT_BOOL(r->settings.fetch_negotiation_algorithm, FETCH_NEGOTIATION_DEFAULT);
+}
diff --git a/repository.h b/repository.h
index 4fb6a5885f..4da275e73f 100644
--- a/repository.h
+++ b/repository.h
@@ -11,6 +11,33 @@ struct pathspec;
struct raw_object_store;
struct submodule_cache;
+enum untracked_cache_setting {
+ UNTRACKED_CACHE_UNSET = -1,
+ UNTRACKED_CACHE_REMOVE = 0,
+ UNTRACKED_CACHE_KEEP = 1,
+ UNTRACKED_CACHE_WRITE = 2
+};
+
+enum fetch_negotiation_setting {
+ FETCH_NEGOTIATION_UNSET = -1,
+ FETCH_NEGOTIATION_NONE = 0,
+ FETCH_NEGOTIATION_DEFAULT = 1,
+ FETCH_NEGOTIATION_SKIPPING = 2,
+};
+
+struct repo_settings {
+ int initialized;
+
+ int core_commit_graph;
+ int gc_write_commit_graph;
+
+ int index_version;
+ enum untracked_cache_setting core_untracked_cache;
+
+ int pack_use_sparse;
+ enum fetch_negotiation_setting fetch_negotiation_algorithm;
+};
+
struct repository {
/* Environment */
/*
@@ -72,6 +99,8 @@ struct repository {
*/
char *submodule_prefix;
+ struct repo_settings settings;
+
/* Subsystems */
/*
* Repository's config which contains key-value pairs from the usual
@@ -157,5 +186,6 @@ int repo_read_index_unmerged(struct repository *);
*/
void repo_update_index_if_able(struct repository *, struct lock_file *);
+void prepare_repo_settings(struct repository *r);
#endif /* REPOSITORY_H */
diff --git a/revision.c b/revision.c
index 07412297f0..51690e480d 100644
--- a/revision.c
+++ b/revision.c
@@ -2523,6 +2523,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
int i, flags, left, seen_dashdash, got_rev_arg = 0, revarg_opt;
struct argv_array prune_data = ARGV_ARRAY_INIT;
const char *submodule = NULL;
+ int seen_end_of_options = 0;
if (opt)
submodule = opt->submodule;
@@ -2552,7 +2553,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
revarg_opt |= REVARG_CANNOT_BE_FILENAME;
for (left = i = 1; i < argc; i++) {
const char *arg = argv[i];
- if (*arg == '-') {
+ if (!seen_end_of_options && *arg == '-') {
int opts;
opts = handle_revision_pseudo_opt(submodule,
@@ -2574,6 +2575,11 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
continue;
}
+ if (!strcmp(arg, "--end-of-options")) {
+ seen_end_of_options = 1;
+ continue;
+ }
+
opts = handle_revision_opt(revs, argc - i, argv + i,
&left, argv, opt);
if (opts > 0) {
diff --git a/sha1-name.c b/sha1-name.c
index 2989e27b71..c665e3f96d 100644
--- a/sha1-name.c
+++ b/sha1-name.c
@@ -403,9 +403,9 @@ static int repo_collect_ambiguous(struct repository *r,
return collect_ambiguous(oid, data);
}
-static struct repository *sort_ambiguous_repo;
-static int sort_ambiguous(const void *a, const void *b)
+static int sort_ambiguous(const void *a, const void *b, void *ctx)
{
+ struct repository *sort_ambiguous_repo = ctx;
int a_type = oid_object_info(sort_ambiguous_repo, a, NULL);
int b_type = oid_object_info(sort_ambiguous_repo, b, NULL);
int a_type_sort;
@@ -434,10 +434,7 @@ static int sort_ambiguous(const void *a, const void *b)
static void sort_ambiguous_oid_array(struct repository *r, struct oid_array *a)
{
- /* mutex will be needed if this code is to be made thread safe */
- sort_ambiguous_repo = r;
- QSORT(a->oid, a->nr, sort_ambiguous);
- sort_ambiguous_repo = NULL;
+ QSORT_S(a->oid, a->nr, sort_ambiguous, r);
}
static enum get_oid_result get_short_oid(struct repository *r,
diff --git a/t/perf/p5600-clone-reference.sh b/t/perf/p5601-clone-reference.sh
index 68fed66347..68fed66347 100755
--- a/t/perf/p5600-clone-reference.sh
+++ b/t/perf/p5601-clone-reference.sh
diff --git a/t/t0000-basic.sh b/t/t0000-basic.sh
index 9ca0818cbe..4c01f60dd3 100755
--- a/t/t0000-basic.sh
+++ b/t/t0000-basic.sh
@@ -274,23 +274,23 @@ test_expect_success 'pretend we have a mix of all possible results' "
test_expect_success C_LOCALE_OUTPUT 'test --verbose' '
test_must_fail run_sub_test_lib_test \
- test-verbose "test verbose" --verbose <<-\EOF &&
+ t1234-verbose "test verbose" --verbose <<-\EOF &&
test_expect_success "passing test" true
test_expect_success "test with output" "echo foo"
test_expect_success "failing test" false
test_done
EOF
- mv test-verbose/out test-verbose/out+ &&
- grep -v "^Initialized empty" test-verbose/out+ >test-verbose/out &&
- check_sub_test_lib_test test-verbose <<-\EOF
- > expecting success: true
+ mv t1234-verbose/out t1234-verbose/out+ &&
+ grep -v "^Initialized empty" t1234-verbose/out+ >t1234-verbose/out &&
+ check_sub_test_lib_test t1234-verbose <<-\EOF
+ > expecting success of 1234.1 '\''passing test'\'': true
> ok 1 - passing test
> Z
- > expecting success: echo foo
+ > expecting success of 1234.2 '\''test with output'\'': echo foo
> foo
> ok 2 - test with output
> Z
- > expecting success: false
+ > expecting success of 1234.3 '\''failing test'\'': false
> not ok 3 - failing test
> # false
> Z
@@ -301,17 +301,17 @@ test_expect_success C_LOCALE_OUTPUT 'test --verbose' '
test_expect_success 'test --verbose-only' '
test_must_fail run_sub_test_lib_test \
- test-verbose-only-2 "test verbose-only=2" \
+ t2345-verbose-only-2 "test verbose-only=2" \
--verbose-only=2 <<-\EOF &&
test_expect_success "passing test" true
test_expect_success "test with output" "echo foo"
test_expect_success "failing test" false
test_done
EOF
- check_sub_test_lib_test test-verbose-only-2 <<-\EOF
+ check_sub_test_lib_test t2345-verbose-only-2 <<-\EOF
> ok 1 - passing test
> Z
- > expecting success: echo foo
+ > expecting success of 2345.2 '\''test with output'\'': echo foo
> foo
> ok 2 - test with output
> Z
diff --git a/t/t0040-parse-options.sh b/t/t0040-parse-options.sh
index cebc77fab0..705a136ed9 100755
--- a/t/t0040-parse-options.sh
+++ b/t/t0040-parse-options.sh
@@ -399,4 +399,11 @@ test_expect_success 'GIT_TEST_DISALLOW_ABBREVIATED_OPTIONS works' '
test-tool parse-options --ye
'
+test_expect_success '--end-of-options treats remainder as args' '
+ test-tool parse-options \
+ --expect="verbose: -1" \
+ --expect="arg 00: --verbose" \
+ --end-of-options --verbose
+'
+
test_done
diff --git a/t/t0410-partial-clone.sh b/t/t0410-partial-clone.sh
index 5bd892f2f7..33e0aa4a89 100755
--- a/t/t0410-partial-clone.sh
+++ b/t/t0410-partial-clone.sh
@@ -234,7 +234,7 @@ test_expect_success 'rev-list stops traversal at missing and promised commit' '
git -C repo config core.repositoryformatversion 1 &&
git -C repo config extensions.partialclone "arbitrary string" &&
- GIT_TEST_COMMIT_GRAPH=0 git -C repo rev-list --exclude-promisor-objects --objects bar >out &&
+ GIT_TEST_COMMIT_GRAPH=0 git -C repo -c core.commitGraph=false rev-list --exclude-promisor-objects --objects bar >out &&
grep $(git -C repo rev-parse bar) out &&
! grep $FOO out
'
@@ -518,4 +518,7 @@ test_expect_success 'fetching of missing objects from an HTTP server' '
git verify-pack --verbose "$IDX" | grep "$HASH"
'
+# DO NOT add non-httpd-specific tests here, because the last part of this
+# test script is only executed when httpd is available and enabled.
+
test_done
diff --git a/t/t1309-early-config.sh b/t/t1309-early-config.sh
index 0c37e7180d..3a0de0ddaa 100755
--- a/t/t1309-early-config.sh
+++ b/t/t1309-early-config.sh
@@ -91,7 +91,12 @@ test_expect_failure 'ignore .git/ with invalid config' '
test_expect_success 'early config and onbranch' '
echo "[broken" >broken &&
- test_with_config "[includeif \"onbranch:refs/heads/master\"]path=../broken"
+ test_with_config "[includeif \"onbranch:master\"]path=../broken"
+'
+
+test_expect_success 'onbranch config outside of git repo' '
+ test_config_global includeIf.onbranch:master.path non-existent &&
+ nongit git help
'
test_done
diff --git a/t/t1600-index.sh b/t/t1600-index.sh
index 42962ed7d4..c77721b580 100755
--- a/t/t1600-index.sh
+++ b/t/t1600-index.sh
@@ -59,17 +59,38 @@ test_expect_success 'out of bounds index.version issues warning' '
)
'
-test_expect_success 'GIT_INDEX_VERSION takes precedence over config' '
+test_index_version () {
+ INDEX_VERSION_CONFIG=$1 &&
+ FEATURE_MANY_FILES=$2 &&
+ ENV_VAR_VERSION=$3
+ EXPECTED_OUTPUT_VERSION=$4 &&
(
rm -f .git/index &&
- GIT_INDEX_VERSION=4 &&
- export GIT_INDEX_VERSION &&
- git config --add index.version 2 &&
+ rm -f .git/config &&
+ if test "$INDEX_VERSION_CONFIG" -ne 0
+ then
+ git config --add index.version $INDEX_VERSION_CONFIG
+ fi &&
+ git config --add feature.manyFiles $FEATURE_MANY_FILES
+ if test "$ENV_VAR_VERSION" -ne 0
+ then
+ GIT_INDEX_VERSION=$ENV_VAR_VERSION &&
+ export GIT_INDEX_VERSION
+ else
+ unset GIT_INDEX_VERSION
+ fi &&
git add a 2>&1 &&
- echo 4 >expect &&
+ echo $EXPECTED_OUTPUT_VERSION >expect &&
test-tool index-version <.git/index >actual &&
test_cmp expect actual
)
+}
+
+test_expect_success 'index version config precedence' '
+ test_index_version 2 false 4 4 &&
+ test_index_version 2 true 0 2 &&
+ test_index_version 0 true 0 4 &&
+ test_index_version 0 true 2 2
'
test_done
diff --git a/t/t2022-checkout-paths.sh b/t/t2022-checkout-paths.sh
index fc3eb43b89..6844afafc0 100755
--- a/t/t2022-checkout-paths.sh
+++ b/t/t2022-checkout-paths.sh
@@ -78,4 +78,15 @@ test_expect_success 'do not touch files that are already up-to-date' '
test_cmp expect actual
'
+test_expect_success 'checkout HEAD adds deleted intent-to-add file back to index' '
+ echo "nonempty" >nonempty &&
+ >empty &&
+ git add nonempty empty &&
+ git commit -m "create files to be deleted" &&
+ git rm --cached nonempty empty &&
+ git add -N nonempty empty &&
+ git checkout HEAD nonempty empty &&
+ git diff --cached --exit-code
+'
+
test_done
diff --git a/t/t2070-restore.sh b/t/t2070-restore.sh
index 2650df1966..21c3f84459 100755
--- a/t/t2070-restore.sh
+++ b/t/t2070-restore.sh
@@ -95,4 +95,15 @@ test_expect_success 'restore --ignore-unmerged ignores unmerged entries' '
)
'
+test_expect_success 'restore --staged adds deleted intent-to-add file back to index' '
+ echo "nonempty" >nonempty &&
+ >empty &&
+ git add nonempty empty &&
+ git commit -m "create files to be deleted" &&
+ git rm --cached nonempty empty &&
+ git add -N nonempty empty &&
+ git restore --staged nonempty empty &&
+ git diff --cached --exit-code
+'
+
test_done
diff --git a/t/t4067-diff-partial-clone.sh b/t/t4067-diff-partial-clone.sh
index 90c8fb2901..4831ad35e6 100755
--- a/t/t4067-diff-partial-clone.sh
+++ b/t/t4067-diff-partial-clone.sh
@@ -75,6 +75,37 @@ test_expect_success 'diff skips same-OID blobs' '
! grep "want $(cat hash-b)" trace
'
+test_expect_success 'when fetching missing objects, diff skips GITLINKs' '
+ test_when_finished "rm -rf sub server client trace" &&
+
+ test_create_repo sub &&
+ test_commit -C sub first &&
+
+ test_create_repo server &&
+ echo a >server/a &&
+ git -C server add a &&
+ git -C server submodule add "file://$(pwd)/sub" &&
+ git -C server commit -m x &&
+
+ test_commit -C server/sub second &&
+ echo another-a >server/a &&
+ git -C server add a sub &&
+ git -C server commit -m x &&
+
+ test_config -C server uploadpack.allowfilter 1 &&
+ test_config -C server uploadpack.allowanysha1inwant 1 &&
+ git clone --bare --filter=blob:limit=0 "file://$(pwd)/server" client &&
+
+ echo a | git hash-object --stdin >hash-old-a &&
+ echo another-a | git hash-object --stdin >hash-new-a &&
+
+ # Ensure that a and another-a are fetched, and check (by successful
+ # execution of the diff) that no invalid OIDs are sent.
+ GIT_TRACE_PACKET="$(pwd)/trace" git -C client diff HEAD^ HEAD &&
+ grep "want $(cat hash-old-a)" trace &&
+ grep "want $(cat hash-new-a)" trace
+'
+
test_expect_success 'diff with rename detection batches blobs' '
test_when_finished "rm -rf server client trace" &&
diff --git a/t/t4202-log.sh b/t/t4202-log.sh
index c20209324c..e88ccb04a9 100755
--- a/t/t4202-log.sh
+++ b/t/t4202-log.sh
@@ -1707,4 +1707,11 @@ test_expect_success '--exclude-promisor-objects does not BUG-crash' '
test_must_fail git log --exclude-promisor-objects source-a
'
+test_expect_success 'log --end-of-options' '
+ git update-ref refs/heads/--source HEAD &&
+ git log --end-of-options --source >actual &&
+ git log >expect &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t5004-archive-corner-cases.sh b/t/t5004-archive-corner-cases.sh
index 271eb5a1fd..3e7b23cb32 100755
--- a/t/t5004-archive-corner-cases.sh
+++ b/t/t5004-archive-corner-cases.sh
@@ -204,4 +204,23 @@ test_expect_success EXPENSIVE,LONG_IS_64BIT,UNZIP,UNZIP_ZIP64_SUPPORT,ZIPINFO \
grep $size big.lst
'
+build_tree() {
+ perl -e '
+ my $hash = $ARGV[0];
+ foreach my $order (2..6) {
+ $first = 10 ** $order;
+ foreach my $i (-13..-9) {
+ my $name = "a" x ($first + $i);
+ print "100644 blob $hash\t$name\n"
+ }
+ }
+ ' "$1"
+}
+
+test_expect_success 'tar archive with long paths' '
+ blob=$(echo foo | git hash-object -w --stdin) &&
+ tree=$(build_tree $blob | git mktree) &&
+ git archive -o long_paths.tar $tree
+'
+
test_done
diff --git a/t/t5307-pack-missing-commit.sh b/t/t5307-pack-missing-commit.sh
index dacb440b27..f4338abb78 100755
--- a/t/t5307-pack-missing-commit.sh
+++ b/t/t5307-pack-missing-commit.sh
@@ -24,11 +24,11 @@ test_expect_success 'check corruption' '
'
test_expect_success 'rev-list notices corruption (1)' '
- test_must_fail env GIT_TEST_COMMIT_GRAPH=0 git rev-list HEAD
+ test_must_fail env GIT_TEST_COMMIT_GRAPH=0 git -c core.commitGraph=false rev-list HEAD
'
test_expect_success 'rev-list notices corruption (2)' '
- test_must_fail env GIT_TEST_COMMIT_GRAPH=0 git rev-list --objects HEAD
+ test_must_fail env GIT_TEST_COMMIT_GRAPH=0 git -c core.commitGraph=false rev-list --objects HEAD
'
test_expect_success 'pack-objects notices corruption' '
diff --git a/t/t5318-commit-graph.sh b/t/t5318-commit-graph.sh
index 22cb9d6643..ab3eccf0fa 100755
--- a/t/t5318-commit-graph.sh
+++ b/t/t5318-commit-graph.sh
@@ -23,11 +23,10 @@ test_expect_success 'write graph with no packs' '
test_path_is_missing info/commit-graph
'
-test_expect_success 'close with correct error on bad input' '
+test_expect_success 'exit with correct error on bad input to --stdin-packs' '
cd "$TRASH_DIRECTORY/full" &&
echo doesnotexist >in &&
- { git commit-graph write --stdin-packs <in 2>stderr; ret=$?; } &&
- test "$ret" = 1 &&
+ test_expect_code 1 git commit-graph write --stdin-packs <in 2>stderr &&
test_i18ngrep "error adding pack" stderr
'
@@ -41,6 +40,15 @@ test_expect_success 'create commits and repack' '
git repack
'
+test_expect_success 'exit with correct error on bad input to --stdin-commits' '
+ cd "$TRASH_DIRECTORY/full" &&
+ echo HEAD | test_expect_code 1 git commit-graph write --stdin-commits 2>stderr &&
+ test_i18ngrep "invalid commit object id" stderr &&
+ # valid tree OID, but not a commit OID
+ git rev-parse HEAD^{tree} | test_expect_code 1 git commit-graph write --stdin-commits 2>stderr &&
+ test_i18ngrep "invalid commit object id" stderr
+'
+
graph_git_two_modes() {
git -c core.commitGraph=true $1 >output
git -c core.commitGraph=false $1 >expect
diff --git a/t/t5324-split-commit-graph.sh b/t/t5324-split-commit-graph.sh
index 99f4ef4c19..e2c39533d3 100755
--- a/t/t5324-split-commit-graph.sh
+++ b/t/t5324-split-commit-graph.sh
@@ -8,6 +8,7 @@ GIT_TEST_COMMIT_GRAPH=0
test_expect_success 'setup repo' '
git init &&
git config core.commitGraph true &&
+ git config gc.writeCommitGraph false &&
infodir=".git/objects/info" &&
graphdir="$infodir/commit-graphs" &&
test_oid_init
@@ -334,6 +335,7 @@ test_expect_success 'split across alternate where alternate is not split' '
git clone --no-hardlinks . alt-split &&
(
cd alt-split &&
+ rm -f .git/objects/info/commit-graph &&
echo "$(pwd)"/../.git/objects >.git/objects/info/alternates &&
test_commit 18 &&
git commit-graph write --reachable --split &&
diff --git a/t/t5500-fetch-pack.sh b/t/t5500-fetch-pack.sh
index 1c71c0ec77..8210f63d41 100755
--- a/t/t5500-fetch-pack.sh
+++ b/t/t5500-fetch-pack.sh
@@ -920,4 +920,7 @@ test_expect_success 'fetch with --filter=blob:limit=0 and HTTP' '
fetch_filter_blob_limit_zero "$HTTPD_DOCUMENT_ROOT_PATH/server" "$HTTPD_URL/smart/server"
'
+# DO NOT add non-httpd-specific tests here, because the last part of this
+# test script is only executed when httpd is available and enabled.
+
test_done
diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh
index 139f7106f7..34b486f1a4 100755
--- a/t/t5510-fetch.sh
+++ b/t/t5510-fetch.sh
@@ -902,6 +902,29 @@ test_expect_success C_LOCALE_OUTPUT 'fetch compact output' '
test_cmp expect actual
'
+test_expect_success '--no-show-forced-updates' '
+ mkdir forced-updates &&
+ (
+ cd forced-updates &&
+ git init &&
+ test_commit 1 &&
+ test_commit 2
+ ) &&
+ git clone forced-updates forced-update-clone &&
+ git clone forced-updates no-forced-update-clone &&
+ git -C forced-updates reset --hard HEAD~1 &&
+ (
+ cd forced-update-clone &&
+ git fetch --show-forced-updates origin 2>output &&
+ test_i18ngrep "(forced update)" output
+ ) &&
+ (
+ cd no-forced-update-clone &&
+ git fetch --no-show-forced-updates origin 2>output &&
+ test_i18ngrep ! "(forced update)" output
+ )
+'
+
setup_negotiation_tip () {
SERVER="$1"
URL="$2"
@@ -978,27 +1001,7 @@ test_expect_success '--negotiation-tip limits "have" lines sent with HTTP protoc
check_negotiation_tip
'
-test_expect_success '--no-show-forced-updates' '
- mkdir forced-updates &&
- (
- cd forced-updates &&
- git init &&
- test_commit 1 &&
- test_commit 2
- ) &&
- git clone forced-updates forced-update-clone &&
- git clone forced-updates no-forced-update-clone &&
- git -C forced-updates reset --hard HEAD~1 &&
- (
- cd forced-update-clone &&
- git fetch --show-forced-updates origin 2>output &&
- test_i18ngrep "(forced update)" output
- ) &&
- (
- cd no-forced-update-clone &&
- git fetch --no-show-forced-updates origin 2>output &&
- ! test_i18ngrep "(forced update)" output
- )
-'
+# DO NOT add non-httpd-specific tests here, because the last part of this
+# test script is only executed when httpd is available and enabled.
test_done
diff --git a/t/t5537-fetch-shallow.sh b/t/t5537-fetch-shallow.sh
index 66f0b64d39..97a67728ca 100755
--- a/t/t5537-fetch-shallow.sh
+++ b/t/t5537-fetch-shallow.sh
@@ -255,4 +255,7 @@ test_expect_success 'shallow fetches check connectivity before writing shallow f
git -C client fsck
'
+# DO NOT add non-httpd-specific tests here, because the last part of this
+# test script is only executed when httpd is available and enabled.
+
test_done
diff --git a/t/t5545-push-options.sh b/t/t5545-push-options.sh
index 6d1d59c9b1..04b34c4de1 100755
--- a/t/t5545-push-options.sh
+++ b/t/t5545-push-options.sh
@@ -278,4 +278,7 @@ test_expect_success 'push options keep quoted characters intact (http)' '
test_cmp expect "$HTTPD_DOCUMENT_ROOT_PATH"/upstream.git/hooks/pre-receive.push_options
'
+# DO NOT add non-httpd-specific tests here, because the last part of this
+# test script is only executed when httpd is available and enabled.
+
test_done
diff --git a/t/t5552-skipping-fetch-negotiator.sh b/t/t5552-skipping-fetch-negotiator.sh
index 8a14be51a1..f70cbcc9ca 100755
--- a/t/t5552-skipping-fetch-negotiator.sh
+++ b/t/t5552-skipping-fetch-negotiator.sh
@@ -60,29 +60,6 @@ test_expect_success 'commits with no parents are sent regardless of skip distanc
have_not_sent c6 c4 c3
'
-test_expect_success 'unknown fetch.negotiationAlgorithm values error out' '
- rm -rf server client trace &&
- git init server &&
- test_commit -C server to_fetch &&
-
- git init client &&
- test_commit -C client on_client &&
- git -C client checkout on_client &&
-
- test_config -C client fetch.negotiationAlgorithm invalid &&
- test_must_fail git -C client fetch "$(pwd)/server" 2>err &&
- test_i18ngrep "unknown fetch negotiation algorithm" err &&
-
- # Explicit "default" value
- test_config -C client fetch.negotiationAlgorithm default &&
- git -C client -c fetch.negotiationAlgorithm=default fetch "$(pwd)/server" &&
-
- # Implementation detail: If there is nothing to fetch, we will not error out
- test_config -C client fetch.negotiationAlgorithm invalid &&
- git -C client fetch "$(pwd)/server" 2>err &&
- test_i18ngrep ! "unknown fetch negotiation algorithm" err
-'
-
test_expect_success 'when two skips collide, favor the larger one' '
rm -rf server client trace &&
git init server &&
diff --git a/t/t5553-set-upstream.sh b/t/t5553-set-upstream.sh
new file mode 100755
index 0000000000..81975ad8f9
--- /dev/null
+++ b/t/t5553-set-upstream.sh
@@ -0,0 +1,178 @@
+#!/bin/sh
+
+test_description='"git fetch/pull --set-upstream" basic tests.'
+. ./test-lib.sh
+
+check_config () {
+ printf "%s\n" "$2" "$3" >"expect.$1" &&
+ {
+ git config "branch.$1.remote" && git config "branch.$1.merge"
+ } >"actual.$1" &&
+ test_cmp "expect.$1" "actual.$1"
+}
+
+check_config_missing () {
+ test_expect_code 1 git config "branch.$1.remote" &&
+ test_expect_code 1 git config "branch.$1.merge"
+}
+
+clear_config () {
+ for branch in "$@"; do
+ test_might_fail git config --unset-all "branch.$branch.remote"
+ test_might_fail git config --unset-all "branch.$branch.merge"
+ done
+}
+
+ensure_fresh_upstream () {
+ rm -rf parent && git init --bare parent
+}
+
+test_expect_success 'setup bare parent fetch' '
+ ensure_fresh_upstream &&
+ git remote add upstream parent
+'
+
+test_expect_success 'setup commit on master and other fetch' '
+ test_commit one &&
+ git push upstream master &&
+ git checkout -b other &&
+ test_commit two &&
+ git push upstream other
+'
+
+# tests for fetch --set-upstream
+
+test_expect_success 'fetch --set-upstream does not set upstream w/o branch' '
+ clear_config master other &&
+ git checkout master &&
+ git fetch --set-upstream upstream &&
+ check_config_missing master &&
+ check_config_missing other
+'
+
+test_expect_success 'fetch --set-upstream upstream master sets branch master but not other' '
+ clear_config master other &&
+ git fetch --set-upstream upstream master &&
+ check_config master upstream refs/heads/master &&
+ check_config_missing other
+'
+
+test_expect_success 'fetch --set-upstream upstream other sets branch other' '
+ clear_config master other &&
+ git fetch --set-upstream upstream other &&
+ check_config master upstream refs/heads/other &&
+ check_config_missing other
+'
+
+test_expect_success 'fetch --set-upstream master:other does not set the branch other2' '
+ clear_config other2 &&
+ git fetch --set-upstream upstream master:other2 &&
+ check_config_missing other2
+'
+
+test_expect_success 'fetch --set-upstream http://nosuchdomain.example.com fails with invalid url' '
+ # master explicitly not cleared, we check that it is not touched from previous value
+ clear_config other other2 &&
+ test_must_fail git fetch --set-upstream http://nosuchdomain.example.com &&
+ check_config master upstream refs/heads/other &&
+ check_config_missing other &&
+ check_config_missing other2
+'
+
+test_expect_success 'fetch --set-upstream with valid URL sets upstream to URL' '
+ clear_config other other2 &&
+ url="file://'"$PWD"'" &&
+ git fetch --set-upstream "$url" &&
+ check_config master "$url" HEAD &&
+ check_config_missing other &&
+ check_config_missing other2
+'
+
+# tests for pull --set-upstream
+
+test_expect_success 'setup bare parent pull' '
+ git remote rm upstream &&
+ ensure_fresh_upstream &&
+ git remote add upstream parent
+'
+
+test_expect_success 'setup commit on master and other pull' '
+ test_commit three &&
+ git push --tags upstream master &&
+ test_commit four &&
+ git push upstream other
+'
+
+test_expect_success 'pull --set-upstream upstream master sets branch master but not other' '
+ clear_config master other &&
+ git pull --set-upstream upstream master &&
+ check_config master upstream refs/heads/master &&
+ check_config_missing other
+'
+
+test_expect_success 'pull --set-upstream master:other2 does not set the branch other2' '
+ clear_config other2 &&
+ git pull --set-upstream upstream master:other2 &&
+ check_config_missing other2
+'
+
+test_expect_success 'pull --set-upstream upstream other sets branch master' '
+ clear_config master other &&
+ git pull --set-upstream upstream other &&
+ check_config master upstream refs/heads/other &&
+ check_config_missing other
+'
+
+test_expect_success 'pull --set-upstream upstream tag does not set the tag' '
+ clear_config three &&
+ git pull --tags --set-upstream upstream three &&
+ check_config_missing three
+'
+
+test_expect_success 'pull --set-upstream http://nosuchdomain.example.com fails with invalid url' '
+ # master explicitly not cleared, we check that it is not touched from previous value
+ clear_config other other2 three &&
+ test_must_fail git pull --set-upstream http://nosuchdomain.example.com &&
+ check_config master upstream refs/heads/other &&
+ check_config_missing other &&
+ check_config_missing other2 &&
+ check_config_missing three
+'
+
+test_expect_success 'pull --set-upstream upstream HEAD sets branch HEAD' '
+ clear_config master other &&
+ git pull --set-upstream upstream HEAD &&
+ check_config master upstream HEAD &&
+ git checkout other &&
+ git pull --set-upstream upstream HEAD &&
+ check_config other upstream HEAD
+'
+
+test_expect_success 'pull --set-upstream upstream with more than one branch does nothing' '
+ clear_config master three &&
+ git pull --set-upstream upstream master three &&
+ check_config_missing master &&
+ check_config_missing three
+'
+
+test_expect_success 'pull --set-upstream with valid URL sets upstream to URL' '
+ clear_config master other other2 &&
+ git checkout master &&
+ url="file://'"$PWD"'" &&
+ git pull --set-upstream "$url" &&
+ check_config master "$url" HEAD &&
+ check_config_missing other &&
+ check_config_missing other2
+'
+
+test_expect_success 'pull --set-upstream with valid URL and branch sets branch' '
+ clear_config master other other2 &&
+ git checkout master &&
+ url="file://'"$PWD"'" &&
+ git pull --set-upstream "$url" master &&
+ check_config master "$url" refs/heads/master &&
+ check_config_missing other &&
+ check_config_missing other2
+'
+
+test_done
diff --git a/t/t5601-clone.sh b/t/t5601-clone.sh
index 37d76808d4..4a3b901f06 100755
--- a/t/t5601-clone.sh
+++ b/t/t5601-clone.sh
@@ -739,4 +739,7 @@ test_expect_success 'partial clone using HTTP' '
partial_clone "$HTTPD_DOCUMENT_ROOT_PATH/server" "$HTTPD_URL/smart/server"
'
+# DO NOT add non-httpd-specific tests here, because the last part of this
+# test script is only executed when httpd is available and enabled.
+
test_done
diff --git a/t/t5616-partial-clone.sh b/t/t5616-partial-clone.sh
index b91ef548f8..565254558f 100755
--- a/t/t5616-partial-clone.sh
+++ b/t/t5616-partial-clone.sh
@@ -417,4 +417,7 @@ test_expect_success 'tolerate server sending REF_DELTA against missing promisor
! test -e "$HTTPD_ROOT_PATH/one-time-sed"
'
+# DO NOT add non-httpd-specific tests here, because the last part of this
+# test script is only executed when httpd is available and enabled.
+
test_done
diff --git a/t/t5700-protocol-v1.sh b/t/t5700-protocol-v1.sh
index 7c9511c593..2571eb90b7 100755
--- a/t/t5700-protocol-v1.sh
+++ b/t/t5700-protocol-v1.sh
@@ -292,4 +292,7 @@ test_expect_success 'push with http:// using protocol v1' '
grep "git< version 1" log
'
+# DO NOT add non-httpd-specific tests here, because the last part of this
+# test script is only executed when httpd is available and enabled.
+
test_done
diff --git a/t/t5702-protocol-v2.sh b/t/t5702-protocol-v2.sh
index 011b81d4fc..fbddd0aea9 100755
--- a/t/t5702-protocol-v2.sh
+++ b/t/t5702-protocol-v2.sh
@@ -723,4 +723,7 @@ test_expect_success 'when server does not send "ready", expect FLUSH' '
test_i18ngrep "expected no other sections to be sent after no .ready." err
'
+# DO NOT add non-httpd-specific tests here, because the last part of this
+# test script is only executed when httpd is available and enabled.
+
test_done
diff --git a/t/t5703-upload-pack-ref-in-want.sh b/t/t5703-upload-pack-ref-in-want.sh
index de4b6106ef..3a2c143c6d 100755
--- a/t/t5703-upload-pack-ref-in-want.sh
+++ b/t/t5703-upload-pack-ref-in-want.sh
@@ -157,106 +157,6 @@ test_expect_success 'want-ref with ref we already have commit for' '
check_output
'
-. "$TEST_DIRECTORY"/lib-httpd.sh
-start_httpd
-
-REPO="$HTTPD_DOCUMENT_ROOT_PATH/repo"
-LOCAL_PRISTINE="$(pwd)/local_pristine"
-
-test_expect_success 'setup repos for change-while-negotiating test' '
- (
- git init "$REPO" &&
- cd "$REPO" &&
- >.git/git-daemon-export-ok &&
- test_commit m1 &&
- git tag -d m1 &&
-
- # Local repo with many commits (so that negotiation will take
- # more than 1 request/response pair)
- git clone "http://127.0.0.1:$LIB_HTTPD_PORT/smart/repo" "$LOCAL_PRISTINE" &&
- cd "$LOCAL_PRISTINE" &&
- git checkout -b side &&
- test_commit_bulk --id=s 33 &&
-
- # Add novel commits to upstream
- git checkout master &&
- cd "$REPO" &&
- test_commit m2 &&
- test_commit m3 &&
- git tag -d m2 m3
- ) &&
- git -C "$LOCAL_PRISTINE" remote set-url origin "http://127.0.0.1:$LIB_HTTPD_PORT/one_time_sed/repo" &&
- git -C "$LOCAL_PRISTINE" config protocol.version 2
-'
-
-inconsistency () {
- # Simulate that the server initially reports $2 as the ref
- # corresponding to $1, and after that, $1 as the ref corresponding to
- # $1. This corresponds to the real-life situation where the server's
- # repository appears to change during negotiation, for example, when
- # different servers in a load-balancing arrangement serve (stateless)
- # RPCs during a single negotiation.
- printf "s/%s/%s/" \
- $(git -C "$REPO" rev-parse $1 | tr -d "\n") \
- $(git -C "$REPO" rev-parse $2 | tr -d "\n") \
- >"$HTTPD_ROOT_PATH/one-time-sed"
-}
-
-test_expect_success 'server is initially ahead - no ref in want' '
- git -C "$REPO" config uploadpack.allowRefInWant false &&
- rm -rf local &&
- cp -r "$LOCAL_PRISTINE" local &&
- inconsistency master 1234567890123456789012345678901234567890 &&
- test_must_fail git -C local fetch 2>err &&
- test_i18ngrep "fatal: remote error: upload-pack: not our ref" err
-'
-
-test_expect_success 'server is initially ahead - ref in want' '
- git -C "$REPO" config uploadpack.allowRefInWant true &&
- rm -rf local &&
- cp -r "$LOCAL_PRISTINE" local &&
- inconsistency master 1234567890123456789012345678901234567890 &&
- git -C local fetch &&
-
- git -C "$REPO" rev-parse --verify master >expected &&
- git -C local rev-parse --verify refs/remotes/origin/master >actual &&
- test_cmp expected actual
-'
-
-test_expect_success 'server is initially behind - no ref in want' '
- git -C "$REPO" config uploadpack.allowRefInWant false &&
- rm -rf local &&
- cp -r "$LOCAL_PRISTINE" local &&
- inconsistency master "master^" &&
- git -C local fetch &&
-
- git -C "$REPO" rev-parse --verify "master^" >expected &&
- git -C local rev-parse --verify refs/remotes/origin/master >actual &&
- test_cmp expected actual
-'
-
-test_expect_success 'server is initially behind - ref in want' '
- git -C "$REPO" config uploadpack.allowRefInWant true &&
- rm -rf local &&
- cp -r "$LOCAL_PRISTINE" local &&
- inconsistency master "master^" &&
- git -C local fetch &&
-
- git -C "$REPO" rev-parse --verify "master" >expected &&
- git -C local rev-parse --verify refs/remotes/origin/master >actual &&
- test_cmp expected actual
-'
-
-test_expect_success 'server loses a ref - ref in want' '
- git -C "$REPO" config uploadpack.allowRefInWant true &&
- rm -rf local &&
- cp -r "$LOCAL_PRISTINE" local &&
- echo "s/master/raster/" >"$HTTPD_ROOT_PATH/one-time-sed" &&
- test_must_fail git -C local fetch 2>err &&
-
- test_i18ngrep "fatal: remote error: unknown ref refs/heads/raster" err
-'
-
REPO="$(pwd)/repo"
LOCAL_PRISTINE="$(pwd)/local_pristine"
@@ -372,4 +272,108 @@ test_expect_success 'fetching with wildcard that matches multiple refs' '
grep "want-ref refs/heads/o/bar" log
'
+. "$TEST_DIRECTORY"/lib-httpd.sh
+start_httpd
+
+REPO="$HTTPD_DOCUMENT_ROOT_PATH/repo"
+LOCAL_PRISTINE="$(pwd)/local_pristine"
+
+test_expect_success 'setup repos for change-while-negotiating test' '
+ (
+ git init "$REPO" &&
+ cd "$REPO" &&
+ >.git/git-daemon-export-ok &&
+ test_commit m1 &&
+ git tag -d m1 &&
+
+ # Local repo with many commits (so that negotiation will take
+ # more than 1 request/response pair)
+ rm -rf "$LOCAL_PRISTINE" &&
+ git clone "http://127.0.0.1:$LIB_HTTPD_PORT/smart/repo" "$LOCAL_PRISTINE" &&
+ cd "$LOCAL_PRISTINE" &&
+ git checkout -b side &&
+ test_commit_bulk --id=s 33 &&
+
+ # Add novel commits to upstream
+ git checkout master &&
+ cd "$REPO" &&
+ test_commit m2 &&
+ test_commit m3 &&
+ git tag -d m2 m3
+ ) &&
+ git -C "$LOCAL_PRISTINE" remote set-url origin "http://127.0.0.1:$LIB_HTTPD_PORT/one_time_sed/repo" &&
+ git -C "$LOCAL_PRISTINE" config protocol.version 2
+'
+
+inconsistency () {
+ # Simulate that the server initially reports $2 as the ref
+ # corresponding to $1, and after that, $1 as the ref corresponding to
+ # $1. This corresponds to the real-life situation where the server's
+ # repository appears to change during negotiation, for example, when
+ # different servers in a load-balancing arrangement serve (stateless)
+ # RPCs during a single negotiation.
+ printf "s/%s/%s/" \
+ $(git -C "$REPO" rev-parse $1 | tr -d "\n") \
+ $(git -C "$REPO" rev-parse $2 | tr -d "\n") \
+ >"$HTTPD_ROOT_PATH/one-time-sed"
+}
+
+test_expect_success 'server is initially ahead - no ref in want' '
+ git -C "$REPO" config uploadpack.allowRefInWant false &&
+ rm -rf local &&
+ cp -r "$LOCAL_PRISTINE" local &&
+ inconsistency master 1234567890123456789012345678901234567890 &&
+ test_must_fail git -C local fetch 2>err &&
+ test_i18ngrep "fatal: remote error: upload-pack: not our ref" err
+'
+
+test_expect_success 'server is initially ahead - ref in want' '
+ git -C "$REPO" config uploadpack.allowRefInWant true &&
+ rm -rf local &&
+ cp -r "$LOCAL_PRISTINE" local &&
+ inconsistency master 1234567890123456789012345678901234567890 &&
+ git -C local fetch &&
+
+ git -C "$REPO" rev-parse --verify master >expected &&
+ git -C local rev-parse --verify refs/remotes/origin/master >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'server is initially behind - no ref in want' '
+ git -C "$REPO" config uploadpack.allowRefInWant false &&
+ rm -rf local &&
+ cp -r "$LOCAL_PRISTINE" local &&
+ inconsistency master "master^" &&
+ git -C local fetch &&
+
+ git -C "$REPO" rev-parse --verify "master^" >expected &&
+ git -C local rev-parse --verify refs/remotes/origin/master >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'server is initially behind - ref in want' '
+ git -C "$REPO" config uploadpack.allowRefInWant true &&
+ rm -rf local &&
+ cp -r "$LOCAL_PRISTINE" local &&
+ inconsistency master "master^" &&
+ git -C local fetch &&
+
+ git -C "$REPO" rev-parse --verify "master" >expected &&
+ git -C local rev-parse --verify refs/remotes/origin/master >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'server loses a ref - ref in want' '
+ git -C "$REPO" config uploadpack.allowRefInWant true &&
+ rm -rf local &&
+ cp -r "$LOCAL_PRISTINE" local &&
+ echo "s/master/raster/" >"$HTTPD_ROOT_PATH/one-time-sed" &&
+ test_must_fail git -C local fetch 2>err &&
+
+ test_i18ngrep "fatal: remote error: unknown ref refs/heads/raster" err
+'
+
+# DO NOT add non-httpd-specific tests here, because the last part of this
+# test script is only executed when httpd is available and enabled.
+
test_done
diff --git a/t/t6000-rev-list-misc.sh b/t/t6000-rev-list-misc.sh
index 52a9e38d66..b8cf82349b 100755
--- a/t/t6000-rev-list-misc.sh
+++ b/t/t6000-rev-list-misc.sh
@@ -140,4 +140,12 @@ test_expect_success '--header shows a NUL after each commit' '
test_cmp expect actual
'
+test_expect_success 'rev-list --end-of-options' '
+ git update-ref refs/heads/--output=yikes HEAD &&
+ git rev-list --end-of-options --output=yikes >actual &&
+ test_path_is_missing yikes &&
+ git rev-list HEAD >expect &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t6011-rev-list-with-bad-commit.sh b/t/t6011-rev-list-with-bad-commit.sh
index 545b461e51..bad02cf5b8 100755
--- a/t/t6011-rev-list-with-bad-commit.sh
+++ b/t/t6011-rev-list-with-bad-commit.sh
@@ -42,7 +42,7 @@ test_expect_success 'corrupt second commit object' \
'
test_expect_success 'rev-list should fail' '
- test_must_fail env GIT_TEST_COMMIT_GRAPH=0 git rev-list --all > /dev/null
+ test_must_fail env GIT_TEST_COMMIT_GRAPH=0 git -c core.commitGraph=false rev-list --all > /dev/null
'
test_expect_success 'git repack _MUST_ fail' \
diff --git a/t/t6501-freshen-objects.sh b/t/t6501-freshen-objects.sh
index 033871ee5f..f30b4849b6 100755
--- a/t/t6501-freshen-objects.sh
+++ b/t/t6501-freshen-objects.sh
@@ -137,7 +137,7 @@ test_expect_success 'do not complain about existing broken links (commit)' '
some message
EOF
commit=$(git hash-object -t commit -w broken-commit) &&
- git gc 2>stderr &&
+ git gc -q 2>stderr &&
verbose git cat-file -e $commit &&
test_must_be_empty stderr
'
@@ -147,7 +147,7 @@ test_expect_success 'do not complain about existing broken links (tree)' '
100644 blob 0000000000000000000000000000000000000003 foo
EOF
tree=$(git mktree --missing <broken-tree) &&
- git gc 2>stderr &&
+ git gc -q 2>stderr &&
git cat-file -e $tree &&
test_must_be_empty stderr
'
@@ -162,7 +162,7 @@ test_expect_success 'do not complain about existing broken links (tag)' '
this is a broken tag
EOF
tag=$(git hash-object -t tag -w broken-tag) &&
- git gc 2>stderr &&
+ git gc -q 2>stderr &&
git cat-file -e $tag &&
test_must_be_empty stderr
'
diff --git a/t/t7814-grep-recurse-submodules.sh b/t/t7814-grep-recurse-submodules.sh
index a11366b4ce..946f91fa57 100755
--- a/t/t7814-grep-recurse-submodules.sh
+++ b/t/t7814-grep-recurse-submodules.sh
@@ -408,4 +408,25 @@ test_expect_success 'grep --recurse-submodules with submodules without .gitmodul
test_cmp expect actual
'
+reset_and_clean () {
+ git reset --hard &&
+ git clean -fd &&
+ git submodule foreach --recursive 'git reset --hard' &&
+ git submodule foreach --recursive 'git clean -fd'
+}
+
+test_expect_success 'grep --recurse-submodules without --cached considers worktree modifications' '
+ reset_and_clean &&
+ echo "A modified line in submodule" >>submodule/a &&
+ echo "submodule/a:A modified line in submodule" >expect &&
+ git grep --recurse-submodules "A modified line in submodule" >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'grep --recurse-submodules with --cached ignores worktree modifications' '
+ reset_and_clean &&
+ echo "A modified line in submodule" >>submodule/a &&
+ test_must_fail git grep --recurse-submodules --cached "A modified line in submodule" >actual 2>&1 &&
+ test_must_be_empty actual
+'
test_done
diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh
index e0b3f28d3a..87bf3a2287 100644
--- a/t/test-lib-functions.sh
+++ b/t/test-lib-functions.sh
@@ -580,7 +580,7 @@ test_expect_failure () {
export test_prereq
if ! test_skip "$@"
then
- say >&3 "checking known breakage: $2"
+ say >&3 "checking known breakage of $TEST_NUMBER.$test_count '$1': $2"
if test_run_ "$2" expecting_failure
then
test_known_broken_ok_ "$1"
@@ -600,7 +600,7 @@ test_expect_success () {
export test_prereq
if ! test_skip "$@"
then
- say >&3 "expecting success: $2"
+ say >&3 "expecting success of $TEST_NUMBER.$test_count '$1': $2"
if test_run_ "$2"
then
test_ok_ "$1"
diff --git a/t/test-lib.sh b/t/test-lib.sh
index 30b07e310f..a9d45642a5 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -212,6 +212,8 @@ fi
TEST_STRESS_JOB_SFX="${GIT_TEST_STRESS_JOB_NR:+.stress-$GIT_TEST_STRESS_JOB_NR}"
TEST_NAME="$(basename "$0" .sh)"
+TEST_NUMBER="${TEST_NAME%%-*}"
+TEST_NUMBER="${TEST_NUMBER#t}"
TEST_RESULTS_DIR="$TEST_OUTPUT_DIRECTORY/test-results"
TEST_RESULTS_BASE="$TEST_RESULTS_DIR/$TEST_NAME$TEST_STRESS_JOB_SFX"
TRASH_DIRECTORY="trash directory.$TEST_NAME$TEST_STRESS_JOB_SFX"
diff --git a/tree-walk.c b/tree-walk.c
index c20b62f49e..bea819d826 100644
--- a/tree-walk.c
+++ b/tree-walk.c
@@ -170,40 +170,61 @@ int tree_entry_gently(struct tree_desc *desc, struct name_entry *entry)
void setup_traverse_info(struct traverse_info *info, const char *base)
{
- int pathlen = strlen(base);
+ size_t pathlen = strlen(base);
static struct traverse_info dummy;
memset(info, 0, sizeof(*info));
if (pathlen && base[pathlen-1] == '/')
pathlen--;
info->pathlen = pathlen ? pathlen + 1 : 0;
- info->name.path = base;
- info->name.pathlen = pathlen;
- if (pathlen) {
- hashcpy(info->name.oid.hash, (const unsigned char *)base + pathlen + 1);
+ info->name = base;
+ info->namelen = pathlen;
+ if (pathlen)
info->prev = &dummy;
- }
}
-char *make_traverse_path(char *path, const struct traverse_info *info, const struct name_entry *n)
+char *make_traverse_path(char *path, size_t pathlen,
+ const struct traverse_info *info,
+ const char *name, size_t namelen)
{
- int len = tree_entry_len(n);
- int pathlen = info->pathlen;
+ /* Always points to the end of the name we're about to add */
+ size_t pos = st_add(info->pathlen, namelen);
+
+ if (pos >= pathlen)
+ BUG("too small buffer passed to make_traverse_path");
- path[pathlen + len] = 0;
+ path[pos] = 0;
for (;;) {
- memcpy(path + pathlen, n->path, len);
- if (!pathlen)
+ if (pos < namelen)
+ BUG("traverse_info pathlen does not match strings");
+ pos -= namelen;
+ memcpy(path + pos, name, namelen);
+
+ if (!pos)
break;
- path[--pathlen] = '/';
- n = &info->name;
- len = tree_entry_len(n);
+ path[--pos] = '/';
+
+ if (!info)
+ BUG("traverse_info ran out of list items");
+ name = info->name;
+ namelen = info->namelen;
info = info->prev;
- pathlen -= len;
}
return path;
}
+void strbuf_make_traverse_path(struct strbuf *out,
+ const struct traverse_info *info,
+ const char *name, size_t namelen)
+{
+ size_t len = traverse_path_len(info, namelen);
+
+ strbuf_grow(out, len);
+ make_traverse_path(out->buf + out->len, out->alloc - out->len,
+ info, name, namelen);
+ strbuf_setlen(out, out->len + len);
+}
+
struct tree_desc_skip {
struct tree_desc_skip *prev;
const void *ptr;
@@ -400,13 +421,12 @@ int traverse_trees(struct index_state *istate,
tx[i].d = t[i];
if (info->prev) {
- strbuf_grow(&base, info->pathlen);
- make_traverse_path(base.buf, info->prev, &info->name);
- base.buf[info->pathlen-1] = '/';
- strbuf_setlen(&base, info->pathlen);
- traverse_path = xstrndup(base.buf, info->pathlen);
+ strbuf_make_traverse_path(&base, info->prev,
+ info->name, info->namelen);
+ strbuf_addch(&base, '/');
+ traverse_path = xstrndup(base.buf, base.len);
} else {
- traverse_path = xstrndup(info->name.path, info->pathlen);
+ traverse_path = xstrndup(info->name, info->pathlen);
}
info->traverse_path = traverse_path;
for (;;) {
diff --git a/tree-walk.h b/tree-walk.h
index 2a5db29e8f..abe2caf4e0 100644
--- a/tree-walk.h
+++ b/tree-walk.h
@@ -58,8 +58,11 @@ enum get_oid_result get_tree_entry_follow_symlinks(struct repository *r, struct
struct traverse_info {
const char *traverse_path;
struct traverse_info *prev;
- struct name_entry name;
- int pathlen;
+ const char *name;
+ size_t namelen;
+ unsigned mode;
+
+ size_t pathlen;
struct pathspec *pathspec;
unsigned long df_conflicts;
@@ -69,12 +72,17 @@ struct traverse_info {
};
int get_tree_entry(struct repository *, const struct object_id *, const char *, struct object_id *, unsigned short *);
-char *make_traverse_path(char *path, const struct traverse_info *info, const struct name_entry *n);
+char *make_traverse_path(char *path, size_t pathlen, const struct traverse_info *info,
+ const char *name, size_t namelen);
+void strbuf_make_traverse_path(struct strbuf *out,
+ const struct traverse_info *info,
+ const char *name, size_t namelen);
void setup_traverse_info(struct traverse_info *info, const char *base);
-static inline int traverse_path_len(const struct traverse_info *info, const struct name_entry *n)
+static inline size_t traverse_path_len(const struct traverse_info *info,
+ size_t namelen)
{
- return info->pathlen + tree_entry_len(n);
+ return st_add(info->pathlen, namelen);
}
/* in general, positive means "kind of interesting" */
diff --git a/unpack-trees.c b/unpack-trees.c
index 62276d4fef..50f257bd5c 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -632,7 +632,7 @@ static int unpack_index_entry(struct cache_entry *ce,
return ret;
}
-static int find_cache_pos(struct traverse_info *, const struct name_entry *);
+static int find_cache_pos(struct traverse_info *, const char *p, size_t len);
static void restore_cache_bottom(struct traverse_info *info, int bottom)
{
@@ -651,7 +651,7 @@ static int switch_cache_bottom(struct traverse_info *info)
if (o->diff_index_cached)
return 0;
ret = o->cache_bottom;
- pos = find_cache_pos(info->prev, &info->name);
+ pos = find_cache_pos(info->prev, info->name, info->namelen);
if (pos < -1)
o->cache_bottom = -2 - pos;
@@ -686,21 +686,19 @@ static int index_pos_by_traverse_info(struct name_entry *names,
struct traverse_info *info)
{
struct unpack_trees_options *o = info->data;
- int len = traverse_path_len(info, names);
- char *name = xmalloc(len + 1 /* slash */ + 1 /* NUL */);
+ struct strbuf name = STRBUF_INIT;
int pos;
- make_traverse_path(name, info, names);
- name[len++] = '/';
- name[len] = '\0';
- pos = index_name_pos(o->src_index, name, len);
+ strbuf_make_traverse_path(&name, info, names->path, names->pathlen);
+ strbuf_addch(&name, '/');
+ pos = index_name_pos(o->src_index, name.buf, name.len);
if (pos >= 0)
BUG("This is a directory and should not exist in index");
pos = -pos - 1;
- if (!starts_with(o->src_index->cache[pos]->name, name) ||
- (pos > 0 && starts_with(o->src_index->cache[pos-1]->name, name)))
+ if (!starts_with(o->src_index->cache[pos]->name, name.buf) ||
+ (pos > 0 && starts_with(o->src_index->cache[pos-1]->name, name.buf)))
BUG("pos must point at the first entry in this directory");
- free(name);
+ strbuf_release(&name);
return pos;
}
@@ -811,8 +809,10 @@ static int traverse_trees_recursive(int n, unsigned long dirmask,
newinfo = *info;
newinfo.prev = info;
newinfo.pathspec = info->pathspec;
- newinfo.name = *p;
- newinfo.pathlen += tree_entry_len(p) + 1;
+ newinfo.name = p->path;
+ newinfo.namelen = p->pathlen;
+ newinfo.mode = p->mode;
+ newinfo.pathlen = st_add3(newinfo.pathlen, tree_entry_len(p), 1);
newinfo.df_conflicts |= df_conflicts;
/*
@@ -863,14 +863,18 @@ static int traverse_trees_recursive(int n, unsigned long dirmask,
* itself - the caller needs to do the final check for the cache
* entry having more data at the end!
*/
-static int do_compare_entry_piecewise(const struct cache_entry *ce, const struct traverse_info *info, const struct name_entry *n)
+static int do_compare_entry_piecewise(const struct cache_entry *ce,
+ const struct traverse_info *info,
+ const char *name, size_t namelen,
+ unsigned mode)
{
- int len, pathlen, ce_len;
+ int pathlen, ce_len;
const char *ce_name;
if (info->prev) {
int cmp = do_compare_entry_piecewise(ce, info->prev,
- &info->name);
+ info->name, info->namelen,
+ info->mode);
if (cmp)
return cmp;
}
@@ -884,15 +888,15 @@ static int do_compare_entry_piecewise(const struct cache_entry *ce, const struct
ce_len -= pathlen;
ce_name = ce->name + pathlen;
- len = tree_entry_len(n);
- return df_name_compare(ce_name, ce_len, S_IFREG, n->path, len, n->mode);
+ return df_name_compare(ce_name, ce_len, S_IFREG, name, namelen, mode);
}
static int do_compare_entry(const struct cache_entry *ce,
const struct traverse_info *info,
- const struct name_entry *n)
+ const char *name, size_t namelen,
+ unsigned mode)
{
- int len, pathlen, ce_len;
+ int pathlen, ce_len;
const char *ce_name;
int cmp;
@@ -902,7 +906,7 @@ static int do_compare_entry(const struct cache_entry *ce,
* it is quicker to use the precomputed version.
*/
if (!info->traverse_path)
- return do_compare_entry_piecewise(ce, info, n);
+ return do_compare_entry_piecewise(ce, info, name, namelen, mode);
cmp = strncmp(ce->name, info->traverse_path, info->pathlen);
if (cmp)
@@ -917,13 +921,12 @@ static int do_compare_entry(const struct cache_entry *ce,
ce_len -= pathlen;
ce_name = ce->name + pathlen;
- len = tree_entry_len(n);
- return df_name_compare(ce_name, ce_len, S_IFREG, n->path, len, n->mode);
+ return df_name_compare(ce_name, ce_len, S_IFREG, name, namelen, mode);
}
static int compare_entry(const struct cache_entry *ce, const struct traverse_info *info, const struct name_entry *n)
{
- int cmp = do_compare_entry(ce, info, n);
+ int cmp = do_compare_entry(ce, info, n->path, n->pathlen, n->mode);
if (cmp)
return cmp;
@@ -931,7 +934,7 @@ static int compare_entry(const struct cache_entry *ce, const struct traverse_inf
* Even if the beginning compared identically, the ce should
* compare as bigger than a directory leading up to it!
*/
- return ce_namelen(ce) > traverse_path_len(info, n);
+ return ce_namelen(ce) > traverse_path_len(info, tree_entry_len(n));
}
static int ce_in_traverse_path(const struct cache_entry *ce,
@@ -939,7 +942,8 @@ static int ce_in_traverse_path(const struct cache_entry *ce,
{
if (!info->prev)
return 1;
- if (do_compare_entry(ce, info->prev, &info->name))
+ if (do_compare_entry(ce, info->prev,
+ info->name, info->namelen, info->mode))
return 0;
/*
* If ce (blob) is the same name as the path (which is a tree
@@ -954,7 +958,7 @@ static struct cache_entry *create_ce_entry(const struct traverse_info *info,
struct index_state *istate,
int is_transient)
{
- int len = traverse_path_len(info, n);
+ size_t len = traverse_path_len(info, tree_entry_len(n));
struct cache_entry *ce =
is_transient ?
make_empty_transient_cache_entry(len) :
@@ -964,7 +968,8 @@ static struct cache_entry *create_ce_entry(const struct traverse_info *info,
ce->ce_flags = create_ce_flags(stage);
ce->ce_namelen = len;
oidcpy(&ce->oid, &n->oid);
- make_traverse_path(ce->name, info, n);
+ /* len+1 because the cache_entry allocates space for NUL */
+ make_traverse_path(ce->name, len + 1, info, n->path, n->pathlen);
return ce;
}
@@ -1057,13 +1062,12 @@ static int unpack_failed(struct unpack_trees_options *o, const char *message)
* the directory.
*/
static int find_cache_pos(struct traverse_info *info,
- const struct name_entry *p)
+ const char *p, size_t p_len)
{
int pos;
struct unpack_trees_options *o = info->data;
struct index_state *index = o->src_index;
int pfxlen = info->pathlen;
- int p_len = tree_entry_len(p);
for (pos = o->cache_bottom; pos < index->cache_nr; pos++) {
const struct cache_entry *ce = index->cache[pos];
@@ -1099,7 +1103,7 @@ static int find_cache_pos(struct traverse_info *info,
ce_len = ce_slash - ce_name;
else
ce_len = ce_namelen(ce) - pfxlen;
- cmp = name_compare(p->path, p_len, ce_name, ce_len);
+ cmp = name_compare(p, p_len, ce_name, ce_len);
/*
* Exact match; if we have a directory we need to
* delay returning it.
@@ -1114,7 +1118,7 @@ static int find_cache_pos(struct traverse_info *info,
* E.g. ce_name == "t-i", and p->path == "t"; we may
* have "t/a" in the index.
*/
- if (p_len < ce_len && !memcmp(ce_name, p->path, p_len) &&
+ if (p_len < ce_len && !memcmp(ce_name, p, p_len) &&
ce_name[p_len] < '/')
continue; /* keep looking */
break;
@@ -1125,7 +1129,7 @@ static int find_cache_pos(struct traverse_info *info,
static struct cache_entry *find_cache_entry(struct traverse_info *info,
const struct name_entry *p)
{
- int pos = find_cache_pos(info, p);
+ int pos = find_cache_pos(info, p->path, p->pathlen);
struct unpack_trees_options *o = info->data;
if (0 <= pos)
@@ -1138,10 +1142,10 @@ static void debug_path(struct traverse_info *info)
{
if (info->prev) {
debug_path(info->prev);
- if (*info->prev->name.path)
+ if (*info->prev->name)
putchar('/');
}
- printf("%s", info->name.path);
+ printf("%s", info->name);
}
static void debug_name_entry(int i, struct name_entry *n)