summaryrefslogtreecommitdiff
path: root/path.c
diff options
context:
space:
mode:
authorJunio C Hamano <gitster@pobox.com>2013-10-28 10:42:29 -0700
committerJunio C Hamano <gitster@pobox.com>2013-10-28 10:42:30 -0700
commite22c1c7f19914aa0dc1b6fe65bbfafed265d6e7f (patch)
treecc9fe2c10ec884cf474443bca6ac511065c95432 /path.c
parent3d092bfc6f2d9a998967979f926c661e9762601c (diff)
parent41894ae3a315f75ebc924881c6ce9a69d70ce9c0 (diff)
downloadgit-e22c1c7f19914aa0dc1b6fe65bbfafed265d6e7f.tar.gz
Merge branch 'jx/relative-path-regression-fix'
* jx/relative-path-regression-fix: Use simpler relative_path when set_git_dir relative_path should honor dos-drive-prefix test: use unambigous leading path (/foo) for MSYS
Diffstat (limited to 'path.c')
-rw-r--r--path.c65
1 files changed, 65 insertions, 0 deletions
diff --git a/path.c b/path.c
index 9fd28bcd08..24594c4112 100644
--- a/path.c
+++ b/path.c
@@ -434,6 +434,16 @@ int adjust_shared_perm(const char *path)
return 0;
}
+static int have_same_root(const char *path1, const char *path2)
+{
+ int is_abs1, is_abs2;
+
+ is_abs1 = is_absolute_path(path1);
+ is_abs2 = is_absolute_path(path2);
+ return (is_abs1 && is_abs2 && tolower(path1[0]) == tolower(path2[0])) ||
+ (!is_abs1 && !is_abs2);
+}
+
/*
* Give path as relative to prefix.
*
@@ -454,6 +464,16 @@ const char *relative_path(const char *in, const char *prefix,
else if (!prefix_len)
return in;
+ if (have_same_root(in, prefix)) {
+ /* bypass dos_drive, for "c:" is identical to "C:" */
+ if (has_dos_drive_prefix(in)) {
+ i = 2;
+ j = 2;
+ }
+ } else {
+ return in;
+ }
+
while (i < prefix_len && j < in_len && prefix[i] == in[j]) {
if (is_dir_sep(prefix[i])) {
while (is_dir_sep(prefix[i]))
@@ -531,6 +551,51 @@ const char *relative_path(const char *in, const char *prefix,
}
/*
+ * A simpler implementation of relative_path
+ *
+ * Get relative path by removing "prefix" from "in". This function
+ * first appears in v1.5.6-1-g044bbbc, and makes git_dir shorter
+ * to increase performance when traversing the path to work_tree.
+ */
+const char *remove_leading_path(const char *in, const char *prefix)
+{
+ static char buf[PATH_MAX + 1];
+ int i = 0, j = 0;
+
+ if (!prefix || !prefix[0])
+ return in;
+ while (prefix[i]) {
+ if (is_dir_sep(prefix[i])) {
+ if (!is_dir_sep(in[j]))
+ return in;
+ while (is_dir_sep(prefix[i]))
+ i++;
+ while (is_dir_sep(in[j]))
+ j++;
+ continue;
+ } else if (in[j] != prefix[i]) {
+ return in;
+ }
+ i++;
+ j++;
+ }
+ if (
+ /* "/foo" is a prefix of "/foo" */
+ in[j] &&
+ /* "/foo" is not a prefix of "/foobar" */
+ !is_dir_sep(prefix[i-1]) && !is_dir_sep(in[j])
+ )
+ return in;
+ while (is_dir_sep(in[j]))
+ j++;
+ if (!in[j])
+ strcpy(buf, ".");
+ else
+ strcpy(buf, in + j);
+ return buf;
+}
+
+/*
* It is okay if dst == src, but they should not overlap otherwise.
*
* Performs the following normalizations on src, storing the result in dst: