зеркало из https://github.com/microsoft/git.git
Merge pull request #536: Allow --no-src during clones and git worktree after clones
These are two highly-requested items from an internal team considering a move to Scalar using Azure Repos. 1. Remove the requirement that we create a `src` directory at clone time. 2. Allow `git worktree` even when using the GVFS protocol. These are not difficult to implement. The `--no-src` option could even be submitted upstream (though the commit will need to drop one bit about an interaction with the local cache path).
This commit is contained in:
Коммит
ffd33cfd18
|
@ -9,7 +9,7 @@ SYNOPSIS
|
||||||
--------
|
--------
|
||||||
[verse]
|
[verse]
|
||||||
scalar clone [--single-branch] [--branch <main-branch>] [--full-clone]
|
scalar clone [--single-branch] [--branch <main-branch>] [--full-clone]
|
||||||
[--local-cache-path <path>] [--cache-server-url <url>]
|
[--local-cache-path <path>] [--cache-server-url <url>] [--[no-]src]
|
||||||
<url> [<enlistment>]
|
<url> [<enlistment>]
|
||||||
scalar list
|
scalar list
|
||||||
scalar register [<enlistment>]
|
scalar register [<enlistment>]
|
||||||
|
@ -83,6 +83,9 @@ remote-tracking branch for the branch this option was used for the initial
|
||||||
cloning. If the HEAD at the remote did not point at any branch when
|
cloning. If the HEAD at the remote did not point at any branch when
|
||||||
`--single-branch` clone was made, no remote-tracking branch is created.
|
`--single-branch` clone was made, no remote-tracking branch is created.
|
||||||
|
|
||||||
|
--no-src::
|
||||||
|
Skip adding a `src` directory within the target enlistment.
|
||||||
|
|
||||||
--[no-]full-clone::
|
--[no-]full-clone::
|
||||||
A sparse-checkout is initialized by default. This behavior can be
|
A sparse-checkout is initialized by default. This behavior can be
|
||||||
turned off via `--full-clone`.
|
turned off via `--full-clone`.
|
||||||
|
|
|
@ -12,7 +12,7 @@ int is_directory(const char *path)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* removes the last path component from 'path' except if 'path' is root */
|
/* removes the last path component from 'path' except if 'path' is root */
|
||||||
static void strip_last_component(struct strbuf *path)
|
void strip_last_path_component(struct strbuf *path)
|
||||||
{
|
{
|
||||||
size_t offset = offset_1st_component(path->buf);
|
size_t offset = offset_1st_component(path->buf);
|
||||||
size_t len = path->len;
|
size_t len = path->len;
|
||||||
|
@ -117,7 +117,7 @@ static char *strbuf_realpath_1(struct strbuf *resolved, const char *path,
|
||||||
continue; /* '.' component */
|
continue; /* '.' component */
|
||||||
} else if (next.len == 2 && !strcmp(next.buf, "..")) {
|
} else if (next.len == 2 && !strcmp(next.buf, "..")) {
|
||||||
/* '..' component; strip the last path component */
|
/* '..' component; strip the last path component */
|
||||||
strip_last_component(resolved);
|
strip_last_path_component(resolved);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,7 +169,7 @@ static char *strbuf_realpath_1(struct strbuf *resolved, const char *path,
|
||||||
* strip off the last component since it will
|
* strip off the last component since it will
|
||||||
* be replaced with the contents of the symlink
|
* be replaced with the contents of the symlink
|
||||||
*/
|
*/
|
||||||
strip_last_component(resolved);
|
strip_last_path_component(resolved);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include "cache.h"
|
#include "cache.h"
|
||||||
|
#include "gvfs.h"
|
||||||
#include "checkout.h"
|
#include "checkout.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "builtin.h"
|
#include "builtin.h"
|
||||||
|
@ -1127,6 +1128,13 @@ int cmd_worktree(int ac, const char **av, const char *prefix)
|
||||||
|
|
||||||
git_config(git_worktree_config, NULL);
|
git_config(git_worktree_config, NULL);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* git-worktree is special-cased to work in Scalar repositories
|
||||||
|
* even when they use the GVFS Protocol.
|
||||||
|
*/
|
||||||
|
if (core_gvfs & GVFS_USE_VIRTUAL_FILESYSTEM)
|
||||||
|
die("'git %s' is not supported on a GVFS repo", "worktree");
|
||||||
|
|
||||||
if (!prefix)
|
if (!prefix)
|
||||||
prefix = "";
|
prefix = "";
|
||||||
|
|
||||||
|
|
2
git.c
2
git.c
|
@ -703,7 +703,7 @@ static struct cmd_struct commands[] = {
|
||||||
{ "verify-tag", cmd_verify_tag, RUN_SETUP },
|
{ "verify-tag", cmd_verify_tag, RUN_SETUP },
|
||||||
{ "version", cmd_version },
|
{ "version", cmd_version },
|
||||||
{ "whatchanged", cmd_whatchanged, RUN_SETUP },
|
{ "whatchanged", cmd_whatchanged, RUN_SETUP },
|
||||||
{ "worktree", cmd_worktree, RUN_SETUP | BLOCK_ON_GVFS_REPO },
|
{ "worktree", cmd_worktree, RUN_SETUP },
|
||||||
{ "write-tree", cmd_write_tree, RUN_SETUP },
|
{ "write-tree", cmd_write_tree, RUN_SETUP },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
11
gvfs.h
11
gvfs.h
|
@ -14,7 +14,18 @@
|
||||||
#define GVFS_SKIP_SHA_ON_INDEX (1 << 0)
|
#define GVFS_SKIP_SHA_ON_INDEX (1 << 0)
|
||||||
#define GVFS_BLOCK_COMMANDS (1 << 1)
|
#define GVFS_BLOCK_COMMANDS (1 << 1)
|
||||||
#define GVFS_MISSING_OK (1 << 2)
|
#define GVFS_MISSING_OK (1 << 2)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This behavior of not deleting outside of the sparse-checkout
|
||||||
|
* is specific to the virtual filesystem support. It is only
|
||||||
|
* enabled by VFS for Git, and so can be used as an indicator
|
||||||
|
* that we are in a virtualized filesystem environment and not
|
||||||
|
* in a Scalar environment. This bit has two names to reflect
|
||||||
|
* that.
|
||||||
|
*/
|
||||||
#define GVFS_NO_DELETE_OUTSIDE_SPARSECHECKOUT (1 << 3)
|
#define GVFS_NO_DELETE_OUTSIDE_SPARSECHECKOUT (1 << 3)
|
||||||
|
#define GVFS_USE_VIRTUAL_FILESYSTEM (1 << 3)
|
||||||
|
|
||||||
#define GVFS_FETCH_SKIP_REACHABILITY_AND_UPLOADPACK (1 << 4)
|
#define GVFS_FETCH_SKIP_REACHABILITY_AND_UPLOADPACK (1 << 4)
|
||||||
#define GVFS_BLOCK_FILTERS_AND_EOL_CONVERSIONS (1 << 6)
|
#define GVFS_BLOCK_FILTERS_AND_EOL_CONVERSIONS (1 << 6)
|
||||||
#define GVFS_PREFETCH_DURING_FETCH (1 << 7)
|
#define GVFS_PREFETCH_DURING_FETCH (1 << 7)
|
||||||
|
|
4
path.h
4
path.h
|
@ -179,6 +179,10 @@ const char *git_path_auto_merge(struct repository *r);
|
||||||
const char *git_path_fetch_head(struct repository *r);
|
const char *git_path_fetch_head(struct repository *r);
|
||||||
const char *git_path_shallow(struct repository *r);
|
const char *git_path_shallow(struct repository *r);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the last path component from 'path' except if 'path' is root.
|
||||||
|
*/
|
||||||
|
void strip_last_path_component(struct strbuf *path);
|
||||||
|
|
||||||
int ends_with_path_components(const char *path, const char *components);
|
int ends_with_path_components(const char *path, const char *components);
|
||||||
|
|
||||||
|
|
24
scalar.c
24
scalar.c
|
@ -16,6 +16,7 @@
|
||||||
#include "help.h"
|
#include "help.h"
|
||||||
#include "json-parser.h"
|
#include "json-parser.h"
|
||||||
#include "remote.h"
|
#include "remote.h"
|
||||||
|
#include "path.h"
|
||||||
|
|
||||||
static int is_unattended(void) {
|
static int is_unattended(void) {
|
||||||
return git_env_bool("Scalar_UNATTENDED", 0);
|
return git_env_bool("Scalar_UNATTENDED", 0);
|
||||||
|
@ -461,8 +462,13 @@ static char *default_cache_root(const char *root)
|
||||||
{
|
{
|
||||||
const char *env;
|
const char *env;
|
||||||
|
|
||||||
if (is_unattended())
|
if (is_unattended()) {
|
||||||
return xstrfmt("%s/.scalarCache", root);
|
struct strbuf path = STRBUF_INIT;
|
||||||
|
strbuf_addstr(&path, root);
|
||||||
|
strip_last_path_component(&path);
|
||||||
|
strbuf_addstr(&path, "/.scalarCache");
|
||||||
|
return strbuf_detach(&path, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
(void)env;
|
(void)env;
|
||||||
|
@ -685,6 +691,8 @@ static int cmd_clone(int argc, const char **argv)
|
||||||
int full_clone = 0, single_branch = 0, dummy = 0;
|
int full_clone = 0, single_branch = 0, dummy = 0;
|
||||||
const char *cache_server_url = NULL, *local_cache_root = NULL;
|
const char *cache_server_url = NULL, *local_cache_root = NULL;
|
||||||
char *default_cache_server_url = NULL, *local_cache_root_abs = NULL;
|
char *default_cache_server_url = NULL, *local_cache_root_abs = NULL;
|
||||||
|
const char *enlistment_parent;
|
||||||
|
int no_src = 0;
|
||||||
struct option clone_options[] = {
|
struct option clone_options[] = {
|
||||||
OPT_STRING('b', "branch", &branch, N_("<branch>"),
|
OPT_STRING('b', "branch", &branch, N_("<branch>"),
|
||||||
N_("branch to checkout after clone")),
|
N_("branch to checkout after clone")),
|
||||||
|
@ -693,6 +701,8 @@ static int cmd_clone(int argc, const char **argv)
|
||||||
OPT_BOOL(0, "single-branch", &single_branch,
|
OPT_BOOL(0, "single-branch", &single_branch,
|
||||||
N_("only download metadata for the branch that will "
|
N_("only download metadata for the branch that will "
|
||||||
"be checked out")),
|
"be checked out")),
|
||||||
|
OPT_BOOL(0, "no-src", &no_src,
|
||||||
|
N_("skip creating a 'src' directory")),
|
||||||
OPT_STRING(0, "cache-server-url", &cache_server_url,
|
OPT_STRING(0, "cache-server-url", &cache_server_url,
|
||||||
N_("<url>"),
|
N_("<url>"),
|
||||||
N_("the url or friendly name of the cache server")),
|
N_("the url or friendly name of the cache server")),
|
||||||
|
@ -743,7 +753,13 @@ static int cmd_clone(int argc, const char **argv)
|
||||||
|
|
||||||
ensure_absolute_path(enlistment, &enlistment);
|
ensure_absolute_path(enlistment, &enlistment);
|
||||||
|
|
||||||
dir = xstrfmt("%s/src", enlistment);
|
if (!no_src) {
|
||||||
|
dir = xstrfmt("%s/src", enlistment);
|
||||||
|
enlistment_parent = "../..";
|
||||||
|
} else {
|
||||||
|
dir = xstrdup(enlistment);
|
||||||
|
enlistment_parent = "..";
|
||||||
|
}
|
||||||
|
|
||||||
if (!local_cache_root)
|
if (!local_cache_root)
|
||||||
local_cache_root = local_cache_root_abs =
|
local_cache_root = local_cache_root_abs =
|
||||||
|
@ -784,7 +800,7 @@ static int cmd_clone(int argc, const char **argv)
|
||||||
struct strbuf path = STRBUF_INIT;
|
struct strbuf path = STRBUF_INIT;
|
||||||
|
|
||||||
strbuf_addstr(&path, enlistment);
|
strbuf_addstr(&path, enlistment);
|
||||||
if (chdir("../..") < 0 ||
|
if (chdir(enlistment_parent) < 0 ||
|
||||||
remove_dir_recursively(&path, 0) < 0)
|
remove_dir_recursively(&path, 0) < 0)
|
||||||
die(_("'--local-cache-path' cannot be inside the src "
|
die(_("'--local-cache-path' cannot be inside the src "
|
||||||
"folder;\nCould not remove '%s'"), enlistment);
|
"folder;\nCould not remove '%s'"), enlistment);
|
||||||
|
|
|
@ -282,7 +282,7 @@ test_expect_success '`scalar clone` with GVFS-enabled server' '
|
||||||
cache_key="url_$(printf "%s" http://$HOST_PORT/ |
|
cache_key="url_$(printf "%s" http://$HOST_PORT/ |
|
||||||
tr A-Z a-z |
|
tr A-Z a-z |
|
||||||
test-tool sha1)" &&
|
test-tool sha1)" &&
|
||||||
echo "$(pwd)/using-gvfs/.scalarCache/$cache_key" >expect &&
|
echo "$(pwd)/.scalarCache/$cache_key" >expect &&
|
||||||
git -C using-gvfs/src config gvfs.sharedCache >actual &&
|
git -C using-gvfs/src config gvfs.sharedCache >actual &&
|
||||||
test_cmp expect actual &&
|
test_cmp expect actual &&
|
||||||
|
|
||||||
|
@ -367,4 +367,12 @@ test_expect_success '`scalar delete` with existing repo' '
|
||||||
test_path_is_missing existing
|
test_path_is_missing existing
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success '`scalar clone --no-src`' '
|
||||||
|
scalar clone --src "file://$(pwd)" with-src &&
|
||||||
|
scalar clone --no-src "file://$(pwd)" without-src &&
|
||||||
|
|
||||||
|
test_path_is_dir with-src/src &&
|
||||||
|
test_path_is_missing without-src/src
|
||||||
|
'
|
||||||
|
|
||||||
test_done
|
test_done
|
||||||
|
|
Загрузка…
Ссылка в новой задаче