Merge branch 'ei/worktree+filter'
* ei/worktree+filter: filter-branch: always export GIT_DIR if it is set setup_git_directory: fix segfault if repository is found in cwd test GIT_WORK_TREE extend rev-parse test for --is-inside-work-tree Use new semantics of is_bare/inside_git_dir/inside_work_tree introduce GIT_WORK_TREE to specify the work tree test git rev-parse rev-parse: introduce --is-bare-repository rev-parse: document --is-inside-git-dir
This commit is contained in:
commit
0305b63654
@ -172,6 +172,13 @@ repository that ends in "/.git" is assumed to be not bare (bare =
|
|||||||
false), while all other repositories are assumed to be bare (bare
|
false), while all other repositories are assumed to be bare (bare
|
||||||
= true).
|
= true).
|
||||||
|
|
||||||
|
core.worktree::
|
||||||
|
Set the path to the working tree. The value will not be
|
||||||
|
used in combination with repositories found automatically in
|
||||||
|
a .git directory (i.e. $GIT_DIR is not set).
|
||||||
|
This can be overriden by the GIT_WORK_TREE environment
|
||||||
|
variable and the '--work-tree' command line option.
|
||||||
|
|
||||||
core.logAllRefUpdates::
|
core.logAllRefUpdates::
|
||||||
Updates to a ref <ref> is logged to the file
|
Updates to a ref <ref> is logged to the file
|
||||||
"$GIT_DIR/logs/<ref>", by appending the new and old
|
"$GIT_DIR/logs/<ref>", by appending the new and old
|
||||||
|
@ -90,8 +90,15 @@ OPTIONS
|
|||||||
Show `$GIT_DIR` if defined else show the path to the .git directory.
|
Show `$GIT_DIR` if defined else show the path to the .git directory.
|
||||||
|
|
||||||
--is-inside-git-dir::
|
--is-inside-git-dir::
|
||||||
Return "true" if we are in the git directory, otherwise "false".
|
When the current working directory is below the repository
|
||||||
Some commands require to be run in a working directory.
|
directory print "true", otherwise "false".
|
||||||
|
|
||||||
|
--is-inside-work-tree::
|
||||||
|
When the current working directory is inside the work tree of the
|
||||||
|
repository print "true", otherwise "false".
|
||||||
|
|
||||||
|
--is-bare-repository::
|
||||||
|
When the repository is bare print "true", otherwise "false".
|
||||||
|
|
||||||
--short, --short=number::
|
--short, --short=number::
|
||||||
Instead of outputting the full SHA1 values of object names try to
|
Instead of outputting the full SHA1 values of object names try to
|
||||||
|
@ -10,7 +10,8 @@ SYNOPSIS
|
|||||||
--------
|
--------
|
||||||
[verse]
|
[verse]
|
||||||
'git' [--version] [--exec-path[=GIT_EXEC_PATH]] [-p|--paginate]
|
'git' [--version] [--exec-path[=GIT_EXEC_PATH]] [-p|--paginate]
|
||||||
[--bare] [--git-dir=GIT_DIR] [--help] COMMAND [ARGS]
|
[--bare] [--git-dir=GIT_DIR] [--work-tree=GIT_WORK_TREE]
|
||||||
|
[--help] COMMAND [ARGS]
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
-----------
|
-----------
|
||||||
@ -103,6 +104,14 @@ OPTIONS
|
|||||||
Set the path to the repository. This can also be controlled by
|
Set the path to the repository. This can also be controlled by
|
||||||
setting the GIT_DIR environment variable.
|
setting the GIT_DIR environment variable.
|
||||||
|
|
||||||
|
--work-tree=<path>::
|
||||||
|
Set the path to the working tree. The value will not be
|
||||||
|
used in combination with repositories found automatically in
|
||||||
|
a .git directory (i.e. $GIT_DIR is not set).
|
||||||
|
This can also be controlled by setting the GIT_WORK_TREE
|
||||||
|
environment variable and the core.worktree configuration
|
||||||
|
variable.
|
||||||
|
|
||||||
--bare::
|
--bare::
|
||||||
Same as --git-dir=`pwd`.
|
Same as --git-dir=`pwd`.
|
||||||
|
|
||||||
@ -347,6 +356,13 @@ git so take care if using Cogito etc.
|
|||||||
specifies a path to use instead of the default `.git`
|
specifies a path to use instead of the default `.git`
|
||||||
for the base of the repository.
|
for the base of the repository.
|
||||||
|
|
||||||
|
'GIT_WORK_TREE'::
|
||||||
|
Set the path to the working tree. The value will not be
|
||||||
|
used in combination with repositories found automatically in
|
||||||
|
a .git directory (i.e. $GIT_DIR is not set).
|
||||||
|
This can also be controlled by the '--work-tree' command line
|
||||||
|
option and the core.worktree configuration variable.
|
||||||
|
|
||||||
git Commits
|
git Commits
|
||||||
~~~~~~~~~~~
|
~~~~~~~~~~~
|
||||||
'GIT_AUTHOR_NAME'::
|
'GIT_AUTHOR_NAME'::
|
||||||
|
@ -470,7 +470,7 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (require_work_tree &&
|
if (require_work_tree &&
|
||||||
(is_bare_repository() || is_inside_git_dir()))
|
(!is_inside_work_tree() || is_inside_git_dir()))
|
||||||
die("This operation must be run in a work tree");
|
die("This operation must be run in a work tree");
|
||||||
|
|
||||||
pathspec = get_pathspec(prefix, argv + i);
|
pathspec = get_pathspec(prefix, argv + i);
|
||||||
|
@ -352,6 +352,16 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
|
|||||||
: "false");
|
: "false");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (!strcmp(arg, "--is-inside-work-tree")) {
|
||||||
|
printf("%s\n", is_inside_work_tree() ? "true"
|
||||||
|
: "false");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!strcmp(arg, "--is-bare-repository")) {
|
||||||
|
printf("%s\n", is_bare_repository() ? "true"
|
||||||
|
: "false");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (!prefixcmp(arg, "--since=")) {
|
if (!prefixcmp(arg, "--since=")) {
|
||||||
show_datestring("--max-age=", arg+8);
|
show_datestring("--max-age=", arg+8);
|
||||||
continue;
|
continue;
|
||||||
|
2
cache.h
2
cache.h
@ -192,6 +192,7 @@ enum object_type {
|
|||||||
};
|
};
|
||||||
|
|
||||||
#define GIT_DIR_ENVIRONMENT "GIT_DIR"
|
#define GIT_DIR_ENVIRONMENT "GIT_DIR"
|
||||||
|
#define GIT_WORK_TREE_ENVIRONMENT "GIT_WORK_TREE"
|
||||||
#define DEFAULT_GIT_DIR_ENVIRONMENT ".git"
|
#define DEFAULT_GIT_DIR_ENVIRONMENT ".git"
|
||||||
#define DB_ENVIRONMENT "GIT_OBJECT_DIRECTORY"
|
#define DB_ENVIRONMENT "GIT_OBJECT_DIRECTORY"
|
||||||
#define INDEX_ENVIRONMENT "GIT_INDEX_FILE"
|
#define INDEX_ENVIRONMENT "GIT_INDEX_FILE"
|
||||||
@ -207,6 +208,7 @@ enum object_type {
|
|||||||
extern int is_bare_repository_cfg;
|
extern int is_bare_repository_cfg;
|
||||||
extern int is_bare_repository(void);
|
extern int is_bare_repository(void);
|
||||||
extern int is_inside_git_dir(void);
|
extern int is_inside_git_dir(void);
|
||||||
|
extern int is_inside_work_tree(void);
|
||||||
extern const char *get_git_dir(void);
|
extern const char *get_git_dir(void);
|
||||||
extern char *get_object_directory(void);
|
extern char *get_object_directory(void);
|
||||||
extern char *get_refs_directory(void);
|
extern char *get_refs_directory(void);
|
||||||
|
@ -587,6 +587,7 @@ pid_t git_connect(int fd[2], char *url, const char *prog, int flags)
|
|||||||
unsetenv(ALTERNATE_DB_ENVIRONMENT);
|
unsetenv(ALTERNATE_DB_ENVIRONMENT);
|
||||||
unsetenv(DB_ENVIRONMENT);
|
unsetenv(DB_ENVIRONMENT);
|
||||||
unsetenv(GIT_DIR_ENVIRONMENT);
|
unsetenv(GIT_DIR_ENVIRONMENT);
|
||||||
|
unsetenv(GIT_WORK_TREE_ENVIRONMENT);
|
||||||
unsetenv(GRAFT_ENVIRONMENT);
|
unsetenv(GRAFT_ENVIRONMENT);
|
||||||
unsetenv(INDEX_ENVIRONMENT);
|
unsetenv(INDEX_ENVIRONMENT);
|
||||||
execlp("sh", "sh", "-c", command, NULL);
|
execlp("sh", "sh", "-c", command, NULL);
|
||||||
|
@ -312,9 +312,10 @@ case "$GIT_DIR" in
|
|||||||
/*)
|
/*)
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
export GIT_DIR="$(pwd)/../../$GIT_DIR"
|
GIT_DIR="$(pwd)/../../$GIT_DIR"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
export GIT_DIR GIT_WORK_TREE=.
|
||||||
|
|
||||||
export GIT_INDEX_FILE="$(pwd)/../index"
|
export GIT_INDEX_FILE="$(pwd)/../index"
|
||||||
git-read-tree # seed the index file
|
git-read-tree # seed the index file
|
||||||
|
@ -29,11 +29,7 @@ set_reflog_action() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
is_bare_repository () {
|
is_bare_repository () {
|
||||||
git-config --bool --get core.bare ||
|
git-rev-parse --is-bare-repository
|
||||||
case "$GIT_DIR" in
|
|
||||||
.git | */.git) echo false ;;
|
|
||||||
*) echo true ;;
|
|
||||||
esac
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cd_to_toplevel () {
|
cd_to_toplevel () {
|
||||||
@ -48,7 +44,7 @@ cd_to_toplevel () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
require_work_tree () {
|
require_work_tree () {
|
||||||
test $(is_bare_repository) = false &&
|
test $(git-rev-parse --is-inside-work-tree) = true &&
|
||||||
test $(git-rev-parse --is-inside-git-dir) = false ||
|
test $(git-rev-parse --is-inside-git-dir) = false ||
|
||||||
die "fatal: $0 cannot be used without a working tree."
|
die "fatal: $0 cannot be used without a working tree."
|
||||||
}
|
}
|
||||||
|
@ -596,8 +596,7 @@ sub post_fetch_checkout {
|
|||||||
my $index = $ENV{GIT_INDEX_FILE} || "$ENV{GIT_DIR}/index";
|
my $index = $ENV{GIT_INDEX_FILE} || "$ENV{GIT_DIR}/index";
|
||||||
return if -f $index;
|
return if -f $index;
|
||||||
|
|
||||||
chomp(my $bare = `git config --bool --get core.bare`);
|
return if command_oneline(qw/rev-parse --is-inside-work-tree/) eq 'false';
|
||||||
return if $bare eq 'true';
|
|
||||||
return if command_oneline(qw/rev-parse --is-inside-git-dir/) eq 'true';
|
return if command_oneline(qw/rev-parse --is-inside-git-dir/) eq 'true';
|
||||||
command_noisy(qw/read-tree -m -u -v HEAD HEAD/);
|
command_noisy(qw/read-tree -m -u -v HEAD HEAD/);
|
||||||
print STDERR "Checked out HEAD:\n ",
|
print STDERR "Checked out HEAD:\n ",
|
||||||
|
35
git.c
35
git.c
@ -4,7 +4,7 @@
|
|||||||
#include "quote.h"
|
#include "quote.h"
|
||||||
|
|
||||||
const char git_usage_string[] =
|
const char git_usage_string[] =
|
||||||
"git [--version] [--exec-path[=GIT_EXEC_PATH]] [-p|--paginate] [--bare] [--git-dir=GIT_DIR] [--help] COMMAND [ARGS]";
|
"git [--version] [--exec-path[=GIT_EXEC_PATH]] [-p|--paginate] [--bare] [--git-dir=GIT_DIR] [--work-tree=GIT_WORK_TREE] [--help] COMMAND [ARGS]";
|
||||||
|
|
||||||
static void prepend_to_path(const char *dir, int len)
|
static void prepend_to_path(const char *dir, int len)
|
||||||
{
|
{
|
||||||
@ -69,6 +69,16 @@ static int handle_options(const char*** argv, int* argc)
|
|||||||
handled++;
|
handled++;
|
||||||
} else if (!prefixcmp(cmd, "--git-dir=")) {
|
} else if (!prefixcmp(cmd, "--git-dir=")) {
|
||||||
setenv(GIT_DIR_ENVIRONMENT, cmd + 10, 1);
|
setenv(GIT_DIR_ENVIRONMENT, cmd + 10, 1);
|
||||||
|
} else if (!strcmp(cmd, "--work-tree")) {
|
||||||
|
if (*argc < 2) {
|
||||||
|
fprintf(stderr, "No directory given for --work-tree.\n" );
|
||||||
|
usage(git_usage_string);
|
||||||
|
}
|
||||||
|
setenv(GIT_WORK_TREE_ENVIRONMENT, (*argv)[1], 1);
|
||||||
|
(*argv)++;
|
||||||
|
(*argc)--;
|
||||||
|
} else if (!prefixcmp(cmd, "--work-tree=")) {
|
||||||
|
setenv(GIT_WORK_TREE_ENVIRONMENT, cmd + 12, 1);
|
||||||
} else if (!strcmp(cmd, "--bare")) {
|
} else if (!strcmp(cmd, "--bare")) {
|
||||||
static char git_dir[PATH_MAX+1];
|
static char git_dir[PATH_MAX+1];
|
||||||
setenv(GIT_DIR_ENVIRONMENT, getcwd(git_dir, sizeof(git_dir)), 1);
|
setenv(GIT_DIR_ENVIRONMENT, getcwd(git_dir, sizeof(git_dir)), 1);
|
||||||
@ -214,7 +224,7 @@ const char git_version_string[] = GIT_VERSION;
|
|||||||
* require working tree to be present -- anything uses this needs
|
* require working tree to be present -- anything uses this needs
|
||||||
* RUN_SETUP for reading from the configuration file.
|
* RUN_SETUP for reading from the configuration file.
|
||||||
*/
|
*/
|
||||||
#define NOT_BARE (1<<2)
|
#define NEED_WORK_TREE (1<<2)
|
||||||
|
|
||||||
struct cmd_struct {
|
struct cmd_struct {
|
||||||
const char *cmd;
|
const char *cmd;
|
||||||
@ -233,10 +243,9 @@ static int run_command(struct cmd_struct *p, int argc, const char **argv)
|
|||||||
prefix = setup_git_directory();
|
prefix = setup_git_directory();
|
||||||
if (p->option & USE_PAGER)
|
if (p->option & USE_PAGER)
|
||||||
setup_pager();
|
setup_pager();
|
||||||
if (p->option & NOT_BARE) {
|
if ((p->option & NEED_WORK_TREE) &&
|
||||||
if (is_bare_repository() || is_inside_git_dir())
|
(!is_inside_work_tree() || is_inside_git_dir()))
|
||||||
die("%s must be run in a work tree", p->cmd);
|
die("%s must be run in a work tree", p->cmd);
|
||||||
}
|
|
||||||
trace_argv_printf(argv, argc, "trace: built-in: git");
|
trace_argv_printf(argv, argc, "trace: built-in: git");
|
||||||
|
|
||||||
status = p->fn(argc, argv, prefix);
|
status = p->fn(argc, argv, prefix);
|
||||||
@ -264,7 +273,7 @@ static void handle_internal_command(int argc, const char **argv)
|
|||||||
{
|
{
|
||||||
const char *cmd = argv[0];
|
const char *cmd = argv[0];
|
||||||
static struct cmd_struct commands[] = {
|
static struct cmd_struct commands[] = {
|
||||||
{ "add", cmd_add, RUN_SETUP | NOT_BARE },
|
{ "add", cmd_add, RUN_SETUP | NEED_WORK_TREE },
|
||||||
{ "annotate", cmd_annotate, RUN_SETUP | USE_PAGER },
|
{ "annotate", cmd_annotate, RUN_SETUP | USE_PAGER },
|
||||||
{ "apply", cmd_apply },
|
{ "apply", cmd_apply },
|
||||||
{ "archive", cmd_archive },
|
{ "archive", cmd_archive },
|
||||||
@ -274,9 +283,9 @@ static void handle_internal_command(int argc, const char **argv)
|
|||||||
{ "cat-file", cmd_cat_file, RUN_SETUP },
|
{ "cat-file", cmd_cat_file, RUN_SETUP },
|
||||||
{ "checkout-index", cmd_checkout_index, RUN_SETUP },
|
{ "checkout-index", cmd_checkout_index, RUN_SETUP },
|
||||||
{ "check-ref-format", cmd_check_ref_format },
|
{ "check-ref-format", cmd_check_ref_format },
|
||||||
{ "check-attr", cmd_check_attr, RUN_SETUP | NOT_BARE },
|
{ "check-attr", cmd_check_attr, RUN_SETUP | NEED_WORK_TREE },
|
||||||
{ "cherry", cmd_cherry, RUN_SETUP },
|
{ "cherry", cmd_cherry, RUN_SETUP },
|
||||||
{ "cherry-pick", cmd_cherry_pick, RUN_SETUP | NOT_BARE },
|
{ "cherry-pick", cmd_cherry_pick, RUN_SETUP | NEED_WORK_TREE },
|
||||||
{ "commit-tree", cmd_commit_tree, RUN_SETUP },
|
{ "commit-tree", cmd_commit_tree, RUN_SETUP },
|
||||||
{ "config", cmd_config },
|
{ "config", cmd_config },
|
||||||
{ "count-objects", cmd_count_objects, RUN_SETUP },
|
{ "count-objects", cmd_count_objects, RUN_SETUP },
|
||||||
@ -304,7 +313,7 @@ static void handle_internal_command(int argc, const char **argv)
|
|||||||
{ "mailsplit", cmd_mailsplit },
|
{ "mailsplit", cmd_mailsplit },
|
||||||
{ "merge-base", cmd_merge_base, RUN_SETUP },
|
{ "merge-base", cmd_merge_base, RUN_SETUP },
|
||||||
{ "merge-file", cmd_merge_file },
|
{ "merge-file", cmd_merge_file },
|
||||||
{ "mv", cmd_mv, RUN_SETUP | NOT_BARE },
|
{ "mv", cmd_mv, RUN_SETUP | NEED_WORK_TREE },
|
||||||
{ "name-rev", cmd_name_rev, RUN_SETUP },
|
{ "name-rev", cmd_name_rev, RUN_SETUP },
|
||||||
{ "pack-objects", cmd_pack_objects, RUN_SETUP },
|
{ "pack-objects", cmd_pack_objects, RUN_SETUP },
|
||||||
{ "pickaxe", cmd_blame, RUN_SETUP | USE_PAGER },
|
{ "pickaxe", cmd_blame, RUN_SETUP | USE_PAGER },
|
||||||
@ -317,9 +326,9 @@ static void handle_internal_command(int argc, const char **argv)
|
|||||||
{ "rerere", cmd_rerere, RUN_SETUP },
|
{ "rerere", cmd_rerere, RUN_SETUP },
|
||||||
{ "rev-list", cmd_rev_list, RUN_SETUP },
|
{ "rev-list", cmd_rev_list, RUN_SETUP },
|
||||||
{ "rev-parse", cmd_rev_parse, RUN_SETUP },
|
{ "rev-parse", cmd_rev_parse, RUN_SETUP },
|
||||||
{ "revert", cmd_revert, RUN_SETUP | NOT_BARE },
|
{ "revert", cmd_revert, RUN_SETUP | NEED_WORK_TREE },
|
||||||
{ "rm", cmd_rm, RUN_SETUP | NOT_BARE },
|
{ "rm", cmd_rm, RUN_SETUP | NEED_WORK_TREE },
|
||||||
{ "runstatus", cmd_runstatus, RUN_SETUP | NOT_BARE },
|
{ "runstatus", cmd_runstatus, RUN_SETUP | NEED_WORK_TREE },
|
||||||
{ "shortlog", cmd_shortlog, RUN_SETUP | USE_PAGER },
|
{ "shortlog", cmd_shortlog, RUN_SETUP | USE_PAGER },
|
||||||
{ "show-branch", cmd_show_branch, RUN_SETUP },
|
{ "show-branch", cmd_show_branch, RUN_SETUP },
|
||||||
{ "show", cmd_show, RUN_SETUP | USE_PAGER },
|
{ "show", cmd_show, RUN_SETUP | USE_PAGER },
|
||||||
|
218
setup.c
218
setup.c
@ -95,7 +95,7 @@ void verify_non_filename(const char *prefix, const char *arg)
|
|||||||
const char *name;
|
const char *name;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
|
||||||
if (is_inside_git_dir())
|
if (!is_inside_work_tree() || is_inside_git_dir())
|
||||||
return;
|
return;
|
||||||
if (*arg == '-')
|
if (*arg == '-')
|
||||||
return; /* flag */
|
return; /* flag */
|
||||||
@ -174,41 +174,96 @@ static int inside_git_dir = -1;
|
|||||||
|
|
||||||
int is_inside_git_dir(void)
|
int is_inside_git_dir(void)
|
||||||
{
|
{
|
||||||
if (inside_git_dir < 0) {
|
if (inside_git_dir >= 0)
|
||||||
char buffer[1024];
|
return inside_git_dir;
|
||||||
|
die("BUG: is_inside_git_dir called before setup_git_directory");
|
||||||
|
}
|
||||||
|
|
||||||
if (is_bare_repository())
|
static int inside_work_tree = -1;
|
||||||
return (inside_git_dir = 1);
|
|
||||||
if (getcwd(buffer, sizeof(buffer))) {
|
int is_inside_work_tree(void)
|
||||||
const char *git_dir = get_git_dir(), *cwd = buffer;
|
{
|
||||||
while (*git_dir && *git_dir == *cwd) {
|
if (inside_git_dir >= 0)
|
||||||
git_dir++;
|
return inside_work_tree;
|
||||||
cwd++;
|
die("BUG: is_inside_work_tree called before setup_git_directory");
|
||||||
}
|
}
|
||||||
inside_git_dir = !*git_dir;
|
|
||||||
} else
|
static char *gitworktree_config;
|
||||||
inside_git_dir = 0;
|
|
||||||
|
static int git_setup_config(const char *var, const char *value)
|
||||||
|
{
|
||||||
|
if (!strcmp(var, "core.worktree")) {
|
||||||
|
if (gitworktree_config)
|
||||||
|
strlcpy(gitworktree_config, value, PATH_MAX);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
return inside_git_dir;
|
return git_default_config(var, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *setup_git_directory_gently(int *nongit_ok)
|
const char *setup_git_directory_gently(int *nongit_ok)
|
||||||
{
|
{
|
||||||
static char cwd[PATH_MAX+1];
|
static char cwd[PATH_MAX+1];
|
||||||
const char *gitdirenv;
|
char worktree[PATH_MAX+1], gitdir[PATH_MAX+1];
|
||||||
int len, offset;
|
const char *gitdirenv, *gitworktree;
|
||||||
|
int wt_rel_gitdir = 0;
|
||||||
|
|
||||||
/*
|
|
||||||
* If GIT_DIR is set explicitly, we're not going
|
|
||||||
* to do any discovery, but we still do repository
|
|
||||||
* validation.
|
|
||||||
*/
|
|
||||||
gitdirenv = getenv(GIT_DIR_ENVIRONMENT);
|
gitdirenv = getenv(GIT_DIR_ENVIRONMENT);
|
||||||
if (gitdirenv) {
|
if (!gitdirenv) {
|
||||||
if (PATH_MAX - 40 < strlen(gitdirenv))
|
int len, offset;
|
||||||
die("'$%s' too big", GIT_DIR_ENVIRONMENT);
|
|
||||||
if (is_git_directory(gitdirenv))
|
if (!getcwd(cwd, sizeof(cwd)-1) || cwd[0] != '/')
|
||||||
|
die("Unable to read current working directory");
|
||||||
|
|
||||||
|
offset = len = strlen(cwd);
|
||||||
|
for (;;) {
|
||||||
|
if (is_git_directory(".git"))
|
||||||
|
break;
|
||||||
|
if (offset == 0) {
|
||||||
|
offset = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
chdir("..");
|
||||||
|
while (cwd[--offset] != '/')
|
||||||
|
; /* do nothing */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (offset >= 0) {
|
||||||
|
inside_work_tree = 1;
|
||||||
|
git_config(git_default_config);
|
||||||
|
if (offset == len) {
|
||||||
|
inside_git_dir = 0;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cwd[len++] = '/';
|
||||||
|
cwd[len] = '\0';
|
||||||
|
inside_git_dir = !prefixcmp(cwd + offset + 1, ".git/");
|
||||||
|
return cwd + offset + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chdir(cwd))
|
||||||
|
die("Cannot come back to cwd");
|
||||||
|
if (!is_git_directory(".")) {
|
||||||
|
if (nongit_ok) {
|
||||||
|
*nongit_ok = 1;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
die("Not a git repository");
|
||||||
|
}
|
||||||
|
setenv(GIT_DIR_ENVIRONMENT, cwd, 1);
|
||||||
|
gitdirenv = getenv(GIT_DIR_ENVIRONMENT);
|
||||||
|
if (!gitdirenv)
|
||||||
|
die("getenv after setenv failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PATH_MAX - 40 < strlen(gitdirenv)) {
|
||||||
|
if (nongit_ok) {
|
||||||
|
*nongit_ok = 1;
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
die("$%s too big", GIT_DIR_ENVIRONMENT);
|
||||||
|
}
|
||||||
|
if (!is_git_directory(gitdirenv)) {
|
||||||
if (nongit_ok) {
|
if (nongit_ok) {
|
||||||
*nongit_ok = 1;
|
*nongit_ok = 1;
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -218,41 +273,92 @@ const char *setup_git_directory_gently(int *nongit_ok)
|
|||||||
|
|
||||||
if (!getcwd(cwd, sizeof(cwd)-1) || cwd[0] != '/')
|
if (!getcwd(cwd, sizeof(cwd)-1) || cwd[0] != '/')
|
||||||
die("Unable to read current working directory");
|
die("Unable to read current working directory");
|
||||||
|
if (chdir(gitdirenv)) {
|
||||||
|
if (nongit_ok) {
|
||||||
|
*nongit_ok = 1;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
die("Cannot change directory to $%s '%s'",
|
||||||
|
GIT_DIR_ENVIRONMENT, gitdirenv);
|
||||||
|
}
|
||||||
|
if (!getcwd(gitdir, sizeof(gitdir)-1) || gitdir[0] != '/')
|
||||||
|
die("Unable to read current working directory");
|
||||||
|
if (chdir(cwd))
|
||||||
|
die("Cannot come back to cwd");
|
||||||
|
|
||||||
offset = len = strlen(cwd);
|
/*
|
||||||
for (;;) {
|
* In case there is a work tree we may change the directory,
|
||||||
if (is_git_directory(".git"))
|
* therefore make GIT_DIR an absolute path.
|
||||||
break;
|
*/
|
||||||
chdir("..");
|
if (gitdirenv[0] != '/') {
|
||||||
do {
|
setenv(GIT_DIR_ENVIRONMENT, gitdir, 1);
|
||||||
if (!offset) {
|
gitdirenv = getenv(GIT_DIR_ENVIRONMENT);
|
||||||
if (is_git_directory(cwd)) {
|
if (!gitdirenv)
|
||||||
if (chdir(cwd))
|
die("getenv after setenv failed");
|
||||||
die("Cannot come back to cwd");
|
if (PATH_MAX - 40 < strlen(gitdirenv)) {
|
||||||
setenv(GIT_DIR_ENVIRONMENT, cwd, 1);
|
if (nongit_ok) {
|
||||||
inside_git_dir = 1;
|
*nongit_ok = 1;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
|
||||||
if (nongit_ok) {
|
|
||||||
if (chdir(cwd))
|
|
||||||
die("Cannot come back to cwd");
|
|
||||||
*nongit_ok = 1;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
die("Not a git repository");
|
|
||||||
}
|
}
|
||||||
} while (cwd[--offset] != '/');
|
die("$%s too big after expansion to absolute path",
|
||||||
|
GIT_DIR_ENVIRONMENT);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (offset == len)
|
strcat(cwd, "/");
|
||||||
return NULL;
|
strcat(gitdir, "/");
|
||||||
|
inside_git_dir = !prefixcmp(cwd, gitdir);
|
||||||
|
|
||||||
/* Make "offset" point to past the '/', and add a '/' at the end */
|
gitworktree = getenv(GIT_WORK_TREE_ENVIRONMENT);
|
||||||
offset++;
|
if (!gitworktree) {
|
||||||
cwd[len++] = '/';
|
gitworktree_config = worktree;
|
||||||
cwd[len] = 0;
|
worktree[0] = '\0';
|
||||||
inside_git_dir = !prefixcmp(cwd + offset, ".git/");
|
}
|
||||||
return cwd + offset;
|
git_config(git_setup_config);
|
||||||
|
if (!gitworktree) {
|
||||||
|
gitworktree_config = NULL;
|
||||||
|
if (worktree[0])
|
||||||
|
gitworktree = worktree;
|
||||||
|
if (gitworktree && gitworktree[0] != '/')
|
||||||
|
wt_rel_gitdir = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wt_rel_gitdir && chdir(gitdirenv))
|
||||||
|
die("Cannot change directory to $%s '%s'",
|
||||||
|
GIT_DIR_ENVIRONMENT, gitdirenv);
|
||||||
|
if (gitworktree && chdir(gitworktree)) {
|
||||||
|
if (nongit_ok) {
|
||||||
|
if (wt_rel_gitdir && chdir(cwd))
|
||||||
|
die("Cannot come back to cwd");
|
||||||
|
*nongit_ok = 1;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (wt_rel_gitdir)
|
||||||
|
die("Cannot change directory to working tree '%s'"
|
||||||
|
" from $%s", gitworktree, GIT_DIR_ENVIRONMENT);
|
||||||
|
else
|
||||||
|
die("Cannot change directory to working tree '%s'",
|
||||||
|
gitworktree);
|
||||||
|
}
|
||||||
|
if (!getcwd(worktree, sizeof(worktree)-1) || worktree[0] != '/')
|
||||||
|
die("Unable to read current working directory");
|
||||||
|
strcat(worktree, "/");
|
||||||
|
inside_work_tree = !prefixcmp(cwd, worktree);
|
||||||
|
|
||||||
|
if (gitworktree && inside_work_tree && !prefixcmp(worktree, gitdir) &&
|
||||||
|
strcmp(worktree, gitdir)) {
|
||||||
|
inside_git_dir = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!inside_work_tree) {
|
||||||
|
if (chdir(cwd))
|
||||||
|
die("Cannot come back to cwd");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strcmp(cwd, worktree))
|
||||||
|
return NULL;
|
||||||
|
return cwd+strlen(worktree);
|
||||||
}
|
}
|
||||||
|
|
||||||
int git_config_perm(const char *var, const char *value)
|
int git_config_perm(const char *var, const char *value)
|
||||||
|
77
t/t1500-rev-parse.sh
Executable file
77
t/t1500-rev-parse.sh
Executable file
@ -0,0 +1,77 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
test_description='test git rev-parse'
|
||||||
|
. ./test-lib.sh
|
||||||
|
|
||||||
|
test_rev_parse() {
|
||||||
|
name=$1
|
||||||
|
shift
|
||||||
|
|
||||||
|
test_expect_success "$name: is-bare-repository" \
|
||||||
|
"test '$1' = \"\$(git rev-parse --is-bare-repository)\""
|
||||||
|
shift
|
||||||
|
[ $# -eq 0 ] && return
|
||||||
|
|
||||||
|
test_expect_success "$name: is-inside-git-dir" \
|
||||||
|
"test '$1' = \"\$(git rev-parse --is-inside-git-dir)\""
|
||||||
|
shift
|
||||||
|
[ $# -eq 0 ] && return
|
||||||
|
|
||||||
|
test_expect_success "$name: is-inside-work-tree" \
|
||||||
|
"test '$1' = \"\$(git rev-parse --is-inside-work-tree)\""
|
||||||
|
shift
|
||||||
|
[ $# -eq 0 ] && return
|
||||||
|
|
||||||
|
test_expect_success "$name: prefix" \
|
||||||
|
"test '$1' = \"\$(git rev-parse --show-prefix)\""
|
||||||
|
shift
|
||||||
|
[ $# -eq 0 ] && return
|
||||||
|
}
|
||||||
|
|
||||||
|
test_rev_parse toplevel false false true ''
|
||||||
|
|
||||||
|
cd .git || exit 1
|
||||||
|
test_rev_parse .git/ false true true .git/
|
||||||
|
cd objects || exit 1
|
||||||
|
test_rev_parse .git/objects/ false true true .git/objects/
|
||||||
|
cd ../.. || exit 1
|
||||||
|
|
||||||
|
mkdir -p sub/dir || exit 1
|
||||||
|
cd sub/dir || exit 1
|
||||||
|
test_rev_parse subdirectory false false true sub/dir/
|
||||||
|
cd ../.. || exit 1
|
||||||
|
|
||||||
|
git config core.bare true
|
||||||
|
test_rev_parse 'core.bare = true' true false true
|
||||||
|
|
||||||
|
git config --unset core.bare
|
||||||
|
test_rev_parse 'core.bare undefined' false false true
|
||||||
|
|
||||||
|
mkdir work || exit 1
|
||||||
|
cd work || exit 1
|
||||||
|
export GIT_DIR=../.git
|
||||||
|
export GIT_CONFIG="$GIT_DIR"/config
|
||||||
|
|
||||||
|
git config core.bare false
|
||||||
|
test_rev_parse 'GIT_DIR=../.git, core.bare = false' false false true ''
|
||||||
|
|
||||||
|
git config core.bare true
|
||||||
|
test_rev_parse 'GIT_DIR=../.git, core.bare = true' true false true ''
|
||||||
|
|
||||||
|
git config --unset core.bare
|
||||||
|
test_rev_parse 'GIT_DIR=../.git, core.bare undefined' false false true ''
|
||||||
|
|
||||||
|
mv ../.git ../repo.git || exit 1
|
||||||
|
export GIT_DIR=../repo.git
|
||||||
|
export GIT_CONFIG="$GIT_DIR"/config
|
||||||
|
|
||||||
|
git config core.bare false
|
||||||
|
test_rev_parse 'GIT_DIR=../repo.git, core.bare = false' false false true ''
|
||||||
|
|
||||||
|
git config core.bare true
|
||||||
|
test_rev_parse 'GIT_DIR=../repo.git, core.bare = true' true false true ''
|
||||||
|
|
||||||
|
git config --unset core.bare
|
||||||
|
test_rev_parse 'GIT_DIR=../repo.git, core.bare undefined' true false true ''
|
||||||
|
|
||||||
|
test_done
|
92
t/t1501-worktree.sh
Executable file
92
t/t1501-worktree.sh
Executable file
@ -0,0 +1,92 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
test_description='test separate work tree'
|
||||||
|
. ./test-lib.sh
|
||||||
|
|
||||||
|
test_rev_parse() {
|
||||||
|
name=$1
|
||||||
|
shift
|
||||||
|
|
||||||
|
test_expect_success "$name: is-bare-repository" \
|
||||||
|
"test '$1' = \"\$(git rev-parse --is-bare-repository)\""
|
||||||
|
shift
|
||||||
|
[ $# -eq 0 ] && return
|
||||||
|
|
||||||
|
test_expect_success "$name: is-inside-git-dir" \
|
||||||
|
"test '$1' = \"\$(git rev-parse --is-inside-git-dir)\""
|
||||||
|
shift
|
||||||
|
[ $# -eq 0 ] && return
|
||||||
|
|
||||||
|
test_expect_success "$name: is-inside-work-tree" \
|
||||||
|
"test '$1' = \"\$(git rev-parse --is-inside-work-tree)\""
|
||||||
|
shift
|
||||||
|
[ $# -eq 0 ] && return
|
||||||
|
|
||||||
|
test_expect_success "$name: prefix" \
|
||||||
|
"test '$1' = \"\$(git rev-parse --show-prefix)\""
|
||||||
|
shift
|
||||||
|
[ $# -eq 0 ] && return
|
||||||
|
}
|
||||||
|
|
||||||
|
mkdir -p work/sub/dir || exit 1
|
||||||
|
mv .git repo.git || exit 1
|
||||||
|
|
||||||
|
say "core.worktree = relative path"
|
||||||
|
export GIT_DIR=repo.git
|
||||||
|
export GIT_CONFIG=$GIT_DIR/config
|
||||||
|
unset GIT_WORK_TREE
|
||||||
|
git config core.worktree ../work
|
||||||
|
test_rev_parse 'outside' false false false
|
||||||
|
cd work || exit 1
|
||||||
|
export GIT_DIR=../repo.git
|
||||||
|
export GIT_CONFIG=$GIT_DIR/config
|
||||||
|
test_rev_parse 'inside' false false true ''
|
||||||
|
cd sub/dir || exit 1
|
||||||
|
export GIT_DIR=../../../repo.git
|
||||||
|
export GIT_CONFIG=$GIT_DIR/config
|
||||||
|
test_rev_parse 'subdirectory' false false true sub/dir/
|
||||||
|
cd ../../.. || exit 1
|
||||||
|
|
||||||
|
say "core.worktree = absolute path"
|
||||||
|
export GIT_DIR=$(pwd)/repo.git
|
||||||
|
export GIT_CONFIG=$GIT_DIR/config
|
||||||
|
git config core.worktree "$(pwd)/work"
|
||||||
|
test_rev_parse 'outside' false false false
|
||||||
|
cd work || exit 1
|
||||||
|
test_rev_parse 'inside' false false true ''
|
||||||
|
cd sub/dir || exit 1
|
||||||
|
test_rev_parse 'subdirectory' false false true sub/dir/
|
||||||
|
cd ../../.. || exit 1
|
||||||
|
|
||||||
|
say "GIT_WORK_TREE=relative path (override core.worktree)"
|
||||||
|
export GIT_DIR=$(pwd)/repo.git
|
||||||
|
export GIT_CONFIG=$GIT_DIR/config
|
||||||
|
git config core.worktree non-existent
|
||||||
|
export GIT_WORK_TREE=work
|
||||||
|
test_rev_parse 'outside' false false false
|
||||||
|
cd work || exit 1
|
||||||
|
export GIT_WORK_TREE=.
|
||||||
|
test_rev_parse 'inside' false false true ''
|
||||||
|
cd sub/dir || exit 1
|
||||||
|
export GIT_WORK_TREE=../..
|
||||||
|
test_rev_parse 'subdirectory' false false true sub/dir/
|
||||||
|
cd ../../.. || exit 1
|
||||||
|
|
||||||
|
mv work repo.git/work
|
||||||
|
|
||||||
|
say "GIT_WORK_TREE=absolute path, work tree below git dir"
|
||||||
|
export GIT_DIR=$(pwd)/repo.git
|
||||||
|
export GIT_CONFIG=$GIT_DIR/config
|
||||||
|
export GIT_WORK_TREE=$(pwd)/repo.git/work
|
||||||
|
test_rev_parse 'outside' false false false
|
||||||
|
cd repo.git || exit 1
|
||||||
|
test_rev_parse 'in repo.git' false true false
|
||||||
|
cd objects || exit 1
|
||||||
|
test_rev_parse 'in repo.git/objects' false true false
|
||||||
|
cd ../work || exit 1
|
||||||
|
test_rev_parse 'in repo.git/work' false false true ''
|
||||||
|
cd sub/dir || exit 1
|
||||||
|
test_rev_parse 'in repo.git/sub/dir' false false true sub/dir/
|
||||||
|
cd ../../../.. || exit 1
|
||||||
|
|
||||||
|
test_done
|
@ -26,6 +26,7 @@ GIT_COMMITTER_EMAIL=committer@example.com
|
|||||||
GIT_COMMITTER_NAME='C O Mitter'
|
GIT_COMMITTER_NAME='C O Mitter'
|
||||||
unset GIT_DIFF_OPTS
|
unset GIT_DIFF_OPTS
|
||||||
unset GIT_DIR
|
unset GIT_DIR
|
||||||
|
unset GIT_WORK_TREE
|
||||||
unset GIT_EXTERNAL_DIFF
|
unset GIT_EXTERNAL_DIFF
|
||||||
unset GIT_INDEX_FILE
|
unset GIT_INDEX_FILE
|
||||||
unset GIT_OBJECT_DIRECTORY
|
unset GIT_OBJECT_DIRECTORY
|
||||||
|
Loading…
Reference in New Issue
Block a user