summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/git-mv.txt2
-rw-r--r--builtin/mv.c10
-rw-r--r--submodule.c34
-rw-r--r--submodule.h1
-rwxr-xr-xt/t7001-mv.sh75
5 files changed, 121 insertions, 1 deletions
diff --git a/Documentation/git-mv.txt b/Documentation/git-mv.txt
index 1f6fce083e..b1f79881ef 100644
--- a/Documentation/git-mv.txt
+++ b/Documentation/git-mv.txt
@@ -49,6 +49,8 @@ SUBMODULES
Moving a submodule using a gitfile (which means they were cloned
with a Git version 1.7.8 or newer) will update the gitfile and
core.worktree setting to make the submodule work in the new location.
+It also will attempt to update the submodule.<name>.path setting in
+the linkgit:gitmodules[5] file and stage that file (unless -n is used).
GIT
---
diff --git a/builtin/mv.c b/builtin/mv.c
index 68b7060a47..7dd6bb491c 100644
--- a/builtin/mv.c
+++ b/builtin/mv.c
@@ -58,7 +58,7 @@ static struct lock_file lock_file;
int cmd_mv(int argc, const char **argv, const char *prefix)
{
- int i, newfd;
+ int i, newfd, gitmodules_modified = 0;
int verbose = 0, show_only = 0, force = 0, ignore_errors = 0;
struct option builtin_mv_options[] = {
OPT__VERBOSE(&verbose, N_("be verbose")),
@@ -72,6 +72,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
struct stat st;
struct string_list src_for_dst = STRING_LIST_INIT_NODUP;
+ gitmodules_config();
git_config(git_default_config, NULL);
argc = parse_options(argc, argv, prefix, builtin_mv_options,
@@ -125,6 +126,8 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
struct strbuf submodule_dotgit = STRBUF_INIT;
if (!S_ISGITLINK(active_cache[first]->ce_mode))
die (_("Huh? Directory %s is in index and no submodule?"), src);
+ if (!is_staging_gitmodules_ok())
+ die (_("Please, stage your changes to .gitmodules or stash them to proceed"));
strbuf_addf(&submodule_dotgit, "%s/.git", src);
submodule_gitfile[i] = read_gitfile(submodule_dotgit.buf);
if (submodule_gitfile[i])
@@ -229,6 +232,8 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
die_errno (_("renaming '%s' failed"), src);
if (submodule_gitfile[i])
connect_work_tree_and_git_dir(dst, submodule_gitfile[i]);
+ if (!update_path_in_gitmodules(src, dst))
+ gitmodules_modified = 1;
}
if (mode == WORKING_DIRECTORY)
@@ -240,6 +245,9 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
rename_cache_entry_at(pos, dst);
}
+ if (gitmodules_modified)
+ stage_updated_gitmodules();
+
if (active_cache_changed) {
if (write_cache(newfd, active_cache, active_nr) ||
commit_locked_index(&lock_file))
diff --git a/submodule.c b/submodule.c
index fb5134a43b..d4e8276f17 100644
--- a/submodule.c
+++ b/submodule.c
@@ -47,6 +47,40 @@ int is_staging_gitmodules_ok(void)
return !gitmodules_is_modified;
}
+/*
+ * Try to update the "path" entry in the "submodule.<name>" section of the
+ * .gitmodules file. Return 0 only if a .gitmodules file was found, a section
+ * with the correct path=<oldpath> setting was found and we could update it.
+ */
+int update_path_in_gitmodules(const char *oldpath, const char *newpath)
+{
+ struct strbuf entry = STRBUF_INIT;
+ struct string_list_item *path_option;
+
+ if (!file_exists(".gitmodules")) /* Do nothing without .gitmodules */
+ return -1;
+
+ if (gitmodules_is_unmerged)
+ die(_("Cannot change unmerged .gitmodules, resolve merge conflicts first"));
+
+ path_option = unsorted_string_list_lookup(&config_name_for_path, oldpath);
+ if (!path_option) {
+ warning(_("Could not find section in .gitmodules where path=%s"), oldpath);
+ return -1;
+ }
+ strbuf_addstr(&entry, "submodule.");
+ strbuf_addstr(&entry, path_option->util);
+ strbuf_addstr(&entry, ".path");
+ if (git_config_set_in_file(".gitmodules", entry.buf, newpath) < 0) {
+ /* Maybe the user already did that, don't error out here */
+ warning(_("Could not update .gitmodules entry %s"), entry.buf);
+ strbuf_release(&entry);
+ return -1;
+ }
+ strbuf_release(&entry);
+ return 0;
+}
+
void stage_updated_gitmodules(void)
{
struct strbuf buf = STRBUF_INIT;
diff --git a/submodule.h b/submodule.h
index 5501354568..e3398917c5 100644
--- a/submodule.h
+++ b/submodule.h
@@ -12,6 +12,7 @@ enum {
};
int is_staging_gitmodules_ok(void);
+int update_path_in_gitmodules(const char *oldpath, const char *newpath);
void stage_updated_gitmodules(void);
void set_diffopt_flags_from_submodule_config(struct diff_options *diffopt,
const char *path);
diff --git a/t/t7001-mv.sh b/t/t7001-mv.sh
index b99177f689..d432f42bcb 100755
--- a/t/t7001-mv.sh
+++ b/t/t7001-mv.sh
@@ -308,8 +308,83 @@ test_expect_success 'git mv moves a submodule with gitfile' '
cd mod/sub &&
git status
) &&
+ echo mod/sub >expected &&
+ git config -f .gitmodules submodule.sub.path >actual &&
+ test_cmp expected actual &&
git update-index --refresh &&
git diff-files --quiet
'
+test_expect_success 'mv does not complain when no .gitmodules file is found' '
+ rm -rf mod/sub &&
+ git reset --hard &&
+ git submodule update &&
+ git rm .gitmodules &&
+ entry="$(git ls-files --stage sub | cut -f 1)" &&
+ git mv sub mod/sub 2>actual.err &&
+ ! test -s actual.err &&
+ ! test -e sub &&
+ [ "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" ] &&
+ (
+ cd mod/sub &&
+ git status
+ ) &&
+ git update-index --refresh &&
+ git diff-files --quiet
+'
+
+test_expect_success 'mv will error out on a modified .gitmodules file unless staged' '
+ rm -rf mod/sub &&
+ git reset --hard &&
+ git submodule update &&
+ git config -f .gitmodules foo.bar true &&
+ entry="$(git ls-files --stage sub | cut -f 1)" &&
+ test_must_fail git mv sub mod/sub 2>actual.err &&
+ test -s actual.err &&
+ test -e sub &&
+ git diff-files --quiet -- sub &&
+ git add .gitmodules &&
+ git mv sub mod/sub 2>actual.err &&
+ ! test -s actual.err &&
+ ! test -e sub &&
+ [ "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" ] &&
+ (
+ cd mod/sub &&
+ git status
+ ) &&
+ git update-index --refresh &&
+ git diff-files --quiet
+'
+
+test_expect_success 'mv issues a warning when section is not found in .gitmodules' '
+ rm -rf mod/sub &&
+ git reset --hard &&
+ git submodule update &&
+ git config -f .gitmodules --remove-section submodule.sub &&
+ git add .gitmodules &&
+ entry="$(git ls-files --stage sub | cut -f 1)" &&
+ echo "warning: Could not find section in .gitmodules where path=sub" >expect.err &&
+ git mv sub mod/sub 2>actual.err &&
+ test_i18ncmp expect.err actual.err &&
+ ! test -e sub &&
+ [ "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" ] &&
+ (
+ cd mod/sub &&
+ git status
+ ) &&
+ git update-index --refresh &&
+ git diff-files --quiet
+'
+
+test_expect_success 'mv --dry-run does not touch the submodule or .gitmodules' '
+ rm -rf mod/sub &&
+ git reset --hard &&
+ git submodule update &&
+ git mv -n sub mod/sub 2>actual.err &&
+ test -f sub/.git &&
+ git diff-index --exit-code HEAD &&
+ git update-index --refresh &&
+ git diff-files --quiet -- sub .gitmodules
+'
+
test_done