make_absolute_path("foo") at root returns "//foo". This patch makes it
return "/foo" correctly.
Signed-off-by: Nguyễn Thái Ngọc Duy <redacted>
---
.. so that "git init" will show "initialized empty Git in /.git"
abspath.c | 5 +++--
1 files changed, 3 insertions(+), 2 deletions(-)
@@ -647,7 +647,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)}if(!getcwd(cwd,PATH_MAX))die_errno("unable to get current working directory");-printf("%s/.git\n",cwd);+printf("%s%s.git\n",cwd,*cwd=='/'&&cwd[1]=='\0'?"":"/");continue;}if(!strcmp(arg,"--is-inside-git-dir")){
This kind of test requires a throw-away root filesystem so that it can
play on. If you have such a system, go ahead, "chmod 777 /" and run
this test manually ("make test" with root permission won't work).
If you don't but have Linux, static linked busybox, rsync and root
permission, then run "t/t1509/prepare-chroot.sh /tmp/test". You will be
instructed to create /dev/null and given a command to chroot into.
Within chroot, you will be placed at directory "t" of Git source code
Feel free to burn your chroot.
Signed-off-by: Nguyễn Thái Ngọc Duy <redacted>
---
May have problem committing. Anyway I don't need commit now.
t/t1509-root-worktree.sh | 244 +++++++++++++++++++++++++++++++++++++++++++++
t/t1509/excludes | 14 +++
t/t1509/prepare-chroot.sh | 38 +++++++
3 files changed, 296 insertions(+), 0 deletions(-)
create mode 100755 t/t1509-root-worktree.sh
create mode 100644 t/t1509/excludes
create mode 100755 t/t1509/prepare-chroot.sh
@@ -0,0 +1,244 @@+#!/bin/sh++test_description='TestGitwhengitrepositoryislocatedatroot++Thistestrequireswriteaccessinroot.Donotbotherifyoudonot+haveathrowawaychrootorVM.++Scriptt1509/prepare-chroot.shmayhelpyousetupchroot,thenyou+canchrootinandexecutethistestfromthere.+'++../test-lib.sh++test_cmp_val(){+echo"$1">expected+echo"$2">result+test_cmpexpectedresult+}++test_vars(){+test_expect_success"$1: gitdir"'+test_cmp_val"'"$2"'""$(gitrev-parse--git-dir)"+'++test_expect_success"$1: worktree"'+test_cmp_val"'"$3"'""$(gitrev-parse--show-toplevel)"+'++test_expect_success"$1: prefix"'+test_cmp_val"'"$4"'""$(gitrev-parse--show-prefix)"+'+}++test_foobar_root(){+test_expect_success'add relative''+test-z"$(cd/&&gitls-files)"&&+gitaddfoo/foome&&+gitaddfoo/bar/barme&&+gitaddme&&+(cd/&&gitls-files--stage)>result&&+test_cmp/ls.expectedresult&&+rm"$(gitrev-parse--git-dir)/index"+'++test_expect_success'add absolute''+test-z"$(cd/&&gitls-files)"&&+gitadd/foo/foome&&+gitadd/foo/bar/barme&&+gitadd/me&&+(cd/&&gitls-files--stage)>result&&+test_cmp/ls.expectedresult&&+rm"$(gitrev-parse--git-dir)/index"+'++}++test_foobar_foo(){+test_expect_success'add relative''+test-z"$(cd/&&gitls-files)"&&+gitaddfoome&&+gitaddbar/barme&&+gitadd../me&&+(cd/&&gitls-files--stage)>result&&+test_cmp/ls.expectedresult&&+rm"$(gitrev-parse--git-dir)/index"+'++test_expect_success'add absolute''+test-z"$(cd/&&gitls-files)"&&+gitadd/foo/foome&&+gitadd/foo/bar/barme&&+gitadd/me&&+(cd/&&gitls-files--stage)>result&&+test_cmp/ls.expectedresult&&+rm"$(gitrev-parse--git-dir)/index"+'+}++test_foobar_foobar(){+test_expect_success'add relative''+test-z"$(cd/&&gitls-files)"&&+gitadd../foome&&+gitaddbarme&&+gitadd../../me&&+(cd/&&gitls-files--stage)>result&&+test_cmp/ls.expectedresult&&+rm"$(gitrev-parse--git-dir)/index"+'++test_expect_success'add absolute''+test-z"$(cd/&&gitls-files)"&&+gitadd/foo/foome&&+gitadd/foo/bar/barme&&+gitadd/me&&+(cd/&&gitls-files--stage)>result&&+test_cmp/ls.expectedresult&&+rm"$(gitrev-parse--git-dir)/index"+'+}++if!test_have_prereqPOSIXPERM||![-w/];then+say"Dangerous test skipped. Read this test if you want to execute it"+test_done+fi++if["$IKNOWWHATIAMDOING"!="YES"];then+say"You must set env var IKNOWWHATIAMDOING=YES in order to run this test"+test_done+fi++ONE_SHA1=d00491fd7e5bb6fa28c517a0bb32b8b506539d4d++test_expect_success'setup''+rm-rf/foo+mkdir/foo&&+mkdir/foo/bar&&+echo1>/foo/foome&&+echo1>/foo/bar/barme&&+echo1>/me+'++say"GIT_DIR absolute, GIT_WORK_TREE set"++test_expect_success'go to /''cd /'++cat>ls.expected<<EOF+100644$ONE_SHA10foo/bar/barme+100644$ONE_SHA10foo/foome+100644$ONE_SHA10me+EOF++exportGIT_DIR="$TRASH_DIRECTORY/.git"+exportGIT_WORK_TREE=/++test_vars'abs gitdir, root'"$GIT_DIR""/"""+test_foobar_root++test_expect_success'go to /foo''cd /foo'++test_vars'abs gitdir, foo'"$GIT_DIR""/""foo/"+test_foobar_foo++test_expect_success'go to /foo/bar''cd /foo/bar'++test_vars'abs gitdir, foo/bar'"$GIT_DIR""/""foo/bar/"+test_foobar_foobar++say"GIT_DIR relative, GIT_WORK_TREE set"++test_expect_success'go to /''cd /'++exportGIT_DIR="$(echo$TRASH_DIRECTORY|sed's,^/,,')/.git"+exportGIT_WORK_TREE=/++test_vars'rel gitdir, root'"$GIT_DIR""/"""+test_foobar_root++test_expect_success'go to /foo''cd /foo'++exportGIT_DIR="../$TRASH_DIRECTORY/.git"+exportGIT_WORK_TREE=/++test_vars'rel gitdir, foo'"$TRASH_DIRECTORY/.git""/""foo/"+test_foobar_foo++test_expect_success'go to /foo/bar''cd /foo/bar'++exportGIT_DIR="../../$TRASH_DIRECTORY/.git"+exportGIT_WORK_TREE=/++test_vars'rel gitdir, foo/bar'"$TRASH_DIRECTORY/.git""/""foo/bar/"+test_foobar_foobar++say"GIT_DIR relative, GIT_WORK_TREE relative"++test_expect_success'go to /''cd /'++exportGIT_DIR="$(echo$TRASH_DIRECTORY|sed's,^/,,')/.git"+exportGIT_WORK_TREE=.++test_vars'rel gitdir, root'"$GIT_DIR""/"""+test_foobar_root++test_expect_success'go to /''cd /foo'++exportGIT_DIR="../$TRASH_DIRECTORY/.git"+exportGIT_WORK_TREE=..++test_vars'rel gitdir, foo'"$TRASH_DIRECTORY/.git""/""foo/"+test_foobar_foo++test_expect_success'go to /foo/bar''cd /foo/bar'++exportGIT_DIR="../../$TRASH_DIRECTORY/.git"+exportGIT_WORK_TREE=../..++test_vars'rel gitdir, foo/bar'"$TRASH_DIRECTORY/.git""/""foo/bar/"+test_foobar_foobar++say".git at root"++unsetGIT_DIR+unsetGIT_WORK_TREE++test_expect_success'go to /''cd /'+test_expect_success'setup''+rm-rf/.git+echo"Initialized empty Git repository in /.git/">expected&&+gitinit>result&&+test_cmpexpectedresult+'++test_vars'auto gitdir, root'".git""/"""+test_foobar_root++test_expect_success'go to /foo''cd /foo'+test_vars'auto gitdir, foo'"/.git""/""foo/"+test_foobar_foo++test_expect_success'go to /foo/bar''cd /foo/bar'+test_vars'auto gitdir, foo/bar'"/.git""/""foo/bar/"+test_foobar_foobar++test_expect_success'cleanup''rm -rf /.git'++say"auto bare gitdir"++# DESTROYYYYY!!!!!+test_expect_failure'setup''+rm-rf/refs/objects/info/hooks+rm/*+cd/&&+echo"Initialized empty Git repository in /">expected&&+gitinit--bare>result&&+test_cmpexpectedresult+'++test_vars'auto gitdir, root'"."""""++test_expect_success'go to /foo''cd /foo'++test_vars'auto gitdir, root'"/"""""++test_done
@@ -0,0 +1,38 @@+#!/bin/sh++die(){+echo>&2"$@"+exit1+}++xmkdir(){+while[-n"$1"];do+[-d"$1"]||mkdir"$1"||die"Unable to mkdir $1"+shift+done+}++R="$1"++[-n"$R"]||die"Usage: prepare-chroot.sh <root>"+[-xgit]||die"This script needs to be executed at git source code's top directory"+[-x/bin/busybox]||die"You need busybox"++xmkdir"$R""$R/bin""$R/etc""$R/lib""$R/dev"+[-c"$R/dev/null"]||die"/dev/null is missing. Do mknod $R/dev/null c 1 3 && chmod 666 $R/dev/null"+echo"root:x:0:0:root:/:/bin/sh">"$R/etc/passwd"+echo"$(id-nu):x:$(id-u):$(id-g)::$(pwd)/t:/bin/sh">>"$R/etc/passwd"+echo"root::0:root">"$R/etc/group"+echo"$(id-ng)::$(id-g):$(id-nu)">>"$R/etc/group"++[-x"$R/bin/busybox"]||cp/bin/busybox"$R/bin/busybox"+[-x"$R/bin/sh"]||ln-s/bin/busybox"$R/bin/sh"+[-x"$R/bin/su"]||ln-s/bin/busybox"$R/bin/su"++mkdir-p"$R$(pwd)"+rsync--exclude-fromt/t1509/excludes-Ha."$R$(pwd)"+lddgit|grep'=> /'|sed's,.* => *\([^ ]*\) .*,\1,'|whilereadi;do+mkdir-p"$R$(dirname$i)"+cp"$i""$R/$i"+done+echo"Execute this in root: 'chroot $R /bin/su - $(id-nu)'"
Git should work regardless where the working directory is located,
even at root. This patch fixes two places where it assumes working
directory always have parent directory.
In setup_git_directory_gently(), when Git goes up to root and finds
.git there, it happily sets worktree to "" instead of "/".
In prefix_path(), loosen the outside repo check a little bit. Usually
when a path XXX is inside worktree /foo, it must be either "/foo", or
"/foo/...". When worktree is simply "/", we can safely ignore the
check: we have a slash at the beginning already.
Not related to worktree, but also set gitdir correctly if a bare repo
is placed (insanely?) at root.
Thanks João Carlos Mendes Luís for pointing out this problem.
Signed-off-by: Nguyễn Thái Ngọc Duy <redacted>
---
I said I would have code change for DOS drive too. But I take it back.
Supporting GIT_DIR=C:\.git might be easy, GIT_DIR=C:.git is not.
setup.c | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)
From: Johannes Sixt <hidden> Date: 2016-06-15 22:48:12
On Dienstag, 9. Februar 2010, Nguyễn Thái Ngọc Duy wrote:
quoted hunk
@@ -54,8 +54,9 @@ const char *make_absolute_path(const char *path) if (len + strlen(last_elem) + 2 > PATH_MAX) die ("Too long path name: '%s/%s'", buf, last_elem);- buf[len] = '/';- strcpy(buf + len + 1, last_elem);+ if (*buf != '/' || buf[1] != '\0')+ buf[len++] = '/';
Huh? You are adding a slash unless buf is exactly "/". That is, when buf
is "/foo/" you still add a slash? That's not exactly avoiding redundancy.
(Disclaimer: I didn't analyze the rest of the function whether my claim is
true.)
char *prefix) }
if (!getcwd(cwd, PATH_MAX))
die_errno("unable to get current working directory");
- printf("%s/.git\n", cwd);
+ printf("%s%s.git\n", cwd, *cwd == '/' && cwd[1] == '\0' ? "" : "/");
On Windows, when you are in the root of a drive, then cwd is "C:/", i.e. there
is a trailing slash just as in the Unix root directory. But you do not take
care of this situation. That is, you would print "C://".
How about:
static inline int is_root_path(const char *path)
{
if (has_dos_drive_prefix(path))
path += 2;
while (is_dir_sep(*path))
path++;
return !*path;
}
and use it though-out your series?
(Simplify the loop to 'return is_dir_sep(*path) && !path[1];' if you can
assume that paths are nomalized.)
-- Hannes
From: Johannes Sixt <hidden> Date: 2016-06-15 22:48:12
On Dienstag, 9. Februar 2010, Nguyễn Thái Ngọc Duy wrote:
I said I would have code change for DOS drive too. But I take it back.
Supporting GIT_DIR=C:\.git might be easy, GIT_DIR=C:.git is not.
One does not set GIT_DIR=C:.git; it would be insane because it means ".git in
an unpredictable directory somewhere on drive C". It would be great to
support GIT_DIR=C:/.git
-- Hannes
From: João Carlos Mendes Luís <hidden> Date: 2016-06-15 22:48:13
Nguyễn Thái Ngọc Duy wrote:
This kind of test requires a throw-away root filesystem so that it can
play on. If you have such a system, go ahead, "chmod 777 /" and run
this test manually ("make test" with root permission won't work).
I've seen you have a prepare-chroot.sh file in there. Is it working or
not? I mean, did you create a chrooted environment to test, or there
was any problem with that?
if (len + strlen(last_elem) + 2 > PATH_MAX)
die ("Too long path name: '%s/%s'",
buf, last_elem);
- buf[len] = '/';
- strcpy(buf + len + 1, last_elem);
+ if (*buf != '/' || buf[1] != '\0')
+ buf[len++] = '/';
Huh? You are adding a slash unless buf is exactly "/". That is, when buf
is "/foo/" you still add a slash? That's not exactly avoiding redundancy.
(Disclaimer: I didn't analyze the rest of the function whether my claim is
true.)
buf is set by getcwd() so it should never be "/foo/" but doing
if (len && buf[len-1] != '/') buf[len++] = '/';
is probably clearer (and works on Windows too).
--
Duy
This kind of test requires a throw-away root filesystem so that it can
play on. If you have such a system, go ahead, "chmod 777 /" and run
this test manually ("make test" with root permission won't work).
I've seen you have a prepare-chroot.sh file in there. Is it working or not?
I mean, did you create a chrooted environment to test, or there was any
problem with that?
That means if you already have a chroot environment, use it. Or you
can use prepare-chroot.sh to create a new chroot environment. Yes I
used prepare-chroot.sh for my testing.
--
Duy
char *prefix) }
if (!getcwd(cwd, PATH_MAX))
die_errno("unable to get current working directory");
- printf("%s/.git\n", cwd);
+ printf("%s%s.git\n", cwd, *cwd == '/' && cwd[1] == '\0' ? "" : "/");
On Windows, when you are in the root of a drive, then cwd is "C:/", i.e. there
is a trailing slash just as in the Unix root directory. But you do not take
care of this situation. That is, you would print "C://".
How about:
static inline int is_root_path(const char *path)
{
if (has_dos_drive_prefix(path))
path += 2;
while (is_dir_sep(*path))
path++;
return !*path;
}
and use it though-out your series?
(Simplify the loop to 'return is_dir_sep(*path) && !path[1];' if you can
assume that paths are nomalized.)
And return the length of root_path, so that I can use this function in
in setup_git_directory_gently() too. Yeah.
--
Duy
On Dienstag, 9. Februar 2010, Nguyễn Thái Ngọc Duy wrote:
> I said I would have code change for DOS drive too. But I take it back.
> Supporting GIT_DIR=C:\.git might be easy, GIT_DIR=C:.git is not.
One does not set GIT_DIR=C:.git; it would be insane because it means ".git in
an unpredictable directory somewhere on drive C". It would be great to
support GIT_DIR=C:/.git
A bit off topic, but make_relative_path() may need more care for the
Windows port. I thought of making relative path between C:/foo and
D:/bar but it should work well for that case. //machine/share1/foo and
//machine/share2/bar may fail though.
--
Duy