Skip to content

Commit

Permalink
mv: move submodules using a gitfile
Browse files Browse the repository at this point in the history
When moving a submodule which uses a gitfile to point to the git directory
stored in .git/modules/<name> of the superproject two changes must be made
to make the submodule work: the .git file and the core.worktree setting
must be adjusted to point from work tree to git directory and back.

Achieve that by remembering which submodule uses a gitfile by storing the
result of read_gitfile() of each submodule. If that is not NULL the new
function connect_work_tree_and_git_dir() is called after renaming the
submodule's work tree which updates the two settings to the new values.

Extend the man page to inform the user about that feature (and while at it
change the description to not talk about a script anymore, as mv is a
builtin for quite some time now).

Signed-off-by: Jens Lehmann <[email protected]>
Signed-off-by: Junio C Hamano <[email protected]>
  • Loading branch information
jlehmann authored and gitster committed Jul 30, 2013
1 parent 1150246 commit a88c915
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 5 deletions.
8 changes: 7 additions & 1 deletion Documentation/git-mv.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ SYNOPSIS

DESCRIPTION
-----------
This script is used to move or rename a file, directory or symlink.
Move or rename a file, directory or symlink.

git mv [-v] [-f] [-n] [-k] <source> <destination>
git mv [-v] [-f] [-n] [-k] <source> ... <destination directory>
Expand Down Expand Up @@ -44,6 +44,12 @@ OPTIONS
--verbose::
Report the names of files as they are moved.

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.

GIT
---
Part of the linkgit:git[1] suite
19 changes: 15 additions & 4 deletions builtin/mv.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "cache-tree.h"
#include "string-list.h"
#include "parse-options.h"
#include "submodule.h"

static const char * const builtin_mv_usage[] = {
N_("git mv [options] <source>... <destination>"),
Expand Down Expand Up @@ -66,7 +67,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
OPT_BOOLEAN('k', NULL, &ignore_errors, N_("skip move/rename errors")),
OPT_END(),
};
const char **source, **destination, **dest_path;
const char **source, **destination, **dest_path, **submodule_gitfile;
enum update_mode { BOTH = 0, WORKING_DIRECTORY, INDEX } *modes;
struct stat st;
struct string_list src_for_dst = STRING_LIST_INIT_NODUP;
Expand All @@ -85,6 +86,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
source = internal_copy_pathspec(prefix, argv, argc, 0);
modes = xcalloc(argc, sizeof(enum update_mode));
dest_path = internal_copy_pathspec(prefix, argv + argc, 1, 0);
submodule_gitfile = xcalloc(argc, sizeof(char *));

if (dest_path[0][0] == '\0')
/* special case: "." was normalized to "" */
Expand Down Expand Up @@ -120,8 +122,14 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
else if (src_is_dir) {
int first = cache_name_pos(src, length);
if (first >= 0) {
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);
strbuf_addf(&submodule_dotgit, "%s/.git", src);
submodule_gitfile[i] = read_gitfile(submodule_dotgit.buf);
if (submodule_gitfile[i])
submodule_gitfile[i] = xstrdup(submodule_gitfile[i]);
strbuf_release(&submodule_dotgit);
} else {
const char *src_w_slash = add_slash(src);
int last, len_w_slash = length + 1;
Expand Down Expand Up @@ -216,9 +224,12 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
int pos;
if (show_only || verbose)
printf(_("Renaming %s to %s\n"), src, dst);
if (!show_only && mode != INDEX &&
rename(src, dst) < 0 && !ignore_errors)
die_errno (_("renaming '%s' failed"), src);
if (!show_only && mode != INDEX) {
if (rename(src, dst) < 0 && !ignore_errors)
die_errno (_("renaming '%s' failed"), src);
if (submodule_gitfile[i])
connect_work_tree_and_git_dir(dst, submodule_gitfile[i]);
}

if (mode == WORKING_DIRECTORY)
continue;
Expand Down
31 changes: 31 additions & 0 deletions submodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -1004,3 +1004,34 @@ int merge_submodule(unsigned char result[20], const char *path,
free(merges.objects);
return 0;
}

/* Update gitfile and core.worktree setting to connect work tree and git dir */
void connect_work_tree_and_git_dir(const char *work_tree, const char *git_dir)
{
struct strbuf file_name = STRBUF_INIT;
struct strbuf rel_path = STRBUF_INIT;
const char *real_work_tree = xstrdup(real_path(work_tree));
FILE *fp;

/* Update gitfile */
strbuf_addf(&file_name, "%s/.git", work_tree);
fp = fopen(file_name.buf, "w");
if (!fp)
die(_("Could not create git link %s"), file_name.buf);
fprintf(fp, "gitdir: %s\n", relative_path(git_dir, real_work_tree,
&rel_path));
fclose(fp);

/* Update core.worktree setting */
strbuf_reset(&file_name);
strbuf_addf(&file_name, "%s/config", git_dir);
if (git_config_set_in_file(file_name.buf, "core.worktree",
relative_path(real_work_tree, git_dir,
&rel_path)))
die(_("Could not set core.worktree in %s"),
file_name.buf);

strbuf_release(&file_name);
strbuf_release(&rel_path);
free((void *)real_work_tree);
}
1 change: 1 addition & 0 deletions submodule.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,6 @@ int merge_submodule(unsigned char result[20], const char *path, const unsigned c
int find_unpushed_submodules(unsigned char new_sha1[20], const char *remotes_name,
struct string_list *needs_pushing);
int push_unpushed_submodules(unsigned char new_sha1[20], const char *remotes_name);
void connect_work_tree_and_git_dir(const char *work_tree, const char *git_dir);

#endif
19 changes: 19 additions & 0 deletions t/t7001-mv.sh
Original file line number Diff line number Diff line change
Expand Up @@ -293,4 +293,23 @@ test_expect_success 'git mv moves a submodule with a .git directory and no .gitm
git diff-files --quiet
'

test_expect_success 'git mv moves a submodule with gitfile' '
rm -rf mod/sub &&
git reset --hard &&
git submodule update &&
entry="$(git ls-files --stage sub | cut -f 1)" &&
(
cd mod &&
git mv ../sub/ .
) &&
! 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_done

0 comments on commit a88c915

Please sign in to comment.