2017-12-12 22:53:52 +03:00
|
|
|
#define NO_THE_INDEX_COMPATIBILITY_MACROS
|
|
|
|
|
2009-10-19 16:38:32 +04:00
|
|
|
#include "cache.h"
|
2017-06-22 21:43:45 +03:00
|
|
|
#include "repository.h"
|
2017-06-14 21:07:36 +03:00
|
|
|
#include "config.h"
|
2015-08-18 03:21:59 +03:00
|
|
|
#include "submodule-config.h"
|
2009-10-19 16:38:32 +04:00
|
|
|
#include "submodule.h"
|
|
|
|
#include "dir.h"
|
|
|
|
#include "diff.h"
|
|
|
|
#include "commit.h"
|
|
|
|
#include "revision.h"
|
2010-01-16 20:42:24 +03:00
|
|
|
#include "run-command.h"
|
2010-03-05 00:20:33 +03:00
|
|
|
#include "diffcore.h"
|
2010-07-07 17:39:13 +04:00
|
|
|
#include "refs.h"
|
2010-08-06 02:39:25 +04:00
|
|
|
#include "string-list.h"
|
2011-09-12 23:56:52 +04:00
|
|
|
#include "sha1-array.h"
|
2011-09-14 01:57:57 +04:00
|
|
|
#include "argv-array.h"
|
2013-07-30 23:50:34 +04:00
|
|
|
#include "blob.h"
|
2015-12-16 03:04:11 +03:00
|
|
|
#include "thread-utils.h"
|
2016-04-28 16:38:20 +03:00
|
|
|
#include "quote.h"
|
2017-04-05 20:47:19 +03:00
|
|
|
#include "remote.h"
|
2016-12-12 22:04:35 +03:00
|
|
|
#include "worktree.h"
|
2017-06-01 03:30:47 +03:00
|
|
|
#include "parse-options.h"
|
2018-03-23 20:20:56 +03:00
|
|
|
#include "object-store.h"
|
2018-07-20 19:33:04 +03:00
|
|
|
#include "commit-reach.h"
|
2010-08-06 02:39:25 +04:00
|
|
|
|
2017-05-26 22:10:12 +03:00
|
|
|
static int config_update_recurse_submodules = RECURSE_SUBMODULES_OFF;
|
2017-10-16 16:58:27 +03:00
|
|
|
static struct string_list changed_submodule_names = STRING_LIST_INIT_DUP;
|
2011-09-12 23:56:52 +04:00
|
|
|
static int initialized_fetch_ref_tips;
|
2017-03-31 04:40:00 +03:00
|
|
|
static struct oid_array ref_tips_before_fetch;
|
|
|
|
static struct oid_array ref_tips_after_fetch;
|
2011-09-12 23:56:52 +04:00
|
|
|
|
2011-05-14 20:26:58 +04:00
|
|
|
/*
|
2017-08-02 22:49:21 +03:00
|
|
|
* Check if the .gitmodules file is unmerged. Parsing of the .gitmodules file
|
|
|
|
* will be disabled because we can't guess what might be configured in
|
|
|
|
* .gitmodules unless the user resolves the conflict.
|
2011-05-14 20:26:58 +04:00
|
|
|
*/
|
2017-08-02 22:49:21 +03:00
|
|
|
int is_gitmodules_unmerged(const struct index_state *istate)
|
|
|
|
{
|
|
|
|
int pos = index_name_pos(istate, GITMODULES_FILE, strlen(GITMODULES_FILE));
|
|
|
|
if (pos < 0) { /* .gitmodules not found or isn't merged */
|
|
|
|
pos = -1 - pos;
|
|
|
|
if (istate->cache_nr > pos) { /* there is a .gitmodules */
|
|
|
|
const struct cache_entry *ce = istate->cache[pos];
|
|
|
|
if (ce_namelen(ce) == strlen(GITMODULES_FILE) &&
|
|
|
|
!strcmp(ce->name, GITMODULES_FILE))
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2009-10-19 16:38:32 +04:00
|
|
|
|
2018-10-05 16:05:59 +03:00
|
|
|
/*
|
|
|
|
* Check if the .gitmodules file is safe to write.
|
|
|
|
*
|
|
|
|
* Writing to the .gitmodules file requires that the file exists in the
|
|
|
|
* working tree or, if it doesn't, that a brand new .gitmodules file is going
|
|
|
|
* to be created (i.e. it's neither in the index nor in the current branch).
|
|
|
|
*
|
|
|
|
* It is not safe to write to .gitmodules if it's not in the working tree but
|
|
|
|
* it is in the index or in the current branch, because writing new values
|
|
|
|
* (and staging them) would blindly overwrite ALL the old content.
|
|
|
|
*/
|
|
|
|
int is_writing_gitmodules_ok(void)
|
|
|
|
{
|
|
|
|
struct object_id oid;
|
|
|
|
return file_exists(GITMODULES_FILE) ||
|
|
|
|
(get_oid(GITMODULES_INDEX, &oid) < 0 && get_oid(GITMODULES_HEAD, &oid) < 0);
|
|
|
|
}
|
|
|
|
|
2013-07-30 23:50:34 +04:00
|
|
|
/*
|
2017-08-02 22:49:20 +03:00
|
|
|
* Check if the .gitmodules file has unstaged modifications. 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.
|
2013-07-30 23:50:34 +04:00
|
|
|
*/
|
2017-12-12 22:53:51 +03:00
|
|
|
int is_staging_gitmodules_ok(struct index_state *istate)
|
2013-07-30 23:50:34 +04:00
|
|
|
{
|
2017-08-02 22:49:20 +03:00
|
|
|
int pos = index_name_pos(istate, GITMODULES_FILE, strlen(GITMODULES_FILE));
|
|
|
|
|
|
|
|
if ((pos >= 0) && (pos < istate->cache_nr)) {
|
|
|
|
struct stat st;
|
|
|
|
if (lstat(GITMODULES_FILE, &st) == 0 &&
|
2018-09-10 19:29:29 +03:00
|
|
|
ie_match_stat(istate, istate->cache[pos], &st, 0) & DATA_CHANGED)
|
2017-08-02 22:49:20 +03:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
2013-07-30 23:50:34 +04:00
|
|
|
}
|
|
|
|
|
2017-08-23 15:36:57 +03:00
|
|
|
static int for_each_remote_ref_submodule(const char *submodule,
|
|
|
|
each_ref_fn fn, void *cb_data)
|
|
|
|
{
|
|
|
|
return refs_for_each_remote_ref(get_submodule_ref_store(submodule),
|
|
|
|
fn, cb_data);
|
|
|
|
}
|
|
|
|
|
2013-08-06 23:15:11 +04:00
|
|
|
/*
|
|
|
|
* 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;
|
2015-08-18 03:21:59 +03:00
|
|
|
const struct submodule *submodule;
|
2018-10-05 16:05:53 +03:00
|
|
|
int ret;
|
2013-08-06 23:15:11 +04:00
|
|
|
|
2017-08-02 22:49:16 +03:00
|
|
|
if (!file_exists(GITMODULES_FILE)) /* Do nothing without .gitmodules */
|
2013-08-06 23:15:11 +04:00
|
|
|
return -1;
|
|
|
|
|
2018-08-13 19:14:31 +03:00
|
|
|
if (is_gitmodules_unmerged(the_repository->index))
|
2013-08-06 23:15:11 +04:00
|
|
|
die(_("Cannot change unmerged .gitmodules, resolve merge conflicts first"));
|
|
|
|
|
2018-03-29 01:35:29 +03:00
|
|
|
submodule = submodule_from_path(the_repository, &null_oid, oldpath);
|
2015-08-18 03:21:59 +03:00
|
|
|
if (!submodule || !submodule->name) {
|
2013-08-06 23:15:11 +04:00
|
|
|
warning(_("Could not find section in .gitmodules where path=%s"), oldpath);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
strbuf_addstr(&entry, "submodule.");
|
2015-08-18 03:21:59 +03:00
|
|
|
strbuf_addstr(&entry, submodule->name);
|
2013-08-06 23:15:11 +04:00
|
|
|
strbuf_addstr(&entry, ".path");
|
2018-10-05 16:05:53 +03:00
|
|
|
ret = config_set_in_gitmodules_file_gently(entry.buf, newpath);
|
2013-08-06 23:15:11 +04:00
|
|
|
strbuf_release(&entry);
|
2018-10-05 16:05:53 +03:00
|
|
|
return ret;
|
2013-08-06 23:15:11 +04:00
|
|
|
}
|
|
|
|
|
2013-08-06 23:15:25 +04:00
|
|
|
/*
|
|
|
|
* 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;
|
2015-08-18 03:21:59 +03:00
|
|
|
const struct submodule *submodule;
|
2013-08-06 23:15:25 +04:00
|
|
|
|
2017-08-02 22:49:16 +03:00
|
|
|
if (!file_exists(GITMODULES_FILE)) /* Do nothing without .gitmodules */
|
2013-08-06 23:15:25 +04:00
|
|
|
return -1;
|
|
|
|
|
2018-08-13 19:14:31 +03:00
|
|
|
if (is_gitmodules_unmerged(the_repository->index))
|
2013-08-06 23:15:25 +04:00
|
|
|
die(_("Cannot change unmerged .gitmodules, resolve merge conflicts first"));
|
|
|
|
|
2018-03-29 01:35:29 +03:00
|
|
|
submodule = submodule_from_path(the_repository, &null_oid, path);
|
2015-08-18 03:21:59 +03:00
|
|
|
if (!submodule || !submodule->name) {
|
2013-08-06 23:15:25 +04:00
|
|
|
warning(_("Could not find section in .gitmodules where path=%s"), path);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
strbuf_addstr(§, "submodule.");
|
2015-08-18 03:21:59 +03:00
|
|
|
strbuf_addstr(§, submodule->name);
|
2017-08-02 22:49:16 +03:00
|
|
|
if (git_config_rename_section_in_file(GITMODULES_FILE, sect.buf, NULL) < 0) {
|
2013-08-06 23:15:25 +04:00
|
|
|
/* 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;
|
|
|
|
}
|
|
|
|
|
2017-12-12 22:53:50 +03:00
|
|
|
void stage_updated_gitmodules(struct index_state *istate)
|
2013-07-30 23:50:34 +04:00
|
|
|
{
|
2017-12-12 22:53:50 +03:00
|
|
|
if (add_file_to_index(istate, GITMODULES_FILE, 0))
|
2013-07-30 23:50:34 +04:00
|
|
|
die(_("staging updated .gitmodules failed"));
|
|
|
|
}
|
|
|
|
|
2018-05-15 23:00:28 +03:00
|
|
|
/* TODO: remove this function, use repo_submodule_init instead. */
|
|
|
|
int add_submodule_odb(const char *path)
|
2009-10-19 16:38:32 +04:00
|
|
|
{
|
|
|
|
struct strbuf objects_directory = STRBUF_INIT;
|
2010-01-31 19:43:49 +03:00
|
|
|
int ret = 0;
|
2009-10-19 16:38:32 +04:00
|
|
|
|
2016-09-01 02:27:22 +03:00
|
|
|
ret = strbuf_git_path_submodule(&objects_directory, path, "objects/");
|
|
|
|
if (ret)
|
|
|
|
goto done;
|
2010-01-31 19:43:49 +03:00
|
|
|
if (!is_directory(objects_directory.buf)) {
|
|
|
|
ret = -1;
|
|
|
|
goto done;
|
|
|
|
}
|
2016-10-03 23:35:03 +03:00
|
|
|
add_to_alternates_memory(objects_directory.buf);
|
2010-01-31 19:43:49 +03:00
|
|
|
done:
|
|
|
|
strbuf_release(&objects_directory);
|
|
|
|
return ret;
|
2009-10-19 16:38:32 +04:00
|
|
|
}
|
|
|
|
|
2010-08-06 02:39:25 +04:00
|
|
|
void set_diffopt_flags_from_submodule_config(struct diff_options *diffopt,
|
|
|
|
const char *path)
|
|
|
|
{
|
2018-03-29 01:35:29 +03:00
|
|
|
const struct submodule *submodule = submodule_from_path(the_repository,
|
|
|
|
&null_oid, path);
|
2015-08-18 03:21:59 +03:00
|
|
|
if (submodule) {
|
2017-08-03 21:19:52 +03:00
|
|
|
const char *ignore;
|
|
|
|
char *key;
|
2010-08-06 02:39:25 +04:00
|
|
|
|
2017-08-03 21:19:52 +03:00
|
|
|
key = xstrfmt("submodule.%s.ignore", submodule->name);
|
|
|
|
if (repo_config_get_string_const(the_repository, key, &ignore))
|
|
|
|
ignore = submodule->ignore;
|
|
|
|
free(key);
|
2010-08-06 02:40:48 +04:00
|
|
|
|
2017-08-03 21:19:52 +03:00
|
|
|
if (ignore)
|
|
|
|
handle_ignore_submodules_arg(diffopt, ignore);
|
2018-08-13 19:14:31 +03:00
|
|
|
else if (is_gitmodules_unmerged(the_repository->index))
|
2017-10-31 21:19:11 +03:00
|
|
|
diffopt->flags.ignore_submodules = 1;
|
2017-06-01 03:30:47 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Cheap function that only determines if we're interested in submodules at all */
|
|
|
|
int git_default_submodule_config(const char *var, const char *value, void *cb)
|
|
|
|
{
|
|
|
|
if (!strcmp(var, "submodule.recurse")) {
|
|
|
|
int v = git_config_bool(var, value) ?
|
|
|
|
RECURSE_SUBMODULES_ON : RECURSE_SUBMODULES_OFF;
|
|
|
|
config_update_recurse_submodules = v;
|
|
|
|
}
|
|
|
|
return 0;
|
2017-05-26 22:10:13 +03:00
|
|
|
}
|
|
|
|
|
2017-05-26 22:10:12 +03:00
|
|
|
int option_parse_recurse_submodules_worktree_updater(const struct option *opt,
|
|
|
|
const char *arg, int unset)
|
|
|
|
{
|
|
|
|
if (unset) {
|
|
|
|
config_update_recurse_submodules = RECURSE_SUBMODULES_OFF;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (arg)
|
|
|
|
config_update_recurse_submodules =
|
|
|
|
parse_update_recurse_submodules_arg(opt->long_name,
|
|
|
|
arg);
|
|
|
|
else
|
|
|
|
config_update_recurse_submodules = RECURSE_SUBMODULES_ON;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-12-16 22:03:17 +03:00
|
|
|
/*
|
|
|
|
* Determine if a submodule has been initialized at a given 'path'
|
|
|
|
*/
|
2017-06-22 21:43:46 +03:00
|
|
|
int is_submodule_active(struct repository *repo, const char *path)
|
2016-12-16 22:03:17 +03:00
|
|
|
{
|
|
|
|
int ret = 0;
|
submodule: decouple url and submodule interest
Currently the submodule.<name>.url config option is used to determine if
a given submodule is of interest to the user. This ends up being
cumbersome in a world where we want to have different submodules checked
out in different worktrees or a more generalized mechanism to select
which submodules are of interest.
In a future with worktree support for submodules, there will be multiple
working trees, each of which may only need a subset of the submodules
checked out. The URL (which is where the submodule repository can be
obtained) should not differ between different working trees.
It may also be convenient for users to more easily specify groups of
submodules they are interested in as opposed to running "git submodule
init <path>" on each submodule they want checked out in their working
tree.
To this end two config options are introduced, submodule.active and
submodule.<name>.active. The submodule.active config holds a pathspec
that specifies which submodules should exist in the working tree. The
submodule.<name>.active config is a boolean flag used to indicate if
that particular submodule should exist in the working tree.
Its important to note that submodule.active functions differently than
the other configuration options since it takes a pathspec. This allows
users to adopt at least two new workflows:
1. Submodules can be grouped with a leading directory, such that a
pathspec e.g. 'lib/' would cover all library-ish modules to allow
those who are interested in library-ish modules to set
"submodule.active = lib/" just once to say any and all modules in
'lib/' are interesting.
2. Once the pathspec-attribute feature is invented, users can label
submodules with attributes to group them, so that a broad pathspec
with attribute requirements, e.g. ':(attr:lib)', can be used to say
any and all modules with the 'lib' attribute are interesting.
Since the .gitattributes file, just like the .gitmodules file, is
tracked by the superproject, when a submodule moves in the
superproject tree, the project can adjust which path gets the
attribute in .gitattributes, just like it can adjust which path has
the submodule in .gitmodules.
Neither of these two additional configuration options solve the problem
of wanting different submodules checked out in different worktrees
because multiple worktrees share .git/config. Only once per-worktree
configurations become a reality can this be solved, but this is a
necessary preparatory step for that future.
Given these multiple ways to check if a submodule is of interest, the
more fine-grained submodule.<name>.active option has the highest order
of precedence followed by the pathspec check against submodule.active.
To ensure backwards compatibility, if neither of these options are set,
git falls back to checking the submodule.<name>.url option to determine
if a submodule is interesting.
Signed-off-by: Brandon Williams <bmwill@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-18 01:38:01 +03:00
|
|
|
char *key = NULL;
|
|
|
|
char *value = NULL;
|
|
|
|
const struct string_list *sl;
|
2017-06-22 21:43:46 +03:00
|
|
|
const struct submodule *module;
|
|
|
|
|
2018-03-29 01:35:30 +03:00
|
|
|
module = submodule_from_path(repo, &null_oid, path);
|
2016-12-16 22:03:17 +03:00
|
|
|
|
submodule: decouple url and submodule interest
Currently the submodule.<name>.url config option is used to determine if
a given submodule is of interest to the user. This ends up being
cumbersome in a world where we want to have different submodules checked
out in different worktrees or a more generalized mechanism to select
which submodules are of interest.
In a future with worktree support for submodules, there will be multiple
working trees, each of which may only need a subset of the submodules
checked out. The URL (which is where the submodule repository can be
obtained) should not differ between different working trees.
It may also be convenient for users to more easily specify groups of
submodules they are interested in as opposed to running "git submodule
init <path>" on each submodule they want checked out in their working
tree.
To this end two config options are introduced, submodule.active and
submodule.<name>.active. The submodule.active config holds a pathspec
that specifies which submodules should exist in the working tree. The
submodule.<name>.active config is a boolean flag used to indicate if
that particular submodule should exist in the working tree.
Its important to note that submodule.active functions differently than
the other configuration options since it takes a pathspec. This allows
users to adopt at least two new workflows:
1. Submodules can be grouped with a leading directory, such that a
pathspec e.g. 'lib/' would cover all library-ish modules to allow
those who are interested in library-ish modules to set
"submodule.active = lib/" just once to say any and all modules in
'lib/' are interesting.
2. Once the pathspec-attribute feature is invented, users can label
submodules with attributes to group them, so that a broad pathspec
with attribute requirements, e.g. ':(attr:lib)', can be used to say
any and all modules with the 'lib' attribute are interesting.
Since the .gitattributes file, just like the .gitmodules file, is
tracked by the superproject, when a submodule moves in the
superproject tree, the project can adjust which path gets the
attribute in .gitattributes, just like it can adjust which path has
the submodule in .gitmodules.
Neither of these two additional configuration options solve the problem
of wanting different submodules checked out in different worktrees
because multiple worktrees share .git/config. Only once per-worktree
configurations become a reality can this be solved, but this is a
necessary preparatory step for that future.
Given these multiple ways to check if a submodule is of interest, the
more fine-grained submodule.<name>.active option has the highest order
of precedence followed by the pathspec check against submodule.active.
To ensure backwards compatibility, if neither of these options are set,
git falls back to checking the submodule.<name>.url option to determine
if a submodule is interesting.
Signed-off-by: Brandon Williams <bmwill@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-18 01:38:01 +03:00
|
|
|
/* early return if there isn't a path->module mapping */
|
|
|
|
if (!module)
|
|
|
|
return 0;
|
2016-12-16 22:03:17 +03:00
|
|
|
|
submodule: decouple url and submodule interest
Currently the submodule.<name>.url config option is used to determine if
a given submodule is of interest to the user. This ends up being
cumbersome in a world where we want to have different submodules checked
out in different worktrees or a more generalized mechanism to select
which submodules are of interest.
In a future with worktree support for submodules, there will be multiple
working trees, each of which may only need a subset of the submodules
checked out. The URL (which is where the submodule repository can be
obtained) should not differ between different working trees.
It may also be convenient for users to more easily specify groups of
submodules they are interested in as opposed to running "git submodule
init <path>" on each submodule they want checked out in their working
tree.
To this end two config options are introduced, submodule.active and
submodule.<name>.active. The submodule.active config holds a pathspec
that specifies which submodules should exist in the working tree. The
submodule.<name>.active config is a boolean flag used to indicate if
that particular submodule should exist in the working tree.
Its important to note that submodule.active functions differently than
the other configuration options since it takes a pathspec. This allows
users to adopt at least two new workflows:
1. Submodules can be grouped with a leading directory, such that a
pathspec e.g. 'lib/' would cover all library-ish modules to allow
those who are interested in library-ish modules to set
"submodule.active = lib/" just once to say any and all modules in
'lib/' are interesting.
2. Once the pathspec-attribute feature is invented, users can label
submodules with attributes to group them, so that a broad pathspec
with attribute requirements, e.g. ':(attr:lib)', can be used to say
any and all modules with the 'lib' attribute are interesting.
Since the .gitattributes file, just like the .gitmodules file, is
tracked by the superproject, when a submodule moves in the
superproject tree, the project can adjust which path gets the
attribute in .gitattributes, just like it can adjust which path has
the submodule in .gitmodules.
Neither of these two additional configuration options solve the problem
of wanting different submodules checked out in different worktrees
because multiple worktrees share .git/config. Only once per-worktree
configurations become a reality can this be solved, but this is a
necessary preparatory step for that future.
Given these multiple ways to check if a submodule is of interest, the
more fine-grained submodule.<name>.active option has the highest order
of precedence followed by the pathspec check against submodule.active.
To ensure backwards compatibility, if neither of these options are set,
git falls back to checking the submodule.<name>.url option to determine
if a submodule is interesting.
Signed-off-by: Brandon Williams <bmwill@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-18 01:38:01 +03:00
|
|
|
/* submodule.<name>.active is set */
|
|
|
|
key = xstrfmt("submodule.%s.active", module->name);
|
2017-06-22 21:43:46 +03:00
|
|
|
if (!repo_config_get_bool(repo, key, &ret)) {
|
submodule: decouple url and submodule interest
Currently the submodule.<name>.url config option is used to determine if
a given submodule is of interest to the user. This ends up being
cumbersome in a world where we want to have different submodules checked
out in different worktrees or a more generalized mechanism to select
which submodules are of interest.
In a future with worktree support for submodules, there will be multiple
working trees, each of which may only need a subset of the submodules
checked out. The URL (which is where the submodule repository can be
obtained) should not differ between different working trees.
It may also be convenient for users to more easily specify groups of
submodules they are interested in as opposed to running "git submodule
init <path>" on each submodule they want checked out in their working
tree.
To this end two config options are introduced, submodule.active and
submodule.<name>.active. The submodule.active config holds a pathspec
that specifies which submodules should exist in the working tree. The
submodule.<name>.active config is a boolean flag used to indicate if
that particular submodule should exist in the working tree.
Its important to note that submodule.active functions differently than
the other configuration options since it takes a pathspec. This allows
users to adopt at least two new workflows:
1. Submodules can be grouped with a leading directory, such that a
pathspec e.g. 'lib/' would cover all library-ish modules to allow
those who are interested in library-ish modules to set
"submodule.active = lib/" just once to say any and all modules in
'lib/' are interesting.
2. Once the pathspec-attribute feature is invented, users can label
submodules with attributes to group them, so that a broad pathspec
with attribute requirements, e.g. ':(attr:lib)', can be used to say
any and all modules with the 'lib' attribute are interesting.
Since the .gitattributes file, just like the .gitmodules file, is
tracked by the superproject, when a submodule moves in the
superproject tree, the project can adjust which path gets the
attribute in .gitattributes, just like it can adjust which path has
the submodule in .gitmodules.
Neither of these two additional configuration options solve the problem
of wanting different submodules checked out in different worktrees
because multiple worktrees share .git/config. Only once per-worktree
configurations become a reality can this be solved, but this is a
necessary preparatory step for that future.
Given these multiple ways to check if a submodule is of interest, the
more fine-grained submodule.<name>.active option has the highest order
of precedence followed by the pathspec check against submodule.active.
To ensure backwards compatibility, if neither of these options are set,
git falls back to checking the submodule.<name>.url option to determine
if a submodule is interesting.
Signed-off-by: Brandon Williams <bmwill@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-18 01:38:01 +03:00
|
|
|
free(key);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
free(key);
|
2016-12-16 22:03:17 +03:00
|
|
|
|
submodule: decouple url and submodule interest
Currently the submodule.<name>.url config option is used to determine if
a given submodule is of interest to the user. This ends up being
cumbersome in a world where we want to have different submodules checked
out in different worktrees or a more generalized mechanism to select
which submodules are of interest.
In a future with worktree support for submodules, there will be multiple
working trees, each of which may only need a subset of the submodules
checked out. The URL (which is where the submodule repository can be
obtained) should not differ between different working trees.
It may also be convenient for users to more easily specify groups of
submodules they are interested in as opposed to running "git submodule
init <path>" on each submodule they want checked out in their working
tree.
To this end two config options are introduced, submodule.active and
submodule.<name>.active. The submodule.active config holds a pathspec
that specifies which submodules should exist in the working tree. The
submodule.<name>.active config is a boolean flag used to indicate if
that particular submodule should exist in the working tree.
Its important to note that submodule.active functions differently than
the other configuration options since it takes a pathspec. This allows
users to adopt at least two new workflows:
1. Submodules can be grouped with a leading directory, such that a
pathspec e.g. 'lib/' would cover all library-ish modules to allow
those who are interested in library-ish modules to set
"submodule.active = lib/" just once to say any and all modules in
'lib/' are interesting.
2. Once the pathspec-attribute feature is invented, users can label
submodules with attributes to group them, so that a broad pathspec
with attribute requirements, e.g. ':(attr:lib)', can be used to say
any and all modules with the 'lib' attribute are interesting.
Since the .gitattributes file, just like the .gitmodules file, is
tracked by the superproject, when a submodule moves in the
superproject tree, the project can adjust which path gets the
attribute in .gitattributes, just like it can adjust which path has
the submodule in .gitmodules.
Neither of these two additional configuration options solve the problem
of wanting different submodules checked out in different worktrees
because multiple worktrees share .git/config. Only once per-worktree
configurations become a reality can this be solved, but this is a
necessary preparatory step for that future.
Given these multiple ways to check if a submodule is of interest, the
more fine-grained submodule.<name>.active option has the highest order
of precedence followed by the pathspec check against submodule.active.
To ensure backwards compatibility, if neither of these options are set,
git falls back to checking the submodule.<name>.url option to determine
if a submodule is interesting.
Signed-off-by: Brandon Williams <bmwill@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-18 01:38:01 +03:00
|
|
|
/* submodule.active is set */
|
2017-06-22 21:43:46 +03:00
|
|
|
sl = repo_config_get_value_multi(repo, "submodule.active");
|
submodule: decouple url and submodule interest
Currently the submodule.<name>.url config option is used to determine if
a given submodule is of interest to the user. This ends up being
cumbersome in a world where we want to have different submodules checked
out in different worktrees or a more generalized mechanism to select
which submodules are of interest.
In a future with worktree support for submodules, there will be multiple
working trees, each of which may only need a subset of the submodules
checked out. The URL (which is where the submodule repository can be
obtained) should not differ between different working trees.
It may also be convenient for users to more easily specify groups of
submodules they are interested in as opposed to running "git submodule
init <path>" on each submodule they want checked out in their working
tree.
To this end two config options are introduced, submodule.active and
submodule.<name>.active. The submodule.active config holds a pathspec
that specifies which submodules should exist in the working tree. The
submodule.<name>.active config is a boolean flag used to indicate if
that particular submodule should exist in the working tree.
Its important to note that submodule.active functions differently than
the other configuration options since it takes a pathspec. This allows
users to adopt at least two new workflows:
1. Submodules can be grouped with a leading directory, such that a
pathspec e.g. 'lib/' would cover all library-ish modules to allow
those who are interested in library-ish modules to set
"submodule.active = lib/" just once to say any and all modules in
'lib/' are interesting.
2. Once the pathspec-attribute feature is invented, users can label
submodules with attributes to group them, so that a broad pathspec
with attribute requirements, e.g. ':(attr:lib)', can be used to say
any and all modules with the 'lib' attribute are interesting.
Since the .gitattributes file, just like the .gitmodules file, is
tracked by the superproject, when a submodule moves in the
superproject tree, the project can adjust which path gets the
attribute in .gitattributes, just like it can adjust which path has
the submodule in .gitmodules.
Neither of these two additional configuration options solve the problem
of wanting different submodules checked out in different worktrees
because multiple worktrees share .git/config. Only once per-worktree
configurations become a reality can this be solved, but this is a
necessary preparatory step for that future.
Given these multiple ways to check if a submodule is of interest, the
more fine-grained submodule.<name>.active option has the highest order
of precedence followed by the pathspec check against submodule.active.
To ensure backwards compatibility, if neither of these options are set,
git falls back to checking the submodule.<name>.url option to determine
if a submodule is interesting.
Signed-off-by: Brandon Williams <bmwill@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-18 01:38:01 +03:00
|
|
|
if (sl) {
|
|
|
|
struct pathspec ps;
|
|
|
|
struct argv_array args = ARGV_ARRAY_INIT;
|
|
|
|
const struct string_list_item *item;
|
2016-12-16 22:03:17 +03:00
|
|
|
|
submodule: decouple url and submodule interest
Currently the submodule.<name>.url config option is used to determine if
a given submodule is of interest to the user. This ends up being
cumbersome in a world where we want to have different submodules checked
out in different worktrees or a more generalized mechanism to select
which submodules are of interest.
In a future with worktree support for submodules, there will be multiple
working trees, each of which may only need a subset of the submodules
checked out. The URL (which is where the submodule repository can be
obtained) should not differ between different working trees.
It may also be convenient for users to more easily specify groups of
submodules they are interested in as opposed to running "git submodule
init <path>" on each submodule they want checked out in their working
tree.
To this end two config options are introduced, submodule.active and
submodule.<name>.active. The submodule.active config holds a pathspec
that specifies which submodules should exist in the working tree. The
submodule.<name>.active config is a boolean flag used to indicate if
that particular submodule should exist in the working tree.
Its important to note that submodule.active functions differently than
the other configuration options since it takes a pathspec. This allows
users to adopt at least two new workflows:
1. Submodules can be grouped with a leading directory, such that a
pathspec e.g. 'lib/' would cover all library-ish modules to allow
those who are interested in library-ish modules to set
"submodule.active = lib/" just once to say any and all modules in
'lib/' are interesting.
2. Once the pathspec-attribute feature is invented, users can label
submodules with attributes to group them, so that a broad pathspec
with attribute requirements, e.g. ':(attr:lib)', can be used to say
any and all modules with the 'lib' attribute are interesting.
Since the .gitattributes file, just like the .gitmodules file, is
tracked by the superproject, when a submodule moves in the
superproject tree, the project can adjust which path gets the
attribute in .gitattributes, just like it can adjust which path has
the submodule in .gitmodules.
Neither of these two additional configuration options solve the problem
of wanting different submodules checked out in different worktrees
because multiple worktrees share .git/config. Only once per-worktree
configurations become a reality can this be solved, but this is a
necessary preparatory step for that future.
Given these multiple ways to check if a submodule is of interest, the
more fine-grained submodule.<name>.active option has the highest order
of precedence followed by the pathspec check against submodule.active.
To ensure backwards compatibility, if neither of these options are set,
git falls back to checking the submodule.<name>.url option to determine
if a submodule is interesting.
Signed-off-by: Brandon Williams <bmwill@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-18 01:38:01 +03:00
|
|
|
for_each_string_list_item(item, sl) {
|
|
|
|
argv_array_push(&args, item->string);
|
|
|
|
}
|
|
|
|
|
|
|
|
parse_pathspec(&ps, 0, 0, NULL, args.argv);
|
2018-08-13 19:14:31 +03:00
|
|
|
ret = match_pathspec(repo->index, &ps, path, strlen(path), 0, NULL, 1);
|
submodule: decouple url and submodule interest
Currently the submodule.<name>.url config option is used to determine if
a given submodule is of interest to the user. This ends up being
cumbersome in a world where we want to have different submodules checked
out in different worktrees or a more generalized mechanism to select
which submodules are of interest.
In a future with worktree support for submodules, there will be multiple
working trees, each of which may only need a subset of the submodules
checked out. The URL (which is where the submodule repository can be
obtained) should not differ between different working trees.
It may also be convenient for users to more easily specify groups of
submodules they are interested in as opposed to running "git submodule
init <path>" on each submodule they want checked out in their working
tree.
To this end two config options are introduced, submodule.active and
submodule.<name>.active. The submodule.active config holds a pathspec
that specifies which submodules should exist in the working tree. The
submodule.<name>.active config is a boolean flag used to indicate if
that particular submodule should exist in the working tree.
Its important to note that submodule.active functions differently than
the other configuration options since it takes a pathspec. This allows
users to adopt at least two new workflows:
1. Submodules can be grouped with a leading directory, such that a
pathspec e.g. 'lib/' would cover all library-ish modules to allow
those who are interested in library-ish modules to set
"submodule.active = lib/" just once to say any and all modules in
'lib/' are interesting.
2. Once the pathspec-attribute feature is invented, users can label
submodules with attributes to group them, so that a broad pathspec
with attribute requirements, e.g. ':(attr:lib)', can be used to say
any and all modules with the 'lib' attribute are interesting.
Since the .gitattributes file, just like the .gitmodules file, is
tracked by the superproject, when a submodule moves in the
superproject tree, the project can adjust which path gets the
attribute in .gitattributes, just like it can adjust which path has
the submodule in .gitmodules.
Neither of these two additional configuration options solve the problem
of wanting different submodules checked out in different worktrees
because multiple worktrees share .git/config. Only once per-worktree
configurations become a reality can this be solved, but this is a
necessary preparatory step for that future.
Given these multiple ways to check if a submodule is of interest, the
more fine-grained submodule.<name>.active option has the highest order
of precedence followed by the pathspec check against submodule.active.
To ensure backwards compatibility, if neither of these options are set,
git falls back to checking the submodule.<name>.url option to determine
if a submodule is interesting.
Signed-off-by: Brandon Williams <bmwill@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-18 01:38:01 +03:00
|
|
|
|
|
|
|
argv_array_clear(&args);
|
|
|
|
clear_pathspec(&ps);
|
|
|
|
return ret;
|
2016-12-16 22:03:17 +03:00
|
|
|
}
|
|
|
|
|
submodule: decouple url and submodule interest
Currently the submodule.<name>.url config option is used to determine if
a given submodule is of interest to the user. This ends up being
cumbersome in a world where we want to have different submodules checked
out in different worktrees or a more generalized mechanism to select
which submodules are of interest.
In a future with worktree support for submodules, there will be multiple
working trees, each of which may only need a subset of the submodules
checked out. The URL (which is where the submodule repository can be
obtained) should not differ between different working trees.
It may also be convenient for users to more easily specify groups of
submodules they are interested in as opposed to running "git submodule
init <path>" on each submodule they want checked out in their working
tree.
To this end two config options are introduced, submodule.active and
submodule.<name>.active. The submodule.active config holds a pathspec
that specifies which submodules should exist in the working tree. The
submodule.<name>.active config is a boolean flag used to indicate if
that particular submodule should exist in the working tree.
Its important to note that submodule.active functions differently than
the other configuration options since it takes a pathspec. This allows
users to adopt at least two new workflows:
1. Submodules can be grouped with a leading directory, such that a
pathspec e.g. 'lib/' would cover all library-ish modules to allow
those who are interested in library-ish modules to set
"submodule.active = lib/" just once to say any and all modules in
'lib/' are interesting.
2. Once the pathspec-attribute feature is invented, users can label
submodules with attributes to group them, so that a broad pathspec
with attribute requirements, e.g. ':(attr:lib)', can be used to say
any and all modules with the 'lib' attribute are interesting.
Since the .gitattributes file, just like the .gitmodules file, is
tracked by the superproject, when a submodule moves in the
superproject tree, the project can adjust which path gets the
attribute in .gitattributes, just like it can adjust which path has
the submodule in .gitmodules.
Neither of these two additional configuration options solve the problem
of wanting different submodules checked out in different worktrees
because multiple worktrees share .git/config. Only once per-worktree
configurations become a reality can this be solved, but this is a
necessary preparatory step for that future.
Given these multiple ways to check if a submodule is of interest, the
more fine-grained submodule.<name>.active option has the highest order
of precedence followed by the pathspec check against submodule.active.
To ensure backwards compatibility, if neither of these options are set,
git falls back to checking the submodule.<name>.url option to determine
if a submodule is interesting.
Signed-off-by: Brandon Williams <bmwill@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-18 01:38:01 +03:00
|
|
|
/* fallback to checking if the URL is set */
|
|
|
|
key = xstrfmt("submodule.%s.url", module->name);
|
2017-06-22 21:43:46 +03:00
|
|
|
ret = !repo_config_get_string(repo, key, &value);
|
submodule: decouple url and submodule interest
Currently the submodule.<name>.url config option is used to determine if
a given submodule is of interest to the user. This ends up being
cumbersome in a world where we want to have different submodules checked
out in different worktrees or a more generalized mechanism to select
which submodules are of interest.
In a future with worktree support for submodules, there will be multiple
working trees, each of which may only need a subset of the submodules
checked out. The URL (which is where the submodule repository can be
obtained) should not differ between different working trees.
It may also be convenient for users to more easily specify groups of
submodules they are interested in as opposed to running "git submodule
init <path>" on each submodule they want checked out in their working
tree.
To this end two config options are introduced, submodule.active and
submodule.<name>.active. The submodule.active config holds a pathspec
that specifies which submodules should exist in the working tree. The
submodule.<name>.active config is a boolean flag used to indicate if
that particular submodule should exist in the working tree.
Its important to note that submodule.active functions differently than
the other configuration options since it takes a pathspec. This allows
users to adopt at least two new workflows:
1. Submodules can be grouped with a leading directory, such that a
pathspec e.g. 'lib/' would cover all library-ish modules to allow
those who are interested in library-ish modules to set
"submodule.active = lib/" just once to say any and all modules in
'lib/' are interesting.
2. Once the pathspec-attribute feature is invented, users can label
submodules with attributes to group them, so that a broad pathspec
with attribute requirements, e.g. ':(attr:lib)', can be used to say
any and all modules with the 'lib' attribute are interesting.
Since the .gitattributes file, just like the .gitmodules file, is
tracked by the superproject, when a submodule moves in the
superproject tree, the project can adjust which path gets the
attribute in .gitattributes, just like it can adjust which path has
the submodule in .gitmodules.
Neither of these two additional configuration options solve the problem
of wanting different submodules checked out in different worktrees
because multiple worktrees share .git/config. Only once per-worktree
configurations become a reality can this be solved, but this is a
necessary preparatory step for that future.
Given these multiple ways to check if a submodule is of interest, the
more fine-grained submodule.<name>.active option has the highest order
of precedence followed by the pathspec check against submodule.active.
To ensure backwards compatibility, if neither of these options are set,
git falls back to checking the submodule.<name>.url option to determine
if a submodule is interesting.
Signed-off-by: Brandon Williams <bmwill@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-18 01:38:01 +03:00
|
|
|
|
|
|
|
free(value);
|
|
|
|
free(key);
|
2016-12-16 22:03:17 +03:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-03-15 00:46:31 +03:00
|
|
|
int is_submodule_populated_gently(const char *path, int *return_error_code)
|
2016-12-16 22:03:16 +03:00
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
char *gitdir = xstrfmt("%s/.git", path);
|
|
|
|
|
2017-03-15 00:46:31 +03:00
|
|
|
if (resolve_gitdir_gently(gitdir, return_error_code))
|
2016-12-16 22:03:16 +03:00
|
|
|
ret = 1;
|
|
|
|
|
|
|
|
free(gitdir);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-05-09 22:17:59 +03:00
|
|
|
/*
|
|
|
|
* Dies if the provided 'prefix' corresponds to an unpopulated submodule
|
|
|
|
*/
|
|
|
|
void die_in_unpopulated_submodule(const struct index_state *istate,
|
|
|
|
const char *prefix)
|
|
|
|
{
|
|
|
|
int i, prefixlen;
|
|
|
|
|
|
|
|
if (!prefix)
|
|
|
|
return;
|
|
|
|
|
|
|
|
prefixlen = strlen(prefix);
|
|
|
|
|
|
|
|
for (i = 0; i < istate->cache_nr; i++) {
|
|
|
|
struct cache_entry *ce = istate->cache[i];
|
|
|
|
int ce_len = ce_namelen(ce);
|
|
|
|
|
|
|
|
if (!S_ISGITLINK(ce->ce_mode))
|
|
|
|
continue;
|
|
|
|
if (prefixlen <= ce_len)
|
|
|
|
continue;
|
|
|
|
if (strncmp(ce->name, prefix, ce_len))
|
|
|
|
continue;
|
|
|
|
if (prefix[ce_len] != '/')
|
|
|
|
continue;
|
|
|
|
|
|
|
|
die(_("in unpopulated submodule '%s'"), ce->name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-12 01:04:24 +03:00
|
|
|
/*
|
|
|
|
* Dies if any paths in the provided pathspec descends into a submodule
|
|
|
|
*/
|
|
|
|
void die_path_inside_submodule(const struct index_state *istate,
|
|
|
|
const struct pathspec *ps)
|
|
|
|
{
|
|
|
|
int i, j;
|
|
|
|
|
|
|
|
for (i = 0; i < istate->cache_nr; i++) {
|
|
|
|
struct cache_entry *ce = istate->cache[i];
|
|
|
|
int ce_len = ce_namelen(ce);
|
|
|
|
|
|
|
|
if (!S_ISGITLINK(ce->ce_mode))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
for (j = 0; j < ps->nr ; j++) {
|
|
|
|
const struct pathspec_item *item = &ps->items[j];
|
|
|
|
|
|
|
|
if (item->len <= ce_len)
|
|
|
|
continue;
|
|
|
|
if (item->match[ce_len] != '/')
|
|
|
|
continue;
|
|
|
|
if (strncmp(ce->name, item->match, ce_len))
|
|
|
|
continue;
|
|
|
|
if (item->len == ce_len + 1)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
die(_("Pathspec '%s' is in submodule '%.*s'"),
|
|
|
|
item->original, ce_len, ce->name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-03 21:19:50 +03:00
|
|
|
enum submodule_update_type parse_submodule_update_type(const char *value)
|
2016-03-01 05:07:11 +03:00
|
|
|
{
|
|
|
|
if (!strcmp(value, "none"))
|
2017-08-03 21:19:50 +03:00
|
|
|
return SM_UPDATE_NONE;
|
2016-03-01 05:07:11 +03:00
|
|
|
else if (!strcmp(value, "checkout"))
|
2017-08-03 21:19:50 +03:00
|
|
|
return SM_UPDATE_CHECKOUT;
|
2016-03-01 05:07:11 +03:00
|
|
|
else if (!strcmp(value, "rebase"))
|
2017-08-03 21:19:50 +03:00
|
|
|
return SM_UPDATE_REBASE;
|
2016-03-01 05:07:11 +03:00
|
|
|
else if (!strcmp(value, "merge"))
|
2017-08-03 21:19:50 +03:00
|
|
|
return SM_UPDATE_MERGE;
|
|
|
|
else if (*value == '!')
|
|
|
|
return SM_UPDATE_COMMAND;
|
|
|
|
else
|
|
|
|
return SM_UPDATE_UNSPECIFIED;
|
|
|
|
}
|
|
|
|
|
|
|
|
int parse_submodule_update_strategy(const char *value,
|
|
|
|
struct submodule_update_strategy *dst)
|
|
|
|
{
|
|
|
|
enum submodule_update_type type;
|
|
|
|
|
|
|
|
free((void*)dst->command);
|
|
|
|
dst->command = NULL;
|
|
|
|
|
|
|
|
type = parse_submodule_update_type(value);
|
|
|
|
if (type == SM_UPDATE_UNSPECIFIED)
|
2016-03-01 05:07:11 +03:00
|
|
|
return -1;
|
2017-08-03 21:19:50 +03:00
|
|
|
|
|
|
|
dst->type = type;
|
|
|
|
if (type == SM_UPDATE_COMMAND)
|
|
|
|
dst->command = xstrdup(value + 1);
|
|
|
|
|
2016-03-01 05:07:11 +03:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
submodule: port init from shell to C
By having the `submodule init` functionality in C, we can reference it
easier from other parts in the code in later patches. The code is split
up to have one function to initialize one submodule and a calling function
that takes care of the rest, such as argument handling and translating the
arguments to the paths of the submodules.
This is the first submodule subcommand that is fully converted to C
except for the usage string, so this is actually removing a call to
the `submodule--helper list` function, which is supposed to be used in
this transition. Instead we'll make a direct call to `module_list_compute`.
An explanation why we need to edit the prefixes in cmd_update in
git-submodule.sh in this patch:
By having no processing in the shell part, we need to convey the notion
of wt_prefix and prefix to the C parts, which former patches punted on
and did the processing of displaying path in the shell.
`wt_prefix` used to hold the path from the repository root to the current
directory, e.g. wt_prefix would be t/ if the user invoked the
`git submodule` command in ~/repo/t and ~repo is the GIT_DIR.
`prefix` used to hold the relative path from the repository root to the
operation, e.g. if you have recursive submodules, the shell script would
modify the `prefix` in each recursive step by adding the submodule path.
We will pass `wt_prefix` into the C helper via `git -C <dir>` as that
will setup git in the directory the user actually called git-submodule.sh
from. The `prefix` will be passed in via the `--prefix` option.
Having `prefix` and `wt_prefix` relative to the GIT_DIR of the
calling superproject is unfortunate with this patch as the C code doesn't
know about a possible recursion from a superproject via `submodule update
--init --recursive`.
To fix this, we change the meaning of `wt_prefix` to point to the current
project instead of the superproject and `prefix` to include any relative
paths issues in the superproject. That way `prefix` will become the leading
part for displaying paths and `wt_prefix` will be empty in recursive
calls for now.
The new notion of `wt_prefix` and `prefix` still allows us to reconstruct
the calling directory in the superproject by just traveling reverse of
`prefix`.
Signed-off-by: Stefan Beller <sbeller@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-04-16 03:50:13 +03:00
|
|
|
const char *submodule_strategy_to_string(const struct submodule_update_strategy *s)
|
|
|
|
{
|
|
|
|
struct strbuf sb = STRBUF_INIT;
|
|
|
|
switch (s->type) {
|
|
|
|
case SM_UPDATE_CHECKOUT:
|
|
|
|
return "checkout";
|
|
|
|
case SM_UPDATE_MERGE:
|
|
|
|
return "merge";
|
|
|
|
case SM_UPDATE_REBASE:
|
|
|
|
return "rebase";
|
|
|
|
case SM_UPDATE_NONE:
|
|
|
|
return "none";
|
|
|
|
case SM_UPDATE_UNSPECIFIED:
|
|
|
|
return NULL;
|
|
|
|
case SM_UPDATE_COMMAND:
|
|
|
|
strbuf_addf(&sb, "!%s", s->command);
|
|
|
|
return strbuf_detach(&sb, NULL);
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2010-06-25 18:56:47 +04:00
|
|
|
void handle_ignore_submodules_arg(struct diff_options *diffopt,
|
|
|
|
const char *arg)
|
|
|
|
{
|
2017-10-31 21:19:11 +03:00
|
|
|
diffopt->flags.ignore_submodules = 0;
|
|
|
|
diffopt->flags.ignore_untracked_in_submodules = 0;
|
|
|
|
diffopt->flags.ignore_dirty_submodules = 0;
|
2010-08-05 12:49:55 +04:00
|
|
|
|
2010-06-25 18:56:47 +04:00
|
|
|
if (!strcmp(arg, "all"))
|
2017-10-31 21:19:11 +03:00
|
|
|
diffopt->flags.ignore_submodules = 1;
|
2010-06-25 18:56:47 +04:00
|
|
|
else if (!strcmp(arg, "untracked"))
|
2017-10-31 21:19:11 +03:00
|
|
|
diffopt->flags.ignore_untracked_in_submodules = 1;
|
2010-06-25 18:56:47 +04:00
|
|
|
else if (!strcmp(arg, "dirty"))
|
2017-10-31 21:19:11 +03:00
|
|
|
diffopt->flags.ignore_dirty_submodules = 1;
|
2010-08-06 02:39:25 +04:00
|
|
|
else if (strcmp(arg, "none"))
|
2010-06-25 18:56:47 +04:00
|
|
|
die("bad --ignore-submodules argument: %s", arg);
|
|
|
|
}
|
|
|
|
|
2011-03-16 10:14:11 +03:00
|
|
|
static int prepare_submodule_summary(struct rev_info *rev, const char *path,
|
|
|
|
struct commit *left, struct commit *right,
|
2016-09-01 02:27:24 +03:00
|
|
|
struct commit_list *merge_bases)
|
2011-03-16 10:14:11 +03:00
|
|
|
{
|
2016-09-01 02:27:24 +03:00
|
|
|
struct commit_list *list;
|
2011-03-16 10:14:11 +03:00
|
|
|
|
2018-09-21 18:57:38 +03:00
|
|
|
repo_init_revisions(the_repository, rev, NULL);
|
2011-03-16 10:14:11 +03:00
|
|
|
setup_revisions(0, NULL, rev, NULL);
|
|
|
|
rev->left_right = 1;
|
|
|
|
rev->first_parent_only = 1;
|
|
|
|
left->object.flags |= SYMMETRIC_LEFT;
|
|
|
|
add_pending_object(rev, &left->object, path);
|
|
|
|
add_pending_object(rev, &right->object, path);
|
|
|
|
for (list = merge_bases; list; list = list->next) {
|
|
|
|
list->item->object.flags |= UNINTERESTING;
|
|
|
|
add_pending_object(rev, &list->item->object,
|
2015-11-10 05:22:28 +03:00
|
|
|
oid_to_hex(&list->item->object.oid));
|
2011-03-16 10:14:11 +03:00
|
|
|
}
|
|
|
|
return prepare_revision_walk(rev);
|
|
|
|
}
|
|
|
|
|
2017-06-30 03:07:00 +03:00
|
|
|
static void print_submodule_summary(struct rev_info *rev, struct diff_options *o)
|
2011-03-16 10:14:11 +03:00
|
|
|
{
|
|
|
|
static const char format[] = " %m %s";
|
|
|
|
struct strbuf sb = STRBUF_INIT;
|
|
|
|
struct commit *commit;
|
|
|
|
|
|
|
|
while ((commit = get_revision(rev))) {
|
|
|
|
struct pretty_print_context ctx = {0};
|
|
|
|
ctx.date_mode = rev->date_mode;
|
2013-06-26 14:19:50 +04:00
|
|
|
ctx.output_encoding = get_log_output_encoding();
|
2011-03-16 10:14:11 +03:00
|
|
|
strbuf_setlen(&sb, 0);
|
|
|
|
format_commit_message(commit, format, &sb, &ctx);
|
|
|
|
strbuf_addch(&sb, '\n');
|
2017-06-30 03:07:00 +03:00
|
|
|
if (commit->object.flags & SYMMETRIC_LEFT)
|
|
|
|
diff_emit_submodule_del(o, sb.buf);
|
|
|
|
else
|
|
|
|
diff_emit_submodule_add(o, sb.buf);
|
2011-03-16 10:14:11 +03:00
|
|
|
}
|
|
|
|
strbuf_release(&sb);
|
|
|
|
}
|
|
|
|
|
2017-03-15 00:46:35 +03:00
|
|
|
static void prepare_submodule_repo_env_no_git_dir(struct argv_array *out)
|
|
|
|
{
|
|
|
|
const char * const *var;
|
|
|
|
|
|
|
|
for (var = local_repo_env; *var; var++) {
|
|
|
|
if (strcmp(*var, CONFIG_DATA_ENVIRONMENT))
|
|
|
|
argv_array_push(out, *var);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void prepare_submodule_repo_env(struct argv_array *out)
|
|
|
|
{
|
|
|
|
prepare_submodule_repo_env_no_git_dir(out);
|
|
|
|
argv_array_pushf(out, "%s=%s", GIT_DIR_ENVIRONMENT,
|
|
|
|
DEFAULT_GIT_DIR_ENVIRONMENT);
|
|
|
|
}
|
|
|
|
|
2016-09-01 02:27:24 +03:00
|
|
|
/* Helper function to display the submodule header line prior to the full
|
|
|
|
* summary output. If it can locate the submodule objects directory it will
|
|
|
|
* attempt to lookup both the left and right commits and put them into the
|
|
|
|
* left and right pointers.
|
|
|
|
*/
|
2017-06-30 03:07:00 +03:00
|
|
|
static void show_submodule_header(struct diff_options *o, const char *path,
|
2016-09-01 02:27:23 +03:00
|
|
|
struct object_id *one, struct object_id *two,
|
2017-06-30 03:07:00 +03:00
|
|
|
unsigned dirty_submodule,
|
2016-09-01 02:27:24 +03:00
|
|
|
struct commit **left, struct commit **right,
|
|
|
|
struct commit_list **merge_bases)
|
2009-10-19 16:38:32 +04:00
|
|
|
{
|
|
|
|
const char *message = NULL;
|
|
|
|
struct strbuf sb = STRBUF_INIT;
|
|
|
|
int fast_forward = 0, fast_backward = 0;
|
|
|
|
|
2010-03-05 00:20:33 +03:00
|
|
|
if (dirty_submodule & DIRTY_SUBMODULE_UNTRACKED)
|
2017-06-30 03:07:00 +03:00
|
|
|
diff_emit_submodule_untracked(o, path);
|
|
|
|
|
2010-03-05 00:20:33 +03:00
|
|
|
if (dirty_submodule & DIRTY_SUBMODULE_MODIFIED)
|
2017-06-30 03:07:00 +03:00
|
|
|
diff_emit_submodule_modified(o, path);
|
2010-03-05 00:20:33 +03:00
|
|
|
|
2016-09-01 02:27:24 +03:00
|
|
|
if (is_null_oid(one))
|
|
|
|
message = "(new submodule)";
|
|
|
|
else if (is_null_oid(two))
|
|
|
|
message = "(submodule deleted)";
|
|
|
|
|
|
|
|
if (add_submodule_odb(path)) {
|
|
|
|
if (!message)
|
2017-09-26 21:27:56 +03:00
|
|
|
message = "(commits not present)";
|
2016-09-01 02:27:24 +03:00
|
|
|
goto output_header;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Attempt to lookup the commit references, and determine if this is
|
|
|
|
* a fast forward or fast backwards update.
|
|
|
|
*/
|
2018-06-29 04:21:58 +03:00
|
|
|
*left = lookup_commit_reference(the_repository, one);
|
|
|
|
*right = lookup_commit_reference(the_repository, two);
|
2016-09-01 02:27:24 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Warn about missing commits in the submodule project, but only if
|
|
|
|
* they aren't null.
|
|
|
|
*/
|
|
|
|
if ((!is_null_oid(one) && !*left) ||
|
|
|
|
(!is_null_oid(two) && !*right))
|
|
|
|
message = "(commits not present)";
|
|
|
|
|
|
|
|
*merge_bases = get_merge_bases(*left, *right);
|
|
|
|
if (*merge_bases) {
|
|
|
|
if ((*merge_bases)->item == *left)
|
|
|
|
fast_forward = 1;
|
|
|
|
else if ((*merge_bases)->item == *right)
|
|
|
|
fast_backward = 1;
|
|
|
|
}
|
|
|
|
|
convert "oidcmp() == 0" to oideq()
Using the more restrictive oideq() should, in the long run,
give the compiler more opportunities to optimize these
callsites. For now, this conversion should be a complete
noop with respect to the generated code.
The result is also perhaps a little more readable, as it
avoids the "zero is equal" idiom. Since it's so prevalent in
C, I think seasoned programmers tend not to even notice it
anymore, but it can sometimes make for awkward double
negations (e.g., we can drop a few !!oidcmp() instances
here).
This patch was generated almost entirely by the included
coccinelle patch. This mechanical conversion should be
completely safe, because we check explicitly for cases where
oidcmp() is compared to 0, which is what oideq() is doing
under the hood. Note that we don't have to catch "!oidcmp()"
separately; coccinelle's standard isomorphisms make sure the
two are treated equivalently.
I say "almost" because I did hand-edit the coccinelle output
to fix up a few style violations (it mostly keeps the
original formatting, but sometimes unwraps long lines).
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-08-29 00:22:40 +03:00
|
|
|
if (oideq(one, two)) {
|
2010-03-05 00:20:33 +03:00
|
|
|
strbuf_release(&sb);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-09-01 02:27:24 +03:00
|
|
|
output_header:
|
2017-06-30 03:07:00 +03:00
|
|
|
strbuf_addf(&sb, "Submodule %s ", path);
|
strbuf: convert strbuf_add_unique_abbrev to use struct object_id
Convert the declaration and definition of strbuf_add_unique_abbrev to
make it take a pointer to struct object_id. Predeclare the struct in
strbuf.h, as cache.h includes strbuf.h before it declares the struct,
and otherwise the struct declaration would have the wrong scope.
Apply the following semantic patch, along with the standard object_id
transforms, to adjust the callers:
@@
expression E1, E2, E3;
@@
- strbuf_add_unique_abbrev(E1, E2.hash, E3);
+ strbuf_add_unique_abbrev(E1, &E2, E3);
@@
expression E1, E2, E3;
@@
- strbuf_add_unique_abbrev(E1, E2->hash, E3);
+ strbuf_add_unique_abbrev(E1, E2, E3);
Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-03-12 05:27:28 +03:00
|
|
|
strbuf_add_unique_abbrev(&sb, one, DEFAULT_ABBREV);
|
2016-10-08 18:38:47 +03:00
|
|
|
strbuf_addstr(&sb, (fast_backward || fast_forward) ? ".." : "...");
|
strbuf: convert strbuf_add_unique_abbrev to use struct object_id
Convert the declaration and definition of strbuf_add_unique_abbrev to
make it take a pointer to struct object_id. Predeclare the struct in
strbuf.h, as cache.h includes strbuf.h before it declares the struct,
and otherwise the struct declaration would have the wrong scope.
Apply the following semantic patch, along with the standard object_id
transforms, to adjust the callers:
@@
expression E1, E2, E3;
@@
- strbuf_add_unique_abbrev(E1, E2.hash, E3);
+ strbuf_add_unique_abbrev(E1, &E2, E3);
@@
expression E1, E2, E3;
@@
- strbuf_add_unique_abbrev(E1, E2->hash, E3);
+ strbuf_add_unique_abbrev(E1, E2, E3);
Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-03-12 05:27:28 +03:00
|
|
|
strbuf_add_unique_abbrev(&sb, two, DEFAULT_ABBREV);
|
2009-10-19 16:38:32 +04:00
|
|
|
if (message)
|
2017-06-30 03:07:00 +03:00
|
|
|
strbuf_addf(&sb, " %s\n", message);
|
2009-10-19 16:38:32 +04:00
|
|
|
else
|
2017-06-30 03:07:00 +03:00
|
|
|
strbuf_addf(&sb, "%s:\n", fast_backward ? " (rewind)" : "");
|
|
|
|
diff_emit_submodule_header(o, sb.buf);
|
2009-10-19 16:38:32 +04:00
|
|
|
|
|
|
|
strbuf_release(&sb);
|
|
|
|
}
|
2010-01-16 20:42:24 +03:00
|
|
|
|
2017-06-30 03:07:00 +03:00
|
|
|
void show_submodule_summary(struct diff_options *o, const char *path,
|
2016-09-01 02:27:24 +03:00
|
|
|
struct object_id *one, struct object_id *two,
|
2017-06-30 03:07:00 +03:00
|
|
|
unsigned dirty_submodule)
|
2016-09-01 02:27:24 +03:00
|
|
|
{
|
|
|
|
struct rev_info rev;
|
|
|
|
struct commit *left = NULL, *right = NULL;
|
|
|
|
struct commit_list *merge_bases = NULL;
|
|
|
|
|
2017-06-30 03:07:00 +03:00
|
|
|
show_submodule_header(o, path, one, two, dirty_submodule,
|
|
|
|
&left, &right, &merge_bases);
|
2016-09-01 02:27:24 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If we don't have both a left and a right pointer, there is no
|
|
|
|
* reason to try and display a summary. The header line should contain
|
|
|
|
* all the information the user needs.
|
|
|
|
*/
|
|
|
|
if (!left || !right)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
/* Treat revision walker failure the same as missing commits */
|
|
|
|
if (prepare_submodule_summary(&rev, path, left, right, merge_bases)) {
|
2017-06-30 03:07:00 +03:00
|
|
|
diff_emit_submodule_error(o, "(revision walker failed)\n");
|
2016-09-01 02:27:24 +03:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2017-06-30 03:07:00 +03:00
|
|
|
print_submodule_summary(&rev, o);
|
2016-09-01 02:27:24 +03:00
|
|
|
|
|
|
|
out:
|
|
|
|
if (merge_bases)
|
|
|
|
free_commit_list(merge_bases);
|
|
|
|
clear_commit_marks(left, ~0);
|
|
|
|
clear_commit_marks(right, ~0);
|
|
|
|
}
|
|
|
|
|
2017-06-30 03:07:00 +03:00
|
|
|
void show_submodule_inline_diff(struct diff_options *o, const char *path,
|
2016-09-01 02:27:25 +03:00
|
|
|
struct object_id *one, struct object_id *two,
|
2017-06-30 03:07:00 +03:00
|
|
|
unsigned dirty_submodule)
|
2016-09-01 02:27:25 +03:00
|
|
|
{
|
2018-02-14 21:59:49 +03:00
|
|
|
const struct object_id *old_oid = the_hash_algo->empty_tree, *new_oid = the_hash_algo->empty_tree;
|
2016-09-01 02:27:25 +03:00
|
|
|
struct commit *left = NULL, *right = NULL;
|
|
|
|
struct commit_list *merge_bases = NULL;
|
|
|
|
struct child_process cp = CHILD_PROCESS_INIT;
|
2017-06-30 03:07:00 +03:00
|
|
|
struct strbuf sb = STRBUF_INIT;
|
2016-09-01 02:27:25 +03:00
|
|
|
|
2017-06-30 03:07:00 +03:00
|
|
|
show_submodule_header(o, path, one, two, dirty_submodule,
|
|
|
|
&left, &right, &merge_bases);
|
2016-09-01 02:27:25 +03:00
|
|
|
|
|
|
|
/* We need a valid left and right commit to display a difference */
|
|
|
|
if (!(left || is_null_oid(one)) ||
|
|
|
|
!(right || is_null_oid(two)))
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
if (left)
|
2018-02-14 21:59:49 +03:00
|
|
|
old_oid = one;
|
2016-09-01 02:27:25 +03:00
|
|
|
if (right)
|
2018-02-14 21:59:49 +03:00
|
|
|
new_oid = two;
|
2016-09-01 02:27:25 +03:00
|
|
|
|
|
|
|
cp.git_cmd = 1;
|
|
|
|
cp.dir = path;
|
2017-06-30 03:07:00 +03:00
|
|
|
cp.out = -1;
|
2016-09-01 02:27:25 +03:00
|
|
|
cp.no_stdin = 1;
|
|
|
|
|
|
|
|
/* TODO: other options may need to be passed here. */
|
2017-05-05 00:43:55 +03:00
|
|
|
argv_array_pushl(&cp.args, "diff", "--submodule=diff", NULL);
|
2017-06-30 03:07:00 +03:00
|
|
|
argv_array_pushf(&cp.args, "--color=%s", want_color(o->use_color) ?
|
|
|
|
"always" : "never");
|
2017-05-05 00:43:55 +03:00
|
|
|
|
2017-10-31 21:19:11 +03:00
|
|
|
if (o->flags.reverse_diff) {
|
2016-09-01 02:27:25 +03:00
|
|
|
argv_array_pushf(&cp.args, "--src-prefix=%s%s/",
|
|
|
|
o->b_prefix, path);
|
|
|
|
argv_array_pushf(&cp.args, "--dst-prefix=%s%s/",
|
|
|
|
o->a_prefix, path);
|
|
|
|
} else {
|
|
|
|
argv_array_pushf(&cp.args, "--src-prefix=%s%s/",
|
|
|
|
o->a_prefix, path);
|
|
|
|
argv_array_pushf(&cp.args, "--dst-prefix=%s%s/",
|
|
|
|
o->b_prefix, path);
|
|
|
|
}
|
2018-02-14 21:59:49 +03:00
|
|
|
argv_array_push(&cp.args, oid_to_hex(old_oid));
|
2016-09-01 02:27:25 +03:00
|
|
|
/*
|
|
|
|
* If the submodule has modified content, we will diff against the
|
|
|
|
* work tree, under the assumption that the user has asked for the
|
|
|
|
* diff format and wishes to actually see all differences even if they
|
|
|
|
* haven't yet been committed to the submodule yet.
|
|
|
|
*/
|
|
|
|
if (!(dirty_submodule & DIRTY_SUBMODULE_MODIFIED))
|
2018-02-14 21:59:49 +03:00
|
|
|
argv_array_push(&cp.args, oid_to_hex(new_oid));
|
2016-09-01 02:27:25 +03:00
|
|
|
|
2017-04-01 02:17:32 +03:00
|
|
|
prepare_submodule_repo_env(&cp.env_array);
|
2017-06-30 03:07:00 +03:00
|
|
|
if (start_command(&cp))
|
|
|
|
diff_emit_submodule_error(o, "(diff failed)\n");
|
|
|
|
|
|
|
|
while (strbuf_getwholeline_fd(&sb, cp.out, '\n') != EOF)
|
|
|
|
diff_emit_submodule_pipethrough(o, sb.buf, sb.len);
|
|
|
|
|
|
|
|
if (finish_command(&cp))
|
|
|
|
diff_emit_submodule_error(o, "(diff failed)\n");
|
2016-09-01 02:27:25 +03:00
|
|
|
|
|
|
|
done:
|
2017-06-30 03:07:00 +03:00
|
|
|
strbuf_release(&sb);
|
2016-09-01 02:27:25 +03:00
|
|
|
if (merge_bases)
|
|
|
|
free_commit_list(merge_bases);
|
|
|
|
if (left)
|
|
|
|
clear_commit_marks(left, ~0);
|
|
|
|
if (right)
|
|
|
|
clear_commit_marks(right, ~0);
|
|
|
|
}
|
|
|
|
|
2017-03-15 00:46:34 +03:00
|
|
|
int should_update_submodules(void)
|
|
|
|
{
|
|
|
|
return config_update_recurse_submodules == RECURSE_SUBMODULES_ON;
|
|
|
|
}
|
|
|
|
|
|
|
|
const struct submodule *submodule_from_ce(const struct cache_entry *ce)
|
|
|
|
{
|
|
|
|
if (!S_ISGITLINK(ce->ce_mode))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (!should_update_submodules())
|
|
|
|
return NULL;
|
|
|
|
|
2018-03-29 01:35:29 +03:00
|
|
|
return submodule_from_path(the_repository, &null_oid, ce->name);
|
2017-03-15 00:46:34 +03:00
|
|
|
}
|
|
|
|
|
2017-05-02 04:02:39 +03:00
|
|
|
static struct oid_array *submodule_commits(struct string_list *submodules,
|
2017-10-16 16:58:27 +03:00
|
|
|
const char *name)
|
2017-05-02 04:02:39 +03:00
|
|
|
{
|
|
|
|
struct string_list_item *item;
|
|
|
|
|
2017-10-16 16:58:27 +03:00
|
|
|
item = string_list_insert(submodules, name);
|
2017-05-02 04:02:39 +03:00
|
|
|
if (item->util)
|
|
|
|
return (struct oid_array *) item->util;
|
|
|
|
|
|
|
|
/* NEEDSWORK: should we have oid_array_init()? */
|
|
|
|
item->util = xcalloc(1, sizeof(struct oid_array));
|
|
|
|
return (struct oid_array *) item->util;
|
|
|
|
}
|
|
|
|
|
2017-10-16 16:58:27 +03:00
|
|
|
struct collect_changed_submodules_cb_data {
|
2018-10-19 20:34:43 +03:00
|
|
|
struct repository *repo;
|
2017-10-16 16:58:27 +03:00
|
|
|
struct string_list *changed;
|
|
|
|
const struct object_id *commit_oid;
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* this would normally be two functions: default_name_from_path() and
|
|
|
|
* path_from_default_name(). Since the default name is the same as
|
|
|
|
* the submodule path we can get away with just one function which only
|
|
|
|
* checks whether there is a submodule in the working directory at that
|
|
|
|
* location.
|
|
|
|
*/
|
|
|
|
static const char *default_name_or_path(const char *path_or_name)
|
|
|
|
{
|
|
|
|
int error_code;
|
|
|
|
|
|
|
|
if (!is_submodule_populated_gently(path_or_name, &error_code))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return path_or_name;
|
|
|
|
}
|
|
|
|
|
2017-05-02 04:02:39 +03:00
|
|
|
static void collect_changed_submodules_cb(struct diff_queue_struct *q,
|
|
|
|
struct diff_options *options,
|
|
|
|
void *data)
|
|
|
|
{
|
2017-10-16 16:58:27 +03:00
|
|
|
struct collect_changed_submodules_cb_data *me = data;
|
|
|
|
struct string_list *changed = me->changed;
|
|
|
|
const struct object_id *commit_oid = me->commit_oid;
|
2017-05-02 04:02:39 +03:00
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < q->nr; i++) {
|
|
|
|
struct diff_filepair *p = q->queue[i];
|
|
|
|
struct oid_array *commits;
|
2017-10-16 16:58:27 +03:00
|
|
|
const struct submodule *submodule;
|
|
|
|
const char *name;
|
|
|
|
|
2017-05-02 04:02:39 +03:00
|
|
|
if (!S_ISGITLINK(p->two->mode))
|
|
|
|
continue;
|
|
|
|
|
2018-10-19 20:34:43 +03:00
|
|
|
submodule = submodule_from_path(me->repo,
|
2018-03-29 01:35:29 +03:00
|
|
|
commit_oid, p->two->path);
|
2017-10-16 16:58:27 +03:00
|
|
|
if (submodule)
|
|
|
|
name = submodule->name;
|
|
|
|
else {
|
|
|
|
name = default_name_or_path(p->two->path);
|
|
|
|
/* make sure name does not collide with existing one */
|
submodule: fix NULL correctness in renamed broken submodules
When fetching with recursing into submodules, the fetch logic inspects
the superproject which submodules actually need to be fetched. This is
tricky for submodules that were renamed in the fetched range of commits.
This was implemented in c68f8375760 (implement fetching of moved
submodules, 2017-10-16), and this patch fixes a mistake in the logic
there.
When the warning is printed, the `name` might be NULL as
default_name_or_path can return NULL, so fix the warning to use the path
as obtained from the diff machinery, as that is not NULL.
While at it, make sure we only attempt to load the submodule if a git
directory of the submodule is found as default_name_or_path will return
NULL in case the git directory cannot be found. Note that passing NULL
to submodule_from_name is just a semantic error, as submodule_from_name
accepts NULL as a value, but then the return value is not the submodule
that was asked for, but some arbitrary other submodule. (Cf. 'config_from'
in submodule-config.c: "If any parameter except the cache is a NULL
pointer just return the first submodule. Can be used to check whether
there are any submodules parsed.")
Reported-by: Duy Nguyen <pclouds@gmail.com>
Helped-by: Duy Nguyen <pclouds@gmail.com>
Helped-by: Heiko Voigt <hvoigt@hvoigt.net>
Signed-off-by: Stefan Beller <sbeller@google.com>
Acked-by: Heiko Voigt <hvoigt@hvoigt.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-06-14 20:31:07 +03:00
|
|
|
if (name)
|
2018-10-19 20:34:43 +03:00
|
|
|
submodule = submodule_from_name(me->repo,
|
submodule: fix NULL correctness in renamed broken submodules
When fetching with recursing into submodules, the fetch logic inspects
the superproject which submodules actually need to be fetched. This is
tricky for submodules that were renamed in the fetched range of commits.
This was implemented in c68f8375760 (implement fetching of moved
submodules, 2017-10-16), and this patch fixes a mistake in the logic
there.
When the warning is printed, the `name` might be NULL as
default_name_or_path can return NULL, so fix the warning to use the path
as obtained from the diff machinery, as that is not NULL.
While at it, make sure we only attempt to load the submodule if a git
directory of the submodule is found as default_name_or_path will return
NULL in case the git directory cannot be found. Note that passing NULL
to submodule_from_name is just a semantic error, as submodule_from_name
accepts NULL as a value, but then the return value is not the submodule
that was asked for, but some arbitrary other submodule. (Cf. 'config_from'
in submodule-config.c: "If any parameter except the cache is a NULL
pointer just return the first submodule. Can be used to check whether
there are any submodules parsed.")
Reported-by: Duy Nguyen <pclouds@gmail.com>
Helped-by: Duy Nguyen <pclouds@gmail.com>
Helped-by: Heiko Voigt <hvoigt@hvoigt.net>
Signed-off-by: Stefan Beller <sbeller@google.com>
Acked-by: Heiko Voigt <hvoigt@hvoigt.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-06-14 20:31:07 +03:00
|
|
|
commit_oid, name);
|
2017-10-16 16:58:27 +03:00
|
|
|
if (submodule) {
|
|
|
|
warning("Submodule in commit %s at path: "
|
|
|
|
"'%s' collides with a submodule named "
|
|
|
|
"the same. Skipping it.",
|
submodule: fix NULL correctness in renamed broken submodules
When fetching with recursing into submodules, the fetch logic inspects
the superproject which submodules actually need to be fetched. This is
tricky for submodules that were renamed in the fetched range of commits.
This was implemented in c68f8375760 (implement fetching of moved
submodules, 2017-10-16), and this patch fixes a mistake in the logic
there.
When the warning is printed, the `name` might be NULL as
default_name_or_path can return NULL, so fix the warning to use the path
as obtained from the diff machinery, as that is not NULL.
While at it, make sure we only attempt to load the submodule if a git
directory of the submodule is found as default_name_or_path will return
NULL in case the git directory cannot be found. Note that passing NULL
to submodule_from_name is just a semantic error, as submodule_from_name
accepts NULL as a value, but then the return value is not the submodule
that was asked for, but some arbitrary other submodule. (Cf. 'config_from'
in submodule-config.c: "If any parameter except the cache is a NULL
pointer just return the first submodule. Can be used to check whether
there are any submodules parsed.")
Reported-by: Duy Nguyen <pclouds@gmail.com>
Helped-by: Duy Nguyen <pclouds@gmail.com>
Helped-by: Heiko Voigt <hvoigt@hvoigt.net>
Signed-off-by: Stefan Beller <sbeller@google.com>
Acked-by: Heiko Voigt <hvoigt@hvoigt.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-06-14 20:31:07 +03:00
|
|
|
oid_to_hex(commit_oid), p->two->path);
|
2017-10-16 16:58:27 +03:00
|
|
|
name = NULL;
|
|
|
|
}
|
2017-05-02 04:02:39 +03:00
|
|
|
}
|
2017-10-16 16:58:27 +03:00
|
|
|
|
|
|
|
if (!name)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
commits = submodule_commits(changed, name);
|
|
|
|
oid_array_append(commits, &p->two->oid);
|
2017-05-02 04:02:39 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Collect the paths of submodules in 'changed' which have changed based on
|
|
|
|
* the revisions as specified in 'argv'. Each entry in 'changed' will also
|
|
|
|
* have a corresponding 'struct oid_array' (in the 'util' field) which lists
|
|
|
|
* what the submodule pointers were updated to during the change.
|
|
|
|
*/
|
2018-10-19 20:34:43 +03:00
|
|
|
static void collect_changed_submodules(struct repository *r,
|
2018-09-21 18:57:35 +03:00
|
|
|
struct string_list *changed,
|
2017-05-02 04:02:39 +03:00
|
|
|
struct argv_array *argv)
|
|
|
|
{
|
|
|
|
struct rev_info rev;
|
|
|
|
const struct commit *commit;
|
|
|
|
|
2018-10-19 20:34:43 +03:00
|
|
|
repo_init_revisions(r, &rev, NULL);
|
2017-05-02 04:02:39 +03:00
|
|
|
setup_revisions(argv->argc, argv->argv, &rev, NULL);
|
|
|
|
if (prepare_revision_walk(&rev))
|
|
|
|
die("revision walk setup failed");
|
|
|
|
|
|
|
|
while ((commit = get_revision(&rev))) {
|
|
|
|
struct rev_info diff_rev;
|
2017-10-16 16:58:27 +03:00
|
|
|
struct collect_changed_submodules_cb_data data;
|
2018-10-19 20:34:43 +03:00
|
|
|
data.repo = r;
|
2017-10-16 16:58:27 +03:00
|
|
|
data.changed = changed;
|
|
|
|
data.commit_oid = &commit->object.oid;
|
2017-05-02 04:02:39 +03:00
|
|
|
|
2018-10-19 20:34:43 +03:00
|
|
|
repo_init_revisions(r, &diff_rev, NULL);
|
2017-05-02 04:02:39 +03:00
|
|
|
diff_rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;
|
|
|
|
diff_rev.diffopt.format_callback = collect_changed_submodules_cb;
|
2017-10-16 16:58:27 +03:00
|
|
|
diff_rev.diffopt.format_callback_data = &data;
|
2017-05-02 04:02:39 +03:00
|
|
|
diff_tree_combined_merge(commit, 1, &diff_rev);
|
|
|
|
}
|
|
|
|
|
|
|
|
reset_revision_walk();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void free_submodules_oids(struct string_list *submodules)
|
|
|
|
{
|
|
|
|
struct string_list_item *item;
|
|
|
|
for_each_string_list_item(item, submodules)
|
|
|
|
oid_array_clear((struct oid_array *) item->util);
|
|
|
|
string_list_clear(submodules, 1);
|
|
|
|
}
|
|
|
|
|
2015-05-25 21:39:07 +03:00
|
|
|
static int has_remote(const char *refname, const struct object_id *oid,
|
|
|
|
int flags, void *cb_data)
|
2011-08-20 02:08:47 +04:00
|
|
|
{
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2017-03-31 04:39:59 +03:00
|
|
|
static int append_oid_to_argv(const struct object_id *oid, void *data)
|
2011-08-20 02:08:47 +04:00
|
|
|
{
|
2016-11-16 18:11:05 +03:00
|
|
|
struct argv_array *argv = data;
|
2017-03-31 04:39:59 +03:00
|
|
|
argv_array_push(argv, oid_to_hex(oid));
|
2016-11-16 18:11:05 +03:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-09-12 20:30:27 +03:00
|
|
|
struct has_commit_data {
|
2018-10-19 20:34:43 +03:00
|
|
|
struct repository *repo;
|
2017-09-12 20:30:27 +03:00
|
|
|
int result;
|
|
|
|
const char *path;
|
|
|
|
};
|
|
|
|
|
2017-03-31 04:39:59 +03:00
|
|
|
static int check_has_commit(const struct object_id *oid, void *data)
|
2011-08-20 02:08:47 +04:00
|
|
|
{
|
2017-09-12 20:30:27 +03:00
|
|
|
struct has_commit_data *cb = data;
|
2016-11-16 18:11:06 +03:00
|
|
|
|
2018-10-19 20:34:43 +03:00
|
|
|
enum object_type type = oid_object_info(cb->repo, oid, NULL);
|
2016-11-16 18:11:06 +03:00
|
|
|
|
2017-09-12 20:30:27 +03:00
|
|
|
switch (type) {
|
|
|
|
case OBJ_COMMIT:
|
|
|
|
return 0;
|
|
|
|
case OBJ_BAD:
|
|
|
|
/*
|
|
|
|
* Object is missing or invalid. If invalid, an error message
|
|
|
|
* has already been printed.
|
|
|
|
*/
|
|
|
|
cb->result = 0;
|
|
|
|
return 0;
|
|
|
|
default:
|
|
|
|
die(_("submodule entry '%s' (%s) is a %s, not a commit"),
|
2018-02-14 21:59:24 +03:00
|
|
|
cb->path, oid_to_hex(oid), type_name(type));
|
2017-09-12 20:30:27 +03:00
|
|
|
}
|
2016-11-16 18:11:06 +03:00
|
|
|
}
|
|
|
|
|
2018-10-19 20:34:43 +03:00
|
|
|
static int submodule_has_commits(struct repository *r,
|
|
|
|
const char *path,
|
|
|
|
struct oid_array *commits)
|
2016-11-16 18:11:06 +03:00
|
|
|
{
|
2018-10-19 20:34:43 +03:00
|
|
|
struct has_commit_data has_commit = { r, 1, path };
|
2016-11-16 18:11:06 +03:00
|
|
|
|
2017-05-02 04:02:38 +03:00
|
|
|
/*
|
2017-06-25 13:20:41 +03:00
|
|
|
* Perform a cheap, but incorrect check for the existence of 'commits'.
|
2017-05-02 04:02:38 +03:00
|
|
|
* This is done by adding the submodule's object store to the in-core
|
2017-06-25 13:20:41 +03:00
|
|
|
* object store, and then querying for each commit's existence. If we
|
2017-05-02 04:02:38 +03:00
|
|
|
* do not have the commit object anywhere, there is no chance we have
|
|
|
|
* it in the object store of the correct submodule and have it
|
|
|
|
* reachable from a ref, so we can fail early without spawning rev-list
|
|
|
|
* which is expensive.
|
|
|
|
*/
|
2016-11-16 18:11:06 +03:00
|
|
|
if (add_submodule_odb(path))
|
|
|
|
return 0;
|
|
|
|
|
2017-03-31 04:40:00 +03:00
|
|
|
oid_array_for_each_unique(commits, check_has_commit, &has_commit);
|
2017-05-02 04:02:38 +03:00
|
|
|
|
2017-09-12 20:30:27 +03:00
|
|
|
if (has_commit.result) {
|
2017-05-02 04:02:38 +03:00
|
|
|
/*
|
|
|
|
* Even if the submodule is checked out and the commit is
|
|
|
|
* present, make sure it exists in the submodule's object store
|
|
|
|
* and that it is reachable from a ref.
|
|
|
|
*/
|
|
|
|
struct child_process cp = CHILD_PROCESS_INIT;
|
|
|
|
struct strbuf out = STRBUF_INIT;
|
|
|
|
|
|
|
|
argv_array_pushl(&cp.args, "rev-list", "-n", "1", NULL);
|
|
|
|
oid_array_for_each_unique(commits, append_oid_to_argv, &cp.args);
|
|
|
|
argv_array_pushl(&cp.args, "--not", "--all", NULL);
|
|
|
|
|
|
|
|
prepare_submodule_repo_env(&cp.env_array);
|
|
|
|
cp.git_cmd = 1;
|
|
|
|
cp.no_stdin = 1;
|
|
|
|
cp.dir = path;
|
|
|
|
|
|
|
|
if (capture_command(&cp, &out, GIT_MAX_HEXSZ + 1) || out.len)
|
2017-09-12 20:30:27 +03:00
|
|
|
has_commit.result = 0;
|
2017-05-02 04:02:38 +03:00
|
|
|
|
|
|
|
strbuf_release(&out);
|
|
|
|
}
|
|
|
|
|
2017-09-12 20:30:27 +03:00
|
|
|
return has_commit.result;
|
2016-11-16 18:11:06 +03:00
|
|
|
}
|
|
|
|
|
2018-10-19 20:34:43 +03:00
|
|
|
static int submodule_needs_pushing(struct repository *r,
|
|
|
|
const char *path,
|
|
|
|
struct oid_array *commits)
|
2016-11-16 18:11:06 +03:00
|
|
|
{
|
2018-10-19 20:34:43 +03:00
|
|
|
if (!submodule_has_commits(r, path, commits))
|
2016-11-16 18:11:07 +03:00
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
2011-08-20 02:08:47 +04:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (for_each_remote_ref_submodule(path, has_remote, NULL) > 0) {
|
2014-08-19 23:09:35 +04:00
|
|
|
struct child_process cp = CHILD_PROCESS_INIT;
|
2011-08-20 02:08:47 +04:00
|
|
|
struct strbuf buf = STRBUF_INIT;
|
|
|
|
int needs_pushing = 0;
|
|
|
|
|
2016-11-16 18:11:06 +03:00
|
|
|
argv_array_push(&cp.args, "rev-list");
|
2017-03-31 04:40:00 +03:00
|
|
|
oid_array_for_each_unique(commits, append_oid_to_argv, &cp.args);
|
2016-11-16 18:11:06 +03:00
|
|
|
argv_array_pushl(&cp.args, "--not", "--remotes", "-n", "1" , NULL);
|
|
|
|
|
2016-04-28 16:39:15 +03:00
|
|
|
prepare_submodule_repo_env(&cp.env_array);
|
2011-08-20 02:08:47 +04:00
|
|
|
cp.git_cmd = 1;
|
|
|
|
cp.no_stdin = 1;
|
|
|
|
cp.out = -1;
|
|
|
|
cp.dir = path;
|
|
|
|
if (start_command(&cp))
|
2016-11-16 18:11:06 +03:00
|
|
|
die("Could not run 'git rev-list <commits> --not --remotes -n 1' command in submodule %s",
|
|
|
|
path);
|
2011-08-20 02:08:47 +04:00
|
|
|
if (strbuf_read(&buf, cp.out, 41))
|
|
|
|
needs_pushing = 1;
|
|
|
|
finish_command(&cp);
|
|
|
|
close(cp.out);
|
|
|
|
strbuf_release(&buf);
|
|
|
|
return needs_pushing;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-10-19 20:34:43 +03:00
|
|
|
int find_unpushed_submodules(struct repository *r,
|
2018-09-21 18:57:35 +03:00
|
|
|
struct oid_array *commits,
|
|
|
|
const char *remotes_name,
|
|
|
|
struct string_list *needs_pushing)
|
2011-08-20 02:08:47 +04:00
|
|
|
{
|
2016-11-16 18:11:04 +03:00
|
|
|
struct string_list submodules = STRING_LIST_INIT_DUP;
|
2017-10-16 16:58:27 +03:00
|
|
|
struct string_list_item *name;
|
2016-11-16 18:11:05 +03:00
|
|
|
struct argv_array argv = ARGV_ARRAY_INIT;
|
2012-03-29 11:21:23 +04:00
|
|
|
|
2016-11-16 18:11:05 +03:00
|
|
|
/* argv.argv[0] will be ignored by setup_revisions */
|
|
|
|
argv_array_push(&argv, "find_unpushed_submodules");
|
2017-03-31 04:40:00 +03:00
|
|
|
oid_array_for_each_unique(commits, append_oid_to_argv, &argv);
|
2016-11-16 18:11:05 +03:00
|
|
|
argv_array_push(&argv, "--not");
|
|
|
|
argv_array_pushf(&argv, "--remotes=%s", remotes_name);
|
|
|
|
|
2018-10-19 20:34:43 +03:00
|
|
|
collect_changed_submodules(r, &submodules, &argv);
|
2011-08-20 02:08:47 +04:00
|
|
|
|
2017-10-16 16:58:27 +03:00
|
|
|
for_each_string_list_item(name, &submodules) {
|
|
|
|
struct oid_array *commits = name->util;
|
|
|
|
const struct submodule *submodule;
|
|
|
|
const char *path = NULL;
|
|
|
|
|
2018-10-19 20:34:43 +03:00
|
|
|
submodule = submodule_from_name(r, &null_oid, name->string);
|
2017-10-16 16:58:27 +03:00
|
|
|
if (submodule)
|
|
|
|
path = submodule->path;
|
|
|
|
else
|
|
|
|
path = default_name_or_path(name->string);
|
|
|
|
|
|
|
|
if (!path)
|
|
|
|
continue;
|
2016-11-16 18:11:06 +03:00
|
|
|
|
2018-10-19 20:34:43 +03:00
|
|
|
if (submodule_needs_pushing(r, path, commits))
|
2017-05-02 04:02:39 +03:00
|
|
|
string_list_insert(needs_pushing, path);
|
2016-11-16 18:11:04 +03:00
|
|
|
}
|
2017-04-29 02:53:58 +03:00
|
|
|
|
|
|
|
free_submodules_oids(&submodules);
|
2017-05-02 04:02:39 +03:00
|
|
|
argv_array_clear(&argv);
|
2011-08-20 02:08:47 +04:00
|
|
|
|
2012-03-29 11:21:23 +04:00
|
|
|
return needs_pushing->nr;
|
2011-08-20 02:08:47 +04:00
|
|
|
}
|
|
|
|
|
2017-04-05 20:47:16 +03:00
|
|
|
static int push_submodule(const char *path,
|
2017-04-05 20:47:19 +03:00
|
|
|
const struct remote *remote,
|
2018-05-17 01:58:23 +03:00
|
|
|
const struct refspec *rs,
|
2017-04-05 20:47:16 +03:00
|
|
|
const struct string_list *push_options,
|
|
|
|
int dry_run)
|
2012-03-29 11:21:24 +04:00
|
|
|
{
|
|
|
|
if (add_submodule_odb(path))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
if (for_each_remote_ref_submodule(path, has_remote, NULL) > 0) {
|
2014-08-19 23:09:35 +04:00
|
|
|
struct child_process cp = CHILD_PROCESS_INIT;
|
2016-11-17 21:46:04 +03:00
|
|
|
argv_array_push(&cp.args, "push");
|
|
|
|
if (dry_run)
|
|
|
|
argv_array_push(&cp.args, "--dry-run");
|
2012-03-29 11:21:24 +04:00
|
|
|
|
2017-04-05 20:47:16 +03:00
|
|
|
if (push_options && push_options->nr) {
|
|
|
|
const struct string_list_item *item;
|
|
|
|
for_each_string_list_item(item, push_options)
|
|
|
|
argv_array_pushf(&cp.args, "--push-option=%s",
|
|
|
|
item->string);
|
|
|
|
}
|
2017-04-05 20:47:19 +03:00
|
|
|
|
|
|
|
if (remote->origin != REMOTE_UNCONFIGURED) {
|
|
|
|
int i;
|
|
|
|
argv_array_push(&cp.args, remote->name);
|
2018-05-17 01:58:23 +03:00
|
|
|
for (i = 0; i < rs->raw_nr; i++)
|
|
|
|
argv_array_push(&cp.args, rs->raw[i]);
|
2017-04-05 20:47:19 +03:00
|
|
|
}
|
|
|
|
|
2016-04-28 16:39:15 +03:00
|
|
|
prepare_submodule_repo_env(&cp.env_array);
|
2012-03-29 11:21:24 +04:00
|
|
|
cp.git_cmd = 1;
|
|
|
|
cp.no_stdin = 1;
|
|
|
|
cp.dir = path;
|
|
|
|
if (run_command(&cp))
|
|
|
|
return 0;
|
|
|
|
close(cp.out);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2017-04-05 20:47:19 +03:00
|
|
|
/*
|
|
|
|
* Perform a check in the submodule to see if the remote and refspec work.
|
|
|
|
* Die if the submodule can't be pushed.
|
|
|
|
*/
|
2017-07-20 20:40:37 +03:00
|
|
|
static void submodule_push_check(const char *path, const char *head,
|
|
|
|
const struct remote *remote,
|
2018-05-17 01:58:23 +03:00
|
|
|
const struct refspec *rs)
|
2017-04-05 20:47:19 +03:00
|
|
|
{
|
|
|
|
struct child_process cp = CHILD_PROCESS_INIT;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
argv_array_push(&cp.args, "submodule--helper");
|
|
|
|
argv_array_push(&cp.args, "push-check");
|
2017-07-20 20:40:37 +03:00
|
|
|
argv_array_push(&cp.args, head);
|
2017-04-05 20:47:19 +03:00
|
|
|
argv_array_push(&cp.args, remote->name);
|
|
|
|
|
2018-05-17 01:58:23 +03:00
|
|
|
for (i = 0; i < rs->raw_nr; i++)
|
|
|
|
argv_array_push(&cp.args, rs->raw[i]);
|
2017-04-05 20:47:19 +03:00
|
|
|
|
|
|
|
prepare_submodule_repo_env(&cp.env_array);
|
|
|
|
cp.git_cmd = 1;
|
|
|
|
cp.no_stdin = 1;
|
|
|
|
cp.no_stdout = 1;
|
|
|
|
cp.dir = path;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Simply indicate if 'submodule--helper push-check' failed.
|
|
|
|
* More detailed error information will be provided by the
|
|
|
|
* child process.
|
|
|
|
*/
|
|
|
|
if (run_command(&cp))
|
|
|
|
die("process for submodule '%s' failed", path);
|
|
|
|
}
|
|
|
|
|
2018-10-19 20:34:43 +03:00
|
|
|
int push_unpushed_submodules(struct repository *r,
|
2018-09-21 18:57:35 +03:00
|
|
|
struct oid_array *commits,
|
2017-04-05 20:47:19 +03:00
|
|
|
const struct remote *remote,
|
2018-05-17 01:58:23 +03:00
|
|
|
const struct refspec *rs,
|
2017-04-05 20:47:16 +03:00
|
|
|
const struct string_list *push_options,
|
2016-11-17 21:46:04 +03:00
|
|
|
int dry_run)
|
2012-03-29 11:21:24 +04:00
|
|
|
{
|
|
|
|
int i, ret = 1;
|
2014-07-18 13:19:00 +04:00
|
|
|
struct string_list needs_pushing = STRING_LIST_INIT_DUP;
|
2012-03-29 11:21:24 +04:00
|
|
|
|
2018-10-19 20:34:43 +03:00
|
|
|
if (!find_unpushed_submodules(r, commits,
|
2018-09-21 18:57:35 +03:00
|
|
|
remote->name, &needs_pushing))
|
2012-03-29 11:21:24 +04:00
|
|
|
return 1;
|
|
|
|
|
2017-04-05 20:47:19 +03:00
|
|
|
/*
|
|
|
|
* Verify that the remote and refspec can be propagated to all
|
|
|
|
* submodules. This check can be skipped if the remote and refspec
|
|
|
|
* won't be propagated due to the remote being unconfigured (e.g. a URL
|
|
|
|
* instead of a remote name).
|
|
|
|
*/
|
2017-07-20 20:40:37 +03:00
|
|
|
if (remote->origin != REMOTE_UNCONFIGURED) {
|
|
|
|
char *head;
|
|
|
|
struct object_id head_oid;
|
|
|
|
|
refs: convert resolve_refdup and refs_resolve_refdup to struct object_id
All of the callers already pass the hash member of struct object_id, so
update them to pass a pointer to the struct directly,
This transformation was done with an update to declaration and
definition and the following semantic patch:
@@
expression E1, E2, E3, E4;
@@
- resolve_refdup(E1, E2, E3.hash, E4)
+ resolve_refdup(E1, E2, &E3, E4)
@@
expression E1, E2, E3, E4;
@@
- resolve_refdup(E1, E2, E3->hash, E4)
+ resolve_refdup(E1, E2, E3, E4)
Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-10-16 01:06:55 +03:00
|
|
|
head = resolve_refdup("HEAD", 0, &head_oid, NULL);
|
2017-07-20 20:40:37 +03:00
|
|
|
if (!head)
|
|
|
|
die(_("Failed to resolve HEAD as a valid ref."));
|
|
|
|
|
2017-04-05 20:47:19 +03:00
|
|
|
for (i = 0; i < needs_pushing.nr; i++)
|
|
|
|
submodule_push_check(needs_pushing.items[i].string,
|
2018-05-17 01:58:23 +03:00
|
|
|
head, remote, rs);
|
2017-07-20 20:40:37 +03:00
|
|
|
free(head);
|
|
|
|
}
|
2017-04-05 20:47:19 +03:00
|
|
|
|
|
|
|
/* Actually push the submodules */
|
2012-03-29 11:21:24 +04:00
|
|
|
for (i = 0; i < needs_pushing.nr; i++) {
|
|
|
|
const char *path = needs_pushing.items[i].string;
|
|
|
|
fprintf(stderr, "Pushing submodule '%s'\n", path);
|
2018-05-17 01:58:23 +03:00
|
|
|
if (!push_submodule(path, remote, rs,
|
2017-04-05 20:47:19 +03:00
|
|
|
push_options, dry_run)) {
|
2012-03-29 11:21:24 +04:00
|
|
|
fprintf(stderr, "Unable to push submodule '%s'\n", path);
|
|
|
|
ret = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
string_list_clear(&needs_pushing, 0);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-04-29 02:53:57 +03:00
|
|
|
static int append_oid_to_array(const char *ref, const struct object_id *oid,
|
|
|
|
int flags, void *data)
|
2011-09-12 23:56:52 +04:00
|
|
|
{
|
2017-04-29 02:53:57 +03:00
|
|
|
struct oid_array *array = data;
|
|
|
|
oid_array_append(array, oid);
|
2011-09-12 23:56:52 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-03-26 19:01:35 +03:00
|
|
|
void check_for_new_submodule_commits(struct object_id *oid)
|
2011-09-12 23:56:52 +04:00
|
|
|
{
|
|
|
|
if (!initialized_fetch_ref_tips) {
|
2017-04-29 02:53:57 +03:00
|
|
|
for_each_ref(append_oid_to_array, &ref_tips_before_fetch);
|
2011-09-12 23:56:52 +04:00
|
|
|
initialized_fetch_ref_tips = 1;
|
|
|
|
}
|
|
|
|
|
2017-03-31 04:40:00 +03:00
|
|
|
oid_array_append(&ref_tips_after_fetch, oid);
|
2011-09-12 23:56:52 +04:00
|
|
|
}
|
|
|
|
|
2018-10-19 20:34:43 +03:00
|
|
|
static void calculate_changed_submodule_paths(struct repository *r)
|
2011-03-07 01:10:46 +03:00
|
|
|
{
|
2011-09-14 01:57:57 +04:00
|
|
|
struct argv_array argv = ARGV_ARRAY_INIT;
|
2017-05-02 04:02:39 +03:00
|
|
|
struct string_list changed_submodules = STRING_LIST_INIT_DUP;
|
2017-10-16 16:58:27 +03:00
|
|
|
const struct string_list_item *name;
|
2011-03-07 01:10:46 +03:00
|
|
|
|
2011-09-09 22:22:03 +04:00
|
|
|
/* No need to check if there are no submodules configured */
|
2018-10-19 20:34:43 +03:00
|
|
|
if (!submodule_from_path(r, NULL, NULL))
|
2011-09-09 22:22:03 +04:00
|
|
|
return;
|
|
|
|
|
2011-09-14 01:57:57 +04:00
|
|
|
argv_array_push(&argv, "--"); /* argv[0] program name */
|
2017-03-31 04:40:00 +03:00
|
|
|
oid_array_for_each_unique(&ref_tips_after_fetch,
|
2017-04-29 02:53:59 +03:00
|
|
|
append_oid_to_argv, &argv);
|
2011-09-14 01:57:57 +04:00
|
|
|
argv_array_push(&argv, "--not");
|
2017-03-31 04:40:00 +03:00
|
|
|
oid_array_for_each_unique(&ref_tips_before_fetch,
|
2017-04-29 02:53:59 +03:00
|
|
|
append_oid_to_argv, &argv);
|
2011-03-07 01:10:46 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Collect all submodules (whether checked out or not) for which new
|
2017-10-16 16:58:27 +03:00
|
|
|
* commits have been recorded upstream in "changed_submodule_names".
|
2011-03-07 01:10:46 +03:00
|
|
|
*/
|
2018-10-19 20:34:43 +03:00
|
|
|
collect_changed_submodules(r, &changed_submodules, &argv);
|
2017-05-02 04:02:39 +03:00
|
|
|
|
2017-10-16 16:58:27 +03:00
|
|
|
for_each_string_list_item(name, &changed_submodules) {
|
|
|
|
struct oid_array *commits = name->util;
|
|
|
|
const struct submodule *submodule;
|
|
|
|
const char *path = NULL;
|
|
|
|
|
2018-10-19 20:34:43 +03:00
|
|
|
submodule = submodule_from_name(r, &null_oid, name->string);
|
2017-10-16 16:58:27 +03:00
|
|
|
if (submodule)
|
|
|
|
path = submodule->path;
|
|
|
|
else
|
|
|
|
path = default_name_or_path(name->string);
|
|
|
|
|
|
|
|
if (!path)
|
|
|
|
continue;
|
2017-05-02 04:02:39 +03:00
|
|
|
|
2018-10-19 20:34:43 +03:00
|
|
|
if (!submodule_has_commits(r, path, commits))
|
2017-10-16 16:58:27 +03:00
|
|
|
string_list_append(&changed_submodule_names, name->string);
|
2011-03-07 01:10:46 +03:00
|
|
|
}
|
2011-09-12 23:56:52 +04:00
|
|
|
|
2017-05-02 04:02:39 +03:00
|
|
|
free_submodules_oids(&changed_submodules);
|
2011-09-14 01:57:57 +04:00
|
|
|
argv_array_clear(&argv);
|
2017-03-31 04:40:00 +03:00
|
|
|
oid_array_clear(&ref_tips_before_fetch);
|
|
|
|
oid_array_clear(&ref_tips_after_fetch);
|
2011-09-12 23:56:52 +04:00
|
|
|
initialized_fetch_ref_tips = 0;
|
2011-03-07 01:10:46 +03:00
|
|
|
}
|
|
|
|
|
2018-10-19 20:34:43 +03:00
|
|
|
int submodule_touches_in_range(struct repository *r,
|
2018-09-21 18:57:35 +03:00
|
|
|
struct object_id *excl_oid,
|
pull: optionally rebase submodules (remote submodule changes only)
Teach pull to optionally update submodules when '--recurse-submodules'
is provided. This will teach pull to run 'submodule update --rebase'
when the '--recurse-submodules' and '--rebase' flags are given under
specific circumstances.
On a rebase workflow:
=====================
1. Both sides change the submodule
------------------------------
Let's assume the following history in a submodule:
H---I---J---K---L local branch
\
M---N---O---P remote branch
and the following in the superproject (recorded submodule in parens):
A(H)---B(I)---F(K)---G(L) local branch
\
C(N)---D(N)---E(P) remote branch
In an ideal world this would rebase the submodule and rewrite
the submodule pointers that the superproject points at such that
the superproject looks like
A(H)---B(I) F(K')---G(L') rebased branch
\ /
C(N)---D(N)---E(P) remote branch
and the submodule as:
J---K---L (old dangeling tip)
/
H---I J'---K'---L' rebased branch
\ /
M---N---O---P remote branch
And if a conflict arises in the submodule the superproject rebase
would stop at that commit at which the submodule conflict occurs.
Currently a "pull --rebase" in the superproject produces
a merge conflict as the submodule pointer changes are
conflicting and cannot be resolved.
2. Local submodule changes only
-----------------------
Assuming histories as above, except that the remote branch
would not contain submodule changes, then a result as
A(H)---B(I) F(K)---G(L) rebased branch
\ /
C(I)---D(I)---E(I) remote branch
is desire-able. This is what currently happens in rebase.
If the recursive flag is given, the ideal git would
produce a superproject as:
A(H)---B(I) F(K')---G(L') rebased branch (incl. sub rebase!)
\ /
C(I)---D(I)---E(I) remote branch
and the submodule as:
J---K---L (old dangeling tip)
/
H---I J'---K'---L' locally rebased branch
\ /
M---N---O---P advanced branch
This patch doesn't address this issue, however
a test is added that this fails up front.
3. Remote submodule changes only
----------------------
Assuming histories as in (1) except that the local superproject branch
would not have touched the submodule the rebase already works out in the
superproject with no conflicts:
A(H)---B(I) F(P)---G(P) rebased branch (no sub changes)
\ /
C(N)---D(N)---E(P) remote branch
The recurse flag as presented in this patch would additionally
update the submodule as:
H---I J'---K'---L' rebased branch
\ /
M---N---O---P remote branch
As neither J, K, L nor J', K', L' are referred to from the superproject,
no rewriting of the superproject commits is required.
Conclusion for 'pull --rebase --recursive'
-----------------------------------------
If there are no local superproject changes it is sufficient to call
"submodule update --rebase" as this produces the desired results. In case
of conflicts, the behavior is the same as in 'submodule update --recursive'
which is assumed to be sane.
This patch implements (3) only.
On a merge workflow:
====================
We'll start off with the same underlying DAG as in (1) in the rebase
workflow. So in an ideal world a 'pull --merge --recursive' would
produce this:
H---I---J---K---L----X
\ /
M---N---O---P
with X as the new merge-commit in the submodule and the superproject
as:
A(H)---B(I)---F(K)---G(L)---Y(X)
\ /
C(N)---D(N)---E(P)
However modifying the submodules on the fly is not supported in git-merge
such that Y(X) is not easy to produce in a single patch. In fact git-merge
doesn't know about submodules at all.
However when at least one side does not contain commits touching the
submodule at all, then we do not need to perform the merge for the
submodule but a fast-forward can be done via checking out either L or P
in the submodule. This strategy is implemented in 68d03e4a6e (Implement
automatic fast-forward merge for submodules, 2010-07-07) already, so
to align with the rebase behavior we need to also update the worktree
of the submodule.
Signed-off-by: Brandon Williams <bmwill@google.com>
Signed-off-by: Stefan Beller <sbeller@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-06-23 22:13:02 +03:00
|
|
|
struct object_id *incl_oid)
|
|
|
|
{
|
|
|
|
struct string_list subs = STRING_LIST_INIT_DUP;
|
|
|
|
struct argv_array args = ARGV_ARRAY_INIT;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
/* No need to check if there are no submodules configured */
|
2018-10-19 20:34:43 +03:00
|
|
|
if (!submodule_from_path(r, NULL, NULL))
|
pull: optionally rebase submodules (remote submodule changes only)
Teach pull to optionally update submodules when '--recurse-submodules'
is provided. This will teach pull to run 'submodule update --rebase'
when the '--recurse-submodules' and '--rebase' flags are given under
specific circumstances.
On a rebase workflow:
=====================
1. Both sides change the submodule
------------------------------
Let's assume the following history in a submodule:
H---I---J---K---L local branch
\
M---N---O---P remote branch
and the following in the superproject (recorded submodule in parens):
A(H)---B(I)---F(K)---G(L) local branch
\
C(N)---D(N)---E(P) remote branch
In an ideal world this would rebase the submodule and rewrite
the submodule pointers that the superproject points at such that
the superproject looks like
A(H)---B(I) F(K')---G(L') rebased branch
\ /
C(N)---D(N)---E(P) remote branch
and the submodule as:
J---K---L (old dangeling tip)
/
H---I J'---K'---L' rebased branch
\ /
M---N---O---P remote branch
And if a conflict arises in the submodule the superproject rebase
would stop at that commit at which the submodule conflict occurs.
Currently a "pull --rebase" in the superproject produces
a merge conflict as the submodule pointer changes are
conflicting and cannot be resolved.
2. Local submodule changes only
-----------------------
Assuming histories as above, except that the remote branch
would not contain submodule changes, then a result as
A(H)---B(I) F(K)---G(L) rebased branch
\ /
C(I)---D(I)---E(I) remote branch
is desire-able. This is what currently happens in rebase.
If the recursive flag is given, the ideal git would
produce a superproject as:
A(H)---B(I) F(K')---G(L') rebased branch (incl. sub rebase!)
\ /
C(I)---D(I)---E(I) remote branch
and the submodule as:
J---K---L (old dangeling tip)
/
H---I J'---K'---L' locally rebased branch
\ /
M---N---O---P advanced branch
This patch doesn't address this issue, however
a test is added that this fails up front.
3. Remote submodule changes only
----------------------
Assuming histories as in (1) except that the local superproject branch
would not have touched the submodule the rebase already works out in the
superproject with no conflicts:
A(H)---B(I) F(P)---G(P) rebased branch (no sub changes)
\ /
C(N)---D(N)---E(P) remote branch
The recurse flag as presented in this patch would additionally
update the submodule as:
H---I J'---K'---L' rebased branch
\ /
M---N---O---P remote branch
As neither J, K, L nor J', K', L' are referred to from the superproject,
no rewriting of the superproject commits is required.
Conclusion for 'pull --rebase --recursive'
-----------------------------------------
If there are no local superproject changes it is sufficient to call
"submodule update --rebase" as this produces the desired results. In case
of conflicts, the behavior is the same as in 'submodule update --recursive'
which is assumed to be sane.
This patch implements (3) only.
On a merge workflow:
====================
We'll start off with the same underlying DAG as in (1) in the rebase
workflow. So in an ideal world a 'pull --merge --recursive' would
produce this:
H---I---J---K---L----X
\ /
M---N---O---P
with X as the new merge-commit in the submodule and the superproject
as:
A(H)---B(I)---F(K)---G(L)---Y(X)
\ /
C(N)---D(N)---E(P)
However modifying the submodules on the fly is not supported in git-merge
such that Y(X) is not easy to produce in a single patch. In fact git-merge
doesn't know about submodules at all.
However when at least one side does not contain commits touching the
submodule at all, then we do not need to perform the merge for the
submodule but a fast-forward can be done via checking out either L or P
in the submodule. This strategy is implemented in 68d03e4a6e (Implement
automatic fast-forward merge for submodules, 2010-07-07) already, so
to align with the rebase behavior we need to also update the worktree
of the submodule.
Signed-off-by: Brandon Williams <bmwill@google.com>
Signed-off-by: Stefan Beller <sbeller@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-06-23 22:13:02 +03:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
argv_array_push(&args, "--"); /* args[0] program name */
|
|
|
|
argv_array_push(&args, oid_to_hex(incl_oid));
|
2018-05-24 23:47:29 +03:00
|
|
|
if (!is_null_oid(excl_oid)) {
|
|
|
|
argv_array_push(&args, "--not");
|
|
|
|
argv_array_push(&args, oid_to_hex(excl_oid));
|
|
|
|
}
|
pull: optionally rebase submodules (remote submodule changes only)
Teach pull to optionally update submodules when '--recurse-submodules'
is provided. This will teach pull to run 'submodule update --rebase'
when the '--recurse-submodules' and '--rebase' flags are given under
specific circumstances.
On a rebase workflow:
=====================
1. Both sides change the submodule
------------------------------
Let's assume the following history in a submodule:
H---I---J---K---L local branch
\
M---N---O---P remote branch
and the following in the superproject (recorded submodule in parens):
A(H)---B(I)---F(K)---G(L) local branch
\
C(N)---D(N)---E(P) remote branch
In an ideal world this would rebase the submodule and rewrite
the submodule pointers that the superproject points at such that
the superproject looks like
A(H)---B(I) F(K')---G(L') rebased branch
\ /
C(N)---D(N)---E(P) remote branch
and the submodule as:
J---K---L (old dangeling tip)
/
H---I J'---K'---L' rebased branch
\ /
M---N---O---P remote branch
And if a conflict arises in the submodule the superproject rebase
would stop at that commit at which the submodule conflict occurs.
Currently a "pull --rebase" in the superproject produces
a merge conflict as the submodule pointer changes are
conflicting and cannot be resolved.
2. Local submodule changes only
-----------------------
Assuming histories as above, except that the remote branch
would not contain submodule changes, then a result as
A(H)---B(I) F(K)---G(L) rebased branch
\ /
C(I)---D(I)---E(I) remote branch
is desire-able. This is what currently happens in rebase.
If the recursive flag is given, the ideal git would
produce a superproject as:
A(H)---B(I) F(K')---G(L') rebased branch (incl. sub rebase!)
\ /
C(I)---D(I)---E(I) remote branch
and the submodule as:
J---K---L (old dangeling tip)
/
H---I J'---K'---L' locally rebased branch
\ /
M---N---O---P advanced branch
This patch doesn't address this issue, however
a test is added that this fails up front.
3. Remote submodule changes only
----------------------
Assuming histories as in (1) except that the local superproject branch
would not have touched the submodule the rebase already works out in the
superproject with no conflicts:
A(H)---B(I) F(P)---G(P) rebased branch (no sub changes)
\ /
C(N)---D(N)---E(P) remote branch
The recurse flag as presented in this patch would additionally
update the submodule as:
H---I J'---K'---L' rebased branch
\ /
M---N---O---P remote branch
As neither J, K, L nor J', K', L' are referred to from the superproject,
no rewriting of the superproject commits is required.
Conclusion for 'pull --rebase --recursive'
-----------------------------------------
If there are no local superproject changes it is sufficient to call
"submodule update --rebase" as this produces the desired results. In case
of conflicts, the behavior is the same as in 'submodule update --recursive'
which is assumed to be sane.
This patch implements (3) only.
On a merge workflow:
====================
We'll start off with the same underlying DAG as in (1) in the rebase
workflow. So in an ideal world a 'pull --merge --recursive' would
produce this:
H---I---J---K---L----X
\ /
M---N---O---P
with X as the new merge-commit in the submodule and the superproject
as:
A(H)---B(I)---F(K)---G(L)---Y(X)
\ /
C(N)---D(N)---E(P)
However modifying the submodules on the fly is not supported in git-merge
such that Y(X) is not easy to produce in a single patch. In fact git-merge
doesn't know about submodules at all.
However when at least one side does not contain commits touching the
submodule at all, then we do not need to perform the merge for the
submodule but a fast-forward can be done via checking out either L or P
in the submodule. This strategy is implemented in 68d03e4a6e (Implement
automatic fast-forward merge for submodules, 2010-07-07) already, so
to align with the rebase behavior we need to also update the worktree
of the submodule.
Signed-off-by: Brandon Williams <bmwill@google.com>
Signed-off-by: Stefan Beller <sbeller@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-06-23 22:13:02 +03:00
|
|
|
|
2018-10-19 20:34:43 +03:00
|
|
|
collect_changed_submodules(r, &subs, &args);
|
pull: optionally rebase submodules (remote submodule changes only)
Teach pull to optionally update submodules when '--recurse-submodules'
is provided. This will teach pull to run 'submodule update --rebase'
when the '--recurse-submodules' and '--rebase' flags are given under
specific circumstances.
On a rebase workflow:
=====================
1. Both sides change the submodule
------------------------------
Let's assume the following history in a submodule:
H---I---J---K---L local branch
\
M---N---O---P remote branch
and the following in the superproject (recorded submodule in parens):
A(H)---B(I)---F(K)---G(L) local branch
\
C(N)---D(N)---E(P) remote branch
In an ideal world this would rebase the submodule and rewrite
the submodule pointers that the superproject points at such that
the superproject looks like
A(H)---B(I) F(K')---G(L') rebased branch
\ /
C(N)---D(N)---E(P) remote branch
and the submodule as:
J---K---L (old dangeling tip)
/
H---I J'---K'---L' rebased branch
\ /
M---N---O---P remote branch
And if a conflict arises in the submodule the superproject rebase
would stop at that commit at which the submodule conflict occurs.
Currently a "pull --rebase" in the superproject produces
a merge conflict as the submodule pointer changes are
conflicting and cannot be resolved.
2. Local submodule changes only
-----------------------
Assuming histories as above, except that the remote branch
would not contain submodule changes, then a result as
A(H)---B(I) F(K)---G(L) rebased branch
\ /
C(I)---D(I)---E(I) remote branch
is desire-able. This is what currently happens in rebase.
If the recursive flag is given, the ideal git would
produce a superproject as:
A(H)---B(I) F(K')---G(L') rebased branch (incl. sub rebase!)
\ /
C(I)---D(I)---E(I) remote branch
and the submodule as:
J---K---L (old dangeling tip)
/
H---I J'---K'---L' locally rebased branch
\ /
M---N---O---P advanced branch
This patch doesn't address this issue, however
a test is added that this fails up front.
3. Remote submodule changes only
----------------------
Assuming histories as in (1) except that the local superproject branch
would not have touched the submodule the rebase already works out in the
superproject with no conflicts:
A(H)---B(I) F(P)---G(P) rebased branch (no sub changes)
\ /
C(N)---D(N)---E(P) remote branch
The recurse flag as presented in this patch would additionally
update the submodule as:
H---I J'---K'---L' rebased branch
\ /
M---N---O---P remote branch
As neither J, K, L nor J', K', L' are referred to from the superproject,
no rewriting of the superproject commits is required.
Conclusion for 'pull --rebase --recursive'
-----------------------------------------
If there are no local superproject changes it is sufficient to call
"submodule update --rebase" as this produces the desired results. In case
of conflicts, the behavior is the same as in 'submodule update --recursive'
which is assumed to be sane.
This patch implements (3) only.
On a merge workflow:
====================
We'll start off with the same underlying DAG as in (1) in the rebase
workflow. So in an ideal world a 'pull --merge --recursive' would
produce this:
H---I---J---K---L----X
\ /
M---N---O---P
with X as the new merge-commit in the submodule and the superproject
as:
A(H)---B(I)---F(K)---G(L)---Y(X)
\ /
C(N)---D(N)---E(P)
However modifying the submodules on the fly is not supported in git-merge
such that Y(X) is not easy to produce in a single patch. In fact git-merge
doesn't know about submodules at all.
However when at least one side does not contain commits touching the
submodule at all, then we do not need to perform the merge for the
submodule but a fast-forward can be done via checking out either L or P
in the submodule. This strategy is implemented in 68d03e4a6e (Implement
automatic fast-forward merge for submodules, 2010-07-07) already, so
to align with the rebase behavior we need to also update the worktree
of the submodule.
Signed-off-by: Brandon Williams <bmwill@google.com>
Signed-off-by: Stefan Beller <sbeller@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-06-23 22:13:02 +03:00
|
|
|
ret = subs.nr;
|
|
|
|
|
|
|
|
argv_array_clear(&args);
|
|
|
|
|
|
|
|
free_submodules_oids(&subs);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2015-12-16 03:04:11 +03:00
|
|
|
struct submodule_parallel_fetch {
|
|
|
|
int count;
|
|
|
|
struct argv_array args;
|
2017-12-12 22:53:52 +03:00
|
|
|
struct repository *r;
|
2015-12-16 03:04:11 +03:00
|
|
|
const char *prefix;
|
|
|
|
int command_line_option;
|
2017-08-02 22:49:19 +03:00
|
|
|
int default_option;
|
2015-12-16 03:04:11 +03:00
|
|
|
int quiet;
|
|
|
|
int result;
|
|
|
|
};
|
2017-08-02 22:49:19 +03:00
|
|
|
#define SPF_INIT {0, ARGV_ARRAY_INIT, NULL, NULL, 0, 0, 0, 0}
|
2015-12-16 03:04:11 +03:00
|
|
|
|
2017-10-16 16:59:05 +03:00
|
|
|
static int get_fetch_recurse_config(const struct submodule *submodule,
|
|
|
|
struct submodule_parallel_fetch *spf)
|
|
|
|
{
|
|
|
|
if (spf->command_line_option != RECURSE_SUBMODULES_DEFAULT)
|
|
|
|
return spf->command_line_option;
|
|
|
|
|
|
|
|
if (submodule) {
|
|
|
|
char *key;
|
|
|
|
const char *value;
|
|
|
|
|
|
|
|
int fetch_recurse = submodule->fetch_recurse;
|
|
|
|
key = xstrfmt("submodule.%s.fetchRecurseSubmodules", submodule->name);
|
2017-12-12 22:53:52 +03:00
|
|
|
if (!repo_config_get_string_const(spf->r, key, &value)) {
|
2017-10-16 16:59:05 +03:00
|
|
|
fetch_recurse = parse_fetch_recurse_submodules_arg(key, value);
|
|
|
|
}
|
|
|
|
free(key);
|
|
|
|
|
|
|
|
if (fetch_recurse != RECURSE_SUBMODULES_NONE)
|
|
|
|
/* local config overrules everything except commandline */
|
|
|
|
return fetch_recurse;
|
|
|
|
}
|
|
|
|
|
|
|
|
return spf->default_option;
|
|
|
|
}
|
|
|
|
|
2015-12-16 03:04:11 +03:00
|
|
|
static int get_next_submodule(struct child_process *cp,
|
|
|
|
struct strbuf *err, void *data, void **task_cb)
|
2010-11-12 15:54:52 +03:00
|
|
|
{
|
2015-12-16 03:04:11 +03:00
|
|
|
int ret = 0;
|
|
|
|
struct submodule_parallel_fetch *spf = data;
|
2011-09-12 23:56:52 +04:00
|
|
|
|
2017-12-12 22:53:52 +03:00
|
|
|
for (; spf->count < spf->r->index->cache_nr; spf->count++) {
|
2010-11-12 15:54:52 +03:00
|
|
|
struct strbuf submodule_path = STRBUF_INIT;
|
|
|
|
struct strbuf submodule_git_dir = STRBUF_INIT;
|
|
|
|
struct strbuf submodule_prefix = STRBUF_INIT;
|
2017-12-12 22:53:52 +03:00
|
|
|
const struct cache_entry *ce = spf->r->index->cache[spf->count];
|
2015-08-18 03:21:59 +03:00
|
|
|
const char *git_dir, *default_argv;
|
|
|
|
const struct submodule *submodule;
|
2017-10-16 16:58:27 +03:00
|
|
|
struct submodule default_submodule = SUBMODULE_INIT;
|
2010-11-12 15:54:52 +03:00
|
|
|
|
|
|
|
if (!S_ISGITLINK(ce->ce_mode))
|
|
|
|
continue;
|
|
|
|
|
2018-03-29 01:35:30 +03:00
|
|
|
submodule = submodule_from_path(spf->r, &null_oid, ce->name);
|
2017-10-16 16:58:27 +03:00
|
|
|
if (!submodule) {
|
|
|
|
const char *name = default_name_or_path(ce->name);
|
|
|
|
if (name) {
|
|
|
|
default_submodule.path = default_submodule.name = name;
|
|
|
|
submodule = &default_submodule;
|
2017-08-03 21:19:51 +03:00
|
|
|
}
|
2017-10-16 16:58:27 +03:00
|
|
|
}
|
2017-08-03 21:19:51 +03:00
|
|
|
|
2017-10-16 16:59:05 +03:00
|
|
|
switch (get_fetch_recurse_config(submodule, spf))
|
|
|
|
{
|
|
|
|
default:
|
|
|
|
case RECURSE_SUBMODULES_DEFAULT:
|
|
|
|
case RECURSE_SUBMODULES_ON_DEMAND:
|
|
|
|
if (!submodule || !unsorted_string_list_lookup(&changed_submodule_names,
|
2017-10-16 16:58:27 +03:00
|
|
|
submodule->name))
|
2011-03-07 01:11:21 +03:00
|
|
|
continue;
|
|
|
|
default_argv = "on-demand";
|
2017-10-16 16:59:05 +03:00
|
|
|
break;
|
|
|
|
case RECURSE_SUBMODULES_ON:
|
|
|
|
default_argv = "yes";
|
|
|
|
break;
|
|
|
|
case RECURSE_SUBMODULES_OFF:
|
|
|
|
continue;
|
2010-11-11 02:55:02 +03:00
|
|
|
}
|
|
|
|
|
2017-12-12 22:53:52 +03:00
|
|
|
strbuf_repo_worktree_path(&submodule_path, spf->r, "%s", ce->name);
|
2010-11-12 15:54:52 +03:00
|
|
|
strbuf_addf(&submodule_git_dir, "%s/.git", submodule_path.buf);
|
2015-12-16 03:04:11 +03:00
|
|
|
strbuf_addf(&submodule_prefix, "%s%s/", spf->prefix, ce->name);
|
2011-08-23 01:04:56 +04:00
|
|
|
git_dir = read_gitfile(submodule_git_dir.buf);
|
2010-11-12 15:54:52 +03:00
|
|
|
if (!git_dir)
|
|
|
|
git_dir = submodule_git_dir.buf;
|
|
|
|
if (is_directory(git_dir)) {
|
2015-12-16 03:04:11 +03:00
|
|
|
child_process_init(cp);
|
|
|
|
cp->dir = strbuf_detach(&submodule_path, NULL);
|
2016-04-28 16:39:15 +03:00
|
|
|
prepare_submodule_repo_env(&cp->env_array);
|
2015-12-16 03:04:11 +03:00
|
|
|
cp->git_cmd = 1;
|
|
|
|
if (!spf->quiet)
|
|
|
|
strbuf_addf(err, "Fetching submodule %s%s\n",
|
|
|
|
spf->prefix, ce->name);
|
|
|
|
argv_array_init(&cp->args);
|
|
|
|
argv_array_pushv(&cp->args, spf->args.argv);
|
|
|
|
argv_array_push(&cp->args, default_argv);
|
|
|
|
argv_array_push(&cp->args, "--submodule-prefix");
|
|
|
|
argv_array_push(&cp->args, submodule_prefix.buf);
|
|
|
|
ret = 1;
|
2010-11-12 15:54:52 +03:00
|
|
|
}
|
|
|
|
strbuf_release(&submodule_path);
|
|
|
|
strbuf_release(&submodule_git_dir);
|
|
|
|
strbuf_release(&submodule_prefix);
|
2015-12-16 03:04:11 +03:00
|
|
|
if (ret) {
|
|
|
|
spf->count++;
|
|
|
|
return 1;
|
|
|
|
}
|
2010-11-12 15:54:52 +03:00
|
|
|
}
|
2015-12-16 03:04:11 +03:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-03-01 00:57:06 +03:00
|
|
|
static int fetch_start_failure(struct strbuf *err,
|
2015-12-16 03:04:11 +03:00
|
|
|
void *cb, void *task_cb)
|
|
|
|
{
|
|
|
|
struct submodule_parallel_fetch *spf = cb;
|
|
|
|
|
|
|
|
spf->result = 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-03-01 00:57:06 +03:00
|
|
|
static int fetch_finish(int retvalue, struct strbuf *err,
|
|
|
|
void *cb, void *task_cb)
|
2015-12-16 03:04:11 +03:00
|
|
|
{
|
|
|
|
struct submodule_parallel_fetch *spf = cb;
|
|
|
|
|
|
|
|
if (retvalue)
|
|
|
|
spf->result = 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-12-12 22:53:52 +03:00
|
|
|
int fetch_populated_submodules(struct repository *r,
|
|
|
|
const struct argv_array *options,
|
2015-12-16 03:04:11 +03:00
|
|
|
const char *prefix, int command_line_option,
|
2017-08-02 22:49:19 +03:00
|
|
|
int default_option,
|
2015-12-16 03:04:12 +03:00
|
|
|
int quiet, int max_parallel_jobs)
|
2015-12-16 03:04:11 +03:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
struct submodule_parallel_fetch spf = SPF_INIT;
|
|
|
|
|
2017-12-12 22:53:52 +03:00
|
|
|
spf.r = r;
|
2015-12-16 03:04:11 +03:00
|
|
|
spf.command_line_option = command_line_option;
|
2017-08-02 22:49:19 +03:00
|
|
|
spf.default_option = default_option;
|
2015-12-16 03:04:11 +03:00
|
|
|
spf.quiet = quiet;
|
|
|
|
spf.prefix = prefix;
|
|
|
|
|
2017-12-12 22:53:52 +03:00
|
|
|
if (!r->worktree)
|
2015-12-16 03:04:11 +03:00
|
|
|
goto out;
|
|
|
|
|
2017-12-12 22:53:52 +03:00
|
|
|
if (repo_read_index(r) < 0)
|
2015-12-16 03:04:11 +03:00
|
|
|
die("index file corrupt");
|
|
|
|
|
|
|
|
argv_array_push(&spf.args, "fetch");
|
|
|
|
for (i = 0; i < options->argc; i++)
|
|
|
|
argv_array_push(&spf.args, options->argv[i]);
|
|
|
|
argv_array_push(&spf.args, "--recurse-submodules-default");
|
|
|
|
/* default value, "--submodule-prefix" and its value are added later */
|
|
|
|
|
2018-10-19 20:34:43 +03:00
|
|
|
calculate_changed_submodule_paths(r);
|
2015-12-16 03:04:11 +03:00
|
|
|
run_processes_parallel(max_parallel_jobs,
|
|
|
|
get_next_submodule,
|
|
|
|
fetch_start_failure,
|
|
|
|
fetch_finish,
|
|
|
|
&spf);
|
|
|
|
|
|
|
|
argv_array_clear(&spf.args);
|
2011-03-07 01:10:46 +03:00
|
|
|
out:
|
2017-10-16 16:58:27 +03:00
|
|
|
string_list_clear(&changed_submodule_names, 1);
|
2015-12-16 03:04:11 +03:00
|
|
|
return spf.result;
|
2010-11-12 15:54:52 +03:00
|
|
|
}
|
|
|
|
|
2010-03-14 01:00:27 +03:00
|
|
|
unsigned is_submodule_modified(const char *path, int ignore_untracked)
|
2010-01-16 20:42:24 +03:00
|
|
|
{
|
2014-08-19 23:09:35 +04:00
|
|
|
struct child_process cp = CHILD_PROCESS_INIT;
|
2010-01-16 20:42:24 +03:00
|
|
|
struct strbuf buf = STRBUF_INIT;
|
2017-03-25 03:36:06 +03:00
|
|
|
FILE *fp;
|
2010-03-05 00:20:33 +03:00
|
|
|
unsigned dirty_submodule = 0;
|
2010-04-10 21:01:12 +04:00
|
|
|
const char *git_dir;
|
2017-03-25 03:36:06 +03:00
|
|
|
int ignore_cp_exit_code = 0;
|
2010-01-16 20:42:24 +03:00
|
|
|
|
2010-04-10 21:01:12 +04:00
|
|
|
strbuf_addf(&buf, "%s/.git", path);
|
2011-08-23 01:04:56 +04:00
|
|
|
git_dir = read_gitfile(buf.buf);
|
2010-04-10 21:01:12 +04:00
|
|
|
if (!git_dir)
|
|
|
|
git_dir = buf.buf;
|
2017-03-25 03:36:08 +03:00
|
|
|
if (!is_git_directory(git_dir)) {
|
|
|
|
if (is_directory(git_dir))
|
|
|
|
die(_("'%s' not recognized as a git repository"), git_dir);
|
2010-01-16 20:42:24 +03:00
|
|
|
strbuf_release(&buf);
|
|
|
|
/* The submodule is not checked out, so it is not modified */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
strbuf_reset(&buf);
|
|
|
|
|
2017-03-25 03:36:07 +03:00
|
|
|
argv_array_pushl(&cp.args, "status", "--porcelain=2", NULL);
|
2010-03-14 01:00:27 +03:00
|
|
|
if (ignore_untracked)
|
2017-03-25 03:36:04 +03:00
|
|
|
argv_array_push(&cp.args, "-uno");
|
2010-03-14 01:00:27 +03:00
|
|
|
|
2016-04-28 16:39:15 +03:00
|
|
|
prepare_submodule_repo_env(&cp.env_array);
|
2010-01-16 20:42:24 +03:00
|
|
|
cp.git_cmd = 1;
|
|
|
|
cp.no_stdin = 1;
|
|
|
|
cp.out = -1;
|
2010-04-10 21:01:12 +04:00
|
|
|
cp.dir = path;
|
2010-01-16 20:42:24 +03:00
|
|
|
if (start_command(&cp))
|
2017-03-25 03:36:07 +03:00
|
|
|
die("Could not run 'git status --porcelain=2' in submodule %s", path);
|
2010-01-16 20:42:24 +03:00
|
|
|
|
2017-03-25 03:36:06 +03:00
|
|
|
fp = xfdopen(cp.out, "r");
|
|
|
|
while (strbuf_getwholeline(&buf, fp, '\n') != EOF) {
|
2017-03-25 03:36:07 +03:00
|
|
|
/* regular untracked files */
|
|
|
|
if (buf.buf[0] == '?')
|
2010-03-05 00:20:33 +03:00
|
|
|
dirty_submodule |= DIRTY_SUBMODULE_UNTRACKED;
|
2017-03-30 01:26:16 +03:00
|
|
|
|
|
|
|
if (buf.buf[0] == 'u' ||
|
|
|
|
buf.buf[0] == '1' ||
|
|
|
|
buf.buf[0] == '2') {
|
|
|
|
/* T = line type, XY = status, SSSS = submodule state */
|
|
|
|
if (buf.len < strlen("T XY SSSS"))
|
2018-05-02 12:38:39 +03:00
|
|
|
BUG("invalid status --porcelain=2 line %s",
|
2017-03-30 01:26:16 +03:00
|
|
|
buf.buf);
|
|
|
|
|
|
|
|
if (buf.buf[5] == 'S' && buf.buf[8] == 'U')
|
|
|
|
/* nested untracked file */
|
|
|
|
dirty_submodule |= DIRTY_SUBMODULE_UNTRACKED;
|
|
|
|
|
|
|
|
if (buf.buf[0] == 'u' ||
|
|
|
|
buf.buf[0] == '2' ||
|
|
|
|
memcmp(buf.buf + 5, "S..U", 4))
|
|
|
|
/* other change */
|
|
|
|
dirty_submodule |= DIRTY_SUBMODULE_MODIFIED;
|
2010-03-05 00:20:33 +03:00
|
|
|
}
|
2017-03-25 03:36:05 +03:00
|
|
|
|
|
|
|
if ((dirty_submodule & DIRTY_SUBMODULE_MODIFIED) &&
|
|
|
|
((dirty_submodule & DIRTY_SUBMODULE_UNTRACKED) ||
|
2017-03-25 03:36:06 +03:00
|
|
|
ignore_untracked)) {
|
|
|
|
/*
|
|
|
|
* We're not interested in any further information from
|
|
|
|
* the child any more, neither output nor its exit code.
|
|
|
|
*/
|
|
|
|
ignore_cp_exit_code = 1;
|
2010-03-05 00:20:33 +03:00
|
|
|
break;
|
2017-03-25 03:36:06 +03:00
|
|
|
}
|
2010-03-05 00:20:33 +03:00
|
|
|
}
|
2017-03-25 03:36:06 +03:00
|
|
|
fclose(fp);
|
2010-01-16 20:42:24 +03:00
|
|
|
|
2017-03-25 03:36:06 +03:00
|
|
|
if (finish_command(&cp) && !ignore_cp_exit_code)
|
2017-03-25 03:36:07 +03:00
|
|
|
die("'git status --porcelain=2' failed in submodule %s", path);
|
2010-01-16 20:42:24 +03:00
|
|
|
|
|
|
|
strbuf_release(&buf);
|
2010-03-05 00:20:33 +03:00
|
|
|
return dirty_submodule;
|
2010-01-16 20:42:24 +03:00
|
|
|
}
|
2010-07-07 17:39:13 +04:00
|
|
|
|
2012-09-26 22:21:13 +04:00
|
|
|
int submodule_uses_gitfile(const char *path)
|
|
|
|
{
|
2014-08-19 23:09:35 +04:00
|
|
|
struct child_process cp = CHILD_PROCESS_INIT;
|
2012-09-26 22:21:13 +04:00
|
|
|
const char *argv[] = {
|
|
|
|
"submodule",
|
|
|
|
"foreach",
|
|
|
|
"--quiet",
|
|
|
|
"--recursive",
|
|
|
|
"test -f .git",
|
|
|
|
NULL,
|
|
|
|
};
|
|
|
|
struct strbuf buf = STRBUF_INIT;
|
|
|
|
const char *git_dir;
|
|
|
|
|
|
|
|
strbuf_addf(&buf, "%s/.git", path);
|
|
|
|
git_dir = read_gitfile(buf.buf);
|
|
|
|
if (!git_dir) {
|
|
|
|
strbuf_release(&buf);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
strbuf_release(&buf);
|
|
|
|
|
|
|
|
/* Now test that all nested submodules use a gitfile too */
|
|
|
|
cp.argv = argv;
|
2016-04-28 16:39:15 +03:00
|
|
|
prepare_submodule_repo_env(&cp.env_array);
|
2012-09-26 22:21:13 +04:00
|
|
|
cp.git_cmd = 1;
|
|
|
|
cp.no_stdin = 1;
|
|
|
|
cp.no_stderr = 1;
|
|
|
|
cp.no_stdout = 1;
|
|
|
|
cp.dir = path;
|
|
|
|
if (run_command(&cp))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2016-12-21 02:20:11 +03:00
|
|
|
/*
|
|
|
|
* 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)
|
2012-09-26 22:21:13 +04:00
|
|
|
{
|
|
|
|
ssize_t len;
|
2014-08-19 23:09:35 +04:00
|
|
|
struct child_process cp = CHILD_PROCESS_INIT;
|
2012-09-26 22:21:13 +04:00
|
|
|
struct strbuf buf = STRBUF_INIT;
|
2016-12-21 02:20:11 +03:00
|
|
|
int ret = 0;
|
2012-09-26 22:21:13 +04:00
|
|
|
|
2015-05-20 00:44:23 +03:00
|
|
|
if (!file_exists(path) || is_empty_dir(path))
|
2016-12-21 02:20:11 +03:00
|
|
|
return 0;
|
2012-09-26 22:21:13 +04:00
|
|
|
|
|
|
|
if (!submodule_uses_gitfile(path))
|
2016-12-21 02:20:11 +03:00
|
|
|
return 1;
|
2012-09-26 22:21:13 +04:00
|
|
|
|
2016-12-21 02:20:11 +03:00
|
|
|
argv_array_pushl(&cp.args, "status", "--porcelain",
|
2016-12-21 02:20:10 +03:00
|
|
|
"--ignore-submodules=none", NULL);
|
2016-12-21 02:20:11 +03:00
|
|
|
|
|
|
|
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");
|
2012-09-26 22:21:13 +04:00
|
|
|
|
2016-04-28 16:39:15 +03:00
|
|
|
prepare_submodule_repo_env(&cp.env_array);
|
2012-09-26 22:21:13 +04:00
|
|
|
cp.git_cmd = 1;
|
|
|
|
cp.no_stdin = 1;
|
|
|
|
cp.out = -1;
|
|
|
|
cp.dir = path;
|
2016-12-21 02:20:11 +03:00
|
|
|
if (start_command(&cp)) {
|
|
|
|
if (flags & SUBMODULE_REMOVAL_DIE_ON_ERROR)
|
2017-04-13 19:40:45 +03:00
|
|
|
die(_("could not start 'git status' in submodule '%s'"),
|
2016-12-21 02:20:11 +03:00
|
|
|
path);
|
|
|
|
ret = -1;
|
|
|
|
goto out;
|
|
|
|
}
|
2012-09-26 22:21:13 +04:00
|
|
|
|
|
|
|
len = strbuf_read(&buf, cp.out, 1024);
|
|
|
|
if (len > 2)
|
2016-12-21 02:20:11 +03:00
|
|
|
ret = 1;
|
2012-09-26 22:21:13 +04:00
|
|
|
close(cp.out);
|
|
|
|
|
2016-12-21 02:20:11 +03:00
|
|
|
if (finish_command(&cp)) {
|
|
|
|
if (flags & SUBMODULE_REMOVAL_DIE_ON_ERROR)
|
2017-04-13 19:40:45 +03:00
|
|
|
die(_("could not run 'git status' in submodule '%s'"),
|
2016-12-21 02:20:11 +03:00
|
|
|
path);
|
|
|
|
ret = -1;
|
|
|
|
}
|
|
|
|
out:
|
2012-09-26 22:21:13 +04:00
|
|
|
strbuf_release(&buf);
|
2016-12-21 02:20:11 +03:00
|
|
|
return ret;
|
2012-09-26 22:21:13 +04:00
|
|
|
}
|
|
|
|
|
submodule: unset core.worktree if no working tree is present
When a submodules work tree is removed, we should unset its core.worktree
setting as the worktree is no longer present. This is not just in line
with the conceptual view of submodules, but it fixes an inconvenience
for looking at submodules that are not checked out:
git clone --recurse-submodules git://github.com/git/git && cd git &&
git checkout --recurse-submodules v2.13.0
git -C .git/modules/sha1collisiondetection log
fatal: cannot chdir to '../../../sha1collisiondetection': \
No such file or directory
With this patch applied, the final call to git log works instead of dying
in its setup, as the checkout will unset the core.worktree setting such
that following log will be run in a bare repository.
This patch covers all commands that are in the unpack machinery, i.e.
checkout, read-tree, reset. A follow up patch will address
"git submodule deinit", which will also make use of the new function
submodule_unset_core_worktree(), which is why we expose it in this patch.
This patch was authored as 4fa4f90ccd (submodule: unset core.worktree if
no working tree is present, 2018-06-12), which was reverted as part of
f178c13fda (Revert "Merge branch 'sb/submodule-core-worktree'",
2018-09-07). The revert was needed as the nearby commit e98317508c
(submodule: ensure core.worktree is set after update, 2018-06-18) is
faulty and at the time of 7e25437d35 (Merge branch
'sb/submodule-core-worktree', 2018-07-18) we could not revert the faulty
commit only, as they were depending on each other: If core.worktree is
unset, we have to have ways to ensure that it is set again once
the working tree reappears again.
Now that 4d6d6ef1fc (Merge branch 'sb/submodule-update-in-c', 2018-09-17),
specifically 74d4731da1 (submodule--helper: replace
connect-gitdir-workingtree by ensure-core-worktree, 2018-08-13) is
present, we already check and ensure core.worktree is set when
populating a new work tree, such that we can re-introduce the commits
that unset core.worktree when removing the worktree.
Signed-off-by: Stefan Beller <sbeller@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Stefan Beller <sbeller@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-12-15 02:59:43 +03:00
|
|
|
void submodule_unset_core_worktree(const struct submodule *sub)
|
|
|
|
{
|
|
|
|
char *config_path = xstrfmt("%s/modules/%s/config",
|
|
|
|
get_git_common_dir(), sub->name);
|
|
|
|
|
|
|
|
if (git_config_set_in_file_gently(config_path, "core.worktree", NULL))
|
|
|
|
warning(_("Could not unset core.worktree setting in submodule '%s'"),
|
|
|
|
sub->path);
|
|
|
|
|
|
|
|
free(config_path);
|
|
|
|
}
|
|
|
|
|
2017-03-15 00:46:36 +03:00
|
|
|
static const char *get_super_prefix_or_empty(void)
|
|
|
|
{
|
|
|
|
const char *s = get_super_prefix();
|
|
|
|
if (!s)
|
|
|
|
s = "";
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
2017-03-15 00:46:37 +03:00
|
|
|
static int submodule_has_dirty_index(const struct submodule *sub)
|
|
|
|
{
|
|
|
|
struct child_process cp = CHILD_PROCESS_INIT;
|
|
|
|
|
2017-05-02 22:32:13 +03:00
|
|
|
prepare_submodule_repo_env(&cp.env_array);
|
2017-03-15 00:46:37 +03:00
|
|
|
|
|
|
|
cp.git_cmd = 1;
|
|
|
|
argv_array_pushl(&cp.args, "diff-index", "--quiet",
|
|
|
|
"--cached", "HEAD", NULL);
|
|
|
|
cp.no_stdin = 1;
|
|
|
|
cp.no_stdout = 1;
|
|
|
|
cp.dir = sub->path;
|
|
|
|
if (start_command(&cp))
|
|
|
|
die("could not recurse into submodule '%s'", sub->path);
|
|
|
|
|
|
|
|
return finish_command(&cp);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void submodule_reset_index(const char *path)
|
|
|
|
{
|
|
|
|
struct child_process cp = CHILD_PROCESS_INIT;
|
2017-05-02 22:32:13 +03:00
|
|
|
prepare_submodule_repo_env(&cp.env_array);
|
2017-03-15 00:46:37 +03:00
|
|
|
|
|
|
|
cp.git_cmd = 1;
|
|
|
|
cp.no_stdin = 1;
|
|
|
|
cp.dir = path;
|
|
|
|
|
|
|
|
argv_array_pushf(&cp.args, "--super-prefix=%s%s/",
|
|
|
|
get_super_prefix_or_empty(), path);
|
|
|
|
argv_array_pushl(&cp.args, "read-tree", "-u", "--reset", NULL);
|
|
|
|
|
2018-05-02 03:25:59 +03:00
|
|
|
argv_array_push(&cp.args, empty_tree_oid_hex());
|
2017-03-15 00:46:37 +03:00
|
|
|
|
|
|
|
if (run_command(&cp))
|
|
|
|
die("could not reset submodule index");
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Moves a submodule at a given path from a given head to another new head.
|
|
|
|
* For edge cases (a submodule coming into existence or removing a submodule)
|
|
|
|
* pass NULL for old or new respectively.
|
|
|
|
*/
|
|
|
|
int submodule_move_head(const char *path,
|
2018-02-14 21:59:49 +03:00
|
|
|
const char *old_head,
|
|
|
|
const char *new_head,
|
2017-03-15 00:46:37 +03:00
|
|
|
unsigned flags)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
struct child_process cp = CHILD_PROCESS_INIT;
|
|
|
|
const struct submodule *sub;
|
2017-04-19 00:37:24 +03:00
|
|
|
int *error_code_ptr, error_code;
|
2017-03-15 00:46:37 +03:00
|
|
|
|
2017-06-22 21:43:46 +03:00
|
|
|
if (!is_submodule_active(the_repository, path))
|
2017-04-19 00:37:23 +03:00
|
|
|
return 0;
|
|
|
|
|
2017-04-19 00:37:24 +03:00
|
|
|
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;
|
|
|
|
|
2018-02-14 21:59:49 +03:00
|
|
|
if (old_head && !is_submodule_populated_gently(path, error_code_ptr))
|
2017-04-19 00:37:24 +03:00
|
|
|
return 0;
|
2017-03-15 00:46:37 +03:00
|
|
|
|
2018-03-29 01:35:29 +03:00
|
|
|
sub = submodule_from_path(the_repository, &null_oid, path);
|
2017-03-15 00:46:37 +03:00
|
|
|
|
|
|
|
if (!sub)
|
2018-05-02 12:38:39 +03:00
|
|
|
BUG("could not get submodule information for '%s'", path);
|
2017-03-15 00:46:37 +03:00
|
|
|
|
2018-02-14 21:59:49 +03:00
|
|
|
if (old_head && !(flags & SUBMODULE_MOVE_HEAD_FORCE)) {
|
2017-03-15 00:46:37 +03:00
|
|
|
/* Check if the submodule has a dirty index. */
|
|
|
|
if (submodule_has_dirty_index(sub))
|
|
|
|
return error(_("submodule '%s' has dirty index"), path);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(flags & SUBMODULE_MOVE_HEAD_DRY_RUN)) {
|
2018-02-14 21:59:49 +03:00
|
|
|
if (old_head) {
|
2017-03-15 00:46:37 +03:00
|
|
|
if (!submodule_uses_gitfile(path))
|
|
|
|
absorb_git_dir_into_superproject("", path,
|
|
|
|
ABSORB_GITDIR_RECURSE_SUBMODULES);
|
|
|
|
} else {
|
2017-04-19 00:37:24 +03:00
|
|
|
char *gitdir = xstrfmt("%s/modules/%s",
|
2017-03-15 00:46:37 +03:00
|
|
|
get_git_common_dir(), sub->name);
|
2018-03-29 01:35:31 +03:00
|
|
|
connect_work_tree_and_git_dir(path, gitdir, 0);
|
2017-04-19 00:37:24 +03:00
|
|
|
free(gitdir);
|
2017-03-15 00:46:37 +03:00
|
|
|
|
|
|
|
/* make sure the index is clean as well */
|
|
|
|
submodule_reset_index(path);
|
|
|
|
}
|
2017-04-19 00:37:24 +03:00
|
|
|
|
2018-02-14 21:59:49 +03:00
|
|
|
if (old_head && (flags & SUBMODULE_MOVE_HEAD_FORCE)) {
|
2017-04-19 00:37:24 +03:00
|
|
|
char *gitdir = xstrfmt("%s/modules/%s",
|
|
|
|
get_git_common_dir(), sub->name);
|
2018-03-29 01:35:31 +03:00
|
|
|
connect_work_tree_and_git_dir(path, gitdir, 1);
|
2017-04-19 00:37:24 +03:00
|
|
|
free(gitdir);
|
|
|
|
}
|
2017-03-15 00:46:37 +03:00
|
|
|
}
|
|
|
|
|
2017-05-02 22:32:13 +03:00
|
|
|
prepare_submodule_repo_env(&cp.env_array);
|
2017-03-15 00:46:37 +03:00
|
|
|
|
|
|
|
cp.git_cmd = 1;
|
|
|
|
cp.no_stdin = 1;
|
|
|
|
cp.dir = path;
|
|
|
|
|
|
|
|
argv_array_pushf(&cp.args, "--super-prefix=%s%s/",
|
|
|
|
get_super_prefix_or_empty(), path);
|
2017-05-02 22:32:14 +03:00
|
|
|
argv_array_pushl(&cp.args, "read-tree", "--recurse-submodules", NULL);
|
2017-03-15 00:46:37 +03:00
|
|
|
|
|
|
|
if (flags & SUBMODULE_MOVE_HEAD_DRY_RUN)
|
|
|
|
argv_array_push(&cp.args, "-n");
|
|
|
|
else
|
|
|
|
argv_array_push(&cp.args, "-u");
|
|
|
|
|
|
|
|
if (flags & SUBMODULE_MOVE_HEAD_FORCE)
|
|
|
|
argv_array_push(&cp.args, "--reset");
|
|
|
|
else
|
|
|
|
argv_array_push(&cp.args, "-m");
|
|
|
|
|
2018-01-05 23:03:04 +03:00
|
|
|
if (!(flags & SUBMODULE_MOVE_HEAD_FORCE))
|
2018-05-02 03:25:59 +03:00
|
|
|
argv_array_push(&cp.args, old_head ? old_head : empty_tree_oid_hex());
|
2018-01-05 23:03:04 +03:00
|
|
|
|
2018-05-02 03:25:59 +03:00
|
|
|
argv_array_push(&cp.args, new_head ? new_head : empty_tree_oid_hex());
|
2017-03-15 00:46:37 +03:00
|
|
|
|
|
|
|
if (run_command(&cp)) {
|
2018-06-21 01:32:53 +03:00
|
|
|
ret = error(_("Submodule '%s' could not be updated."), path);
|
2017-03-15 00:46:37 +03:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(flags & SUBMODULE_MOVE_HEAD_DRY_RUN)) {
|
2018-02-14 21:59:49 +03:00
|
|
|
if (new_head) {
|
2017-05-02 22:32:12 +03:00
|
|
|
child_process_init(&cp);
|
2017-03-15 00:46:37 +03:00
|
|
|
/* also set the HEAD accordingly */
|
2017-05-02 22:32:12 +03:00
|
|
|
cp.git_cmd = 1;
|
|
|
|
cp.no_stdin = 1;
|
|
|
|
cp.dir = path;
|
2017-03-15 00:46:37 +03:00
|
|
|
|
2017-05-02 22:32:14 +03:00
|
|
|
prepare_submodule_repo_env(&cp.env_array);
|
2017-07-24 20:36:01 +03:00
|
|
|
argv_array_pushl(&cp.args, "update-ref", "HEAD",
|
2018-02-14 21:59:49 +03:00
|
|
|
"--no-deref", new_head, NULL);
|
2017-03-15 00:46:37 +03:00
|
|
|
|
2017-05-02 22:32:12 +03:00
|
|
|
if (run_command(&cp)) {
|
2017-03-15 00:46:37 +03:00
|
|
|
ret = -1;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
struct strbuf sb = STRBUF_INIT;
|
|
|
|
|
|
|
|
strbuf_addf(&sb, "%s/.git", path);
|
|
|
|
unlink_or_warn(sb.buf);
|
|
|
|
strbuf_release(&sb);
|
|
|
|
|
|
|
|
if (is_empty_dir(path))
|
|
|
|
rmdir_or_warn(path);
|
submodule: unset core.worktree if no working tree is present
When a submodules work tree is removed, we should unset its core.worktree
setting as the worktree is no longer present. This is not just in line
with the conceptual view of submodules, but it fixes an inconvenience
for looking at submodules that are not checked out:
git clone --recurse-submodules git://github.com/git/git && cd git &&
git checkout --recurse-submodules v2.13.0
git -C .git/modules/sha1collisiondetection log
fatal: cannot chdir to '../../../sha1collisiondetection': \
No such file or directory
With this patch applied, the final call to git log works instead of dying
in its setup, as the checkout will unset the core.worktree setting such
that following log will be run in a bare repository.
This patch covers all commands that are in the unpack machinery, i.e.
checkout, read-tree, reset. A follow up patch will address
"git submodule deinit", which will also make use of the new function
submodule_unset_core_worktree(), which is why we expose it in this patch.
This patch was authored as 4fa4f90ccd (submodule: unset core.worktree if
no working tree is present, 2018-06-12), which was reverted as part of
f178c13fda (Revert "Merge branch 'sb/submodule-core-worktree'",
2018-09-07). The revert was needed as the nearby commit e98317508c
(submodule: ensure core.worktree is set after update, 2018-06-18) is
faulty and at the time of 7e25437d35 (Merge branch
'sb/submodule-core-worktree', 2018-07-18) we could not revert the faulty
commit only, as they were depending on each other: If core.worktree is
unset, we have to have ways to ensure that it is set again once
the working tree reappears again.
Now that 4d6d6ef1fc (Merge branch 'sb/submodule-update-in-c', 2018-09-17),
specifically 74d4731da1 (submodule--helper: replace
connect-gitdir-workingtree by ensure-core-worktree, 2018-08-13) is
present, we already check and ensure core.worktree is set when
populating a new work tree, such that we can re-introduce the commits
that unset core.worktree when removing the worktree.
Signed-off-by: Stefan Beller <sbeller@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Stefan Beller <sbeller@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-12-15 02:59:43 +03:00
|
|
|
|
|
|
|
submodule_unset_core_worktree(sub);
|
2017-03-15 00:46:37 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
out:
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2016-12-12 22:04:35 +03:00
|
|
|
/*
|
|
|
|
* Embeds a single submodules git directory into the superprojects git dir,
|
|
|
|
* non recursively.
|
|
|
|
*/
|
|
|
|
static void relocate_single_git_dir_into_superproject(const char *prefix,
|
|
|
|
const char *path)
|
|
|
|
{
|
|
|
|
char *old_git_dir = NULL, *real_old_git_dir = NULL, *real_new_git_dir = NULL;
|
|
|
|
const char *new_git_dir;
|
|
|
|
const struct submodule *sub;
|
|
|
|
|
|
|
|
if (submodule_uses_worktrees(path))
|
|
|
|
die(_("relocate_gitdir for submodule '%s' with "
|
|
|
|
"more than one worktree not supported"), path);
|
|
|
|
|
|
|
|
old_git_dir = xstrfmt("%s/.git", path);
|
|
|
|
if (read_gitfile(old_git_dir))
|
|
|
|
/* If it is an actual gitfile, it doesn't need migration. */
|
|
|
|
return;
|
|
|
|
|
2017-03-08 18:43:40 +03:00
|
|
|
real_old_git_dir = real_pathdup(old_git_dir, 1);
|
2016-12-12 22:04:35 +03:00
|
|
|
|
2018-03-29 01:35:29 +03:00
|
|
|
sub = submodule_from_path(the_repository, &null_oid, path);
|
2016-12-12 22:04:35 +03:00
|
|
|
if (!sub)
|
|
|
|
die(_("could not lookup name for submodule '%s'"), path);
|
|
|
|
|
|
|
|
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);
|
2017-03-08 18:43:40 +03:00
|
|
|
real_new_git_dir = real_pathdup(new_git_dir, 1);
|
2016-12-12 22:04:35 +03:00
|
|
|
|
|
|
|
fprintf(stderr, _("Migrating git directory of '%s%s' from\n'%s' to\n'%s'\n"),
|
2017-03-15 00:46:36 +03:00
|
|
|
get_super_prefix_or_empty(), path,
|
2016-12-12 22:04:35 +03:00
|
|
|
real_old_git_dir, real_new_git_dir);
|
|
|
|
|
|
|
|
relocate_gitdir(path, real_old_git_dir, real_new_git_dir);
|
|
|
|
|
|
|
|
free(old_git_dir);
|
|
|
|
free(real_old_git_dir);
|
|
|
|
free(real_new_git_dir);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Migrate the git directory of the submodule given by path from
|
|
|
|
* having its git directory within the working tree to the git dir nested
|
|
|
|
* in its superprojects git dir under modules/.
|
|
|
|
*/
|
|
|
|
void absorb_git_dir_into_superproject(const char *prefix,
|
|
|
|
const char *path,
|
|
|
|
unsigned flags)
|
|
|
|
{
|
2017-01-26 02:04:50 +03:00
|
|
|
int err_code;
|
|
|
|
const char *sub_git_dir;
|
2016-12-12 22:04:35 +03:00
|
|
|
struct strbuf gitdir = STRBUF_INIT;
|
|
|
|
strbuf_addf(&gitdir, "%s/.git", path);
|
2017-01-26 02:04:50 +03:00
|
|
|
sub_git_dir = resolve_gitdir_gently(gitdir.buf, &err_code);
|
2016-12-12 22:04:35 +03:00
|
|
|
|
|
|
|
/* Not populated? */
|
2017-01-26 02:04:50 +03:00
|
|
|
if (!sub_git_dir) {
|
|
|
|
const struct submodule *sub;
|
|
|
|
|
|
|
|
if (err_code == READ_GITFILE_ERR_STAT_FAILED) {
|
|
|
|
/* unpopulated as expected */
|
|
|
|
strbuf_release(&gitdir);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (err_code != READ_GITFILE_ERR_NOT_A_REPO)
|
|
|
|
/* We don't know what broke here. */
|
|
|
|
read_gitfile_error_die(err_code, path, NULL);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Maybe populated, but no git directory was found?
|
|
|
|
* This can happen if the superproject is a submodule
|
|
|
|
* itself and was just absorbed. The absorption of the
|
|
|
|
* superproject did not rewrite the git file links yet,
|
|
|
|
* fix it now.
|
|
|
|
*/
|
2018-03-29 01:35:29 +03:00
|
|
|
sub = submodule_from_path(the_repository, &null_oid, path);
|
2017-01-26 02:04:50 +03:00
|
|
|
if (!sub)
|
|
|
|
die(_("could not lookup name for submodule '%s'"), path);
|
2017-03-15 00:46:24 +03:00
|
|
|
connect_work_tree_and_git_dir(path,
|
2018-03-29 01:35:31 +03:00
|
|
|
git_path("modules/%s", sub->name), 0);
|
2017-01-26 02:04:50 +03:00
|
|
|
} else {
|
|
|
|
/* Is it already absorbed into the superprojects git dir? */
|
2017-03-08 18:43:40 +03:00
|
|
|
char *real_sub_git_dir = real_pathdup(sub_git_dir, 1);
|
|
|
|
char *real_common_git_dir = real_pathdup(get_git_common_dir(), 1);
|
2016-12-12 22:04:35 +03:00
|
|
|
|
2017-01-26 02:04:50 +03:00
|
|
|
if (!starts_with(real_sub_git_dir, real_common_git_dir))
|
|
|
|
relocate_single_git_dir_into_superproject(prefix, path);
|
|
|
|
|
|
|
|
free(real_sub_git_dir);
|
|
|
|
free(real_common_git_dir);
|
|
|
|
}
|
|
|
|
strbuf_release(&gitdir);
|
2016-12-12 22:04:35 +03:00
|
|
|
|
|
|
|
if (flags & ABSORB_GITDIR_RECURSE_SUBMODULES) {
|
|
|
|
struct child_process cp = CHILD_PROCESS_INIT;
|
|
|
|
struct strbuf sb = STRBUF_INIT;
|
|
|
|
|
|
|
|
if (flags & ~ABSORB_GITDIR_RECURSE_SUBMODULES)
|
2018-05-02 12:38:39 +03:00
|
|
|
BUG("we don't know how to pass the flags down?");
|
2016-12-12 22:04:35 +03:00
|
|
|
|
2017-03-15 00:46:36 +03:00
|
|
|
strbuf_addstr(&sb, get_super_prefix_or_empty());
|
2016-12-12 22:04:35 +03:00
|
|
|
strbuf_addstr(&sb, path);
|
|
|
|
strbuf_addch(&sb, '/');
|
|
|
|
|
|
|
|
cp.dir = path;
|
|
|
|
cp.git_cmd = 1;
|
|
|
|
cp.no_stdin = 1;
|
|
|
|
argv_array_pushl(&cp.args, "--super-prefix", sb.buf,
|
|
|
|
"submodule--helper",
|
|
|
|
"absorb-git-dirs", NULL);
|
|
|
|
prepare_submodule_repo_env(&cp.env_array);
|
|
|
|
if (run_command(&cp))
|
|
|
|
die(_("could not recurse into submodule '%s'"), path);
|
|
|
|
|
|
|
|
strbuf_release(&sb);
|
|
|
|
}
|
|
|
|
}
|
2017-03-09 02:07:42 +03:00
|
|
|
|
|
|
|
const char *get_superproject_working_tree(void)
|
|
|
|
{
|
|
|
|
struct child_process cp = CHILD_PROCESS_INIT;
|
|
|
|
struct strbuf sb = STRBUF_INIT;
|
|
|
|
const char *one_up = real_path_if_valid("../");
|
|
|
|
const char *cwd = xgetcwd();
|
|
|
|
const char *ret = NULL;
|
|
|
|
const char *subpath;
|
|
|
|
int code;
|
|
|
|
ssize_t len;
|
|
|
|
|
|
|
|
if (!is_inside_work_tree())
|
|
|
|
/*
|
|
|
|
* FIXME:
|
|
|
|
* We might have a superproject, but it is harder
|
|
|
|
* to determine.
|
|
|
|
*/
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (!one_up)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
subpath = relative_path(cwd, one_up, &sb);
|
|
|
|
|
|
|
|
prepare_submodule_repo_env(&cp.env_array);
|
|
|
|
argv_array_pop(&cp.env_array);
|
|
|
|
|
|
|
|
argv_array_pushl(&cp.args, "--literal-pathspecs", "-C", "..",
|
|
|
|
"ls-files", "-z", "--stage", "--full-name", "--",
|
|
|
|
subpath, NULL);
|
|
|
|
strbuf_reset(&sb);
|
|
|
|
|
|
|
|
cp.no_stdin = 1;
|
|
|
|
cp.no_stderr = 1;
|
|
|
|
cp.out = -1;
|
|
|
|
cp.git_cmd = 1;
|
|
|
|
|
|
|
|
if (start_command(&cp))
|
|
|
|
die(_("could not start ls-files in .."));
|
|
|
|
|
|
|
|
len = strbuf_read(&sb, cp.out, PATH_MAX);
|
|
|
|
close(cp.out);
|
|
|
|
|
|
|
|
if (starts_with(sb.buf, "160000")) {
|
|
|
|
int super_sub_len;
|
|
|
|
int cwd_len = strlen(cwd);
|
|
|
|
char *super_sub, *super_wt;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* There is a superproject having this repo as a submodule.
|
|
|
|
* The format is <mode> SP <hash> SP <stage> TAB <full name> \0,
|
|
|
|
* We're only interested in the name after the tab.
|
|
|
|
*/
|
|
|
|
super_sub = strchr(sb.buf, '\t') + 1;
|
2018-09-27 21:10:54 +03:00
|
|
|
super_sub_len = strlen(super_sub);
|
2017-03-09 02:07:42 +03:00
|
|
|
|
|
|
|
if (super_sub_len > cwd_len ||
|
|
|
|
strcmp(&cwd[cwd_len - super_sub_len], super_sub))
|
2018-05-02 12:38:41 +03:00
|
|
|
BUG("returned path string doesn't match cwd?");
|
2017-03-09 02:07:42 +03:00
|
|
|
|
|
|
|
super_wt = xstrdup(cwd);
|
|
|
|
super_wt[cwd_len - super_sub_len] = '\0';
|
|
|
|
|
|
|
|
ret = real_path(super_wt);
|
|
|
|
free(super_wt);
|
|
|
|
}
|
|
|
|
strbuf_release(&sb);
|
|
|
|
|
|
|
|
code = finish_command(&cp);
|
|
|
|
|
|
|
|
if (code == 128)
|
|
|
|
/* '../' is not a git repository */
|
|
|
|
return NULL;
|
|
|
|
if (code == 0 && len == 0)
|
|
|
|
/* There is an unrelated git repository at '../' */
|
|
|
|
return NULL;
|
|
|
|
if (code)
|
|
|
|
die(_("ls-tree returned unexpected return code %d"), code);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
2017-03-26 05:42:30 +03:00
|
|
|
|
2017-09-25 18:59:26 +03:00
|
|
|
/*
|
|
|
|
* Put the gitdir for a submodule (given relative to the main
|
|
|
|
* repository worktree) into `buf`, or return -1 on error.
|
|
|
|
*/
|
2017-03-26 05:42:30 +03:00
|
|
|
int submodule_to_gitdir(struct strbuf *buf, const char *submodule)
|
|
|
|
{
|
|
|
|
const struct submodule *sub;
|
|
|
|
const char *git_dir;
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
strbuf_reset(buf);
|
|
|
|
strbuf_addstr(buf, submodule);
|
|
|
|
strbuf_complete(buf, '/');
|
|
|
|
strbuf_addstr(buf, ".git");
|
|
|
|
|
|
|
|
git_dir = read_gitfile(buf->buf);
|
|
|
|
if (git_dir) {
|
|
|
|
strbuf_reset(buf);
|
|
|
|
strbuf_addstr(buf, git_dir);
|
|
|
|
}
|
|
|
|
if (!is_git_directory(buf->buf)) {
|
2018-03-29 01:35:29 +03:00
|
|
|
sub = submodule_from_path(the_repository, &null_oid, submodule);
|
2017-03-26 05:42:30 +03:00
|
|
|
if (!sub) {
|
|
|
|
ret = -1;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
strbuf_reset(buf);
|
|
|
|
strbuf_git_path(buf, "%s/%s", "modules", sub->name);
|
|
|
|
}
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
return ret;
|
|
|
|
}
|