Use simpler relative_path when set_git_dir

Using a relative_path as git_dir first appears in v1.5.6-1-g044bbbc. It will make git_dir shorter only if git_dir is inside work_tree, and this will increase performance. But my last refactor effort on relative_path function (commit v1.8.3-rc2-12-ge02ca72) changed that. Always use relative_path as git_dir may bring troubles like $gmane/234434. Because new relative_path is a combination of original relative_path from path.c and original path_relative from quote.c, so in order to restore the origin implementation, save the original relative_path as remove_leading_path, and call it in setup.c. Suggested-by: Karsten Blees <karsten.blees@gmail.com> Signed-off-by: Jiang Xin <worldhello.net@gmail.com> Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>

Jiang Xin committed Oct 14, 2013 at 10:29 UTC 41894ae3a315f75ebc924881c6ce9a69d70ce9c0
3 files changed +47 -4
cache.h
+1
@@ -737,6 +737,7 @@ int is_directory(const char *);
737 const char *real_path(const char *path);
738 const char *real_path_if_valid(const char *path);
739 const char *absolute_path(const char *path);
740 +const char *remove_leading_path(const char *in, const char *prefix);
741 const char *relative_path(const char *in, const char *prefix, struct strbuf *sb);
742 int normalize_path_copy(char *dst, const char *src);
743 int longest_ancestor_length(const char *path, struct string_list *prefixes);
path.c
+45
@@ -557,6 +557,51 @@ const char *relative_path(const char *in, const char *prefix,
557 return sb->buf;
558 }
559
560 +/*
561 + * A simpler implementation of relative_path
562 + *
563 + * Get relative path by removing "prefix" from "in". This function
564 + * first appears in v1.5.6-1-g044bbbc, and makes git_dir shorter
565 + * to increase performance when traversing the path to work_tree.
566 + */
567 +const char *remove_leading_path(const char *in, const char *prefix)
568 +{
569 + static char buf[PATH_MAX + 1];
570 + int i = 0, j = 0;
571 +
572 + if (!prefix || !prefix[0])
573 + return in;
574 + while (prefix[i]) {
575 + if (is_dir_sep(prefix[i])) {
576 + if (!is_dir_sep(in[j]))
577 + return in;
578 + while (is_dir_sep(prefix[i]))
579 + i++;
580 + while (is_dir_sep(in[j]))
581 + j++;
582 + continue;
583 + } else if (in[j] != prefix[i]) {
584 + return in;
585 + }
586 + i++;
587 + j++;
588 + }
589 + if (
590 + /* "/foo" is a prefix of "/foo" */
591 + in[j] &&
592 + /* "/foo" is not a prefix of "/foobar" */
593 + !is_dir_sep(prefix[i-1]) && !is_dir_sep(in[j])
594 + )
595 + return in;
596 + while (is_dir_sep(in[j]))
597 + j++;
598 + if (!in[j])
599 + strcpy(buf, ".");
600 + else
601 + strcpy(buf, in + j);
602 + return buf;
603 +}
604 +
605 /*
606 * It is okay if dst == src, but they should not overlap otherwise.
607 *
setup.c
+1 -4
@@ -360,7 +360,6 @@ int is_inside_work_tree(void)
360
361 void setup_work_tree(void)
362 {
363 - struct strbuf sb = STRBUF_INIT;
363 const char *work_tree, *git_dir;
364 static int initialized = 0;
365
@@ -380,10 +379,8 @@ void setup_work_tree(void)
379 if (getenv(GIT_WORK_TREE_ENVIRONMENT))
380 setenv(GIT_WORK_TREE_ENVIRONMENT, ".", 1);
381
383 - set_git_dir(relative_path(git_dir, work_tree, &sb));
382 + set_git_dir(remove_leading_path(git_dir, work_tree));
383 initialized = 1;
385 -
386 - strbuf_release(&sb);
384 }
385
386 static int check_repository_format_gently(const char *gitdir, int *nongit_ok)