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:
commit
5f074ca7e8
@ -21,6 +21,27 @@
|
||||
#include "parse-options.h"
|
||||
#include "unpack-trees.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[] = {
|
||||
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),
|
||||
OPT_SET_INT(0, "keep", &reset_type,
|
||||
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('N', "intent-to-add", &intent_to_add,
|
||||
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_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);
|
||||
if (unborn) {
|
||||
/* 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);
|
||||
if (sub)
|
||||
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;
|
||||
default:
|
||||
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);
|
||||
|
||||
return submodule_move_head(ce->name,
|
||||
NULL, oid_to_hex(&ce->oid),
|
||||
SUBMODULE_MOVE_HEAD_FORCE);
|
||||
NULL, oid_to_hex(&ce->oid), 0);
|
||||
} else
|
||||
return submodule_move_head(ce->name,
|
||||
"HEAD", oid_to_hex(&ce->oid),
|
||||
SUBMODULE_MOVE_HEAD_FORCE);
|
||||
state->force ? SUBMODULE_MOVE_HEAD_FORCE : 0);
|
||||
}
|
||||
|
||||
if (!changed)
|
||||
|
31
submodule.c
31
submodule.c
@ -1402,6 +1402,23 @@ int submodule_move_head(const char *path,
|
||||
int ret = 0;
|
||||
struct child_process cp = CHILD_PROCESS_INIT;
|
||||
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);
|
||||
|
||||
@ -1420,15 +1437,21 @@ int submodule_move_head(const char *path,
|
||||
absorb_git_dir_into_superproject("", path,
|
||||
ABSORB_GITDIR_RECURSE_SUBMODULES);
|
||||
} else {
|
||||
struct strbuf sb = STRBUF_INIT;
|
||||
strbuf_addf(&sb, "%s/modules/%s",
|
||||
char *gitdir = xstrfmt("%s/modules/%s",
|
||||
get_git_common_dir(), sub->name);
|
||||
connect_work_tree_and_git_dir(path, sb.buf);
|
||||
strbuf_release(&sb);
|
||||
connect_work_tree_and_git_dir(path, gitdir);
|
||||
free(gitdir);
|
||||
|
||||
/* make sure the index is clean as well */
|
||||
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);
|
||||
|
@ -73,6 +73,7 @@ create_lib_submodule_repo () {
|
||||
|
||||
git checkout -b "add_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 submodule.sub1.ignore all &&
|
||||
git add .gitmodules &&
|
||||
@ -1212,14 +1213,31 @@ test_submodule_forced_switch_recursing () {
|
||||
)
|
||||
'
|
||||
# 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 &&
|
||||
reset_work_tree_to_interested invalid_sub1 &&
|
||||
(
|
||||
cd submodule_update &&
|
||||
git branch -t valid_sub1 origin/valid_sub1 &&
|
||||
test_must_fail $command valid_sub1 &&
|
||||
test_superproject_content origin/invalid_sub1
|
||||
$command valid_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_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 --merge"
|
||||
|
@ -252,14 +252,18 @@ static int check_submodule_move_head(const struct cache_entry *ce,
|
||||
const char *new_id,
|
||||
struct unpack_trees_options *o)
|
||||
{
|
||||
unsigned flags = SUBMODULE_MOVE_HEAD_DRY_RUN;
|
||||
const struct submodule *sub = submodule_from_ce(ce);
|
||||
if (!sub)
|
||||
return 0;
|
||||
|
||||
if (o->reset)
|
||||
flags |= SUBMODULE_MOVE_HEAD_FORCE;
|
||||
|
||||
switch (sub->update_strategy.type) {
|
||||
case SM_UPDATE_UNSPECIFIED:
|
||||
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 :
|
||||
add_rejected_path(o, ERROR_WOULD_LOSE_SUBMODULE, ce->name);
|
||||
return 0;
|
||||
@ -308,6 +312,7 @@ static void unlink_entry(const struct cache_entry *ce)
|
||||
case SM_UPDATE_CHECKOUT:
|
||||
case SM_UPDATE_REBASE:
|
||||
case SM_UPDATE_MERGE:
|
||||
/* state.force is set at the caller. */
|
||||
submodule_move_head(ce->name, "HEAD", NULL,
|
||||
SUBMODULE_MOVE_HEAD_FORCE);
|
||||
break;
|
||||
|
Loading…
Reference in New Issue
Block a user