зеркало из https://github.com/microsoft/git.git
Merge branch 'sb/reset-recurse-submodules'
"git reset" learned "--recurse-submodules" option. * sb/reset-recurse-submodules: builtin/reset: add --recurse-submodules switch submodule.c: submodule_move_head works with broken submodules submodule.c: uninitialized submodules are ignored in recursive commands entry.c: submodule recursing: respect force flag correctly
This commit is contained in:
Коммит
5f074ca7e8
|
@ -21,6 +21,27 @@
|
||||||
#include "parse-options.h"
|
#include "parse-options.h"
|
||||||
#include "unpack-trees.h"
|
#include "unpack-trees.h"
|
||||||
#include "cache-tree.h"
|
#include "cache-tree.h"
|
||||||
|
#include "submodule.h"
|
||||||
|
#include "submodule-config.h"
|
||||||
|
|
||||||
|
static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT;
|
||||||
|
|
||||||
|
static int option_parse_recurse_submodules(const struct option *opt,
|
||||||
|
const char *arg, int unset)
|
||||||
|
{
|
||||||
|
if (unset) {
|
||||||
|
recurse_submodules = RECURSE_SUBMODULES_OFF;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (arg)
|
||||||
|
recurse_submodules =
|
||||||
|
parse_update_recurse_submodules_arg(opt->long_name,
|
||||||
|
arg);
|
||||||
|
else
|
||||||
|
recurse_submodules = RECURSE_SUBMODULES_ON;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static const char * const git_reset_usage[] = {
|
static const char * const git_reset_usage[] = {
|
||||||
N_("git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<commit>]"),
|
N_("git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<commit>]"),
|
||||||
|
@ -283,6 +304,9 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
|
||||||
N_("reset HEAD, index and working tree"), MERGE),
|
N_("reset HEAD, index and working tree"), MERGE),
|
||||||
OPT_SET_INT(0, "keep", &reset_type,
|
OPT_SET_INT(0, "keep", &reset_type,
|
||||||
N_("reset HEAD but keep local changes"), KEEP),
|
N_("reset HEAD but keep local changes"), KEEP),
|
||||||
|
{ OPTION_CALLBACK, 0, "recurse-submodules", &recurse_submodules,
|
||||||
|
"reset", "control recursive updating of submodules",
|
||||||
|
PARSE_OPT_OPTARG, option_parse_recurse_submodules },
|
||||||
OPT_BOOL('p', "patch", &patch_mode, N_("select hunks interactively")),
|
OPT_BOOL('p', "patch", &patch_mode, N_("select hunks interactively")),
|
||||||
OPT_BOOL('N', "intent-to-add", &intent_to_add,
|
OPT_BOOL('N', "intent-to-add", &intent_to_add,
|
||||||
N_("record only the fact that removed paths will be added later")),
|
N_("record only the fact that removed paths will be added later")),
|
||||||
|
@ -295,6 +319,12 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
|
||||||
PARSE_OPT_KEEP_DASHDASH);
|
PARSE_OPT_KEEP_DASHDASH);
|
||||||
parse_args(&pathspec, argv, prefix, patch_mode, &rev);
|
parse_args(&pathspec, argv, prefix, patch_mode, &rev);
|
||||||
|
|
||||||
|
if (recurse_submodules != RECURSE_SUBMODULES_DEFAULT) {
|
||||||
|
gitmodules_config();
|
||||||
|
git_config(submodule_config, NULL);
|
||||||
|
set_config_update_recurse_submodules(RECURSE_SUBMODULES_ON);
|
||||||
|
}
|
||||||
|
|
||||||
unborn = !strcmp(rev, "HEAD") && get_sha1("HEAD", oid.hash);
|
unborn = !strcmp(rev, "HEAD") && get_sha1("HEAD", oid.hash);
|
||||||
if (unborn) {
|
if (unborn) {
|
||||||
/* reset on unborn branch: treat as reset to empty tree */
|
/* reset on unborn branch: treat as reset to empty tree */
|
||||||
|
|
8
entry.c
8
entry.c
|
@ -208,7 +208,8 @@ static int write_entry(struct cache_entry *ce,
|
||||||
sub = submodule_from_ce(ce);
|
sub = submodule_from_ce(ce);
|
||||||
if (sub)
|
if (sub)
|
||||||
return submodule_move_head(ce->name,
|
return submodule_move_head(ce->name,
|
||||||
NULL, oid_to_hex(&ce->oid), SUBMODULE_MOVE_HEAD_FORCE);
|
NULL, oid_to_hex(&ce->oid),
|
||||||
|
state->force ? SUBMODULE_MOVE_HEAD_FORCE : 0);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return error("unknown file mode for %s in index", path);
|
return error("unknown file mode for %s in index", path);
|
||||||
|
@ -282,12 +283,11 @@ int checkout_entry(struct cache_entry *ce,
|
||||||
unlink_or_warn(ce->name);
|
unlink_or_warn(ce->name);
|
||||||
|
|
||||||
return submodule_move_head(ce->name,
|
return submodule_move_head(ce->name,
|
||||||
NULL, oid_to_hex(&ce->oid),
|
NULL, oid_to_hex(&ce->oid), 0);
|
||||||
SUBMODULE_MOVE_HEAD_FORCE);
|
|
||||||
} else
|
} else
|
||||||
return submodule_move_head(ce->name,
|
return submodule_move_head(ce->name,
|
||||||
"HEAD", oid_to_hex(&ce->oid),
|
"HEAD", oid_to_hex(&ce->oid),
|
||||||
SUBMODULE_MOVE_HEAD_FORCE);
|
state->force ? SUBMODULE_MOVE_HEAD_FORCE : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!changed)
|
if (!changed)
|
||||||
|
|
31
submodule.c
31
submodule.c
|
@ -1402,6 +1402,23 @@ int submodule_move_head(const char *path,
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
struct child_process cp = CHILD_PROCESS_INIT;
|
struct child_process cp = CHILD_PROCESS_INIT;
|
||||||
const struct submodule *sub;
|
const struct submodule *sub;
|
||||||
|
int *error_code_ptr, error_code;
|
||||||
|
|
||||||
|
if (!is_submodule_initialized(path))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (flags & SUBMODULE_MOVE_HEAD_FORCE)
|
||||||
|
/*
|
||||||
|
* Pass non NULL pointer to is_submodule_populated_gently
|
||||||
|
* to prevent die()-ing. We'll use connect_work_tree_and_git_dir
|
||||||
|
* to fixup the submodule in the force case later.
|
||||||
|
*/
|
||||||
|
error_code_ptr = &error_code;
|
||||||
|
else
|
||||||
|
error_code_ptr = NULL;
|
||||||
|
|
||||||
|
if (old && !is_submodule_populated_gently(path, error_code_ptr))
|
||||||
|
return 0;
|
||||||
|
|
||||||
sub = submodule_from_path(null_sha1, path);
|
sub = submodule_from_path(null_sha1, path);
|
||||||
|
|
||||||
|
@ -1420,15 +1437,21 @@ int submodule_move_head(const char *path,
|
||||||
absorb_git_dir_into_superproject("", path,
|
absorb_git_dir_into_superproject("", path,
|
||||||
ABSORB_GITDIR_RECURSE_SUBMODULES);
|
ABSORB_GITDIR_RECURSE_SUBMODULES);
|
||||||
} else {
|
} else {
|
||||||
struct strbuf sb = STRBUF_INIT;
|
char *gitdir = xstrfmt("%s/modules/%s",
|
||||||
strbuf_addf(&sb, "%s/modules/%s",
|
|
||||||
get_git_common_dir(), sub->name);
|
get_git_common_dir(), sub->name);
|
||||||
connect_work_tree_and_git_dir(path, sb.buf);
|
connect_work_tree_and_git_dir(path, gitdir);
|
||||||
strbuf_release(&sb);
|
free(gitdir);
|
||||||
|
|
||||||
/* make sure the index is clean as well */
|
/* make sure the index is clean as well */
|
||||||
submodule_reset_index(path);
|
submodule_reset_index(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (old && (flags & SUBMODULE_MOVE_HEAD_FORCE)) {
|
||||||
|
char *gitdir = xstrfmt("%s/modules/%s",
|
||||||
|
get_git_common_dir(), sub->name);
|
||||||
|
connect_work_tree_and_git_dir(path, gitdir);
|
||||||
|
free(gitdir);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
prepare_submodule_repo_env_no_git_dir(&cp.env_array);
|
prepare_submodule_repo_env_no_git_dir(&cp.env_array);
|
||||||
|
|
|
@ -73,6 +73,7 @@ create_lib_submodule_repo () {
|
||||||
|
|
||||||
git checkout -b "add_sub1" &&
|
git checkout -b "add_sub1" &&
|
||||||
git submodule add ../submodule_update_sub1 sub1 &&
|
git submodule add ../submodule_update_sub1 sub1 &&
|
||||||
|
git submodule add ../submodule_update_sub1 uninitialized_sub &&
|
||||||
git config -f .gitmodules submodule.sub1.ignore all &&
|
git config -f .gitmodules submodule.sub1.ignore all &&
|
||||||
git config submodule.sub1.ignore all &&
|
git config submodule.sub1.ignore all &&
|
||||||
git add .gitmodules &&
|
git add .gitmodules &&
|
||||||
|
@ -1212,14 +1213,31 @@ test_submodule_forced_switch_recursing () {
|
||||||
)
|
)
|
||||||
'
|
'
|
||||||
# Updating a submodule from an invalid sha1 updates
|
# Updating a submodule from an invalid sha1 updates
|
||||||
test_expect_success "$command: modified submodule does not update submodule work tree from invalid commit" '
|
test_expect_success "$command: modified submodule does update submodule work tree from invalid commit" '
|
||||||
prolog &&
|
prolog &&
|
||||||
reset_work_tree_to_interested invalid_sub1 &&
|
reset_work_tree_to_interested invalid_sub1 &&
|
||||||
(
|
(
|
||||||
cd submodule_update &&
|
cd submodule_update &&
|
||||||
git branch -t valid_sub1 origin/valid_sub1 &&
|
git branch -t valid_sub1 origin/valid_sub1 &&
|
||||||
test_must_fail $command valid_sub1 &&
|
$command valid_sub1 &&
|
||||||
test_superproject_content origin/invalid_sub1
|
test_superproject_content origin/valid_sub1 &&
|
||||||
|
test_submodule_content sub1 origin/valid_sub1
|
||||||
|
)
|
||||||
|
'
|
||||||
|
|
||||||
|
# Old versions of Git were buggy writing the .git link file
|
||||||
|
# (e.g. before f8eaa0ba98b and then moving the superproject repo
|
||||||
|
# whose submodules contained absolute paths)
|
||||||
|
test_expect_success "$command: updating submodules fixes .git links" '
|
||||||
|
prolog &&
|
||||||
|
reset_work_tree_to_interested add_sub1 &&
|
||||||
|
(
|
||||||
|
cd submodule_update &&
|
||||||
|
git branch -t modify_sub1 origin/modify_sub1 &&
|
||||||
|
echo "gitdir: bogus/path" >sub1/.git &&
|
||||||
|
$command modify_sub1 &&
|
||||||
|
test_superproject_content origin/modify_sub1 &&
|
||||||
|
test_submodule_content sub1 origin/modify_sub1
|
||||||
)
|
)
|
||||||
'
|
'
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,14 @@ test_description='reset can handle submodules'
|
||||||
. ./test-lib.sh
|
. ./test-lib.sh
|
||||||
. "$TEST_DIRECTORY"/lib-submodule-update.sh
|
. "$TEST_DIRECTORY"/lib-submodule-update.sh
|
||||||
|
|
||||||
|
KNOWN_FAILURE_SUBMODULE_RECURSIVE_NESTED=1
|
||||||
|
KNOWN_FAILURE_DIRECTORY_SUBMODULE_CONFLICTS=1
|
||||||
|
KNOWN_FAILURE_SUBMODULE_OVERWRITE_IGNORED_UNTRACKED=1
|
||||||
|
|
||||||
|
test_submodule_switch_recursing "git reset --recurse-submodules --keep"
|
||||||
|
|
||||||
|
test_submodule_forced_switch_recursing "git reset --hard --recurse-submodules"
|
||||||
|
|
||||||
test_submodule_switch "git reset --keep"
|
test_submodule_switch "git reset --keep"
|
||||||
|
|
||||||
test_submodule_switch "git reset --merge"
|
test_submodule_switch "git reset --merge"
|
||||||
|
|
|
@ -252,14 +252,18 @@ static int check_submodule_move_head(const struct cache_entry *ce,
|
||||||
const char *new_id,
|
const char *new_id,
|
||||||
struct unpack_trees_options *o)
|
struct unpack_trees_options *o)
|
||||||
{
|
{
|
||||||
|
unsigned flags = SUBMODULE_MOVE_HEAD_DRY_RUN;
|
||||||
const struct submodule *sub = submodule_from_ce(ce);
|
const struct submodule *sub = submodule_from_ce(ce);
|
||||||
if (!sub)
|
if (!sub)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (o->reset)
|
||||||
|
flags |= SUBMODULE_MOVE_HEAD_FORCE;
|
||||||
|
|
||||||
switch (sub->update_strategy.type) {
|
switch (sub->update_strategy.type) {
|
||||||
case SM_UPDATE_UNSPECIFIED:
|
case SM_UPDATE_UNSPECIFIED:
|
||||||
case SM_UPDATE_CHECKOUT:
|
case SM_UPDATE_CHECKOUT:
|
||||||
if (submodule_move_head(ce->name, old_id, new_id, SUBMODULE_MOVE_HEAD_DRY_RUN))
|
if (submodule_move_head(ce->name, old_id, new_id, flags))
|
||||||
return o->gently ? -1 :
|
return o->gently ? -1 :
|
||||||
add_rejected_path(o, ERROR_WOULD_LOSE_SUBMODULE, ce->name);
|
add_rejected_path(o, ERROR_WOULD_LOSE_SUBMODULE, ce->name);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -308,6 +312,7 @@ static void unlink_entry(const struct cache_entry *ce)
|
||||||
case SM_UPDATE_CHECKOUT:
|
case SM_UPDATE_CHECKOUT:
|
||||||
case SM_UPDATE_REBASE:
|
case SM_UPDATE_REBASE:
|
||||||
case SM_UPDATE_MERGE:
|
case SM_UPDATE_MERGE:
|
||||||
|
/* state.force is set at the caller. */
|
||||||
submodule_move_head(ce->name, "HEAD", NULL,
|
submodule_move_head(ce->name, "HEAD", NULL,
|
||||||
SUBMODULE_MOVE_HEAD_FORCE);
|
SUBMODULE_MOVE_HEAD_FORCE);
|
||||||
break;
|
break;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче