Browse Source

rev-parse: add --prefix option

This makes 'git rev-parse' behave as if it were invoked from the
specified subdirectory of a repository, with the difference that any
file paths which it prints are prefixed with the full path from the top
of the working tree.

This is useful for shell scripts where we may want to cd to the top of
the working tree but need to handle relative paths given by the user on
the command line.

Signed-off-by: John Keeping <john@keeping.me.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
maint
John Keeping 12 years ago committed by Junio C Hamano
parent
commit
12b9d32790
  1. 16
      Documentation/git-rev-parse.txt
  2. 24
      builtin/rev-parse.c
  3. 96
      t/t1513-rev-parse-prefix.sh

16
Documentation/git-rev-parse.txt

@ -59,6 +59,22 @@ OPTIONS @@ -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

24
builtin/rev-parse.c

@ -212,11 +212,17 @@ static void show_datestring(const char *flag, const char *datestr) @@ -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" @@ -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) @@ -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) @@ -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) @@ -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) @@ -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);
}

96
t/t1513-rev-parse-prefix.sh

@ -0,0 +1,96 @@ @@ -0,0 +1,96 @@
#!/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 'prefix ignored with HEAD:top' '
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
Loading…
Cancel
Save