rev-parse: add --show-superproject-working-tree

In some situations it is useful to know if the given repository
is a submodule of another repository.

Add the flag --show-superproject-working-tree to git-rev-parse
to make it easy to find out if there is a superproject. When no
superproject exists, the output will be empty.

Signed-off-by: Stefan Beller <sbeller@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Stefan Beller 2017-03-08 15:07:42 -08:00 коммит произвёл Junio C Hamano
Родитель e0688e9b28
Коммит bf0231c661
5 изменённых файлов: 117 добавлений и 0 удалений

Просмотреть файл

@ -261,6 +261,12 @@ print a message to stderr and exit with nonzero status.
--show-toplevel::
Show the absolute path of the top-level directory.
--show-superproject-working-tree
Show the absolute path of the root of the superproject's
working tree (if exists) that uses the current repository as
its submodule. Outputs nothing if the current repository is
not used as a submodule by any project.
--shared-index-path::
Show the path to the shared index file in split index mode, or
empty if not in split-index mode.

Просмотреть файл

@ -12,6 +12,7 @@
#include "diff.h"
#include "revision.h"
#include "split-index.h"
#include "submodule.h"
#define DO_REVS 1
#define DO_NOREV 2
@ -779,6 +780,12 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
puts(work_tree);
continue;
}
if (!strcmp(arg, "--show-superproject-working-tree")) {
const char *superproject = get_superproject_working_tree();
if (superproject)
puts(superproject);
continue;
}
if (!strcmp(arg, "--show-prefix")) {
if (prefix)
puts(prefix);

Просмотреть файл

@ -1514,3 +1514,85 @@ void absorb_git_dir_into_superproject(const char *prefix,
strbuf_release(&sb);
}
}
const char *get_superproject_working_tree(void)
{
struct child_process cp = CHILD_PROCESS_INIT;
struct strbuf sb = STRBUF_INIT;
const char *one_up = real_path_if_valid("../");
const char *cwd = xgetcwd();
const char *ret = NULL;
const char *subpath;
int code;
ssize_t len;
if (!is_inside_work_tree())
/*
* FIXME:
* We might have a superproject, but it is harder
* to determine.
*/
return NULL;
if (!one_up)
return NULL;
subpath = relative_path(cwd, one_up, &sb);
prepare_submodule_repo_env(&cp.env_array);
argv_array_pop(&cp.env_array);
argv_array_pushl(&cp.args, "--literal-pathspecs", "-C", "..",
"ls-files", "-z", "--stage", "--full-name", "--",
subpath, NULL);
strbuf_reset(&sb);
cp.no_stdin = 1;
cp.no_stderr = 1;
cp.out = -1;
cp.git_cmd = 1;
if (start_command(&cp))
die(_("could not start ls-files in .."));
len = strbuf_read(&sb, cp.out, PATH_MAX);
close(cp.out);
if (starts_with(sb.buf, "160000")) {
int super_sub_len;
int cwd_len = strlen(cwd);
char *super_sub, *super_wt;
/*
* There is a superproject having this repo as a submodule.
* The format is <mode> SP <hash> SP <stage> TAB <full name> \0,
* We're only interested in the name after the tab.
*/
super_sub = strchr(sb.buf, '\t') + 1;
super_sub_len = sb.buf + sb.len - super_sub - 1;
if (super_sub_len > cwd_len ||
strcmp(&cwd[cwd_len - super_sub_len], super_sub))
die (_("BUG: returned path string doesn't match cwd?"));
super_wt = xstrdup(cwd);
super_wt[cwd_len - super_sub_len] = '\0';
ret = real_path(super_wt);
free(super_wt);
}
strbuf_release(&sb);
code = finish_command(&cp);
if (code == 128)
/* '../' is not a git repository */
return NULL;
if (code == 0 && len == 0)
/* There is an unrelated git repository at '../' */
return NULL;
if (code)
die(_("ls-tree returned unexpected return code %d"), code);
return ret;
}

Просмотреть файл

@ -93,4 +93,12 @@ extern void prepare_submodule_repo_env(struct argv_array *out);
extern void absorb_git_dir_into_superproject(const char *prefix,
const char *path,
unsigned flags);
/*
* Return the absolute path of the working tree of the superproject, which this
* project is a submodule of. If this repository is not a submodule of
* another repository, return NULL.
*/
extern const char *get_superproject_working_tree(void);
#endif

Просмотреть файл

@ -116,4 +116,18 @@ test_expect_success 'git-path inside sub-dir' '
test_cmp expect actual
'
test_expect_success 'showing the superproject correctly' '
git rev-parse --show-superproject-working-tree >out &&
test_must_be_empty out &&
test_create_repo super &&
test_commit -C super test_commit &&
test_create_repo sub &&
test_commit -C sub test_commit &&
git -C super submodule add ../sub dir/sub &&
echo $(pwd)/super >expect &&
git -C super/dir/sub rev-parse --show-superproject-working-tree >out &&
test_cmp expect out
'
test_done