From: "Nguyễn Thái Ngọc Duy" <pclouds@gmail.com>
To: git@vger.kernel.org, Junio C Hamano <gitster@pobox.com>,
srabbelier@gmail.com, tfransosi@gmail.com,
Jonathan Niedier <jrnieder@gmail.com>,
Matthieu.Moy@grenoble-inp.fr
Cc: "Nguyễn Thái Ngọc Duy" <pclouds@gmail.com>
Subject: [PATCH] get_sha1: support relative path ":path" syntax
Date: Sun, 28 Nov 2010 10:37:32 +0700 [thread overview]
Message-ID: <1290915452-6339-1-git-send-email-pclouds@gmail.com> (raw)
In-Reply-To: <7v4obimr5l.fsf@alter.siamese.dyndns.org>
Currently :path and ref:path can be used to refer to a specific object
in index or ref respectively. "path" component is absolute path. This
patch allows "path" to be written as "./path" or "../path", which is
relative to user's original cwd.
This does not work in commands for which startup_info is NULL
(i.e. non-builtin ones, it seems none of them needs this anyway).
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
Updated the message when startup_info == NULL
Documentation/revisions.txt | 4 ++
sha1_name.c | 37 ++++++++++++++++++++++--
t/t1506-rev-parse-diagnosis.sh | 62 ++++++++++++++++++++++++++++++++++++++++
3 files changed, 100 insertions(+), 3 deletions(-)
diff --git a/Documentation/revisions.txt b/Documentation/revisions.txt
index 3d4b79c..8b519d7 100644
--- a/Documentation/revisions.txt
+++ b/Documentation/revisions.txt
@@ -121,6 +121,10 @@ the `$GIT_DIR/refs` directory or from the `$GIT_DIR/packed-refs` file.
':path' (with an empty part before the colon, e.g. `:README`)
is a special case of the syntax described next: content
recorded in the index at the given path.
+ A path starting with './' or '../' is relative to current working directory.
+ The given path will be converted to be relative to working tree's root directory.
+ This is most useful to address a blob or tree from a commit or tree that has
+ the same tree structure with the working tree.
* A colon, optionally followed by a stage number (0 to 3) and a
colon, followed by a path (e.g. `:0:README`); this names a blob object in the
diff --git a/sha1_name.c b/sha1_name.c
index 484081d..f918faf 100644
--- a/sha1_name.c
+++ b/sha1_name.c
@@ -1046,6 +1046,23 @@ int get_sha1_with_mode_1(const char *name, unsigned char *sha1, unsigned *mode,
return ret;
}
+static char *resolve_relative_path(const char *rel)
+{
+ if (prefixcmp(rel, "./") && prefixcmp(rel, "../"))
+ return NULL;
+
+ if (!startup_info)
+ die("BUG: startup_info struct is not initialized.");
+
+ if (!is_inside_work_tree())
+ die("relative path syntax can't be used outside working tree.");
+
+ /* die() inside prefix_path() if resolved path is outside worktree */
+ return prefix_path(startup_info->prefix,
+ startup_info->prefix ? strlen(startup_info->prefix) : 0,
+ rel);
+}
+
int get_sha1_with_context_1(const char *name, unsigned char *sha1,
struct object_context *oc,
int gently, const char *prefix)
@@ -1060,25 +1077,31 @@ int get_sha1_with_context_1(const char *name, unsigned char *sha1,
if (!ret)
return ret;
/* sha1:path --> object name of path in ent sha1
- * :path -> object name of path in index
+ * :path -> object name of absolute path in index
+ * :./path -> object name of path relative to cwd in index
* :[0-3]:path -> object name of path in index at stage
* :/foo -> recent commit matching foo
*/
if (name[0] == ':') {
int stage = 0;
struct cache_entry *ce;
+ char *new_path = NULL;
int pos;
if (namelen > 2 && name[1] == '/')
return get_sha1_oneline(name + 2, sha1);
if (namelen < 3 ||
name[2] != ':' ||
- name[1] < '0' || '3' < name[1])
+ name[1] < '0' || '3' < name[1]) {
cp = name + 1;
+ new_path = resolve_relative_path(cp);
+ if (new_path)
+ cp = new_path;
+ }
else {
stage = name[1] - '0';
cp = name + 3;
}
- namelen = namelen - (cp - name);
+ namelen = strlen(cp);
strncpy(oc->path, cp,
sizeof(oc->path));
@@ -1096,12 +1119,14 @@ int get_sha1_with_context_1(const char *name, unsigned char *sha1,
break;
if (ce_stage(ce) == stage) {
hashcpy(sha1, ce->sha1);
+ free(new_path);
return 0;
}
pos++;
}
if (!gently)
diagnose_invalid_index_path(stage, prefix, cp);
+ free(new_path);
return -1;
}
for (cp = name, bracket_depth = 0; *cp; cp++) {
@@ -1122,6 +1147,11 @@ int get_sha1_with_context_1(const char *name, unsigned char *sha1,
}
if (!get_sha1_1(name, cp-name, tree_sha1)) {
const char *filename = cp+1;
+ char *new_filename = NULL;
+
+ new_filename = resolve_relative_path(filename);
+ if (new_filename)
+ filename = new_filename;
ret = get_tree_entry(tree_sha1, filename, sha1, &oc->mode);
if (!gently) {
diagnose_invalid_sha1_path(prefix, filename,
@@ -1133,6 +1163,7 @@ int get_sha1_with_context_1(const char *name, unsigned char *sha1,
sizeof(oc->path));
oc->path[sizeof(oc->path)-1] = '\0';
+ free(new_filename);
return ret;
} else {
if (!gently)
diff --git a/t/t1506-rev-parse-diagnosis.sh b/t/t1506-rev-parse-diagnosis.sh
index 0eeeb0e..f7a4076 100755
--- a/t/t1506-rev-parse-diagnosis.sh
+++ b/t/t1506-rev-parse-diagnosis.sh
@@ -31,6 +31,43 @@ test_expect_success 'correct file objects' '
test $HASH_file = $(git rev-parse :0:file.txt) )
'
+test_expect_success 'correct relative file objects (0)' '
+ git rev-parse :file.txt >expected &&
+ git rev-parse :./file.txt >result &&
+ test_cmp expected result
+'
+
+test_expect_success 'correct relative file objects (1)' '
+ git rev-parse HEAD:file.txt >expected &&
+ git rev-parse HEAD:./file.txt >result &&
+ test_cmp expected result
+'
+
+test_expect_success 'correct relative file objects (2)' '
+ (
+ cd subdir &&
+ git rev-parse HEAD:../file.txt >result &&
+ test_cmp ../expected result
+ )
+'
+
+test_expect_success 'correct relative file objects (3)' '
+ (
+ cd subdir &&
+ git rev-parse HEAD:../subdir/../file.txt >result &&
+ test_cmp ../expected result
+ )
+'
+
+test_expect_success 'correct relative file objects (4)' '
+ git rev-parse HEAD:subdir/file.txt >expected &&
+ (
+ cd subdir &&
+ git rev-parse HEAD:./file.txt >result &&
+ test_cmp ../expected result
+ )
+'
+
test_expect_success 'incorrect revision id' '
test_must_fail git rev-parse foobar:file.txt 2>error &&
grep "Invalid object name '"'"'foobar'"'"'." error &&
@@ -75,4 +112,29 @@ test_expect_success 'invalid @{n} reference' '
grep "fatal: Log for [^ ]* only has [0-9][0-9]* entries." error
'
+test_expect_success 'relative path not found' '
+ (
+ cd subdir &&
+ test_must_fail git rev-parse HEAD:./nonexistent.txt 2>error &&
+ grep subdir/nonexistent.txt error
+ )
+'
+
+test_expect_success 'relative path outside worktree' '
+ test_must_fail git rev-parse HEAD:../file.txt >output 2>error &&
+ test -z "$(cat output)" &&
+ grep "outside repository" error
+'
+
+test_expect_success 'relative path when cwd is outside worktree' '
+ test_must_fail git --git-dir=.git --work-tree=subdir rev-parse HEAD:./file.txt >output 2>error &&
+ test -z "$(cat output)" &&
+ grep "relative path syntax can.t be used outside working tree." error
+'
+
+test_expect_success 'relative path when startup_info is NULL' '
+ test_must_fail test-match-trees HEAD:./file.txt HEAD:./file.txt 2>error &&
+ grep "Relative path syntax is not supported in this command" error
+'
+
test_done
--
1.7.3.2.316.gda8b3
next prev parent reply other threads:[~2010-11-28 3:44 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-11-11 14:08 [PATCH 0/3] Support relative path in <blah>:path syntax Nguyễn Thái Ngọc Duy
2010-11-11 14:08 ` [PATCH 1/3] setup: save prefix (original cwd relative to toplevel) in startup_info Nguyễn Thái Ngọc Duy
2010-11-11 14:08 ` [PATCH 2/3] Make prefix_path() return char* without const Nguyễn Thái Ngọc Duy
2010-11-11 14:08 ` [PATCH 3/3] get_sha1: support relative path ":path" syntax Nguyễn Thái Ngọc Duy
2010-11-14 20:22 ` Thiago Farina
2010-11-15 3:56 ` [PATCH] " Nguyễn Thái Ngọc Duy
2010-11-15 14:56 ` Sverre Rabbelier
2010-11-15 17:29 ` Junio C Hamano
2010-11-15 18:59 ` Junio C Hamano
2010-11-28 3:37 ` Nguyễn Thái Ngọc Duy [this message]
2010-11-17 17:54 ` [PATCH 0/3] Support relative path in <blah>:path syntax Junio C Hamano
2010-11-18 1:47 ` Nguyen Thai Ngoc Duy
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=1290915452-6339-1-git-send-email-pclouds@gmail.com \
--to=pclouds@gmail.com \
--cc=Matthieu.Moy@grenoble-inp.fr \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
--cc=jrnieder@gmail.com \
--cc=srabbelier@gmail.com \
--cc=tfransosi@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).