Merge branch 'lh/git-file'
* lh/git-file: Teach GIT-VERSION-GEN about the .git file Teach git-submodule.sh about the .git file Teach resolve_gitlink_ref() about the .git file Add platform-independent .git "symlink"
This commit is contained in:
commit
e2e2defc14
@ -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
|
||||||
|
@ -11,7 +11,7 @@ LF='
|
|||||||
if test -f version
|
if test -f version
|
||||||
then
|
then
|
||||||
VN=$(cat version) || VN="$DEF_VER"
|
VN=$(cat version) || VN="$DEF_VER"
|
||||||
elif test -d .git &&
|
elif test -d .git -o -f .git &&
|
||||||
VN=$(git describe --abbrev=4 HEAD 2>/dev/null) &&
|
VN=$(git describe --abbrev=4 HEAD 2>/dev/null) &&
|
||||||
case "$VN" in
|
case "$VN" in
|
||||||
*$LF*) (exit 1) ;;
|
*$LF*) (exit 1) ;;
|
||||||
|
1
cache.h
1
cache.h
@ -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;
|
|||||||
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);
|
||||||
|
@ -300,7 +300,7 @@ cmd_update()
|
|||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ! test -d "$path"/.git
|
if ! test -d "$path"/.git -o -f "$path"/.git
|
||||||
then
|
then
|
||||||
module_clone "$path" "$url" || exit
|
module_clone "$path" "$url" || exit
|
||||||
subsha1=
|
subsha1=
|
||||||
@ -555,7 +555,7 @@ cmd_status()
|
|||||||
do
|
do
|
||||||
name=$(module_name "$path") || exit
|
name=$(module_name "$path") || exit
|
||||||
url=$(git config submodule."$name".url)
|
url=$(git config submodule."$name".url)
|
||||||
if test -z "$url" || ! test -d "$path"/.git
|
if test -z "$url" || ! test -d "$path"/.git -o -f "$path"/.git
|
||||||
then
|
then
|
||||||
say "-$sha1 $path"
|
say "-$sha1 $path"
|
||||||
continue;
|
continue;
|
||||||
|
15
refs.c
15
refs.c
@ -352,6 +352,7 @@ int resolve_gitlink_ref(const char *path, const char *refname, unsigned char *re
|
|||||||
{
|
{
|
||||||
int len = strlen(path), retval;
|
int len = strlen(path), retval;
|
||||||
char *gitdir;
|
char *gitdir;
|
||||||
|
const char *tmp;
|
||||||
|
|
||||||
while (len && path[len-1] == '/')
|
while (len && path[len-1] == '/')
|
||||||
len--;
|
len--;
|
||||||
@ -359,9 +360,19 @@ int resolve_gitlink_ref(const char *path, const char *refname, unsigned char *re
|
|||||||
return -1;
|
return -1;
|
||||||
gitdir = xmalloc(len + MAXREFLEN + 8);
|
gitdir = xmalloc(len + MAXREFLEN + 8);
|
||||||
memcpy(gitdir, path, len);
|
memcpy(gitdir, path, len);
|
||||||
memcpy(gitdir + len, "/.git/", 7);
|
memcpy(gitdir + len, "/.git", 6);
|
||||||
|
len += 5;
|
||||||
|
|
||||||
retval = resolve_gitlink_ref_recursive(gitdir, len+6, refname, result, 0);
|
tmp = read_gitfile_gently(gitdir);
|
||||||
|
if (tmp) {
|
||||||
|
free(gitdir);
|
||||||
|
len = strlen(tmp);
|
||||||
|
gitdir = xmalloc(len + MAXREFLEN + 3);
|
||||||
|
memcpy(gitdir, tmp, len);
|
||||||
|
}
|
||||||
|
gitdir[len] = '/';
|
||||||
|
gitdir[++len] = '\0';
|
||||||
|
retval = resolve_gitlink_ref_recursive(gitdir, len, refname, result, 0);
|
||||||
free(gitdir);
|
free(gitdir);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
47
setup.c
47
setup.c
@ -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)
|
|||||||
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)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* 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)
|
|||||||
*/
|
*/
|
||||||
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(".")) {
|
||||||
|
103
t/t0002-gitfile.sh
Executable file
103
t/t0002-gitfile.sh
Executable file
@ -0,0 +1,103 @@
|
|||||||
|
#!/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
|
Loading…
Reference in New Issue
Block a user