Merge branch 'jl/submodule-mv'
"git mv A B" when moving a submodule A does "the right thing",
inclusing relocating its working tree and adjusting the paths in
the .gitmodules file.
* jl/submodule-mv: (53 commits)
rm: delete .gitmodules entry of submodules removed from the work tree
mv: update the path entry in .gitmodules for moved submodules
submodule.c: add .gitmodules staging helper functions
mv: move submodules using a gitfile
mv: move submodules together with their work trees
rm: do not set a variable twice without intermediate reading.
t6131 - skip tests if on case-insensitive file system
parse_pathspec: accept :(icase)path syntax
pathspec: support :(glob) syntax
pathspec: make --literal-pathspecs disable pathspec magic
pathspec: support :(literal) syntax for noglob pathspec
kill limit_pathspec_to_literal() as it's only used by parse_pathspec()
parse_pathspec: preserve prefix length via PATHSPEC_PREFIX_ORIGIN
parse_pathspec: make sure the prefix part is wildcard-free
rename field "raw" to "_raw" in struct pathspec
tree-diff: remove the use of pathspec's raw[] in follow-rename codepath
remove match_pathspec() in favor of match_pathspec_depth()
remove init_pathspec() in favor of parse_pathspec()
remove diff_tree_{setup,release}_paths
convert common_prefix() to use struct pathspec
...
This commit is contained in:
149
submodule.c
149
submodule.c
@ -10,6 +10,7 @@
|
||||
#include "string-list.h"
|
||||
#include "sha1-array.h"
|
||||
#include "argv-array.h"
|
||||
#include "blob.h"
|
||||
|
||||
static struct string_list config_name_for_path;
|
||||
static struct string_list config_fetch_recurse_submodules_for_name;
|
||||
@ -30,6 +31,118 @@ static struct sha1_array ref_tips_after_fetch;
|
||||
*/
|
||||
static int gitmodules_is_unmerged;
|
||||
|
||||
/*
|
||||
* This flag is set if the .gitmodules file had unstaged modifications on
|
||||
* startup. This must be checked before allowing modifications to the
|
||||
* .gitmodules file with the intention to stage them later, because when
|
||||
* continuing we would stage the modifications the user didn't stage herself
|
||||
* too. That might change in a future version when we learn to stage the
|
||||
* changes we do ourselves without staging any previous modifications.
|
||||
*/
|
||||
static int gitmodules_is_modified;
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to remove the "submodule.<name>" section from .gitmodules where the given
|
||||
* path is configured. Return 0 only if a .gitmodules file was found, a section
|
||||
* with the correct path=<path> setting was found and we could remove it.
|
||||
*/
|
||||
int remove_path_from_gitmodules(const char *path)
|
||||
{
|
||||
struct strbuf sect = 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, path);
|
||||
if (!path_option) {
|
||||
warning(_("Could not find section in .gitmodules where path=%s"), path);
|
||||
return -1;
|
||||
}
|
||||
strbuf_addstr(§, "submodule.");
|
||||
strbuf_addstr(§, path_option->util);
|
||||
if (git_config_rename_section_in_file(".gitmodules", sect.buf, NULL) < 0) {
|
||||
/* Maybe the user already did that, don't error out here */
|
||||
warning(_("Could not remove .gitmodules entry for %s"), path);
|
||||
strbuf_release(§);
|
||||
return -1;
|
||||
}
|
||||
strbuf_release(§);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void stage_updated_gitmodules(void)
|
||||
{
|
||||
struct strbuf buf = STRBUF_INIT;
|
||||
struct stat st;
|
||||
int pos;
|
||||
struct cache_entry *ce;
|
||||
int namelen = strlen(".gitmodules");
|
||||
|
||||
pos = cache_name_pos(".gitmodules", namelen);
|
||||
if (pos < 0) {
|
||||
warning(_("could not find .gitmodules in index"));
|
||||
return;
|
||||
}
|
||||
ce = active_cache[pos];
|
||||
ce->ce_flags = namelen;
|
||||
if (strbuf_read_file(&buf, ".gitmodules", 0) < 0)
|
||||
die(_("reading updated .gitmodules failed"));
|
||||
if (lstat(".gitmodules", &st) < 0)
|
||||
die_errno(_("unable to stat updated .gitmodules"));
|
||||
fill_stat_cache_info(ce, &st);
|
||||
ce->ce_mode = ce_mode_from_stat(ce, st.st_mode);
|
||||
if (remove_cache_entry_at(pos) < 0)
|
||||
die(_("unable to remove .gitmodules from index"));
|
||||
if (write_sha1_file(buf.buf, buf.len, blob_type, ce->sha1))
|
||||
die(_("adding updated .gitmodules failed"));
|
||||
if (add_cache_entry(ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE))
|
||||
die(_("staging updated .gitmodules failed"));
|
||||
}
|
||||
|
||||
static int add_submodule_odb(const char *path)
|
||||
{
|
||||
struct strbuf objects_directory = STRBUF_INIT;
|
||||
@ -116,6 +229,11 @@ void gitmodules_config(void)
|
||||
!memcmp(ce->name, ".gitmodules", 11))
|
||||
gitmodules_is_unmerged = 1;
|
||||
}
|
||||
} else if (pos < active_nr) {
|
||||
struct stat st;
|
||||
if (lstat(".gitmodules", &st) == 0 &&
|
||||
ce_match_stat(active_cache[pos], &st, 0) & DATA_CHANGED)
|
||||
gitmodules_is_modified = 1;
|
||||
}
|
||||
|
||||
if (!gitmodules_is_unmerged)
|
||||
@ -1010,3 +1128,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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user