From: Chris Packham <judge.packham@gmail.com>
To: git@vger.kernel.org
Cc: Jens.Lehmann@web.de, pclouds@gmail.com, gitster@pobox.com
Subject: [RFC/PATCHv2 1/5] worktree: provide better prefix to go back to original cwd
Date: Fri, 15 Oct 2010 16:26:40 -0700 [thread overview]
Message-ID: <1287185204-843-2-git-send-email-judge.packham@gmail.com> (raw)
In-Reply-To: <1287185204-843-1-git-send-email-judge.packham@gmail.com>
From: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
When both GIT_DIR and GIT_WORK_TREE are set, if cwd is outside worktree,
prefix (the one passed to every builtin commands) will be set to NULL,
which means "user stays at worktree topdir".
As a consequence, command line arguments are supposed to be relative
to worktree topdir, not current working directory. Not very intuitive.
Moreover, output from such situation is (again) relative to worktree
topdir. Users are expected to understand that.
This patch allows builtin commands access to original cwd even if it's
outside worktree, via cwd_to_worktree and worktree_to_cwd fields. As
the name implies, if you stay at original cwd, "cd $(cwd_to_worktree)"
would take you to worktree topdir and vice versa.
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
builtin/rev-parse.c | 10 ++++
cache.h | 2 +
setup.c | 108 ++++++++++++++++++++++++++++++++++++++++++--
t/t1510-worktree-prefix.sh | 52 +++++++++++++++++++++
4 files changed, 168 insertions(+), 4 deletions(-)
create mode 100755 t/t1510-worktree-prefix.sh
diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c
index a5a1c86..525610e 100644
--- a/builtin/rev-parse.c
+++ b/builtin/rev-parse.c
@@ -623,6 +623,16 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
puts(prefix);
continue;
}
+ if (!strcmp(arg, "--cwd-to-worktree")) {
+ if (startup_info->cwd_to_worktree)
+ puts(startup_info->cwd_to_worktree);
+ continue;
+ }
+ if (!strcmp(arg, "--worktree-to-cwd")) {
+ if (startup_info->worktree_to_cwd)
+ puts(startup_info->worktree_to_cwd);
+ continue;
+ }
if (!strcmp(arg, "--show-cdup")) {
const char *pfx = prefix;
if (!is_inside_work_tree()) {
diff --git a/cache.h b/cache.h
index 33decd9..c001272 100644
--- a/cache.h
+++ b/cache.h
@@ -1117,6 +1117,8 @@ const char *split_cmdline_strerror(int cmdline_errno);
/* git.c */
struct startup_info {
int have_repository;
+ char *cwd_to_worktree; /* chdir("this"); from cwd would return to worktree */
+ char *worktree_to_cwd; /* chdir("this"); from worktree would return to cwd */
};
extern struct startup_info *startup_info;
diff --git a/setup.c b/setup.c
index a3b76de..413703b 100644
--- a/setup.c
+++ b/setup.c
@@ -313,10 +313,109 @@ const char *read_gitfile_gently(const char *path)
return path;
}
+/*
+ * Given "foo/bar" and "hey/hello/world", return "../../hey/hello/world/"
+ * Either path1 or path2 can be NULL
+ */
+static char *make_path_to_path(const char *path1, const char *path2)
+{
+ int nr_back = 0;
+ int i, pathlen = path2 ? strlen(path2) : 0;
+ char *buf, *p;
+
+ if (path1 && *path1) {
+ nr_back = 1;
+ while (*path1) {
+ if (*path1 == '/')
+ nr_back++;
+ path1++;
+ }
+ }
+
+ if (!nr_back && !pathlen)
+ return NULL;
+
+ p = buf = xmalloc(3*nr_back + pathlen + 2); /* "../"^nr_back + path2 + '/' + NULL */
+ for (i = 0; i < nr_back; i++) {
+ memcpy(p, "../", 3);
+ p += 3;
+ }
+ if (pathlen) {
+ memcpy(p, path2, pathlen);
+ p += pathlen;
+ *p++ = '/';
+ }
+ *p = '\0';
+ return buf;
+}
+
+/*
+ * Return a prefix if cwd inside worktree, or NULL otherwise.
+ * Also fill startup_info struct.
+ */
+static const char *setup_prefix(const char *cwd)
+{
+ const char *worktree = get_git_work_tree();
+ int len = 0, cwd_len = strlen(cwd), worktree_len = strlen(worktree);
+
+ while (worktree[len] && worktree[len] == cwd[len])
+ len++;
+
+ if (!worktree[len] && !cwd[len]) {
+ if (startup_info) {
+ startup_info->cwd_to_worktree = NULL;
+ startup_info->worktree_to_cwd = NULL;
+ }
+ return NULL;
+ }
+ /* get /foo/, not /foo/baa if /foo/baa1 and /foo/baa2 are given */
+ else if (worktree[len] && cwd[len]) {
+ while (len && worktree[len] != '/')
+ len--;
+ len++;
+ }
+ else {
+ if (worktree[len]) {
+ if (worktree[len] != '/') {
+ while (len && worktree[len] != '/')
+ len--;
+ }
+ }
+ else {
+ if (cwd[len] != '/') {
+ while (len && cwd[len] != '/')
+ len--;
+ }
+ }
+ len++; /* must be a slash here, skip it */
+ }
+
+ if (len < cwd_len && len < worktree_len) {
+ if (startup_info) {
+ startup_info->cwd_to_worktree = make_path_to_path(cwd+len, worktree+len);
+ startup_info->worktree_to_cwd = make_path_to_path(worktree+len, cwd+len);
+ }
+ return NULL;
+ }
+
+ if (startup_info) {
+ if (len < cwd_len) { /* cwd inside worktree */
+ startup_info->cwd_to_worktree = make_path_to_path(cwd+len, NULL);
+ startup_info->worktree_to_cwd = make_path_to_path(NULL, cwd+len);
+ }
+ else {
+ startup_info->cwd_to_worktree = make_path_to_path(NULL, worktree+len);
+ startup_info->worktree_to_cwd = make_path_to_path(worktree+len, NULL);
+ }
+ }
+
+ return len < cwd_len ? cwd+len : NULL;
+}
+
static const char *setup_explicit_git_dir(const char *gitdirenv,
const char *work_tree_env, int *nongit_ok)
{
- static char buffer[1024 + 1];
+ static char buffer[PATH_MAX];
const char *retval;
if (PATH_MAX - 40 < strlen(gitdirenv))
@@ -337,9 +436,10 @@ static const char *setup_explicit_git_dir(const char *gitdirenv,
}
if (check_repository_format_gently(nongit_ok))
return NULL;
- retval = get_relative_cwd(buffer, sizeof(buffer) - 1,
- get_git_work_tree());
- if (!retval || !*retval)
+ if (!getcwd(buffer, sizeof(buffer)))
+ die_errno("can't find the current directory");
+ retval = setup_prefix(buffer);
+ if (!retval)
return NULL;
set_git_dir(make_absolute_path(gitdirenv));
if (chdir(work_tree_env) < 0)
diff --git a/t/t1510-worktree-prefix.sh b/t/t1510-worktree-prefix.sh
new file mode 100755
index 0000000..3839493
--- /dev/null
+++ b/t/t1510-worktree-prefix.sh
@@ -0,0 +1,52 @@
+#!/bin/sh
+
+test_description='test rev-parse --cwd-to-worktree and --worktree-to-cwd'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+ mkdir foo bar &&
+ mv .git foo &&
+ mkdir foo/bar &&
+ GIT_DIR=`pwd`/foo/.git &&
+ GIT_WORK_TREE=`pwd`/foo &&
+ export GIT_DIR GIT_WORK_TREE
+'
+
+test_expect_success 'at root' '
+ (
+ cd foo &&
+ git rev-parse --cwd-to-worktree --worktree-to-cwd >result &&
+ : >expected &&
+ test_cmp expected result
+ )
+'
+
+test_expect_success 'cwd inside worktree' '
+ (
+ cd foo/bar &&
+ git rev-parse --cwd-to-worktree --worktree-to-cwd >result &&
+ echo ../ >expected &&
+ echo bar/ >>expected &&
+ test_cmp expected result
+ )
+'
+
+test_expect_success 'cwd outside worktree' '
+ git rev-parse --cwd-to-worktree --worktree-to-cwd >result &&
+ echo foo/ >expected &&
+ echo ../ >>expected &&
+ test_cmp expected result
+'
+
+test_expect_success 'cwd outside worktree (2)' '
+ (
+ cd bar &&
+ git rev-parse --cwd-to-worktree --worktree-to-cwd >result &&
+ echo ../foo/ >expected &&
+ echo ../bar/ >>expected &&
+ test_cmp expected result
+ )
+'
+
+test_done
--
1.7.3.1
next prev parent reply other threads:[~2010-10-15 23:27 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-10-15 23:26 [RGC/PATCHv2] grep: submodule support Chris Packham
2010-10-15 23:26 ` Chris Packham [this message]
2010-10-16 18:42 ` [RFC/PATCHv2 1/5] worktree: provide better prefix to go back to original cwd Jonathan Nieder
2010-10-17 2:48 ` Chris Packham
2010-10-17 10:01 ` Nguyen Thai Ngoc Duy
2010-10-18 2:05 ` Chris Packham
2010-10-15 23:26 ` [RFC/PATCHv2 2/5] grep: output the path from cwd to worktree Chris Packham
2010-10-15 23:26 ` [RFC/PATCHv2 3/5] grep_cache: check pathspec first Chris Packham
2010-10-15 23:26 ` [RFC/PATCHv2 4/5] add test for git grep --recursive Chris Packham
2010-10-15 23:26 ` [RFC/PATCHv2 5/5] grep: add support for grepping in submodules Chris Packham
2010-10-17 10:28 ` Nguyen Thai Ngoc Duy
2010-10-18 2:01 ` Chris Packham
2010-10-18 3:37 ` Nguyen Thai Ngoc Duy
2010-10-16 15:54 ` [RGC/PATCHv2] grep: submodule support Jens Lehmann
2010-10-17 2:13 ` Chris Packham
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1287185204-843-2-git-send-email-judge.packham@gmail.com \
--to=judge.packham@gmail.com \
--cc=Jens.Lehmann@web.de \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
--cc=pclouds@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).