1
0
Fork 0
mirror of https://github.com/git/git.git synced 2024-05-06 14:36:18 +02:00

update submodules: add submodule_move_head

In later patches we introduce the options and flag for commands
that modify the working directory, e.g. git-checkout.

This piece of code will be used universally for
all these working tree modifications as it
* supports dry run to answer the question:
  "Is it safe to change the submodule to this new state?"
  e.g. is it overwriting untracked files or are there local
  changes that would be overwritten?
* supports a force flag that can be used for resetting
  the tree.

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-14 14:46:37 -07:00 committed by Junio C Hamano
parent 202275b96b
commit 6e3c1595c6
2 changed files with 144 additions and 0 deletions

View File

@ -1247,6 +1247,143 @@ static const char *get_super_prefix_or_empty(void)
return s;
}
static int submodule_has_dirty_index(const struct submodule *sub)
{
struct child_process cp = CHILD_PROCESS_INIT;
prepare_submodule_repo_env_no_git_dir(&cp.env_array);
cp.git_cmd = 1;
argv_array_pushl(&cp.args, "diff-index", "--quiet",
"--cached", "HEAD", NULL);
cp.no_stdin = 1;
cp.no_stdout = 1;
cp.dir = sub->path;
if (start_command(&cp))
die("could not recurse into submodule '%s'", sub->path);
return finish_command(&cp);
}
static void submodule_reset_index(const char *path)
{
struct child_process cp = CHILD_PROCESS_INIT;
prepare_submodule_repo_env_no_git_dir(&cp.env_array);
cp.git_cmd = 1;
cp.no_stdin = 1;
cp.dir = path;
argv_array_pushf(&cp.args, "--super-prefix=%s%s/",
get_super_prefix_or_empty(), path);
argv_array_pushl(&cp.args, "read-tree", "-u", "--reset", NULL);
argv_array_push(&cp.args, EMPTY_TREE_SHA1_HEX);
if (run_command(&cp))
die("could not reset submodule index");
}
/**
* Moves a submodule at a given path from a given head to another new head.
* For edge cases (a submodule coming into existence or removing a submodule)
* pass NULL for old or new respectively.
*/
int submodule_move_head(const char *path,
const char *old,
const char *new,
unsigned flags)
{
int ret = 0;
struct child_process cp = CHILD_PROCESS_INIT;
const struct submodule *sub;
sub = submodule_from_path(null_sha1, path);
if (!sub)
die("BUG: could not get submodule information for '%s'", path);
if (old && !(flags & SUBMODULE_MOVE_HEAD_FORCE)) {
/* Check if the submodule has a dirty index. */
if (submodule_has_dirty_index(sub))
return error(_("submodule '%s' has dirty index"), path);
}
if (!(flags & SUBMODULE_MOVE_HEAD_DRY_RUN)) {
if (old) {
if (!submodule_uses_gitfile(path))
absorb_git_dir_into_superproject("", path,
ABSORB_GITDIR_RECURSE_SUBMODULES);
} else {
struct strbuf sb = STRBUF_INIT;
strbuf_addf(&sb, "%s/modules/%s",
get_git_common_dir(), sub->name);
connect_work_tree_and_git_dir(path, sb.buf);
strbuf_release(&sb);
/* make sure the index is clean as well */
submodule_reset_index(path);
}
}
prepare_submodule_repo_env_no_git_dir(&cp.env_array);
cp.git_cmd = 1;
cp.no_stdin = 1;
cp.dir = path;
argv_array_pushf(&cp.args, "--super-prefix=%s%s/",
get_super_prefix_or_empty(), path);
argv_array_pushl(&cp.args, "read-tree", NULL);
if (flags & SUBMODULE_MOVE_HEAD_DRY_RUN)
argv_array_push(&cp.args, "-n");
else
argv_array_push(&cp.args, "-u");
if (flags & SUBMODULE_MOVE_HEAD_FORCE)
argv_array_push(&cp.args, "--reset");
else
argv_array_push(&cp.args, "-m");
argv_array_push(&cp.args, old ? old : EMPTY_TREE_SHA1_HEX);
argv_array_push(&cp.args, new ? new : EMPTY_TREE_SHA1_HEX);
if (run_command(&cp)) {
ret = -1;
goto out;
}
if (!(flags & SUBMODULE_MOVE_HEAD_DRY_RUN)) {
if (new) {
struct child_process cp1 = CHILD_PROCESS_INIT;
/* also set the HEAD accordingly */
cp1.git_cmd = 1;
cp1.no_stdin = 1;
cp1.dir = path;
argv_array_pushl(&cp1.args, "update-ref", "HEAD",
new ? new : EMPTY_TREE_SHA1_HEX, NULL);
if (run_command(&cp1)) {
ret = -1;
goto out;
}
} else {
struct strbuf sb = STRBUF_INIT;
strbuf_addf(&sb, "%s/.git", path);
unlink_or_warn(sb.buf);
strbuf_release(&sb);
if (is_empty_dir(path))
rmdir_or_warn(path);
}
}
out:
return ret;
}
static int find_first_merges(struct object_array *result, const char *path,
struct commit *a, struct commit *b)
{

View File

@ -96,6 +96,13 @@ extern int push_unpushed_submodules(struct sha1_array *commits,
extern void connect_work_tree_and_git_dir(const char *work_tree, const char *git_dir);
extern int parallel_submodules(void);
#define SUBMODULE_MOVE_HEAD_DRY_RUN (1<<0)
#define SUBMODULE_MOVE_HEAD_FORCE (1<<1)
extern int submodule_move_head(const char *path,
const char *old,
const char *new,
unsigned flags);
/*
* Prepare the "env_array" parameter of a "struct child_process" for executing
* a submodule by clearing any repo-specific envirionment variables, but