}
}
- static void error_removing_concrete_submodules(struct string_list *files, int *errs)
- {
- print_error_files(files,
- Q_("the following submodule (or one of its nested "
- "submodules)\n"
- "uses a .git directory:",
- "the following submodules (or one of their nested "
- "submodules)\n"
- "use a .git directory:", files->nr),
- _("\n(use 'rm -rf' if you really want to remove "
- "it including all of its history)"),
- errs);
- string_list_clear(files, 0);
- }
-
- static int check_submodules_use_gitfiles(void)
+ static void submodules_absorb_gitdir_if_needed(const char *prefix)
{
int i;
- int errs = 0;
- struct string_list files = STRING_LIST_INIT_NODUP;
-
for (i = 0; i < list.nr; i++) {
const char *name = list.entry[i].name;
int pos;
continue;
if (!submodule_uses_gitfile(name))
- string_list_append(&files, name);
+ absorb_git_dir_into_superproject(prefix, name,
+ ABSORB_GITDIR_RECURSE_SUBMODULES);
}
-
- error_removing_concrete_submodules(&files, &errs);
-
- return errs;
}
static int check_local_mod(struct object_id *head, int index_only)
int errs = 0;
struct string_list files_staged = STRING_LIST_INIT_NODUP;
struct string_list files_cached = STRING_LIST_INIT_NODUP;
- struct string_list files_submodule = STRING_LIST_INIT_NODUP;
struct string_list files_local = STRING_LIST_INIT_NODUP;
no_head = is_null_oid(head);
*/
if (ce_match_stat(ce, &st, 0) ||
(S_ISGITLINK(ce->ce_mode) &&
- !ok_to_remove_submodule(ce->name)))
+ bad_to_remove_submodule(ce->name,
+ SUBMODULE_REMOVAL_DIE_ON_ERROR |
+ SUBMODULE_REMOVAL_IGNORE_IGNORED_UNTRACKED)))
local_changes = 1;
/*
else if (!index_only) {
if (staged_changes)
string_list_append(&files_cached, name);
- if (local_changes) {
- if (S_ISGITLINK(ce->ce_mode) &&
- !submodule_uses_gitfile(name))
- string_list_append(&files_submodule, name);
- else
- string_list_append(&files_local, name);
- }
+ if (local_changes)
+ string_list_append(&files_local, name);
}
}
print_error_files(&files_staged,
&errs);
string_list_clear(&files_cached, 0);
- error_removing_concrete_submodules(&files_submodule, &errs);
-
print_error_files(&files_local,
Q_("the following file has local modifications:",
"the following files have local modifications:",
if (!index_only)
setup_work_tree();
- hold_locked_index(&lock_file, 1);
+ hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
if (read_cache() < 0)
die(_("index file corrupt"));
exit(0);
}
+ if (!index_only)
+ submodules_absorb_gitdir_if_needed(prefix);
+
/*
* If not forced, the file, the index and the HEAD (if exists)
* must match; but the file can already been removed, since
oidclr(&oid);
if (check_local_mod(&oid, index_only))
exit(1);
- } else if (!index_only) {
- if (check_submodules_use_gitfiles())
- exit(1);
}
/*
*/
if (!index_only) {
int removed = 0, gitmodules_modified = 0;
- struct strbuf buf = STRBUF_INIT;
for (i = 0; i < list.nr; i++) {
const char *path = list.entry[i].name;
if (list.entry[i].is_submodule) {
- if (is_empty_dir(path)) {
- if (!rmdir(path)) {
- removed = 1;
- if (!remove_path_from_gitmodules(path))
- gitmodules_modified = 1;
- continue;
- }
- } else {
- strbuf_reset(&buf);
- strbuf_addstr(&buf, path);
- if (!remove_dir_recursively(&buf, 0)) {
- removed = 1;
- if (!remove_path_from_gitmodules(path))
- gitmodules_modified = 1;
- strbuf_release(&buf);
- continue;
- } else if (!file_exists(path))
- /* Submodule was removed by user */
- if (!remove_path_from_gitmodules(path))
- gitmodules_modified = 1;
- /* Fallthrough and let remove_path() fail. */
- }
+ struct strbuf buf = STRBUF_INIT;
+
+ strbuf_addstr(&buf, path);
+ if (remove_dir_recursively(&buf, 0))
+ die(_("could not remove '%s'"), path);
+ strbuf_release(&buf);
+
+ removed = 1;
+ if (!remove_path_from_gitmodules(path))
+ gitmodules_modified = 1;
+ continue;
}
if (!remove_path(path)) {
removed = 1;
if (!removed)
die_errno("git rm: '%s'", path);
}
- strbuf_release(&buf);
if (gitmodules_modified)
stage_updated_gitmodules();
}
}
}
+void gitmodules_config_sha1(const unsigned char *commit_sha1)
+{
+ struct strbuf rev = STRBUF_INIT;
+ unsigned char sha1[20];
+
+ if (gitmodule_sha1_from_commit(commit_sha1, sha1, &rev)) {
+ git_config_from_blob_sha1(submodule_config, rev.buf,
+ sha1, NULL);
+ }
+ strbuf_release(&rev);
+}
+
+/*
+ * Determine if a submodule has been initialized at a given 'path'
+ */
+int is_submodule_initialized(const char *path)
+{
+ int ret = 0;
+ const struct submodule *module = NULL;
+
+ module = submodule_from_path(null_sha1, path);
+
+ if (module) {
+ char *key = xstrfmt("submodule.%s.url", module->name);
+ char *value = NULL;
+
+ ret = !git_config_get_string(key, &value);
+
+ free(value);
+ free(key);
+ }
+
+ return ret;
+}
+
+/*
+ * Determine if a submodule has been populated at a given 'path'
+ */
+int is_submodule_populated(const char *path)
+{
+ int ret = 0;
+ char *gitdir = xstrfmt("%s/.git", path);
+
+ if (resolve_gitdir(gitdir))
+ ret = 1;
+
+ free(gitdir);
+ return ret;
+}
+
int parse_submodule_update_strategy(const char *value,
struct submodule_update_strategy *dst)
{
return 1;
}
-static int submodule_needs_pushing(const char *path, const unsigned char sha1[20])
+static int append_sha1_to_argv(const unsigned char sha1[20], void *data)
+{
+ struct argv_array *argv = data;
+ argv_array_push(argv, sha1_to_hex(sha1));
+ return 0;
+}
+
+static int check_has_commit(const unsigned char sha1[20], void *data)
+{
+ int *has_commit = data;
+
+ if (!lookup_commit_reference(sha1))
+ *has_commit = 0;
+
+ return 0;
+}
+
+static int submodule_has_commits(const char *path, struct sha1_array *commits)
{
- if (add_submodule_odb(path) || !lookup_commit_reference(sha1))
+ int has_commit = 1;
+
+ if (add_submodule_odb(path))
+ return 0;
+
+ sha1_array_for_each_unique(commits, check_has_commit, &has_commit);
+ return has_commit;
+}
+
+static int submodule_needs_pushing(const char *path, struct sha1_array *commits)
+{
+ if (!submodule_has_commits(path, commits))
+ /*
+ * NOTE: We do consider it safe to return "no" here. The
+ * correct answer would be "We do not know" instead of
+ * "No push needed", but it is quite hard to change
+ * the submodule pointer without having the submodule
+ * around. If a user did however change the submodules
+ * without having the submodule around, this indicates
+ * an expert who knows what they are doing or a
+ * maintainer integrating work from other people. In
+ * both cases it should be safe to skip this check.
+ */
return 0;
if (for_each_remote_ref_submodule(path, has_remote, NULL) > 0) {
struct child_process cp = CHILD_PROCESS_INIT;
- const char *argv[] = {"rev-list", NULL, "--not", "--remotes", "-n", "1" , NULL};
struct strbuf buf = STRBUF_INIT;
int needs_pushing = 0;
- argv[1] = sha1_to_hex(sha1);
- cp.argv = argv;
+ argv_array_push(&cp.args, "rev-list");
+ sha1_array_for_each_unique(commits, append_sha1_to_argv, &cp.args);
+ argv_array_pushl(&cp.args, "--not", "--remotes", "-n", "1" , NULL);
+
prepare_submodule_repo_env(&cp.env_array);
cp.git_cmd = 1;
cp.no_stdin = 1;
cp.out = -1;
cp.dir = path;
if (start_command(&cp))
- die("Could not run 'git rev-list %s --not --remotes -n 1' command in submodule %s",
- sha1_to_hex(sha1), path);
+ die("Could not run 'git rev-list <commits> --not --remotes -n 1' command in submodule %s",
+ path);
if (strbuf_read(&buf, cp.out, 41))
needs_pushing = 1;
finish_command(&cp);
return 0;
}
+static struct sha1_array *submodule_commits(struct string_list *submodules,
+ const char *path)
+{
+ struct string_list_item *item;
+
+ item = string_list_insert(submodules, path);
+ if (item->util)
+ return (struct sha1_array *) item->util;
+
+ /* NEEDSWORK: should we have sha1_array_init()? */
+ item->util = xcalloc(1, sizeof(struct sha1_array));
+ return (struct sha1_array *) item->util;
+}
+
static void collect_submodules_from_diff(struct diff_queue_struct *q,
struct diff_options *options,
void *data)
{
int i;
- struct string_list *needs_pushing = data;
+ struct string_list *submodules = data;
for (i = 0; i < q->nr; i++) {
struct diff_filepair *p = q->queue[i];
+ struct sha1_array *commits;
if (!S_ISGITLINK(p->two->mode))
continue;
- if (submodule_needs_pushing(p->two->path, p->two->oid.hash))
- string_list_insert(needs_pushing, p->two->path);
+ commits = submodule_commits(submodules, p->two->path);
+ sha1_array_append(commits, p->two->oid.hash);
}
}
diff_tree_combined_merge(commit, 1, &rev);
}
-int find_unpushed_submodules(unsigned char new_sha1[20],
+static void free_submodules_sha1s(struct string_list *submodules)
+{
+ struct string_list_item *item;
+ for_each_string_list_item(item, submodules)
+ sha1_array_clear((struct sha1_array *) item->util);
+ string_list_clear(submodules, 1);
+}
+
+int find_unpushed_submodules(struct sha1_array *commits,
const char *remotes_name, struct string_list *needs_pushing)
{
struct rev_info rev;
struct commit *commit;
- const char *argv[] = {NULL, NULL, "--not", "NULL", NULL};
- int argc = ARRAY_SIZE(argv) - 1;
- char *sha1_copy;
-
- struct strbuf remotes_arg = STRBUF_INIT;
+ struct string_list submodules = STRING_LIST_INIT_DUP;
+ struct string_list_item *submodule;
+ struct argv_array argv = ARGV_ARRAY_INIT;
- strbuf_addf(&remotes_arg, "--remotes=%s", remotes_name);
init_revisions(&rev, NULL);
- sha1_copy = xstrdup(sha1_to_hex(new_sha1));
- argv[1] = sha1_copy;
- argv[3] = remotes_arg.buf;
- setup_revisions(argc, argv, &rev, NULL);
+
+ /* argv.argv[0] will be ignored by setup_revisions */
+ argv_array_push(&argv, "find_unpushed_submodules");
+ sha1_array_for_each_unique(commits, append_sha1_to_argv, &argv);
+ argv_array_push(&argv, "--not");
+ argv_array_pushf(&argv, "--remotes=%s", remotes_name);
+
+ setup_revisions(argv.argc, argv.argv, &rev, NULL);
if (prepare_revision_walk(&rev))
die("revision walk setup failed");
while ((commit = get_revision(&rev)) != NULL)
- find_unpushed_submodule_commits(commit, needs_pushing);
+ find_unpushed_submodule_commits(commit, &submodules);
reset_revision_walk();
- free(sha1_copy);
- strbuf_release(&remotes_arg);
+ argv_array_clear(&argv);
+
+ for_each_string_list_item(submodule, &submodules) {
+ struct sha1_array *commits = (struct sha1_array *) submodule->util;
+
+ if (submodule_needs_pushing(submodule->string, commits))
+ string_list_insert(needs_pushing, submodule->string);
+ }
+ free_submodules_sha1s(&submodules);
return needs_pushing->nr;
}
-static int push_submodule(const char *path)
+static int push_submodule(const char *path, int dry_run)
{
if (add_submodule_odb(path))
return 1;
if (for_each_remote_ref_submodule(path, has_remote, NULL) > 0) {
struct child_process cp = CHILD_PROCESS_INIT;
- const char *argv[] = {"push", NULL};
+ argv_array_push(&cp.args, "push");
+ if (dry_run)
+ argv_array_push(&cp.args, "--dry-run");
- cp.argv = argv;
prepare_submodule_repo_env(&cp.env_array);
cp.git_cmd = 1;
cp.no_stdin = 1;
return 1;
}
-int push_unpushed_submodules(unsigned char new_sha1[20], const char *remotes_name)
+int push_unpushed_submodules(struct sha1_array *commits,
+ const char *remotes_name,
+ int dry_run)
{
int i, ret = 1;
struct string_list needs_pushing = STRING_LIST_INIT_DUP;
- if (!find_unpushed_submodules(new_sha1, remotes_name, &needs_pushing))
+ if (!find_unpushed_submodules(commits, remotes_name, &needs_pushing))
return 1;
for (i = 0; i < needs_pushing.nr; i++) {
const char *path = needs_pushing.items[i].string;
fprintf(stderr, "Pushing submodule '%s'\n", path);
- if (!push_submodule(path)) {
+ if (!push_submodule(path, dry_run)) {
fprintf(stderr, "Unable to push submodule '%s'\n", path);
ret = 0;
}
return 1;
}
- int ok_to_remove_submodule(const char *path)
+ /*
+ * Check if it is a bad idea to remove a submodule, i.e. if we'd lose data
+ * when doing so.
+ *
+ * Return 1 if we'd lose data, return 0 if the removal is fine,
+ * and negative values for errors.
+ */
+ int bad_to_remove_submodule(const char *path, unsigned flags)
{
ssize_t len;
struct child_process cp = CHILD_PROCESS_INIT;
- const char *argv[] = {
- "status",
- "--porcelain",
- "-u",
- "--ignore-submodules=none",
- NULL,
- };
struct strbuf buf = STRBUF_INIT;
- int ok_to_remove = 1;
+ int ret = 0;
if (!file_exists(path) || is_empty_dir(path))
- return 1;
+ return 0;
if (!submodule_uses_gitfile(path))
- return 0;
+ return 1;
+
+ argv_array_pushl(&cp.args, "status", "--porcelain",
+ "--ignore-submodules=none", NULL);
+
+ if (flags & SUBMODULE_REMOVAL_IGNORE_UNTRACKED)
+ argv_array_push(&cp.args, "-uno");
+ else
+ argv_array_push(&cp.args, "-uall");
+
+ if (!(flags & SUBMODULE_REMOVAL_IGNORE_IGNORED_UNTRACKED))
+ argv_array_push(&cp.args, "--ignored");
- cp.argv = argv;
prepare_submodule_repo_env(&cp.env_array);
cp.git_cmd = 1;
cp.no_stdin = 1;
cp.out = -1;
cp.dir = path;
- if (start_command(&cp))
- die("Could not run 'git status --porcelain -uall --ignore-submodules=none' in submodule %s", path);
+ if (start_command(&cp)) {
+ if (flags & SUBMODULE_REMOVAL_DIE_ON_ERROR)
+ die(_("could not start 'git status in submodule '%s'"),
+ path);
+ ret = -1;
+ goto out;
+ }
len = strbuf_read(&buf, cp.out, 1024);
if (len > 2)
- ok_to_remove = 0;
+ ret = 1;
close(cp.out);
- if (finish_command(&cp))
- die("'git status --porcelain -uall --ignore-submodules=none' failed in submodule %s", path);
-
+ if (finish_command(&cp)) {
+ if (flags & SUBMODULE_REMOVAL_DIE_ON_ERROR)
+ die(_("could not run 'git status in submodule '%s'"),
+ path);
+ ret = -1;
+ }
+ out:
strbuf_release(&buf);
- return ok_to_remove;
+ return ret;
}
static int find_first_merges(struct object_array *result, const char *path,
/* If it is an actual gitfile, it doesn't need migration. */
return;
- real_old_git_dir = xstrdup(real_path(old_git_dir));
+ real_old_git_dir = real_pathdup(old_git_dir);
sub = submodule_from_path(null_sha1, path);
if (!sub)
new_git_dir = git_path("modules/%s", sub->name);
if (safe_create_leading_directories_const(new_git_dir) < 0)
die(_("could not create directory '%s'"), new_git_dir);
- real_new_git_dir = xstrdup(real_path(new_git_dir));
+ real_new_git_dir = real_pathdup(new_git_dir);
if (!prefix)
prefix = get_super_prefix();
goto out;
/* Is it already absorbed into the superprojects git dir? */
- real_sub_git_dir = xstrdup(real_path(sub_git_dir));
- real_common_git_dir = xstrdup(real_path(get_git_common_dir()));
+ real_sub_git_dir = real_pathdup(sub_git_dir);
+ real_common_git_dir = real_pathdup(get_git_common_dir());
if (!skip_prefix(real_sub_git_dir, real_common_git_dir, &v))
relocate_single_git_dir_into_superproject(prefix, path);
struct diff_options;
struct argv_array;
+struct sha1_array;
enum {
RECURSE_SUBMODULES_CHECK = -4,
};
#define SUBMODULE_UPDATE_STRATEGY_INIT {SM_UPDATE_UNSPECIFIED, NULL}
- int is_staging_gitmodules_ok(void);
- int update_path_in_gitmodules(const char *oldpath, const char *newpath);
- int remove_path_from_gitmodules(const char *path);
- void stage_updated_gitmodules(void);
- void set_diffopt_flags_from_submodule_config(struct diff_options *diffopt,
+ extern int is_staging_gitmodules_ok(void);
+ extern int update_path_in_gitmodules(const char *oldpath, const char *newpath);
+ extern int remove_path_from_gitmodules(const char *path);
+ extern void stage_updated_gitmodules(void);
+ extern void set_diffopt_flags_from_submodule_config(struct diff_options *,
const char *path);
- int submodule_config(const char *var, const char *value, void *cb);
- void gitmodules_config(void);
+ extern int submodule_config(const char *var, const char *value, void *cb);
+ extern void gitmodules_config(void);
+extern void gitmodules_config_sha1(const unsigned char *commit_sha1);
+extern int is_submodule_initialized(const char *path);
+extern int is_submodule_populated(const char *path);
- int parse_submodule_update_strategy(const char *value,
+ extern int parse_submodule_update_strategy(const char *value,
struct submodule_update_strategy *dst);
- const char *submodule_strategy_to_string(const struct submodule_update_strategy *s);
- void handle_ignore_submodules_arg(struct diff_options *diffopt, const char *);
- void show_submodule_summary(FILE *f, const char *path,
+ extern const char *submodule_strategy_to_string(const struct submodule_update_strategy *s);
+ extern void handle_ignore_submodules_arg(struct diff_options *, const char *);
+ extern void show_submodule_summary(FILE *f, const char *path,
const char *line_prefix,
struct object_id *one, struct object_id *two,
unsigned dirty_submodule, const char *meta,
const char *del, const char *add, const char *reset);
- void show_submodule_inline_diff(FILE *f, const char *path,
+ extern void show_submodule_inline_diff(FILE *f, const char *path,
const char *line_prefix,
struct object_id *one, struct object_id *two,
unsigned dirty_submodule, const char *meta,
const char *del, const char *add, const char *reset,
const struct diff_options *opt);
- void set_config_fetch_recurse_submodules(int value);
- void check_for_new_submodule_commits(unsigned char new_sha1[20]);
- int fetch_populated_submodules(const struct argv_array *options,
+ extern void set_config_fetch_recurse_submodules(int value);
+ extern void check_for_new_submodule_commits(unsigned char new_sha1[20]);
+ extern int fetch_populated_submodules(const struct argv_array *options,
const char *prefix, int command_line_option,
int quiet, int max_parallel_jobs);
- unsigned is_submodule_modified(const char *path, int ignore_untracked);
- int submodule_uses_gitfile(const char *path);
- int ok_to_remove_submodule(const char *path);
- int merge_submodule(unsigned char result[20], const char *path, const unsigned char base[20],
- const unsigned char a[20], const unsigned char b[20], int search);
- int find_unpushed_submodules(struct sha1_array *commits, const char *remotes_name,
- struct string_list *needs_pushing);
+ extern unsigned is_submodule_modified(const char *path, int ignore_untracked);
+ extern int submodule_uses_gitfile(const char *path);
+
+ #define SUBMODULE_REMOVAL_DIE_ON_ERROR (1<<0)
+ #define SUBMODULE_REMOVAL_IGNORE_UNTRACKED (1<<1)
+ #define SUBMODULE_REMOVAL_IGNORE_IGNORED_UNTRACKED (1<<2)
+ extern int bad_to_remove_submodule(const char *path, unsigned flags);
+ extern int merge_submodule(unsigned char result[20], const char *path,
+ const unsigned char base[20],
+ const unsigned char a[20],
+ const unsigned char b[20], int search);
-extern int find_unpushed_submodules(unsigned char new_sha1[20],
++extern int find_unpushed_submodules(struct sha1_array *commits,
+ const char *remotes_name,
+ struct string_list *needs_pushing);
-extern int push_unpushed_submodules(unsigned char new_sha1[20],
- const char *remotes_name);
+extern int push_unpushed_submodules(struct sha1_array *commits,
+ const char *remotes_name,
+ int dry_run);
- int parallel_submodules(void);
+ extern void connect_work_tree_and_git_dir(const char *work_tree, const char *git_dir);
+ extern int parallel_submodules(void);
/*
* Prepare the "env_array" parameter of a "struct child_process" for executing
* a submodule by clearing any repo-specific envirionment variables, but
* retaining any config in the environment.
*/
- void prepare_submodule_repo_env(struct argv_array *out);
+ extern void prepare_submodule_repo_env(struct argv_array *out);
#define ABSORB_GITDIR_RECURSE_SUBMODULES (1<<0)
extern void absorb_git_dir_into_superproject(const char *prefix,
'
test_expect_success '"rm" command printed' '
- echo frotz > test-file &&
+ echo frotz >test-file &&
git add test-file &&
git commit -m "add file for rm test" &&
- git rm test-file > rm-output &&
+ git rm test-file >rm-output &&
test $(grep "^rm " rm-output | wc -l) = 1 &&
rm -f test-file rm-output &&
git commit -m "remove file from rm test"
'
test_expect_success '"rm" command suppressed with --quiet' '
- echo frotz > test-file &&
+ echo frotz >test-file &&
git add test-file &&
git commit -m "add file for rm --quiet test" &&
- git rm --quiet test-file > rm-output &&
- test $(wc -l < rm-output) = 0 &&
+ git rm --quiet test-file >rm-output &&
+ test_must_be_empty rm-output &&
rm -f test-file rm-output &&
git commit -m "remove file from rm --quiet test"
'
mkdir repo &&
(cd repo &&
git init &&
- echo something > somefile &&
+ echo something >somefile &&
git add somefile &&
git commit -m "add a file" &&
(cd .. &&
git commit -m "add submodule" &&
git rm submod &&
test ! -e submod &&
- git status -s -uno --ignore-submodules=none > actual &&
+ git status -s -uno --ignore-submodules=none >actual &&
test_cmp expect actual &&
test_must_fail git config -f .gitmodules submodule.sub.url &&
test_must_fail git config -f .gitmodules submodule.sub.path
git submodule update &&
rm -rf submod &&
git rm submod &&
- git status -s -uno --ignore-submodules=none > actual &&
+ git status -s -uno --ignore-submodules=none >actual &&
test_cmp expect actual &&
test_must_fail git config -f .gitmodules submodule.sub.url &&
test_must_fail git config -f .gitmodules submodule.sub.path
git submodule update &&
git rm submod &&
test ! -d submod &&
- git status -s -uno --ignore-submodules=none > actual &&
+ git status -s -uno --ignore-submodules=none >actual &&
test_cmp expect actual &&
test_must_fail git config -f .gitmodules submodule.sub.url &&
test_must_fail git config -f .gitmodules submodule.sub.path
git submodule update &&
git rm submod/ &&
test ! -d submod &&
- git status -s -uno --ignore-submodules=none > actual &&
+ git status -s -uno --ignore-submodules=none >actual &&
test_cmp expect actual
'
test_expect_success 'rm of a populated submodule with different HEAD fails unless forced' '
git reset --hard &&
git submodule update &&
- (cd submod &&
- git checkout HEAD^
- ) &&
+ git -C submod checkout HEAD^ &&
test_must_fail git rm submod &&
test -d submod &&
test -f submod/.git &&
- git status -s -uno --ignore-submodules=none > actual &&
+ git status -s -uno --ignore-submodules=none >actual &&
test_cmp expect.modified actual &&
git rm -f submod &&
test ! -d submod &&
- git status -s -uno --ignore-submodules=none > actual &&
+ git status -s -uno --ignore-submodules=none >actual &&
test_cmp expect actual &&
test_must_fail git config -f .gitmodules submodule.sub.url &&
test_must_fail git config -f .gitmodules submodule.sub.path
test_expect_success 'rm of a populated submodule with modifications fails unless forced' '
git reset --hard &&
git submodule update &&
- (cd submod &&
- echo X >empty
- ) &&
+ echo X >submod/empty &&
test_must_fail git rm submod &&
test -d submod &&
test -f submod/.git &&
- git status -s -uno --ignore-submodules=none > actual &&
+ git status -s -uno --ignore-submodules=none >actual &&
test_cmp expect.modified actual &&
git rm -f submod &&
test ! -d submod &&
- git status -s -uno --ignore-submodules=none > actual &&
+ git status -s -uno --ignore-submodules=none >actual &&
test_cmp expect actual
'
test_expect_success 'rm of a populated submodule with untracked files fails unless forced' '
git reset --hard &&
git submodule update &&
- (cd submod &&
- echo X >untracked
- ) &&
+ echo X >submod/untracked &&
test_must_fail git rm submod &&
test -d submod &&
test -f submod/.git &&
- git status -s -uno --ignore-submodules=none > actual &&
+ git status -s -uno --ignore-submodules=none >actual &&
test_cmp expect.modified actual &&
git rm -f submod &&
test ! -d submod &&
- git status -s -uno --ignore-submodules=none > actual &&
+ git status -s -uno --ignore-submodules=none >actual &&
test_cmp expect actual
'
git add nitfol &&
git commit -m "added nitfol 2" &&
git checkout -b conflict1 master &&
- (cd submod &&
- git fetch &&
- git checkout branch1
- ) &&
+ git -C submod fetch &&
+ git -C submod checkout branch1 &&
git add submod &&
git commit -m "submod 1" &&
git checkout -b conflict2 master &&
- (cd submod &&
- git checkout branch2
- ) &&
+ git -C submod checkout branch2 &&
git add submod &&
git commit -m "submod 2"
'
test_must_fail git merge conflict2 &&
git rm submod &&
test ! -d submod &&
- git status -s -uno --ignore-submodules=none > actual &&
+ git status -s -uno --ignore-submodules=none >actual &&
test_cmp expect actual
'
git checkout conflict1 &&
git reset --hard &&
git submodule update &&
- (cd submod &&
- git checkout HEAD^
- ) &&
+ git -C submod checkout HEAD^ &&
test_must_fail git merge conflict2 &&
test_must_fail git rm submod &&
test -d submod &&
test -f submod/.git &&
- git status -s -uno --ignore-submodules=none > actual &&
+ git status -s -uno --ignore-submodules=none >actual &&
test_cmp expect.conflict actual &&
git rm -f submod &&
test ! -d submod &&
- git status -s -uno --ignore-submodules=none > actual &&
+ git status -s -uno --ignore-submodules=none >actual &&
test_cmp expect actual &&
test_must_fail git config -f .gitmodules submodule.sub.url &&
test_must_fail git config -f .gitmodules submodule.sub.path
git checkout conflict1 &&
git reset --hard &&
git submodule update &&
- (cd submod &&
- echo X >empty
- ) &&
+ echo X >submod/empty &&
test_must_fail git merge conflict2 &&
test_must_fail git rm submod &&
test -d submod &&
test -f submod/.git &&
- git status -s -uno --ignore-submodules=none > actual &&
+ git status -s -uno --ignore-submodules=none >actual &&
test_cmp expect.conflict actual &&
git rm -f submod &&
test ! -d submod &&
- git status -s -uno --ignore-submodules=none > actual &&
+ git status -s -uno --ignore-submodules=none >actual &&
test_cmp expect actual &&
test_must_fail git config -f .gitmodules submodule.sub.url &&
test_must_fail git config -f .gitmodules submodule.sub.path
git checkout conflict1 &&
git reset --hard &&
git submodule update &&
- (cd submod &&
- echo X >untracked
- ) &&
+ echo X >submod/untracked &&
test_must_fail git merge conflict2 &&
test_must_fail git rm submod &&
test -d submod &&
test -f submod/.git &&
- git status -s -uno --ignore-submodules=none > actual &&
+ git status -s -uno --ignore-submodules=none >actual &&
test_cmp expect.conflict actual &&
git rm -f submod &&
test ! -d submod &&
- git status -s -uno --ignore-submodules=none > actual &&
+ git status -s -uno --ignore-submodules=none >actual &&
test_cmp expect actual
'
test_must_fail git rm submod &&
test -d submod &&
test -d submod/.git &&
- git status -s -uno --ignore-submodules=none > actual &&
+ git status -s -uno --ignore-submodules=none >actual &&
test_cmp expect.conflict actual &&
test_must_fail git rm -f submod &&
test -d submod &&
test -d submod/.git &&
- git status -s -uno --ignore-submodules=none > actual &&
+ git status -s -uno --ignore-submodules=none >actual &&
test_cmp expect.conflict actual &&
git merge --abort &&
rm -rf submod
test_must_fail git merge conflict2 &&
git rm submod &&
test ! -d submod &&
- git status -s -uno --ignore-submodules=none > actual &&
+ git status -s -uno --ignore-submodules=none >actual &&
test_cmp expect actual
'
- test_expect_success 'rm of a populated submodule with a .git directory fails even when forced' '
+ test_expect_success 'rm of a populated submodule with a .git directory migrates git dir' '
git checkout -f master &&
git reset --hard &&
git submodule update &&
(cd submod &&
rm .git &&
cp -R ../.git/modules/sub .git &&
- GIT_WORK_TREE=. git config --unset core.worktree
+ GIT_WORK_TREE=. git config --unset core.worktree &&
+ rm -r ../.git/modules/sub
) &&
- test_must_fail git rm submod &&
- test -d submod &&
- test -d submod/.git &&
- git status -s -uno --ignore-submodules=none >actual &&
- ! test -s actual &&
- test_must_fail git rm -f submod &&
- test -d submod &&
- test -d submod/.git &&
+ git rm submod 2>output.err &&
+ ! test -d submod &&
+ ! test -d submod/.git &&
git status -s -uno --ignore-submodules=none >actual &&
- ! test -s actual &&
- rm -rf submod
+ test -s actual &&
+ test_i18ngrep Migrating output.err
'
cat >expect.deepmodified <<EOF
test_expect_success 'rm recursively removes work tree of unmodified submodules' '
git rm submod &&
test ! -d submod &&
- git status -s -uno --ignore-submodules=none > actual &&
+ git status -s -uno --ignore-submodules=none >actual &&
test_cmp expect actual
'
test_expect_success 'rm of a populated nested submodule with different nested HEAD fails unless forced' '
git reset --hard &&
git submodule update --recursive &&
- (cd submod/subsubmod &&
- git checkout HEAD^
- ) &&
+ git -C submod/subsubmod checkout HEAD^ &&
test_must_fail git rm submod &&
test -d submod &&
test -f submod/.git &&
- git status -s -uno --ignore-submodules=none > actual &&
+ git status -s -uno --ignore-submodules=none >actual &&
test_cmp expect.modified actual &&
git rm -f submod &&
test ! -d submod &&
- git status -s -uno --ignore-submodules=none > actual &&
+ git status -s -uno --ignore-submodules=none >actual &&
test_cmp expect actual
'
test_expect_success 'rm of a populated nested submodule with nested modifications fails unless forced' '
git reset --hard &&
git submodule update --recursive &&
- (cd submod/subsubmod &&
- echo X >empty
- ) &&
+ echo X >submod/subsubmod/empty &&
test_must_fail git rm submod &&
test -d submod &&
test -f submod/.git &&
- git status -s -uno --ignore-submodules=none > actual &&
+ git status -s -uno --ignore-submodules=none >actual &&
test_cmp expect.modified actual &&
git rm -f submod &&
test ! -d submod &&
- git status -s -uno --ignore-submodules=none > actual &&
+ git status -s -uno --ignore-submodules=none >actual &&
test_cmp expect actual
'
test_expect_success 'rm of a populated nested submodule with nested untracked files fails unless forced' '
git reset --hard &&
git submodule update --recursive &&
- (cd submod/subsubmod &&
- echo X >untracked
- ) &&
+ echo X >submod/subsubmod/untracked &&
test_must_fail git rm submod &&
test -d submod &&
test -f submod/.git &&
- git status -s -uno --ignore-submodules=none > actual &&
+ git status -s -uno --ignore-submodules=none >actual &&
test_cmp expect.modified actual &&
git rm -f submod &&
test ! -d submod &&
- git status -s -uno --ignore-submodules=none > actual &&
+ git status -s -uno --ignore-submodules=none >actual &&
test_cmp expect actual
'
git submodule update --recursive &&
(cd submod/subsubmod &&
rm .git &&
- cp -R ../../.git/modules/sub/modules/sub .git &&
+ mv ../../.git/modules/sub/modules/sub .git &&
GIT_WORK_TREE=. git config --unset core.worktree
) &&
- test_must_fail git rm submod &&
- test -d submod &&
- test -d submod/subsubmod/.git &&
- git status -s -uno --ignore-submodules=none >actual &&
- ! test -s actual &&
- test_must_fail git rm -f submod &&
- test -d submod &&
- test -d submod/subsubmod/.git &&
+ git rm submod 2>output.err &&
+ ! test -d submod &&
+ ! test -d submod/subsubmod/.git &&
git status -s -uno --ignore-submodules=none >actual &&
- ! test -s actual &&
- rm -rf submod
+ test -s actual &&
+ test_i18ngrep Migrating output.err
'
test_expect_success 'checking out a commit after submodule removal needs manual updates' '
- git commit -m "submodule removal" submod &&
+ git commit -m "submodule removal" submod .gitmodules &&
git checkout HEAD^ &&
git submodule update &&
- git checkout -q HEAD^ 2>actual &&
+ git checkout -q HEAD^ &&
git checkout -q master 2>actual &&
test_i18ngrep "^warning: unable to rmdir submod:" actual &&
git status -s submod >actual &&
echo "?? submod/" >expected &&
test_cmp expected actual &&
rm -rf submod &&
- git status -s -uno --ignore-submodules=none > actual &&
+ git status -s -uno --ignore-submodules=none >actual &&
! test -s actual
'