This merges the upstreamable part of the Scalar patches.

Minor merge conflicts (caused by the gvfs-helper) were resolved
trivially.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
This commit is contained in:
Johannes Schindelin 2021-08-24 20:54:39 +02:00
Родитель 67bdb9bf8b 818c1bf7be
Коммит f4b6ff78f5
19 изменённых файлов: 440 добавлений и 221 удалений

1
.gitignore поставляемый
Просмотреть файл

@ -194,6 +194,7 @@
/config-list.h
/command-list.h
/hook-list.h
/scalar
*.tar.gz
*.dsc
*.deb

Просмотреть файл

@ -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

Просмотреть файл

@ -791,3 +791,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.

Просмотреть файл

@ -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

Просмотреть файл

@ -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 <url>` 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 `<repo>/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.

Просмотреть файл

@ -0,0 +1,98 @@
Getting Started
===============
Registering existing Git repos
------------------------------
To add a repository to the list of registered repos, run `scalar register [<path>]`.
If `<path>` 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 [<path>]` 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] <url> [<dir>]
```
Create a local copy of the repository at `<url>`. If specified, create the `<dir>`
directory and place the repository there. Otherwise, the last section of the `<url>`
will be used for `<dir>`.
At the end, the repo is located at `<dir>/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 <url>`
* Please choose the **Clone with HTTPS** option in the `Clone Repository` dialog in Azure Repos, not **Clone with SSH**.
* `cd <root>\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 <dir1> <dir2> ...`
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 <path>` to discover the directories
in `<path>`.
### 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=<ref>`: 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 <path>`
from outside of your enlistment to unregister the enlistment from the filesystem
watcher and delete the enlistment at `<path>`.

Просмотреть файл

@ -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)

Просмотреть файл

@ -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 `<repo-name>/src` to make it easy to
place build artifacts outside of the Git repository, such as in
`<repo-name>/bin` or `<repo-name>/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/

Просмотреть файл

@ -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.

Просмотреть файл

@ -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 =
@ -2547,6 +2552,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)
@ -2554,10 +2560,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)
@ -2696,9 +2698,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)
git-gvfs-helper$X: gvfs-helper.o http.o GIT-LDFLAGS $(GITLIBS)
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
@ -3071,7 +3072,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.

Просмотреть файл

@ -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);
}

Просмотреть файл

@ -3244,6 +3244,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;
@ -3264,11 +3265,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;

Просмотреть файл

@ -792,6 +792,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)
@ -1015,7 +1018,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)

2
contrib/scalar/.gitignore поставляемый
Просмотреть файл

@ -1,2 +0,0 @@
/*.exe
/scalar

Просмотреть файл

@ -1,35 +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
../../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
.PHONY: $(GITLIBS) all clean test FORCE

Просмотреть файл

@ -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 <key>=<value>` and `-C <directory>`.
- `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.

Просмотреть файл

@ -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

Просмотреть файл

@ -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
@ -53,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;
@ -96,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);
@ -109,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;
@ -169,6 +179,13 @@ 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
{ "core.configWriteLockTimeoutMS", "150" },
{ NULL, NULL },
};
int i;
@ -211,16 +228,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);
@ -236,6 +262,56 @@ 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 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);
@ -246,6 +322,9 @@ static int register_dir(void)
if (!res)
res = toggle_maintenance(1);
if (!res)
res = start_fsmonitor_daemon();
return res;
}
@ -259,6 +338,9 @@ static int unregister_dir(void)
if (add_or_remove_enlistment(0) < 0)
res = -1;
if (stop_fsmonitor_daemon() < 0)
res = -1;
return res;
}
@ -1046,6 +1128,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;
@ -1085,6 +1186,7 @@ static struct {
{ "run", cmd_run },
{ "reconfigure", cmd_reconfigure },
{ "delete", cmd_delete },
{ "help", cmd_help },
{ "version", cmd_version },
{ "diagnose", cmd_diagnose },
{ NULL, NULL},
@ -1118,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);

Просмотреть файл

@ -2,21 +2,26 @@
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
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 &&