Skip to content

Commit

Permalink
Merge advanced VFS-specific features
Browse files Browse the repository at this point in the history
Most of these were done in private before microsoft/git. However,
the following pull requests modified the core feature:

	msysgit#85
	msysgit#89
	msysgit#91
	msysgit#98
	msysgit#243
	msysgit#263

Signed-off-by: Derrick Stolee <dstolee@microsoft.com>
  • Loading branch information
dscho committed Oct 3, 2022
2 parents 72a5c13 + 0a56d43 commit ff3d431
Show file tree
Hide file tree
Showing 18 changed files with 489 additions and 42 deletions.
59 changes: 59 additions & 0 deletions BRANCHES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
Branches used in this repo
==========================

The document explains the branching structure that we are using in the VFSForGit repository as well as the forking strategy that we have adopted for contributing.

Repo Branches
-------------

1. `vfs-#`

These branches are used to track the specific version that match Git for Windows with the VFSForGit specific patches on top. When a new version of Git for Windows is released, the VFSForGit patches will be rebased on that windows version and a new gvfs-# branch created to create pull requests against.

#### Examples

```
vfs-2.27.0
vfs-2.30.0
```

The versions of git for VFSForGit are based on the Git for Windows versions. v2.20.0.vfs.1 will correspond with the v2.20.0.windows.1 with the VFSForGit specific patches applied to the windows version.

2. `vfs-#-exp`

These branches are for releasing experimental features to early adopters. They
should contain everything within the corresponding `vfs-#` branch; if the base
branch updates, then merge into the `vfs-#-exp` branch as well.

Tags
----

We are using annotated tags to build the version number for git. The build will look back through the commit history to find the first tag matching `v[0-9]*vfs*` and build the git version number using that tag.

Full releases are of the form `v2.XX.Y.vfs.Z.W` where `v2.XX.Y` comes from the
upstream version and `Z.W` are custom updates within our fork. Specifically,
the `.Z` value represents the "compatibility level" with VFS for Git. Only
increase this version when making a breaking change with a released version
of VFS for Git. The `.W` version is used for minor updates between major
versions.

Experimental releases are of the form `v2.XX.Y.vfs.Z.W.exp`. The `.exp`
suffix indicates that experimental features are available. The rest of the
version string comes from the full release tag. These versions will only
be made available as pre-releases on the releases page, never a full release.

Forking
-------

A personal fork of this repository and a branch in that repository should be used for development.

These branches should be based on the latest vfs-# branch. If there are work in progress pull requests that you have based on a previous version branch when a new version branch is created, you will need to move your patches to the new branch to get them in that latest version.

#### Example

```
git clone <personal fork repo URL>
git remote add ms https://github.com/Microsoft/git.git
git checkout -b my-changes ms/vfs-2.20.0 --no-track
git push -fu origin HEAD
```
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -973,6 +973,7 @@ LIB_OBJS += gettext.o
LIB_OBJS += gpg-interface.o
LIB_OBJS += graph.o
LIB_OBJS += grep.o
LIB_OBJS += gvfs.o
LIB_OBJS += hash-lookup.o
LIB_OBJS += hashmap.o
LIB_OBJS += help.o
Expand Down
18 changes: 18 additions & 0 deletions apply.c
Original file line number Diff line number Diff line change
Expand Up @@ -3353,6 +3353,24 @@ static int checkout_target(struct index_state *istate,
{
struct checkout costate = CHECKOUT_INIT;

/*
* Do not checkout the entry if the skipworktree bit is set
*
* Both callers of this method (check_preimage and load_current)
* check for the existance of the file before calling this
* method so we know that the file doesn't exist at this point
* and we don't need to perform that check again here.
* We just need to check the skip-worktree and return.
*
* This is to prevent git from creating a file in the
* working directory that has the skip-worktree bit on,
* then updating the index from the patch and not keeping
* the working directory version up to date with what it
* changed the index version to be.
*/
if (ce_skip_worktree(ce))
return 0;

costate.refresh_cache = 1;
costate.istate = istate;
if (checkout_entry(ce, &costate, NULL, NULL) ||
Expand Down
4 changes: 4 additions & 0 deletions builtin/gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

#include "builtin.h"
#include "repository.h"
#include "gvfs.h"
#include "config.h"
#include "tempfile.h"
#include "lockfile.h"
Expand Down Expand Up @@ -610,6 +611,9 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
if (quiet)
strvec_push(&repack, "-q");

if ((!auto_gc || (auto_gc && gc_auto_threshold > 0)) && gvfs_config_is_set(GVFS_BLOCK_COMMANDS))
die(_("'git gc' is not supported on a GVFS repo"));

if (auto_gc) {
/*
* Auto-gc should be least intrusive as possible.
Expand Down
10 changes: 10 additions & 0 deletions builtin/update-index.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
*/
#define USE_THE_INDEX_COMPATIBILITY_MACROS
#include "cache.h"
#include "gvfs.h"
#include "bulk-checkin.h"
#include "config.h"
#include "lockfile.h"
Expand Down Expand Up @@ -1170,7 +1171,13 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
argc = parse_options_end(&ctx);

getline_fn = nul_term_line ? strbuf_getline_nul : strbuf_getline_lf;
if (mark_skip_worktree_only && gvfs_config_is_set(GVFS_BLOCK_COMMANDS))
die(_("modifying the skip worktree bit is not supported on a GVFS repo"));

if (preferred_index_format) {
if (preferred_index_format != 4 && gvfs_config_is_set(GVFS_BLOCK_COMMANDS))
die(_("changing the index version is not supported on a GVFS repo"));

if (preferred_index_format < INDEX_FORMAT_LB ||
INDEX_FORMAT_UB < preferred_index_format)
die("index-version %d not in range: %d..%d",
Expand Down Expand Up @@ -1211,6 +1218,9 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
end_odb_transaction();

if (split_index > 0) {
if (gvfs_config_is_set(GVFS_BLOCK_COMMANDS))
die(_("split index is not supported on a GVFS repo"));

if (git_config_get_split_index() == 0)
warning(_("core.splitIndex is set to false; "
"remove or change it, if you really want to "
Expand Down
24 changes: 23 additions & 1 deletion cache-tree.c
Original file line number Diff line number Diff line change
Expand Up @@ -423,7 +423,29 @@ static int update_one(struct cache_tree *it,
continue;

strbuf_grow(&buffer, entlen + 100);
strbuf_addf(&buffer, "%o %.*s%c", mode, entlen, path + baselen, '\0');

switch (mode) {
case 0100644:
strbuf_add(&buffer, "100644 ", 7);
break;
case 0100664:
strbuf_add(&buffer, "100664 ", 7);
break;
case 0100755:
strbuf_add(&buffer, "100755 ", 7);
break;
case 0120000:
strbuf_add(&buffer, "120000 ", 7);
break;
case 0160000:
strbuf_add(&buffer, "160000 ", 7);
break;
default:
strbuf_addf(&buffer, "%o ", mode);
break;
}
strbuf_add(&buffer, path + baselen, entlen);
strbuf_addch(&buffer, '\0');
strbuf_add(&buffer, oid->hash, the_hash_algo->rawsz);

#if DEBUG_CACHE_TREE
Expand Down
100 changes: 92 additions & 8 deletions git.c
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
#include "builtin.h"
#include "gvfs.h"
#include "config.h"
#include "exec-cmd.h"
#include "help.h"
#include "run-command.h"
#include "alias.h"
#include "shallow.h"
#include "dir.h"
#include "hook.h"

#define RUN_SETUP (1<<0)
#define RUN_SETUP_GENTLY (1<<1)
Expand All @@ -17,6 +20,7 @@
#define SUPPORT_SUPER_PREFIX (1<<4)
#define DELAY_PAGER_CONFIG (1<<5)
#define NO_PARSEOPT (1<<6) /* parse-options is not used */
#define BLOCK_ON_GVFS_REPO (1<<7) /* command not allowed in GVFS repos */

struct cmd_struct {
const char *cmd;
Expand Down Expand Up @@ -417,6 +421,68 @@ static int handle_alias(int *argcp, const char ***argv)
return ret;
}

/* Runs pre/post-command hook */
static struct strvec sargv = STRVEC_INIT;
static int run_post_hook = 0;
static int exit_code = -1;

static int run_pre_command_hook(const char **argv)
{
char *lock;
int ret = 0;
struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;

/*
* Ensure the global pre/post command hook is only called for
* the outer command and not when git is called recursively
* or spawns multiple commands (like with the alias command)
*/
lock = getenv("COMMAND_HOOK_LOCK");
if (lock && !strcmp(lock, "true"))
return 0;
setenv("COMMAND_HOOK_LOCK", "true", 1);

/* call the hook proc */
strvec_pushv(&sargv, argv);
strvec_pushf(&sargv, "--git-pid=%"PRIuMAX, (uintmax_t)getpid());
strvec_pushv(&opt.args, sargv.v);
ret = run_hooks_opt("pre-command", &opt);

if (!ret)
run_post_hook = 1;
return ret;
}

static int run_post_command_hook(void)
{
char *lock;
int ret = 0;
struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;

/*
* Only run post_command if pre_command succeeded in this process
*/
if (!run_post_hook)
return 0;
lock = getenv("COMMAND_HOOK_LOCK");
if (!lock || strcmp(lock, "true"))
return 0;

strvec_pushv(&opt.args, sargv.v);
strvec_pushf(&opt.args, "--exit_code=%u", exit_code);
ret = run_hooks_opt("post-command", &opt);

run_post_hook = 0;
strvec_clear(&sargv);
setenv("COMMAND_HOOK_LOCK", "false", 1);
return ret;
}

static void post_command_hook_atexit(void)
{
run_post_command_hook();
}

static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
{
int status, help;
Expand Down Expand Up @@ -457,18 +523,26 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
if (!help && p->option & NEED_WORK_TREE)
setup_work_tree();

if (!help && p->option & BLOCK_ON_GVFS_REPO && gvfs_config_is_set(GVFS_BLOCK_COMMANDS))
die("'git %s' is not supported on a GVFS repo", p->cmd);

if (run_pre_command_hook(argv))
die("pre-command hook aborted command");

trace_argv_printf(argv, "trace: built-in: git");
trace2_cmd_name(p->cmd);
trace2_cmd_list_config();
trace2_cmd_list_env_vars();

validate_cache_entries(the_repository->index);
status = p->fn(argc, argv, prefix);
exit_code = status = p->fn(argc, argv, prefix);
validate_cache_entries(the_repository->index);

if (status)
return status;

run_post_command_hook();

/* Somebody closed stdout? */
if (fstat(fileno(stdout), &st))
return 0;
Expand Down Expand Up @@ -537,7 +611,7 @@ static struct cmd_struct commands[] = {
{ "for-each-ref", cmd_for_each_ref, RUN_SETUP },
{ "for-each-repo", cmd_for_each_repo, RUN_SETUP_GENTLY },
{ "format-patch", cmd_format_patch, RUN_SETUP },
{ "fsck", cmd_fsck, RUN_SETUP },
{ "fsck", cmd_fsck, RUN_SETUP | BLOCK_ON_GVFS_REPO},
{ "fsck-objects", cmd_fsck, RUN_SETUP },
{ "fsmonitor--daemon", cmd_fsmonitor__daemon, SUPPORT_SUPER_PREFIX | RUN_SETUP },
{ "gc", cmd_gc, RUN_SETUP },
Expand Down Expand Up @@ -578,7 +652,7 @@ static struct cmd_struct commands[] = {
{ "pack-refs", cmd_pack_refs, RUN_SETUP },
{ "patch-id", cmd_patch_id, RUN_SETUP_GENTLY | NO_PARSEOPT },
{ "pickaxe", cmd_blame, RUN_SETUP },
{ "prune", cmd_prune, RUN_SETUP },
{ "prune", cmd_prune, RUN_SETUP | BLOCK_ON_GVFS_REPO},
{ "prune-packed", cmd_prune_packed, RUN_SETUP },
{ "pull", cmd_pull, RUN_SETUP | NEED_WORK_TREE },
{ "push", cmd_push, RUN_SETUP },
Expand All @@ -590,7 +664,7 @@ static struct cmd_struct commands[] = {
{ "remote", cmd_remote, RUN_SETUP },
{ "remote-ext", cmd_remote_ext, NO_PARSEOPT },
{ "remote-fd", cmd_remote_fd, NO_PARSEOPT },
{ "repack", cmd_repack, RUN_SETUP },
{ "repack", cmd_repack, RUN_SETUP | BLOCK_ON_GVFS_REPO },
{ "replace", cmd_replace, RUN_SETUP },
{ "rerere", cmd_rerere, RUN_SETUP },
{ "reset", cmd_reset, RUN_SETUP },
Expand All @@ -610,7 +684,7 @@ static struct cmd_struct commands[] = {
{ "stash", cmd_stash, RUN_SETUP | NEED_WORK_TREE },
{ "status", cmd_status, RUN_SETUP | NEED_WORK_TREE },
{ "stripspace", cmd_stripspace },
{ "submodule--helper", cmd_submodule__helper, RUN_SETUP | SUPPORT_SUPER_PREFIX | NO_PARSEOPT },
{ "submodule--helper", cmd_submodule__helper, RUN_SETUP | SUPPORT_SUPER_PREFIX | NO_PARSEOPT | BLOCK_ON_GVFS_REPO },
{ "switch", cmd_switch, RUN_SETUP | NEED_WORK_TREE },
{ "symbolic-ref", cmd_symbolic_ref, RUN_SETUP },
{ "tag", cmd_tag, RUN_SETUP | DELAY_PAGER_CONFIG },
Expand All @@ -628,7 +702,7 @@ static struct cmd_struct commands[] = {
{ "verify-tag", cmd_verify_tag, RUN_SETUP },
{ "version", cmd_version },
{ "whatchanged", cmd_whatchanged, RUN_SETUP },
{ "worktree", cmd_worktree, RUN_SETUP },
{ "worktree", cmd_worktree, RUN_SETUP | BLOCK_ON_GVFS_REPO },
{ "write-tree", cmd_write_tree, RUN_SETUP },
};

Expand Down Expand Up @@ -749,13 +823,16 @@ static void execv_dashed_external(const char **argv)
*/
trace_argv_printf(cmd.args.v, "trace: exec:");

if (run_pre_command_hook(cmd.args.v))
die("pre-command hook aborted command");

/*
* If we fail because the command is not found, it is
* OK to return. Otherwise, we just pass along the status code,
* or our usual generic code if we were not even able to exec
* the program.
*/
status = run_command(&cmd);
exit_code = status = run_command(&cmd);

/*
* If the child process ran and we are now going to exit, emit a
Expand All @@ -766,6 +843,8 @@ static void execv_dashed_external(const char **argv)
exit(status);
else if (errno != ENOENT)
exit(128);

run_post_command_hook();
}

static int run_argv(int *argcp, const char ***argv)
Expand Down Expand Up @@ -873,6 +952,7 @@ int cmd_main(int argc, const char **argv)
}

trace_command_performance(argv);
atexit(post_command_hook_atexit);

/*
* "git-xxxx" is the same as "git xxxx", but we obviously:
Expand Down Expand Up @@ -902,10 +982,14 @@ int cmd_main(int argc, const char **argv)
} else {
/* The user didn't specify a command; give them help */
commit_pager_choice();
if (run_pre_command_hook(argv))
die("pre-command hook aborted command");
printf(_("usage: %s\n\n"), git_usage_string);
list_common_cmds_help();
printf("\n%s\n", _(git_more_info_string));
exit(1);
exit_code = 1;
run_post_command_hook();
exit(exit_code);
}
cmd = argv[0];

Expand Down
Loading

0 comments on commit ff3d431

Please sign in to comment.