This adds a prefix string to any filename arguments encountered after it
has been specified.

Signed-off-by: John Keeping <j...@keeping.me.uk>
---
 Documentation/git-rev-parse.txt | 16 ++++++++
 builtin/rev-parse.c             | 24 ++++++++---
 t/t1513-rev-parse-prefix.sh     | 90 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 125 insertions(+), 5 deletions(-)
 create mode 100755 t/t1513-rev-parse-prefix.sh

diff --git a/Documentation/git-rev-parse.txt b/Documentation/git-rev-parse.txt
index 1f9ed6c..0ab2b77 100644
--- a/Documentation/git-rev-parse.txt
+++ b/Documentation/git-rev-parse.txt
@@ -59,6 +59,22 @@ OPTIONS
        If there is no parameter given by the user, use `<arg>`
        instead.
 
+--prefix <arg>::
+       Behave as if 'git rev-parse' was invoked from the `<arg>`
+       subdirectory of the working tree.  Any relative filenames are
+       resolved as if they are prefixed by `<arg>` and will be printed
+       in that form.
++
+This can be used to convert arguments to a command run in a subdirectory
+so that they can still be used after moving to the top-level of the
+repository.  For example:
++
+----
+prefix=$(git rev-parse --show-prefix)
+cd "$(git rev-parse --show-toplevel)"
+eval "set -- $(git rev-parse --sq --prefix "$prefix" "$@")"
+----
+
 --verify::
        Verify that exactly one parameter is provided, and that it
        can be turned into a raw 20-byte SHA-1 that can be used to
diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c
index f267a1d..de894c7 100644
--- a/builtin/rev-parse.c
+++ b/builtin/rev-parse.c
@@ -212,11 +212,17 @@ static void show_datestring(const char *flag, const char 
*datestr)
        show(buffer);
 }
 
-static int show_file(const char *arg)
+static int show_file(const char *arg, int output_prefix)
 {
        show_default();
        if ((filter & (DO_NONFLAGS|DO_NOREV)) == (DO_NONFLAGS|DO_NOREV)) {
-               show(arg);
+               if (output_prefix) {
+                       const char *prefix = startup_info->prefix;
+                       show(prefix_filename(prefix,
+                                            prefix ? strlen(prefix) : 0,
+                                            arg));
+               } else
+                       show(arg);
                return 1;
        }
        return 0;
@@ -470,6 +476,7 @@ N_("git rev-parse --parseopt [options] -- [<args>...]\n"
 int cmd_rev_parse(int argc, const char **argv, const char *prefix)
 {
        int i, as_is = 0, verify = 0, quiet = 0, revs_count = 0, type = 0;
+       int output_prefix = 0;
        unsigned char sha1[20];
        const char *name = NULL;
 
@@ -503,7 +510,7 @@ int cmd_rev_parse(int argc, const char **argv, const char 
*prefix)
                const char *arg = argv[i];
 
                if (as_is) {
-                       if (show_file(arg) && as_is < 2)
+                       if (show_file(arg, output_prefix) && as_is < 2)
                                verify_filename(prefix, arg, 0);
                        continue;
                }
@@ -527,7 +534,7 @@ int cmd_rev_parse(int argc, const char **argv, const char 
*prefix)
                                as_is = 2;
                                /* Pass on the "--" if we show anything but 
files.. */
                                if (filter & (DO_FLAGS | DO_REVS))
-                                       show_file(arg);
+                                       show_file(arg, 0);
                                continue;
                        }
                        if (!strcmp(arg, "--default")) {
@@ -535,6 +542,13 @@ int cmd_rev_parse(int argc, const char **argv, const char 
*prefix)
                                i++;
                                continue;
                        }
+                       if (!strcmp(arg, "--prefix")) {
+                               prefix = argv[i+1];
+                               startup_info->prefix = prefix;
+                               output_prefix = 1;
+                               i++;
+                               continue;
+                       }
                        if (!strcmp(arg, "--revs-only")) {
                                filter &= ~DO_NOREV;
                                continue;
@@ -754,7 +768,7 @@ int cmd_rev_parse(int argc, const char **argv, const char 
*prefix)
                if (verify)
                        die_no_single_rev(quiet);
                as_is = 1;
-               if (!show_file(arg))
+               if (!show_file(arg, output_prefix))
                        continue;
                verify_filename(prefix, arg, 1);
        }
diff --git a/t/t1513-rev-parse-prefix.sh b/t/t1513-rev-parse-prefix.sh
new file mode 100755
index 0000000..5ef48d2
--- /dev/null
+++ b/t/t1513-rev-parse-prefix.sh
@@ -0,0 +1,90 @@
+#!/bin/sh
+
+test_description='Tests for rev-parse --prefix'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+       mkdir -p sub1/sub2 &&
+       echo top >top &&
+       echo file1 >sub1/file1 &&
+       echo file2 >sub1/sub2/file2 &&
+       git add top sub1/file1 sub1/sub2/file2 &&
+       git commit -m commit
+'
+
+test_expect_success 'empty prefix -- file' '
+       git rev-parse --prefix "" -- top sub1/file1 >actual &&
+       cat <<-EOF >expected &&
+       --
+       top
+       sub1/file1
+       EOF
+       test_cmp expected actual
+'
+
+test_expect_success 'valid prefix -- file' '
+       git rev-parse --prefix sub1/ -- file1 sub2/file2 >actual &&
+       cat <<-EOF >expected &&
+       --
+       sub1/file1
+       sub1/sub2/file2
+       EOF
+       test_cmp expected actual
+'
+
+test_expect_success 'valid prefix -- ../file' '
+       git rev-parse --prefix sub1/ -- ../top sub2/file2 >actual &&
+       cat <<-EOF >expected &&
+       --
+       sub1/../top
+       sub1/sub2/file2
+       EOF
+       test_cmp expected actual
+'
+
+test_expect_success 'empty prefix HEAD:./path' '
+       git rev-parse --prefix "" HEAD:./top >actual &&
+       git rev-parse HEAD:top >expected &&
+       test_cmp expected actual
+'
+
+test_expect_success 'valid prefix HEAD:./path' '
+       git rev-parse --prefix sub1/ HEAD:./file1 >actual &&
+       git rev-parse HEAD:sub1/file1 >expected &&
+       test_cmp expected actual
+'
+
+test_expect_success 'valid prefix HEAD:../path' '
+       git rev-parse --prefix sub1/ HEAD:../top >actual &&
+       git rev-parse HEAD:top >expected &&
+       test_cmp expected actual
+'
+
+test_expect_success 'disambiguate path with valid prefix' '
+       git rev-parse --prefix sub1/ file1 >actual &&
+       cat <<-EOF >expected &&
+       sub1/file1
+       EOF
+       test_cmp expected actual
+'
+
+test_expect_success 'file and refs with prefix' '
+       git rev-parse --prefix sub1/ master file1 >actual &&
+       cat <<-EOF >expected &&
+       $(git rev-parse master)
+       sub1/file1
+       EOF
+       test_cmp expected actual
+'
+
+test_expect_success 'two-levels deep' '
+       git rev-parse --prefix sub1/sub2/ -- file2 >actual &&
+       cat <<-EOF >expected &&
+       --
+       sub1/sub2/file2
+       EOF
+       test_cmp expected actual
+'
+
+test_done
-- 
1.8.2.694.ga76e9c3.dirty

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to