From a58539c35f1c98f3af31a4aa78be74b9f261534b Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 16 Nov 2021 17:45:18 +0100 Subject: [PATCH 01/15] cmake: optionally build `scalar`, too Unlike the `Makefile`-based build, the CMake configuration unfortunately does not let us easily encapsulate Scalar's build definition in the `contrib/scalar/` subdirectory: The `scalar` executable needs to link in `libgit.a` and `common-main.o`, for example. Also, `scalar.c` includes Git's header files, which means that `scalar.c` needs to be compiled with the very same flags as `libgit.a` lest `scalar.o` and `libgit.a` have different ideas of, say, `platform_SHA_CTX`, which would naturally lead to memory corruption, crashes and quite tricky debugging (talking from experience). To alleviate that lack of encapsulation somewhat, we guard the Scalar parts in `CMakeLists.txt` via the `INCLUDE_SCALAR` environment variable. This not only allows the CMake-based build to exclude Scalar by default, but also gives better visual cues as to which sections are related to Scalar. Signed-off-by: Johannes Schindelin --- contrib/buildsystems/CMakeLists.txt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt index 1b23f2440d8e45..2162210a4734cb 100644 --- a/contrib/buildsystems/CMakeLists.txt +++ b/contrib/buildsystems/CMakeLists.txt @@ -775,6 +775,13 @@ if(CURL_FOUND) endif() endif() +if(DEFINED ENV{INCLUDE_SCALAR} AND NOT ENV{INCLUDE_SCALAR} STREQUAL "") + add_executable(scalar ${CMAKE_SOURCE_DIR}/contrib/scalar/scalar.c) + target_link_libraries(scalar common-main) + set_target_properties(scalar PROPERTIES RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR}/contrib/scalar) + set_target_properties(scalar PROPERTIES RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR}/contrib/scalar) +endif() + parse_makefile_for_executables(git_builtin_extra "BUILT_INS") option(SKIP_DASHED_BUILT_INS "Skip hardlinking the dashed versions of the built-ins") @@ -1002,6 +1009,13 @@ string(REPLACE "@@BUILD_DIR@@" "${CMAKE_BINARY_DIR}" content "${content}") string(REPLACE "@@PROG@@" "git-cvsserver" content "${content}") file(WRITE ${CMAKE_BINARY_DIR}/bin-wrappers/git-cvsserver ${content}) +if(DEFINED ENV{INCLUDE_SCALAR} AND NOT ENV{INCLUDE_SCALAR} STREQUAL "") + file(STRINGS ${CMAKE_SOURCE_DIR}/wrap-for-bin.sh content NEWLINE_CONSUME) + string(REPLACE "@@BUILD_DIR@@" "${CMAKE_BINARY_DIR}" content "${content}") + string(REPLACE "@@PROG@@" "contrib/scalar/scalar${EXE_EXTENSION}" content "${content}") + file(WRITE ${CMAKE_BINARY_DIR}/bin-wrappers/scalar ${content}) +endif() + #options for configuring test options option(PERL_TESTS "Perform tests that use perl" ON) option(PYTHON_TESTS "Perform tests that use python" ON) From 1d2e333e89e1f8841fe2717a42173eb28f6d0311 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Wed, 14 Apr 2021 20:33:39 +0200 Subject: [PATCH 02/15] ci: also run the `scalar` tests Since Scalar depends on `libgit.a`, it makes sense to ensure in the CI and the PR builds that it does not get broken in case of industrious refactorings of the core Git code (speaking from experience here). Signed-off-by: Johannes Schindelin --- .github/workflows/main.yml | 15 +++++++++++++++ ci/run-build-and-tests.sh | 2 ++ ci/run-test-slice.sh | 5 +++++ 3 files changed, 22 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 3fa88b78b6db04..a479400d5dfad1 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -91,6 +91,13 @@ jobs: HOME: ${{runner.workspace}} NO_PERL: 1 run: . /etc/profile && ci/make-test-artifacts.sh artifacts + - name: build Scalar + shell: bash + run: | + make -C contrib/scalar && + mkdir -p artifacts/bin-wrappers artifacts/contrib/scalar && + cp contrib/scalar/scalar.exe artifacts/contrib/scalar/ && + cp bin-wrappers/scalar artifacts/bin-wrappers/ - name: zip up tracked files run: git archive -o artifacts/tracked.tar.gz HEAD - name: upload tracked files and build artifacts @@ -157,6 +164,8 @@ jobs: run: compat\vcbuild\vcpkg_copy_dlls.bat release - name: generate Visual Studio solution shell: bash + env: + INCLUDE_SCALAR: YesPlease run: | cmake `pwd`/contrib/buildsystems/ -DCMAKE_PREFIX_PATH=`pwd`/compat/vcbuild/vcpkg/installed/x64-windows \ -DNO_GETTEXT=YesPlease -DPERL_TESTS=OFF -DPYTHON_TESTS=OFF -DCURL_NO_CURL_CMAKE=ON @@ -170,6 +179,12 @@ jobs: run: | mkdir -p artifacts && eval "$(make -n artifacts-tar INCLUDE_DLLS_IN_ARTIFACTS=YesPlease ARTIFACTS_DIRECTORY=artifacts NO_GETTEXT=YesPlease 2>&1 | grep ^tar)" + - name: copy Scalar + shell: bash + run: | + mkdir -p artifacts/bin-wrappers artifacts/contrib/scalar && + cp contrib/scalar/scalar.exe artifacts/contrib/scalar/ && + cp bin-wrappers/scalar artifacts/bin-wrappers/ - name: zip up tracked files run: git archive -o artifacts/tracked.tar.gz HEAD - name: upload tracked files and build artifacts diff --git a/ci/run-build-and-tests.sh b/ci/run-build-and-tests.sh index 8ebff4259676e3..0d1824f437ea73 100755 --- a/ci/run-build-and-tests.sh +++ b/ci/run-build-and-tests.sh @@ -53,4 +53,6 @@ then fi check_unignored_build_artifacts +make -C contrib/scalar $MAKE_TARGETS + save_good_tree diff --git a/ci/run-test-slice.sh b/ci/run-test-slice.sh index a3c67956a8df8f..6dd8af20c04d12 100755 --- a/ci/run-test-slice.sh +++ b/ci/run-test-slice.sh @@ -15,4 +15,9 @@ group "Run tests" make --quiet -C t T="$(cd t && tr '\n' ' ')" || handle_failed_tests +if test 0 = "$1" +then + make -C contrib/scalar test +fi + check_unignored_build_artifacts From aee7bd17d27c3e26be70d735d8db71b14120b946 Mon Sep 17 00:00:00 2001 From: Matthew John Cheetham Date: Wed, 19 May 2021 11:06:08 +0100 Subject: [PATCH 03/15] scalar: enable built-in FSMonitor on `register` Using the built-in FSMonitor makes many common commands quite a bit faster. So let's teach the `scalar register` command to enable the built-in FSMonitor and kick-start the fsmonitor--daemon process (for convenience). For simplicity, we only support the built-in FSMonitor (and no external file system monitor such as e.g. Watchman). Signed-off-by: Matthew John Cheetham Signed-off-by: Johannes Schindelin --- contrib/scalar/scalar.c | 36 ++++++++++++++++++++++++++++++++ contrib/scalar/t/t9099-scalar.sh | 11 ++++++++++ 2 files changed, 47 insertions(+) diff --git a/contrib/scalar/scalar.c b/contrib/scalar/scalar.c index 28176914e57b91..455b382165de5f 100644 --- a/contrib/scalar/scalar.c +++ b/contrib/scalar/scalar.c @@ -13,6 +13,8 @@ #include "help.h" #include "archive.h" #include "object-store.h" +#include "simple-ipc.h" +#include "fsmonitor-ipc.h" /* * Remove the deepest subdirectory in the provided path string. Path must not @@ -169,6 +171,12 @@ static int set_recommended_config(int reconfigure) { "core.autoCRLF", "false" }, { "core.safeCRLF", "false" }, { "fetch.showForcedUpdates", "false" }, +#ifdef HAVE_FSMONITOR_DAEMON_BACKEND + /* + * Enable the built-in FSMonitor on supported platforms. + */ + { "core.fsmonitor", "true" }, +#endif { NULL, NULL }, }; int i; @@ -236,6 +244,31 @@ static int add_or_remove_enlistment(int add) "scalar.repo", the_repository->worktree, NULL); } +static int start_fsmonitor_daemon(void) +{ +#ifdef HAVE_FSMONITOR_DAEMON_BACKEND + struct strbuf err = STRBUF_INIT; + struct child_process cp = CHILD_PROCESS_INIT; + + cp.git_cmd = 1; + strvec_pushl(&cp.args, "fsmonitor--daemon", "start", NULL); + if (!pipe_command(&cp, NULL, 0, NULL, 0, &err, 0)) { + strbuf_release(&err); + return 0; + } + + if (fsmonitor_ipc__get_state() != IPC_STATE__LISTENING) { + write_in_full(2, err.buf, err.len); + strbuf_release(&err); + return error(_("could not start the FSMonitor daemon")); + } + + strbuf_release(&err); +#endif + + return 0; +} + static int register_dir(void) { int res = add_or_remove_enlistment(1); @@ -246,6 +279,9 @@ static int register_dir(void) if (!res) res = toggle_maintenance(1); + if (!res) + res = start_fsmonitor_daemon(); + return res; } diff --git a/contrib/scalar/t/t9099-scalar.sh b/contrib/scalar/t/t9099-scalar.sh index 10b1172a8aa0d2..526f64d001c6c1 100755 --- a/contrib/scalar/t/t9099-scalar.sh +++ b/contrib/scalar/t/t9099-scalar.sh @@ -13,10 +13,21 @@ PATH=$PWD/..:$PATH GIT_TEST_MAINT_SCHEDULER="crontab:test-tool crontab ../cron.txt,launchctl:true,schtasks:true" export GIT_TEST_MAINT_SCHEDULER +test_lazy_prereq BUILTIN_FSMONITOR ' + git version --build-options | grep -q "feature:.*fsmonitor--daemon" +' + test_expect_success 'scalar shows a usage' ' test_expect_code 129 scalar -h ' +test_expect_success BUILTIN_FSMONITOR 'scalar register starts fsmon daemon' ' + git init test/src && + test_must_fail git -C test/src fsmonitor--daemon status && + scalar register test/src && + git -C test/src fsmonitor--daemon status +' + test_expect_success 'scalar unregister' ' git init vanish/src && scalar register vanish/src && From c367746d4bf669f5984916eb6b504ae9386aa425 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 18 May 2021 22:48:24 +0200 Subject: [PATCH 04/15] git_config_set_multivar_in_file_gently(): add a lock timeout In particular when multiple processes want to write to the config simultaneously, it would come in handy to not fail immediately when another process locked the config, but to gently try again. This will help with Scalar's functional test suite which wants to register multiple repositories for maintenance semi-simultaneously. As not all code paths calling this function read the config (e.g. `git config`), we have to read the config setting via `git_config_get_ulong()`. Signed-off-by: Johannes Schindelin --- Documentation/config/core.txt | 9 +++++++++ config.c | 8 +++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/Documentation/config/core.txt b/Documentation/config/core.txt index 41e330f30694da..1facd716d254fd 100644 --- a/Documentation/config/core.txt +++ b/Documentation/config/core.txt @@ -721,3 +721,12 @@ core.abbrev:: If set to "no", no abbreviation is made and the object names are shown in their full length. The minimum length is 4. + +core.configWriteLockTimeoutMS:: + When processes try to write to the config concurrently, it is likely + that one process "wins" and the other process(es) fail to lock the + config file. By configuring a timeout larger than zero, Git can be + told to try to lock the config again a couple times within the + specified timeout. If the timeout is configure to zero (which is the + default), Git will fail immediately when the config is already + locked. diff --git a/config.c b/config.c index 9b0e9c93285fb3..e4089f983101e5 100644 --- a/config.c +++ b/config.c @@ -3153,6 +3153,7 @@ int git_config_set_multivar_in_file_gently(const char *config_filename, const char *value_pattern, unsigned flags) { + static unsigned long timeout_ms = ULONG_MAX; int fd = -1, in_fd = -1; int ret; struct lock_file lock = LOCK_INIT; @@ -3173,11 +3174,16 @@ int git_config_set_multivar_in_file_gently(const char *config_filename, if (!config_filename) config_filename = filename_buf = git_pathdup("config"); + if ((long)timeout_ms < 0 && + git_config_get_ulong("core.configWriteLockTimeoutMS", &timeout_ms)) + timeout_ms = 0; + /* * The lock serves a purpose in addition to locking: the new * contents of .git/config will be written into it. */ - fd = hold_lock_file_for_update(&lock, config_filename, 0); + fd = hold_lock_file_for_update_timeout(&lock, config_filename, 0, + timeout_ms); if (fd < 0) { error_errno(_("could not lock config file %s"), config_filename); ret = CONFIG_NO_LOCK; From c14069f235531591ab479bfe66cff2e236fe002a Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 23 Apr 2021 00:17:20 +0200 Subject: [PATCH 05/15] scalar unregister: stop FSMonitor daemon Especially on Windows, we will need to stop that daemon, just in case that the directory needs to be removed (the daemon would otherwise hold a handle to that directory, preventing it from being deleted). Signed-off-by: Johannes Schindelin --- contrib/scalar/scalar.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/contrib/scalar/scalar.c b/contrib/scalar/scalar.c index 455b382165de5f..9937fc596263eb 100644 --- a/contrib/scalar/scalar.c +++ b/contrib/scalar/scalar.c @@ -269,6 +269,31 @@ static int start_fsmonitor_daemon(void) return 0; } +static int stop_fsmonitor_daemon(void) +{ +#ifdef HAVE_FSMONITOR_DAEMON_BACKEND + struct strbuf err = STRBUF_INIT; + struct child_process cp = CHILD_PROCESS_INIT; + + cp.git_cmd = 1; + strvec_pushl(&cp.args, "fsmonitor--daemon", "stop", NULL); + if (!pipe_command(&cp, NULL, 0, NULL, 0, &err, 0)) { + strbuf_release(&err); + return 0; + } + + if (fsmonitor_ipc__get_state() == IPC_STATE__LISTENING) { + write_in_full(2, err.buf, err.len); + strbuf_release(&err); + return error(_("could not stop the FSMonitor daemon")); + } + + strbuf_release(&err); +#endif + + return 0; +} + static int register_dir(void) { int res = add_or_remove_enlistment(1); @@ -295,6 +320,9 @@ static int unregister_dir(void) if (add_or_remove_enlistment(0) < 0) res = -1; + if (stop_fsmonitor_daemon() < 0) + res = -1; + return res; } From 87bc79160b767fbb7bae0f6a77219b9be5208b4d Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 18 May 2021 23:22:56 +0200 Subject: [PATCH 06/15] scalar: set the config write-lock timeout to 150ms By default, Git fails immediately when locking a config file for writing fails due to an existing lock. With this change, Scalar-registered repositories will fall back to trying a couple times within a 150ms timeout. Signed-off-by: Johannes Schindelin --- contrib/scalar/scalar.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/contrib/scalar/scalar.c b/contrib/scalar/scalar.c index 9937fc596263eb..85ead6be17f198 100644 --- a/contrib/scalar/scalar.c +++ b/contrib/scalar/scalar.c @@ -177,6 +177,7 @@ static int set_recommended_config(int reconfigure) */ { "core.fsmonitor", "true" }, #endif + { "core.configWriteLockTimeoutMS", "150" }, { NULL, NULL }, }; int i; @@ -219,16 +220,25 @@ static int set_recommended_config(int reconfigure) static int toggle_maintenance(int enable) { + unsigned long ul; + + if (git_config_get_ulong("core.configWriteLockTimeoutMS", &ul)) + git_config_push_parameter("core.configWriteLockTimeoutMS=150"); + return run_git("maintenance", enable ? "start" : "unregister", NULL); } static int add_or_remove_enlistment(int add) { int res; + unsigned long ul; if (!the_repository->worktree) die(_("Scalar enlistments require a worktree")); + if (git_config_get_ulong("core.configWriteLockTimeoutMS", &ul)) + git_config_push_parameter("core.configWriteLockTimeoutMS=150"); + res = run_git("config", "--global", "--get", "--fixed-value", "scalar.repo", the_repository->worktree, NULL); From 3ab8f7c89b80b40797914e7ab6d14f8d8ed77266 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 16 Nov 2021 18:08:24 +0100 Subject: [PATCH 07/15] scalar: allow installing the command Now that we implemented Scalar's core functionality, let's offer users the option to install the command via `make -C contrib/scalar install`. Signed-off-by: Johannes Schindelin --- contrib/scalar/Makefile | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/contrib/scalar/Makefile b/contrib/scalar/Makefile index 37f283f35d74d6..3944efe2caa23d 100644 --- a/contrib/scalar/Makefile +++ b/contrib/scalar/Makefile @@ -32,4 +32,14 @@ clean: test: all $(MAKE) -C t -.PHONY: $(GITLIBS) all clean test FORCE +INSTALL = install +prefix = $(HOME) +bindir = $(prefix)/bin +DESTDIR_SQ = $(subst ','\'',$(DESTDIR)) +bindir_SQ = $(subst ','\'',$(bindir)) + +install: + $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)' + $(INSTALL) scalar$(X) '$(DESTDIR_SQ)$(bindir_SQ)' + +.PHONY: $(GITLIBS) all clean test install FORCE From ae2d4cad92f82c9068b805733016b1aeb7081990 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 3 May 2021 15:34:03 +0200 Subject: [PATCH 08/15] scalar: allow building and installing the documentation Now that Scalar is reasonably complete, we are comfortable having users install its documentation, too. Signed-off-by: Johannes Schindelin --- contrib/scalar/.gitignore | 3 +++ contrib/scalar/Makefile | 26 +++++++++++++++++++++++++- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/contrib/scalar/.gitignore b/contrib/scalar/.gitignore index ff3d47e84d0436..00441073f59cf5 100644 --- a/contrib/scalar/.gitignore +++ b/contrib/scalar/.gitignore @@ -1,2 +1,5 @@ +/*.xml +/*.1 +/*.html /*.exe /scalar diff --git a/contrib/scalar/Makefile b/contrib/scalar/Makefile index 3944efe2caa23d..df5ef37af94a82 100644 --- a/contrib/scalar/Makefile +++ b/contrib/scalar/Makefile @@ -21,6 +21,7 @@ $(TARGETS): $(GITLIBS) scalar.c clean: $(RM) $(TARGETS) ../../bin-wrappers/scalar + $(RM) scalar.1 scalar.html scalar.xml ../../bin-wrappers/scalar: ../../wrap-for-bin.sh Makefile @mkdir -p ../../bin-wrappers @@ -35,11 +36,34 @@ test: all INSTALL = install prefix = $(HOME) bindir = $(prefix)/bin +mandir ?= $(prefix)/share/man +man1dir = $(mandir)/man1 +htmldir ?= $(prefix)/share/doc/git-doc DESTDIR_SQ = $(subst ','\'',$(DESTDIR)) bindir_SQ = $(subst ','\'',$(bindir)) +man1dir_SQ = $(subst ','\'',$(man1dir)) +htmldir_SQ = $(subst ','\'',$(htmldir)) install: $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)' $(INSTALL) scalar$(X) '$(DESTDIR_SQ)$(bindir_SQ)' -.PHONY: $(GITLIBS) all clean test install FORCE +docs: scalar.html scalar.1 + +scalar.html: | scalar.1 # prevent them from trying to build `doc.dep` in parallel + +scalar.html scalar.1: scalar.txt + $(QUIET_SUBDIR0)../../Documentation$(QUIET_SUBDIR1) \ + MAN_TXT=../contrib/scalar/scalar.txt \ + ../contrib/scalar/$@ + $(QUIET)test scalar.1 != "$@" || mv ../../Documentation/$@ . + +install-doc: scalar.1 + $(INSTALL) -d -m 755 $(DESTDIR_SQ)$(man1dir_SQ) + $(INSTALL) -m 644 $^ $(DESTDIR_SQ)$(man1dir_SQ) + +install-html: scalar.html + $(INSTALL) -d -m 755 $(DESTDIR_SQ)$(htmldir_SQ) + $(INSTALL) -m 644 $^ $(DESTDIR_SQ)$(htmldir_SQ) + +.PHONY: $(GITLIBS) all clean test docs install install-doc install-html FORCE From 531e65176205fdcaefcc041a1c4af58119918342 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 4 May 2021 10:32:24 +0200 Subject: [PATCH 09/15] git help: special-case `scalar` With this commit, `git help scalar` will open the appropriate manual or HTML page (instead of looking for `gitscalar`). Signed-off-by: Johannes Schindelin --- builtin/help.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/builtin/help.c b/builtin/help.c index 222f994f863cba..cad2df4f25fb84 100644 --- a/builtin/help.c +++ b/builtin/help.c @@ -430,6 +430,8 @@ static const char *cmd_to_page(const char *git_cmd) return git_cmd; else if (is_git_command(git_cmd)) return xstrfmt("git-%s", git_cmd); + else if (!strcmp("scalar", git_cmd)) + return xstrdup(git_cmd); else return xstrfmt("git%s", git_cmd); } From 17729c69e297b1b359ede2f138a93e13b7e47e73 Mon Sep 17 00:00:00 2001 From: Derrick Stolee Date: Wed, 16 Jun 2021 10:01:37 -0400 Subject: [PATCH 10/15] scalar: add docs from microsoft/scalar These docs have been altered to fit the version implemented in C within microsoft/git. This means in particular that the advanced.md file no longer applied at all. Some other areas were removed or significantly edited. Signed-off-by: Derrick Stolee --- contrib/scalar/docs/faq.md | 51 ++++++++++++++ contrib/scalar/docs/getting-started.md | 98 ++++++++++++++++++++++++++ contrib/scalar/docs/index.md | 50 +++++++++++++ contrib/scalar/docs/philosophy.md | 66 +++++++++++++++++ contrib/scalar/docs/troubleshooting.md | 20 ++++++ 5 files changed, 285 insertions(+) create mode 100644 contrib/scalar/docs/faq.md create mode 100644 contrib/scalar/docs/getting-started.md create mode 100644 contrib/scalar/docs/index.md create mode 100644 contrib/scalar/docs/philosophy.md create mode 100644 contrib/scalar/docs/troubleshooting.md diff --git a/contrib/scalar/docs/faq.md b/contrib/scalar/docs/faq.md new file mode 100644 index 00000000000000..a14f78a996d5d5 --- /dev/null +++ b/contrib/scalar/docs/faq.md @@ -0,0 +1,51 @@ +Frequently Asked Questions +========================== + +Using Scalar +------------ + +### I don't want a sparse clone, I want every file after I clone! + +Run `scalar clone --full-clone ` to initialize your repo to include +every file. You can switch to a sparse-checkout later by running +`git sparse-checkout init --cone`. + +### I already cloned without `--full-clone`. How do I get everything? + +Run `git sparse-checkout disable`. + +Scalar Design Decisions +----------------------- + +There may be many design decisions within Scalar that are confusing at first +glance. Some of them may cause friction when you use Scalar with your existing +repos and existing habits. + +> Scalar has the most benefit when users design repositories +> with efficient patterns. + +For example: Scalar uses the sparse-checkout feature to limit the size of the +working directory within a large monorepo. It is designed to work efficiently +with monorepos that are highly componentized, allowing most developers to +need many fewer files in their daily work. + +### Why does `scalar clone` create a `/src` folder? + +Scalar uses a file system watcher to keep track of changes under this `src` folder. +Any activity in this folder is assumed to be important to Git operations. By +creating the `src` folder, we are making it easy for your build system to +create output folders outside the `src` directory. We commonly see systems +create folders for build outputs and package downloads. Scalar itself creates +these folders during its builds. + +Your build system may create build artifacts such as `.obj` or `.lib` files +next to your source code. These are commonly "hidden" from Git using +`.gitignore` files. Having such artifacts in your source tree creates +additional work for Git because it needs to look at these files and match them +against the `.gitignore` patterns. + +By following the `src` pattern Scalar tries to establish and placing your build +intermediates and outputs parallel with the `src` folder and not inside it, +you can help optimize Git command performance for developers in the repository +by limiting the number of files Git needs to consider for many common +operations. diff --git a/contrib/scalar/docs/getting-started.md b/contrib/scalar/docs/getting-started.md new file mode 100644 index 00000000000000..dec60ce407713a --- /dev/null +++ b/contrib/scalar/docs/getting-started.md @@ -0,0 +1,98 @@ +Getting Started +=============== + +Registering existing Git repos +------------------------------ + +To add a repository to the list of registered repos, run `scalar register []`. +If `` is not provided, then the "current repository" is discovered from +the working directory by scanning the parent paths for a path containing a `.git` +folder, possibly inside a `src` folder. + +To see which repositories are currently tracked by the service, run +`scalar list`. + +Run `scalar unregister []` to remove the repo from this list. + +Creating a new Scalar clone +--------------------------------------------------- + +The `clone` verb creates a local enlistment of a remote repository using the +partial clone feature available e.g. on GitHub. + + +``` +scalar clone [options] [] +``` + +Create a local copy of the repository at ``. If specified, create the `` +directory and place the repository there. Otherwise, the last section of the `` +will be used for ``. + +At the end, the repo is located at `/src`. By default, the sparse-checkout +feature is enabled and the only files present are those in the root of your +Git repository. Use `git sparse-checkout set` to expand the set of directories +you want to see, or `git sparse-checkout disable` to expand to all files. You +can explore the subdirectories outside your sparse-checkout specification using +`git ls-tree HEAD`. + +### Sparse Repo Mode + +By default, Scalar reduces your working directory to only the files at the +root of the repository. You need to add the folders you care about to build up +to your working set. + +* `scalar clone ` + * Please choose the **Clone with HTTPS** option in the `Clone Repository` dialog in Azure Repos, not **Clone with SSH**. +* `cd \src` +* At this point, your `src` directory only contains files that appear in your root + tree. No folders are populated. +* Set the directory list for your sparse-checkout using: + 1. `git sparse-checkout set ...` + 2. `git sparse-checkout set --stdin < dir-list.txt` +* Run git commands as you normally would. +* To fully populate your working directory, run `git sparse-checkout disable`. + +If instead you want to start with all files on-disk, you can clone with the +`--full-clone` option. To enable sparse-checkout after the fact, run +`git sparse-checkout init --cone`. This will initialize your sparse-checkout +patterns to only match the files at root. + +If you are unfamiliar with what directories are available in the repository, +then you can run `git ls-tree -d --name-only HEAD` to discover the directories +at root, or `git ls-tree -d --name-only HEAD ` to discover the directories +in ``. + +### Options + +These options allow a user to customize their initial enlistment. + +* `--full-clone`: If specified, do not initialize the sparse-checkout feature. + All files will be present in your `src` directory. This uses a Git partial + clone: blobs are downloaded on demand. + +* `--branch=`: Specify the branch to checkout after clone. + +### Advanced Options + +The options below are not intended for use by a typical user. These are +usually used by build machines to create a temporary enlistment that +operates on a single commit. + +* `--single-branch`: Use this option to only download metadata for the branch + that will be checked out. This is helpful for build machines that target + a remote with many branches. Any `git fetch` commands after the clone will + still ask for all branches. + +* `--no-prefetch`: Use this option to not prefetch commits after clone. This + is not recommended for anyone planning to use their clone for history + traversal. Use of this option will make commands like `git log` or + `git pull` extremely slow and is therefore not recommended. + +Removing a Scalar Clone +----------------------- + +Since the `scalar clone` command sets up a file-system watcher (when available), +that watcher could prevent deleting the enlistment. Run `scalar delete ` +from outside of your enlistment to unregister the enlistment from the filesystem +watcher and delete the enlistment at ``. diff --git a/contrib/scalar/docs/index.md b/contrib/scalar/docs/index.md new file mode 100644 index 00000000000000..f9f5ab06e09253 --- /dev/null +++ b/contrib/scalar/docs/index.md @@ -0,0 +1,50 @@ +Scalar: Enabling Git at Scale +============================= + +Scalar is a tool that helps Git scale to some of the largest Git repositories. +It achieves this by enabling some advanced Git features, such as: + +* *Partial clone:* reduces time to get a working repository by not + downloading all Git objects right away. + +* *Background prefetch:* downloads Git object data from all remotes every + hour, reducing the amount of time for foreground `git fetch` calls. + +* *Sparse-checkout:* limits the size of your working directory. + +* *File system monitor:* tracks the recently modified files and eliminates + the need for Git to scan the entire worktree. + +* *Commit-graph:* accelerates commit walks and reachability calculations, + speeding up commands like `git log`. + +* *Multi-pack-index:* enables fast object lookups across many pack-files. + +* *Incremental repack:* Repacks the packed Git data into fewer pack-file + without disrupting concurrent commands by using the multi-pack-index. + +By running `scalar register` in any Git repo, Scalar will automatically enable +these features for that repo (except partial clone) and start running suggested +maintenance in the background using +[the `git maintenance` feature](https://git-scm.com/docs/git-maintenance). + +Repos cloned with the `scalar clone` command use partial clone to significantly +reduce the amount of data required to get started using a repository. By +delaying all blob downloads until they are required, Scalar allows you to work +with very large repositories quickly. + +Documentation +------------- + +* [Getting Started](getting-started.md): Get started with Scalar. + Includes `scalar register`, `scalar unregister`, `scalar clone`, and + `scalar delete`. + +* [Troubleshooting](troubleshooting.md): + Collect diagnostic information or update custom settings. Includes + `scalar diagnose`. + +* [The Philosophy of Scalar](philosophy.md): Why does Scalar work the way + it does, and how do we make decisions about its future? + +* [Frequently Asked Questions](faq.md) diff --git a/contrib/scalar/docs/philosophy.md b/contrib/scalar/docs/philosophy.md new file mode 100644 index 00000000000000..51486a75e41f0d --- /dev/null +++ b/contrib/scalar/docs/philosophy.md @@ -0,0 +1,66 @@ +The Philosophy of Scalar +======================== + +The team building Scalar has **opinions** about Git performance. Scalar +takes out the guesswork by automatically configuring your Git repositories +to take advantage of the latest and greatest features. It is difficult to +say that these are the absolute best settings for every repository, but +these settings do work for some of the largest repositories in the world. + +Scalar intends to do very little more than the standard Git client. We +actively implement new features into Git instead of Scalar, then update +Scalar only to configure those new settings. In particular, we ported +features like background maintenance to Git to make Scalar simpler and +make Git more powerful. + +Services such as GitHub support partial clone , a standard adopted by the Git +project to download only part of the Git objects when cloning, and fetching +further objects on demand. If your hosting service supports partial clone, then +we absolutely recommend it as a way to greatly speed up your clone and fetch +times and to reduce how much disk space your Git repository requires. Scalar +will help with this! + +Most of the value of Scalar can be found in the core Git client. However, most +of the advanced features that really optimize Git's performance are off by +default for compatibility reasons. To really take advantage of Git's latest and +greatest features, you either need to study the [`git config` +documentation](https://git-scm.com/docs/git-config) and regularly read [the Git +release notes](https://github.com/git/git/tree/master/Documentation/RelNotes). +Even if you do all that work and customize your Git settings on your machines, +you likely will want to share those settings with other team members. Or, you +can just use Scalar! + +Using `scalar register` on an existing Git repository will give you these +benefits: + +* Additional compression of your `.git/index` file. +* Hourly background `git fetch` operations, keeping you in-sync with your + remotes. +* Advanced data structures, such as the `commit-graph` and `multi-pack-index` + are updated automatically in the background. +* If using macOS or Windows, then Scalar configures Git's builtin File System + Monitor, providing faster commands such as `git status` or `git add`. + +Additionally, if you use `scalar clone` to create a new repository, then +you will automatically get these benefits: + +* Use Git's partial clone feature to only download the files you need for + your current checkout. +* Use Git's [sparse-checkout feature][sparse-checkout] to minimize the + number of files required in your working directory. + [Read more about sparse-checkout here.][sparse-checkout-blog] +* Create the Git repository inside `/src` to make it easy to + place build artifacts outside of the Git repository, such as in + `/bin` or `/packages`. + +We also admit that these **opinions** can always be improved! If you have +an idea of how to improve our setup, consider +[creating an issue](https://github.com/microsoft/scalar/issues/new) or +contributing a pull request! Some [existing](https://github.com/microsoft/scalar/issues/382) +[issues](https://github.com/microsoft/scalar/issues/388) have already +improved our configuration settings and roadmap! + +[gvfs-protocol]: https://github.com/microsoft/VFSForGit/blob/HEAD/Protocol.md +[microsoft-git]: https://github.com/microsoft/git +[sparse-checkout]: https://git-scm.com/docs/git-sparse-checkout +[sparse-checkout-blog]: https://github.blog/2020-01-17-bring-your-monorepo-down-to-size-with-sparse-checkout/ diff --git a/contrib/scalar/docs/troubleshooting.md b/contrib/scalar/docs/troubleshooting.md new file mode 100644 index 00000000000000..8ec56ad437ff09 --- /dev/null +++ b/contrib/scalar/docs/troubleshooting.md @@ -0,0 +1,20 @@ +Troubleshooting +=============== + +Diagnosing Issues +----------------- + +The `scalar diagnose` command collects logs and config details for the current +repository. The resulting zip file helps root-cause issues. + +When run inside your repository, creates a zip file containing several important +files for that repository. This includes: + +* Configuration files from your `.git` folder, such as the `config` file, + `index`, `hooks`, and `refs`. + +* A summary of your Git object database, including the number of loose objects + and the names and sizes of pack-files. + +As the `diagnose` command completes, it provides the path of the resulting +zip file. This zip can be attached to bug reports to make the analysis easier. From eb7ac055257f0ca93aac3f15bb5e2bffc51c0702 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 18 May 2021 22:32:58 +0200 Subject: [PATCH 11/15] scalar: implement the `help` subcommand It is merely handing off to `git help scalar`. Signed-off-by: Johannes Schindelin --- contrib/scalar/scalar.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/contrib/scalar/scalar.c b/contrib/scalar/scalar.c index 85ead6be17f198..e99fa1a2804acd 100644 --- a/contrib/scalar/scalar.c +++ b/contrib/scalar/scalar.c @@ -1120,6 +1120,25 @@ static int cmd_delete(int argc, const char **argv) return res; } +static int cmd_help(int argc, const char **argv) +{ + struct option options[] = { + OPT_END(), + }; + const char * const usage[] = { + N_("scalar help"), + NULL + }; + + argc = parse_options(argc, argv, NULL, options, + usage, 0); + + if (argc != 0) + usage_with_options(usage, options); + + return run_git("help", "scalar", NULL); +} + static int cmd_version(int argc, const char **argv) { int verbose = 0, build_options = 0; @@ -1159,6 +1178,7 @@ static struct { { "run", cmd_run }, { "reconfigure", cmd_reconfigure }, { "delete", cmd_delete }, + { "help", cmd_help }, { "version", cmd_version }, { "diagnose", cmd_diagnose }, { NULL, NULL}, From d2e5e79729983062fce8cbc45dfc7a90882fe65c Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 16 Nov 2021 18:10:47 +0100 Subject: [PATCH 12/15] scalar: move it out of contrib/ With this patch, `scalar` becomes a fully-supported top-level Git command. The Scalar executable is installed by default as well as its documentation, and its (minimal) regression test is run as part of the full test suite. Signed-off-by: Johannes Schindelin --- .github/workflows/main.yml | 15 ---- .gitignore | 1 + Documentation/Makefile | 2 + {contrib/scalar => Documentation}/scalar.txt | 4 +- .../docs => Documentation/scalar}/faq.md | 0 .../scalar}/getting-started.md | 0 .../docs => Documentation/scalar}/index.md | 0 .../scalar}/philosophy.md | 0 .../scalar}/troubleshooting.md | 0 Makefile | 17 ++-- ci/run-build-and-tests.sh | 2 - ci/run-test-slice.sh | 5 -- contrib/buildsystems/CMakeLists.txt | 19 +---- contrib/scalar/.gitignore | 5 -- contrib/scalar/Makefile | 69 ---------------- contrib/scalar/README.md | 82 ------------------- contrib/scalar/t/Makefile | 81 ------------------ contrib/scalar/scalar.c => scalar.c | 0 {contrib/scalar/t => t}/t9099-scalar.sh | 8 +- 19 files changed, 19 insertions(+), 291 deletions(-) rename {contrib/scalar => Documentation}/scalar.txt (99%) rename {contrib/scalar/docs => Documentation/scalar}/faq.md (100%) rename {contrib/scalar/docs => Documentation/scalar}/getting-started.md (100%) rename {contrib/scalar/docs => Documentation/scalar}/index.md (100%) rename {contrib/scalar/docs => Documentation/scalar}/philosophy.md (100%) rename {contrib/scalar/docs => Documentation/scalar}/troubleshooting.md (100%) delete mode 100644 contrib/scalar/.gitignore delete mode 100644 contrib/scalar/Makefile delete mode 100644 contrib/scalar/README.md delete mode 100644 contrib/scalar/t/Makefile rename contrib/scalar/scalar.c => scalar.c (100%) rename {contrib/scalar/t => t}/t9099-scalar.sh (96%) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index a479400d5dfad1..3fa88b78b6db04 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -91,13 +91,6 @@ jobs: HOME: ${{runner.workspace}} NO_PERL: 1 run: . /etc/profile && ci/make-test-artifacts.sh artifacts - - name: build Scalar - shell: bash - run: | - make -C contrib/scalar && - mkdir -p artifacts/bin-wrappers artifacts/contrib/scalar && - cp contrib/scalar/scalar.exe artifacts/contrib/scalar/ && - cp bin-wrappers/scalar artifacts/bin-wrappers/ - name: zip up tracked files run: git archive -o artifacts/tracked.tar.gz HEAD - name: upload tracked files and build artifacts @@ -164,8 +157,6 @@ jobs: run: compat\vcbuild\vcpkg_copy_dlls.bat release - name: generate Visual Studio solution shell: bash - env: - INCLUDE_SCALAR: YesPlease run: | cmake `pwd`/contrib/buildsystems/ -DCMAKE_PREFIX_PATH=`pwd`/compat/vcbuild/vcpkg/installed/x64-windows \ -DNO_GETTEXT=YesPlease -DPERL_TESTS=OFF -DPYTHON_TESTS=OFF -DCURL_NO_CURL_CMAKE=ON @@ -179,12 +170,6 @@ jobs: run: | mkdir -p artifacts && eval "$(make -n artifacts-tar INCLUDE_DLLS_IN_ARTIFACTS=YesPlease ARTIFACTS_DIRECTORY=artifacts NO_GETTEXT=YesPlease 2>&1 | grep ^tar)" - - name: copy Scalar - shell: bash - run: | - mkdir -p artifacts/bin-wrappers artifacts/contrib/scalar && - cp contrib/scalar/scalar.exe artifacts/contrib/scalar/ && - cp bin-wrappers/scalar artifacts/bin-wrappers/ - name: zip up tracked files run: git archive -o artifacts/tracked.tar.gz HEAD - name: upload tracked files and build artifacts diff --git a/.gitignore b/.gitignore index a45221576418e7..af31bfb2019fee 100644 --- a/.gitignore +++ b/.gitignore @@ -192,6 +192,7 @@ /config-list.h /command-list.h /hook-list.h +/scalar *.tar.gz *.dsc *.deb diff --git a/Documentation/Makefile b/Documentation/Makefile index f2e7fc1daa5f95..95422c787f7747 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -22,6 +22,8 @@ MAN1_TXT += git.txt MAN1_TXT += gitk.txt MAN1_TXT += gitweb.txt +MAN1_TXT += scalar.txt + # man5 / man7 guides (note: new guides should also be added to command-list.txt) MAN5_TXT += gitattributes.txt MAN5_TXT += githooks.txt diff --git a/contrib/scalar/scalar.txt b/Documentation/scalar.txt similarity index 99% rename from contrib/scalar/scalar.txt rename to Documentation/scalar.txt index c0425e065338fd..b11e9eecf218ce 100644 --- a/contrib/scalar/scalar.txt +++ b/Documentation/scalar.txt @@ -162,6 +162,6 @@ SEE ALSO -------- linkgit:git-clone[1], linkgit:git-maintenance[1]. -Scalar +GIT --- -Associated with the linkgit:git[1] suite +Part of the linkgit:git[1] suite diff --git a/contrib/scalar/docs/faq.md b/Documentation/scalar/faq.md similarity index 100% rename from contrib/scalar/docs/faq.md rename to Documentation/scalar/faq.md diff --git a/contrib/scalar/docs/getting-started.md b/Documentation/scalar/getting-started.md similarity index 100% rename from contrib/scalar/docs/getting-started.md rename to Documentation/scalar/getting-started.md diff --git a/contrib/scalar/docs/index.md b/Documentation/scalar/index.md similarity index 100% rename from contrib/scalar/docs/index.md rename to Documentation/scalar/index.md diff --git a/contrib/scalar/docs/philosophy.md b/Documentation/scalar/philosophy.md similarity index 100% rename from contrib/scalar/docs/philosophy.md rename to Documentation/scalar/philosophy.md diff --git a/contrib/scalar/docs/troubleshooting.md b/Documentation/scalar/troubleshooting.md similarity index 100% rename from contrib/scalar/docs/troubleshooting.md rename to Documentation/scalar/troubleshooting.md diff --git a/Makefile b/Makefile index 04d0fd1fe60702..4e0aa1054623dd 100644 --- a/Makefile +++ b/Makefile @@ -692,6 +692,11 @@ all:: $(FUZZ_OBJS) FUZZ_PROGRAMS += $(patsubst %.o,%,$(FUZZ_OBJS)) +SCALAR_OBJS := scalar.o + +PROGRAMS += scalar$(X) +BINDIR_PROGRAMS_NEED_X += scalar + # Empty... EXTRA_PROGRAMS = @@ -2536,6 +2541,7 @@ OBJECTS += $(GIT_OBJS) OBJECTS += $(PROGRAM_OBJS) OBJECTS += $(TEST_OBJS) OBJECTS += $(XDIFF_OBJS) +OBJECTS += $(SCALAR_OBJS) OBJECTS += $(FUZZ_OBJS) OBJECTS += $(REFTABLE_OBJS) $(REFTABLE_TEST_OBJS) @@ -2543,10 +2549,6 @@ ifndef NO_CURL OBJECTS += http.o http-walker.o remote-curl.o endif -SCALAR_SOURCES := contrib/scalar/scalar.c -SCALAR_OBJECTS := $(SCALAR_SOURCES:c=o) -OBJECTS += $(SCALAR_OBJECTS) - .PHONY: objects objects: $(OBJECTS) @@ -2678,9 +2680,8 @@ $(REMOTE_CURL_PRIMARY): remote-curl.o http.o http-walker.o GIT-LDFLAGS $(GITLIBS $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \ $(CURL_LIBCURL) $(EXPAT_LIBEXPAT) $(LIBS) -contrib/scalar/scalar$X: $(SCALAR_OBJECTS) GIT-LDFLAGS $(GITLIBS) - $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) \ - $(filter %.o,$^) $(LIBS) +scalar$X: $(SCALAR_OBJS) GIT-LDFLAGS $(GITLIBS) + $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS) $(LIB_FILE): $(LIB_OBJS) $(QUIET_AR)$(RM) $@ && $(AR) $(ARFLAGS) $@ $^ @@ -3049,7 +3050,7 @@ bin-wrappers/%: wrap-for-bin.sh $(call mkdir_p_parent_template) $(QUIET_GEN)sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \ -e 's|@@BUILD_DIR@@|$(shell pwd)|' \ - -e 's|@@PROG@@|$(patsubst test-%,t/helper/test-%$(X),$(@F))$(patsubst git%,$(X),$(filter $(@F),$(BINDIR_PROGRAMS_NEED_X)))|' < $< > $@ && \ + -e 's|@@PROG@@|$(patsubst test-%,t/helper/test-%$(X),$(@F))$(patsubst scalar,$(X),$(patsubst git%,$(X),$(filter $(@F),$(BINDIR_PROGRAMS_NEED_X))))|' < $< > $@ && \ chmod +x $@ # GNU make supports exporting all variables by "export" without parameters. diff --git a/ci/run-build-and-tests.sh b/ci/run-build-and-tests.sh index 0d1824f437ea73..8ebff4259676e3 100755 --- a/ci/run-build-and-tests.sh +++ b/ci/run-build-and-tests.sh @@ -53,6 +53,4 @@ then fi check_unignored_build_artifacts -make -C contrib/scalar $MAKE_TARGETS - save_good_tree diff --git a/ci/run-test-slice.sh b/ci/run-test-slice.sh index 6dd8af20c04d12..a3c67956a8df8f 100755 --- a/ci/run-test-slice.sh +++ b/ci/run-test-slice.sh @@ -15,9 +15,4 @@ group "Run tests" make --quiet -C t T="$(cd t && tr '\n' ' ')" || handle_failed_tests -if test 0 = "$1" -then - make -C contrib/scalar test -fi - check_unignored_build_artifacts diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt index 2162210a4734cb..0f044f58ce576a 100644 --- a/contrib/buildsystems/CMakeLists.txt +++ b/contrib/buildsystems/CMakeLists.txt @@ -757,6 +757,9 @@ target_link_libraries(git-sh-i18n--envsubst common-main) add_executable(git-shell ${CMAKE_SOURCE_DIR}/shell.c) target_link_libraries(git-shell common-main) +add_executable(scalar ${CMAKE_SOURCE_DIR}/scalar.c) +target_link_libraries(scalar common-main) + if(CURL_FOUND) add_library(http_obj OBJECT ${CMAKE_SOURCE_DIR}/http.c) @@ -775,13 +778,6 @@ if(CURL_FOUND) endif() endif() -if(DEFINED ENV{INCLUDE_SCALAR} AND NOT ENV{INCLUDE_SCALAR} STREQUAL "") - add_executable(scalar ${CMAKE_SOURCE_DIR}/contrib/scalar/scalar.c) - target_link_libraries(scalar common-main) - set_target_properties(scalar PROPERTIES RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR}/contrib/scalar) - set_target_properties(scalar PROPERTIES RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR}/contrib/scalar) -endif() - parse_makefile_for_executables(git_builtin_extra "BUILT_INS") option(SKIP_DASHED_BUILT_INS "Skip hardlinking the dashed versions of the built-ins") @@ -984,7 +980,7 @@ endif() #wrapper scripts set(wrapper_scripts - git git-upload-pack git-receive-pack git-upload-archive git-shell git-remote-ext) + git git-upload-pack git-receive-pack git-upload-archive git-shell git-remote-ext scalar) set(wrapper_test_scripts test-fake-ssh test-tool) @@ -1009,13 +1005,6 @@ string(REPLACE "@@BUILD_DIR@@" "${CMAKE_BINARY_DIR}" content "${content}") string(REPLACE "@@PROG@@" "git-cvsserver" content "${content}") file(WRITE ${CMAKE_BINARY_DIR}/bin-wrappers/git-cvsserver ${content}) -if(DEFINED ENV{INCLUDE_SCALAR} AND NOT ENV{INCLUDE_SCALAR} STREQUAL "") - file(STRINGS ${CMAKE_SOURCE_DIR}/wrap-for-bin.sh content NEWLINE_CONSUME) - string(REPLACE "@@BUILD_DIR@@" "${CMAKE_BINARY_DIR}" content "${content}") - string(REPLACE "@@PROG@@" "contrib/scalar/scalar${EXE_EXTENSION}" content "${content}") - file(WRITE ${CMAKE_BINARY_DIR}/bin-wrappers/scalar ${content}) -endif() - #options for configuring test options option(PERL_TESTS "Perform tests that use perl" ON) option(PYTHON_TESTS "Perform tests that use python" ON) diff --git a/contrib/scalar/.gitignore b/contrib/scalar/.gitignore deleted file mode 100644 index 00441073f59cf5..00000000000000 --- a/contrib/scalar/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -/*.xml -/*.1 -/*.html -/*.exe -/scalar diff --git a/contrib/scalar/Makefile b/contrib/scalar/Makefile deleted file mode 100644 index df5ef37af94a82..00000000000000 --- a/contrib/scalar/Makefile +++ /dev/null @@ -1,69 +0,0 @@ -# The default target of this Makefile is... -all:: - -# Import tree-wide shared Makefile behavior and libraries -include ../../shared.mak - -include ../../config.mak.uname --include ../../config.mak.autogen --include ../../config.mak - -TARGETS = scalar$(X) scalar.o -GITLIBS = ../../common-main.o ../../libgit.a ../../xdiff/lib.a - -all:: scalar$(X) ../../bin-wrappers/scalar - -$(GITLIBS): - $(QUIET_SUBDIR0)../.. $(QUIET_SUBDIR1) $(subst ../../,,$@) - -$(TARGETS): $(GITLIBS) scalar.c - $(QUIET_SUBDIR0)../.. $(QUIET_SUBDIR1) $(patsubst %,contrib/scalar/%,$@) - -clean: - $(RM) $(TARGETS) ../../bin-wrappers/scalar - $(RM) scalar.1 scalar.html scalar.xml - -../../bin-wrappers/scalar: ../../wrap-for-bin.sh Makefile - @mkdir -p ../../bin-wrappers - $(QUIET_GEN)sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \ - -e 's|@@BUILD_DIR@@|$(shell cd ../.. && pwd)|' \ - -e 's|@@PROG@@|contrib/scalar/scalar$(X)|' < $< > $@ && \ - chmod +x $@ - -test: all - $(MAKE) -C t - -INSTALL = install -prefix = $(HOME) -bindir = $(prefix)/bin -mandir ?= $(prefix)/share/man -man1dir = $(mandir)/man1 -htmldir ?= $(prefix)/share/doc/git-doc -DESTDIR_SQ = $(subst ','\'',$(DESTDIR)) -bindir_SQ = $(subst ','\'',$(bindir)) -man1dir_SQ = $(subst ','\'',$(man1dir)) -htmldir_SQ = $(subst ','\'',$(htmldir)) - -install: - $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)' - $(INSTALL) scalar$(X) '$(DESTDIR_SQ)$(bindir_SQ)' - -docs: scalar.html scalar.1 - -scalar.html: | scalar.1 # prevent them from trying to build `doc.dep` in parallel - -scalar.html scalar.1: scalar.txt - $(QUIET_SUBDIR0)../../Documentation$(QUIET_SUBDIR1) \ - MAN_TXT=../contrib/scalar/scalar.txt \ - ../contrib/scalar/$@ - $(QUIET)test scalar.1 != "$@" || mv ../../Documentation/$@ . - -install-doc: scalar.1 - $(INSTALL) -d -m 755 $(DESTDIR_SQ)$(man1dir_SQ) - $(INSTALL) -m 644 $^ $(DESTDIR_SQ)$(man1dir_SQ) - -install-html: scalar.html - $(INSTALL) -d -m 755 $(DESTDIR_SQ)$(htmldir_SQ) - $(INSTALL) -m 644 $^ $(DESTDIR_SQ)$(htmldir_SQ) - -.PHONY: $(GITLIBS) all clean test docs install install-doc install-html FORCE diff --git a/contrib/scalar/README.md b/contrib/scalar/README.md deleted file mode 100644 index 634b5771ed393c..00000000000000 --- a/contrib/scalar/README.md +++ /dev/null @@ -1,82 +0,0 @@ -# Scalar - an opinionated repository management tool - -Scalar is an add-on to Git that helps users take advantage of advanced -performance features in Git. Originally implemented in C# using .NET Core, -based on the learnings from the VFS for Git project, most of the techniques -developed by the Scalar project have been integrated into core Git already: - -* partial clone, -* commit graphs, -* multi-pack index, -* sparse checkout (cone mode), -* scheduled background maintenance, -* etc - -This directory contains the remaining parts of Scalar that are not (yet) in -core Git. - -## Roadmap - -The idea is to populate this directory via incremental patch series and -eventually move to a top-level directory next to `gitk-git/` and to `git-gui/`. The -current plan involves the following patch series: - -- `scalar-the-beginning`: The initial patch series which sets up - `contrib/scalar/` and populates it with a minimal `scalar` command that - demonstrates the fundamental ideas. - -- `scalar-c-and-C`: The `scalar` command learns about two options that can be - specified before the command, `-c =` and `-C `. - -- `scalar-diagnose`: The `scalar` command is taught the `diagnose` subcommand. - -- `scalar-and-builtin-fsmonitor`: The built-in FSMonitor is enabled in `scalar - register` and in `scalar clone`, for an enormous performance boost when - working in large worktrees. This patch series necessarily depends on Jeff - Hostetler's FSMonitor patch series to be integrated into Git. - -- `scalar-gentler-config-locking`: Scalar enlistments are registered in the - user's Git config. This usually does not represent any problem because it is - rare for a user to register an enlistment. However, in Scalar's functional - tests, Scalar enlistments are created galore, and in parallel, which can lead - to lock contention. This patch series works around that problem by re-trying - to lock the config file in a gentle fashion. - -- `scalar-extra-docs`: Add some extensive documentation that has been written - in the original Scalar project (all subject to discussion, of course). - -- `optionally-install-scalar`: Now that Scalar is feature (and documentation) - complete and is verified in CI builds, let's offer to install it. - -- `move-scalar-to-toplevel`: Now that Scalar is complete, let's move it next to - `gitk-git/` and to `git-gui/`, making it a top-level command. - -The following two patch series exist in Microsoft's fork of Git and are -publicly available. There is no current plan to upstream them, not because I -want to withhold these patches, but because I don't think the Git community is -interested in these patches. - -There are some interesting ideas there, but the implementation is too specific -to Azure Repos and/or VFS for Git to be of much help in general (and also: my -colleagues tried to upstream some patches already and the enthusiasm for -integrating things related to Azure Repos and VFS for Git can be summarized in -very, very few words). - -These still exist mainly because the GVFS protocol is what Azure Repos has -instead of partial clone, while Git is focused on improving partial clone: - -- `scalar-with-gvfs`: The primary purpose of this patch series is to support - existing Scalar users whose repositories are hosted in Azure Repos (which - does not support Git's partial clones, but supports its predecessor, the GVFS - protocol, which is used by Scalar to emulate the partial clone). - - Since the GVFS protocol will never be supported by core Git, this patch - series will remain in Microsoft's fork of Git. - -- `run-scalar-functional-tests`: The Scalar project developed a quite - comprehensive set of integration tests (or, "Functional Tests"). They are the - sole remaining part of the original C#-based Scalar project, and this patch - adds a GitHub workflow that runs them all. - - Since the tests partially depend on features that are only provided in the - `scalar-with-gvfs` patch series, this patch cannot be upstreamed. diff --git a/contrib/scalar/t/Makefile b/contrib/scalar/t/Makefile deleted file mode 100644 index 01e82e56d15629..00000000000000 --- a/contrib/scalar/t/Makefile +++ /dev/null @@ -1,81 +0,0 @@ -# Import tree-wide shared Makefile behavior and libraries -include ../../../shared.mak - -# Run scalar tests -# -# Copyright (c) 2005,2021 Junio C Hamano, Johannes Schindelin -# - --include ../../../config.mak.autogen --include ../../../config.mak - -SHELL_PATH ?= $(SHELL) -PERL_PATH ?= /usr/bin/perl -RM ?= rm -f -PROVE ?= prove -DEFAULT_TEST_TARGET ?= test -TEST_LINT ?= test-lint - -ifdef TEST_OUTPUT_DIRECTORY -TEST_RESULTS_DIRECTORY = $(TEST_OUTPUT_DIRECTORY)/test-results -else -TEST_RESULTS_DIRECTORY = ../../../t/test-results -endif - -# Shell quote; -SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH)) -PERL_PATH_SQ = $(subst ','\'',$(PERL_PATH)) -TEST_RESULTS_DIRECTORY_SQ = $(subst ','\'',$(TEST_RESULTS_DIRECTORY)) - -T = $(sort $(wildcard t[0-9][0-9][0-9][0-9]-*.sh)) - -all: $(DEFAULT_TEST_TARGET) - -test: $(TEST_LINT) - $(MAKE) aggregate-results-and-cleanup - -prove: $(TEST_LINT) - @echo "*** prove ***"; GIT_CONFIG=.git/config $(PROVE) --exec '$(SHELL_PATH_SQ)' $(GIT_PROVE_OPTS) $(T) :: $(GIT_TEST_OPTS) - $(MAKE) clean-except-prove-cache - -$(T): - @echo "*** $@ ***"; GIT_CONFIG=.git/config '$(SHELL_PATH_SQ)' $@ $(GIT_TEST_OPTS) - -clean-except-prove-cache: - $(RM) -r 'trash directory'.* '$(TEST_RESULTS_DIRECTORY_SQ)' - $(RM) -r valgrind/bin - -clean: clean-except-prove-cache - $(RM) .prove - -test-lint: test-lint-duplicates test-lint-executable test-lint-shell-syntax - -test-lint-duplicates: - @dups=`echo $(T) | tr ' ' '\n' | sed 's/-.*//' | sort | uniq -d` && \ - test -z "$$dups" || { \ - echo >&2 "duplicate test numbers:" $$dups; exit 1; } - -test-lint-executable: - @bad=`for i in $(T); do test -x "$$i" || echo $$i; done` && \ - test -z "$$bad" || { \ - echo >&2 "non-executable tests:" $$bad; exit 1; } - -test-lint-shell-syntax: - @'$(PERL_PATH_SQ)' ../../../t/check-non-portable-shell.pl $(T) - -aggregate-results-and-cleanup: $(T) - $(MAKE) aggregate-results - $(MAKE) clean - -aggregate-results: - for f in '$(TEST_RESULTS_DIRECTORY_SQ)'/t*-*.counts; do \ - echo "$$f"; \ - done | '$(SHELL_PATH_SQ)' ../../../t/aggregate-results.sh - -valgrind: - $(MAKE) GIT_TEST_OPTS="$(GIT_TEST_OPTS) --valgrind" - -test-results: - mkdir -p test-results - -.PHONY: $(T) aggregate-results clean valgrind diff --git a/contrib/scalar/scalar.c b/scalar.c similarity index 100% rename from contrib/scalar/scalar.c rename to scalar.c diff --git a/contrib/scalar/t/t9099-scalar.sh b/t/t9099-scalar.sh similarity index 96% rename from contrib/scalar/t/t9099-scalar.sh rename to t/t9099-scalar.sh index 526f64d001c6c1..61f9611cc193e4 100755 --- a/contrib/scalar/t/t9099-scalar.sh +++ b/t/t9099-scalar.sh @@ -2,13 +2,7 @@ test_description='test the `scalar` command' -TEST_DIRECTORY=$PWD/../../../t -export TEST_DIRECTORY - -# Make it work with --no-bin-wrappers -PATH=$PWD/..:$PATH - -. ../../../t/test-lib.sh +. ./test-lib.sh GIT_TEST_MAINT_SCHEDULER="crontab:test-tool crontab ../cron.txt,launchctl:true,schtasks:true" export GIT_TEST_MAINT_SCHEDULER From 84d67330b1c39efde9b99ce16370a0ccab920c80 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 10 May 2022 13:43:05 +0200 Subject: [PATCH 13/15] scalar (Windows): use forward slashes as directory separators Git traditionally uses those, not backslashes, ever. Signed-off-by: Johannes Schindelin --- scalar.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scalar.c b/scalar.c index e99fa1a2804acd..c3eb14de855a17 100644 --- a/scalar.c +++ b/scalar.c @@ -55,6 +55,9 @@ static void setup_enlistment_directory(int argc, const char **argv, die(_("need a working directory")); strbuf_trim_trailing_dir_sep(&path); +#ifdef GIT_WINDOWS_NATIVE + convert_slashes(path.buf); +#endif do { const size_t len = path.len; From ef629cf5148d0086d4de2396b84094770ff98a4e Mon Sep 17 00:00:00 2001 From: Derrick Stolee Date: Thu, 17 Jun 2021 11:40:09 -0400 Subject: [PATCH 14/15] scalar: add retry logic to run_git() Use a fixed 3 tries total to see how that increases our chances of success for subcommands such as 'git fetch'. Signed-off-by: Derrick Stolee --- scalar.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/scalar.c b/scalar.c index c3eb14de855a17..abed1f5e636a77 100644 --- a/scalar.c +++ b/scalar.c @@ -101,12 +101,14 @@ static void setup_enlistment_directory(int argc, const char **argv, setup_git_directory(); } +static int git_retries = 3; + static int run_git(const char *arg, ...) { struct strvec argv = STRVEC_INIT; va_list args; const char *p; - int res; + int res, attempts; va_start(args, arg); strvec_push(&argv, arg); @@ -114,7 +116,10 @@ static int run_git(const char *arg, ...) strvec_push(&argv, p); va_end(args); - res = run_command_v_opt(argv.v, RUN_GIT_CMD); + for (attempts = 0, res = 1; + res && attempts < git_retries; + attempts++) + res = run_command_v_opt(argv.v, RUN_GIT_CMD); strvec_clear(&argv); return res; From 818c1bf7be814794ebfa2b08ab3d96fdc7c7ace9 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 27 May 2021 07:26:11 +0200 Subject: [PATCH 15/15] scalar: support the `config` command for backwards compatibility The .NET version supported running `scalar config` to reconfigure the current enlistment, and now the C port does, too. Signed-off-by: Johannes Schindelin --- scalar.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scalar.c b/scalar.c index abed1f5e636a77..15f32f88843afe 100644 --- a/scalar.c +++ b/scalar.c @@ -1220,6 +1220,9 @@ int cmd_main(int argc, const char **argv) argv++; argc--; + if (!strcmp(argv[0], "config")) + argv[0] = "reconfigure"; + for (i = 0; builtins[i].name; i++) if (!strcmp(builtins[i].name, argv[0])) return !!builtins[i].fn(argc, argv);