提交 b44ebb19 编写于 作者: L Lars Hjemli 提交者: Junio C Hamano

Add platform-independent .git "symlink"

This patch allows .git to be a regular textfile containing the path of
the real git directory (prefixed with "gitdir: "), which can be useful on
platforms lacking support for real symlinks.
Signed-off-by: NLars Hjemli <hjemli@gmail.com>
Signed-off-by: NJunio C Hamano <gitster@pobox.com>
上级 2a5fe254
...@@ -3,7 +3,10 @@ git repository layout ...@@ -3,7 +3,10 @@ git repository layout
You may find these things in your git repository (`.git` You may find these things in your git repository (`.git`
directory for a repository associated with your working tree, or directory for a repository associated with your working tree, or
`'project'.git` directory for a public 'bare' repository). `'project'.git` directory for a public 'bare' repository. It is
also possible to have a working tree where `.git` is a plain
ascii file containing `gitdir: <path>`, i.e. the path to the
real git repository).
objects:: objects::
Object store associated with this repository. Usually Object store associated with this repository. Usually
......
...@@ -311,6 +311,7 @@ extern char *get_index_file(void); ...@@ -311,6 +311,7 @@ extern char *get_index_file(void);
extern char *get_graft_file(void); extern char *get_graft_file(void);
extern int set_git_dir(const char *path); extern int set_git_dir(const char *path);
extern const char *get_git_work_tree(void); extern const char *get_git_work_tree(void);
extern const char *read_gitfile_gently(const char *path);
#define ALTERNATE_DB_ENVIRONMENT "GIT_ALTERNATE_OBJECT_DIRECTORIES" #define ALTERNATE_DB_ENVIRONMENT "GIT_ALTERNATE_OBJECT_DIRECTORIES"
......
...@@ -49,6 +49,8 @@ static char *git_object_dir, *git_index_file, *git_refs_dir, *git_graft_file; ...@@ -49,6 +49,8 @@ static char *git_object_dir, *git_index_file, *git_refs_dir, *git_graft_file;
static void setup_git_env(void) static void setup_git_env(void)
{ {
git_dir = getenv(GIT_DIR_ENVIRONMENT); git_dir = getenv(GIT_DIR_ENVIRONMENT);
if (!git_dir)
git_dir = read_gitfile_gently(DEFAULT_GIT_DIR_ENVIRONMENT);
if (!git_dir) if (!git_dir)
git_dir = DEFAULT_GIT_DIR_ENVIRONMENT; git_dir = DEFAULT_GIT_DIR_ENVIRONMENT;
git_object_dir = getenv(DB_ENVIRONMENT); git_object_dir = getenv(DB_ENVIRONMENT);
......
...@@ -314,6 +314,44 @@ static int check_repository_format_gently(int *nongit_ok) ...@@ -314,6 +314,44 @@ static int check_repository_format_gently(int *nongit_ok)
return 0; return 0;
} }
/*
* Try to read the location of the git directory from the .git file,
* return path to git directory if found.
*/
const char *read_gitfile_gently(const char *path)
{
char *buf;
struct stat st;
int fd;
size_t len;
if (stat(path, &st))
return NULL;
if (!S_ISREG(st.st_mode))
return NULL;
fd = open(path, O_RDONLY);
if (fd < 0)
die("Error opening %s: %s", path, strerror(errno));
buf = xmalloc(st.st_size + 1);
len = read_in_full(fd, buf, st.st_size);
close(fd);
if (len != st.st_size)
die("Error reading %s", path);
buf[len] = '\0';
if (prefixcmp(buf, "gitdir: "))
die("Invalid gitfile format: %s", path);
while (buf[len - 1] == '\n' || buf[len - 1] == '\r')
len--;
if (len < 9)
die("No path in gitfile: %s", path);
buf[len] = '\0';
if (!is_git_directory(buf + 8))
die("Not a git repository: %s", buf + 8);
path = make_absolute_path(buf + 8);
free(buf);
return path;
}
/* /*
* We cannot decide in this function whether we are in the work tree or * We cannot decide in this function whether we are in the work tree or
* not, since the config can only be read _after_ this function was called. * not, since the config can only be read _after_ this function was called.
...@@ -323,6 +361,7 @@ const char *setup_git_directory_gently(int *nongit_ok) ...@@ -323,6 +361,7 @@ const char *setup_git_directory_gently(int *nongit_ok)
const char *work_tree_env = getenv(GIT_WORK_TREE_ENVIRONMENT); const char *work_tree_env = getenv(GIT_WORK_TREE_ENVIRONMENT);
static char cwd[PATH_MAX+1]; static char cwd[PATH_MAX+1];
const char *gitdirenv; const char *gitdirenv;
const char *gitfile_dir;
int len, offset; int len, offset;
/* /*
...@@ -377,8 +416,10 @@ const char *setup_git_directory_gently(int *nongit_ok) ...@@ -377,8 +416,10 @@ const char *setup_git_directory_gently(int *nongit_ok)
/* /*
* Test in the following order (relative to the cwd): * Test in the following order (relative to the cwd):
* - .git (file containing "gitdir: <path>")
* - .git/ * - .git/
* - ./ (bare) * - ./ (bare)
* - ../.git
* - ../.git/ * - ../.git/
* - ../ (bare) * - ../ (bare)
* - ../../.git/ * - ../../.git/
...@@ -386,6 +427,12 @@ const char *setup_git_directory_gently(int *nongit_ok) ...@@ -386,6 +427,12 @@ const char *setup_git_directory_gently(int *nongit_ok)
*/ */
offset = len = strlen(cwd); offset = len = strlen(cwd);
for (;;) { for (;;) {
gitfile_dir = read_gitfile_gently(DEFAULT_GIT_DIR_ENVIRONMENT);
if (gitfile_dir) {
if (set_git_dir(gitfile_dir))
die("Repository setup failed");
break;
}
if (is_git_directory(DEFAULT_GIT_DIR_ENVIRONMENT)) if (is_git_directory(DEFAULT_GIT_DIR_ENVIRONMENT))
break; break;
if (is_git_directory(".")) { if (is_git_directory(".")) {
......
#!/bin/sh
test_description='.git file
Verify that plumbing commands work when .git is a file
'
. ./test-lib.sh
objpath() {
echo "$1" | sed -e 's|\(..\)|\1/|'
}
objck() {
p=$(objpath "$1")
if test ! -f "$REAL/objects/$p"
then
echo "Object not found: $REAL/objects/$p"
false
fi
}
test_expect_success 'initial setup' '
REAL="$(pwd)/.real" &&
mv .git "$REAL"
'
test_expect_success 'bad setup: invalid .git file format' '
echo "gitdir $REAL" >.git &&
if git rev-parse 2>.err
then
echo "git rev-parse accepted an invalid .git file"
false
fi &&
if ! grep -qe "Invalid gitfile format" .err
then
echo "git rev-parse returned wrong error"
false
fi
'
test_expect_success 'bad setup: invalid .git file path' '
echo "gitdir: $REAL.not" >.git &&
if git rev-parse 2>.err
then
echo "git rev-parse accepted an invalid .git file path"
false
fi &&
if ! grep -qe "Not a git repository" .err
then
echo "git rev-parse returned wrong error"
false
fi
'
test_expect_success 'final setup + check rev-parse --git-dir' '
echo "gitdir: $REAL" >.git &&
test "$REAL" = "$(git rev-parse --git-dir)"
'
test_expect_success 'check hash-object' '
echo "foo" >bar &&
SHA=$(cat bar | git hash-object -w --stdin) &&
objck $SHA
'
test_expect_success 'check cat-file' '
git cat-file blob $SHA >actual &&
diff -u bar actual
'
test_expect_success 'check update-index' '
if test -f "$REAL/index"
then
echo "Hmm, $REAL/index exists?"
false
fi &&
rm -f "$REAL/objects/$(objpath $SHA)" &&
git update-index --add bar &&
if ! test -f "$REAL/index"
then
echo "$REAL/index not found"
false
fi &&
objck $SHA
'
test_expect_success 'check write-tree' '
SHA=$(git write-tree) &&
objck $SHA
'
test_expect_success 'check commit-tree' '
SHA=$(echo "commit bar" | git commit-tree $SHA) &&
objck $SHA
'
test_expect_success 'check rev-list' '
echo $SHA >"$REAL/HEAD" &&
test "$SHA" = "$(git rev-list HEAD)"
'
test_done
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册