return 1;
}
+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);
+}
+
/*
* 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
}
}
-/* For loading from the .gitmodules file. */
-static int git_modules_config(const char *var, const char *value, void *cb)
-{
- if (starts_with(var, "submodule."))
- return parse_submodule_config_option(var, value);
- return 0;
-}
-
-/* Loads all submodule settings from the config. */
-int 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;
- } else {
- return git_modules_config(var, value, cb);
- }
-}
-
/* 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)
{
return 0;
}
-void load_submodule_cache(void)
-{
- if (config_update_recurse_submodules == RECURSE_SUBMODULES_OFF)
- return;
-
- gitmodules_config();
- git_config(submodule_config, NULL);
-}
-
-static int gitmodules_cb(const char *var, const char *value, void *data)
-{
- struct repository *repo = data;
- return submodule_config_option(repo, var, value);
-}
-
-void repo_read_gitmodules(struct repository *repo)
-{
- if (repo->worktree) {
- char *gitmodules;
-
- if (repo_read_index(repo) < 0)
- return;
-
- gitmodules = repo_worktree_path(repo, GITMODULES_FILE);
-
- if (!is_gitmodules_unmerged(repo->index))
- git_config_from_file(gitmodules_cb, gitmodules, repo);
-
- free(gitmodules);
- }
-}
-
-void gitmodules_config(void)
-{
- repo_read_gitmodules(the_repository);
-}
-
-void gitmodules_config_oid(const struct object_id *commit_oid)
-{
- struct strbuf rev = STRBUF_INIT;
- struct object_id oid;
-
- if (gitmodule_oid_from_commit(commit_oid, &oid, &rev)) {
- git_config_from_blob_oid(submodule_config, rev.buf,
- &oid, NULL);
- }
- strbuf_release(&rev);
-}
-
/*
* Determine if a submodule has been initialized at a given 'path'
*/
return prepare_revision_walk(rev);
}
-static void print_submodule_summary(struct rev_info *rev, FILE *f,
- const char *line_prefix,
- const char *del, const char *add, const char *reset)
+static void print_submodule_summary(struct rev_info *rev, struct diff_options *o)
{
static const char format[] = " %m %s";
struct strbuf sb = STRBUF_INIT;
ctx.date_mode = rev->date_mode;
ctx.output_encoding = get_log_output_encoding();
strbuf_setlen(&sb, 0);
- strbuf_addstr(&sb, line_prefix);
- if (commit->object.flags & SYMMETRIC_LEFT) {
- if (del)
- strbuf_addstr(&sb, del);
- }
- else if (add)
- strbuf_addstr(&sb, add);
format_commit_message(commit, format, &sb, &ctx);
- if (reset)
- strbuf_addstr(&sb, reset);
strbuf_addch(&sb, '\n');
- fprintf(f, "%s", sb.buf);
+ if (commit->object.flags & SYMMETRIC_LEFT)
+ diff_emit_submodule_del(o, sb.buf);
+ else
+ diff_emit_submodule_add(o, sb.buf);
}
strbuf_release(&sb);
}
* attempt to lookup both the left and right commits and put them into the
* left and right pointers.
*/
-static void show_submodule_header(FILE *f, const char *path,
- const char *line_prefix,
+static void show_submodule_header(struct diff_options *o, const char *path,
struct object_id *one, struct object_id *two,
- unsigned dirty_submodule, const char *meta,
- const char *reset,
+ unsigned dirty_submodule,
struct commit **left, struct commit **right,
struct commit_list **merge_bases)
{
int fast_forward = 0, fast_backward = 0;
if (dirty_submodule & DIRTY_SUBMODULE_UNTRACKED)
- fprintf(f, "%sSubmodule %s contains untracked content\n",
- line_prefix, path);
+ diff_emit_submodule_untracked(o, path);
+
if (dirty_submodule & DIRTY_SUBMODULE_MODIFIED)
- fprintf(f, "%sSubmodule %s contains modified content\n",
- line_prefix, path);
+ diff_emit_submodule_modified(o, path);
if (is_null_oid(one))
message = "(new submodule)";
}
output_header:
- strbuf_addf(&sb, "%s%sSubmodule %s ", line_prefix, meta, path);
+ strbuf_addf(&sb, "Submodule %s ", path);
strbuf_add_unique_abbrev(&sb, one->hash, DEFAULT_ABBREV);
strbuf_addstr(&sb, (fast_backward || fast_forward) ? ".." : "...");
strbuf_add_unique_abbrev(&sb, two->hash, DEFAULT_ABBREV);
if (message)
- strbuf_addf(&sb, " %s%s\n", message, reset);
+ strbuf_addf(&sb, " %s\n", message);
else
- strbuf_addf(&sb, "%s:%s\n", fast_backward ? " (rewind)" : "", reset);
- fwrite(sb.buf, sb.len, 1, f);
+ strbuf_addf(&sb, "%s:\n", fast_backward ? " (rewind)" : "");
+ diff_emit_submodule_header(o, sb.buf);
strbuf_release(&sb);
}
-void show_submodule_summary(FILE *f, const char *path,
- const char *line_prefix,
+void show_submodule_summary(struct diff_options *o, const char *path,
struct object_id *one, struct object_id *two,
- unsigned dirty_submodule, const char *meta,
- const char *del, const char *add, const char *reset)
+ unsigned dirty_submodule)
{
struct rev_info rev;
struct commit *left = NULL, *right = NULL;
struct commit_list *merge_bases = NULL;
- show_submodule_header(f, path, line_prefix, one, two, dirty_submodule,
- meta, reset, &left, &right, &merge_bases);
+ show_submodule_header(o, path, one, two, dirty_submodule,
+ &left, &right, &merge_bases);
/*
* If we don't have both a left and a right pointer, there is no
/* Treat revision walker failure the same as missing commits */
if (prepare_submodule_summary(&rev, path, left, right, merge_bases)) {
- fprintf(f, "%s(revision walker failed)\n", line_prefix);
+ diff_emit_submodule_error(o, "(revision walker failed)\n");
goto out;
}
- print_submodule_summary(&rev, f, line_prefix, del, add, reset);
+ print_submodule_summary(&rev, o);
out:
if (merge_bases)
clear_commit_marks(right, ~0);
}
-void show_submodule_inline_diff(FILE *f, const char *path,
- const char *line_prefix,
+void show_submodule_inline_diff(struct diff_options *o, const char *path,
struct object_id *one, struct object_id *two,
- unsigned dirty_submodule, const char *meta,
- const char *del, const char *add, const char *reset,
- const struct diff_options *o)
+ unsigned dirty_submodule)
{
const struct object_id *old = &empty_tree_oid, *new = &empty_tree_oid;
struct commit *left = NULL, *right = NULL;
struct commit_list *merge_bases = NULL;
- struct strbuf submodule_dir = STRBUF_INIT;
struct child_process cp = CHILD_PROCESS_INIT;
+ struct strbuf sb = STRBUF_INIT;
- show_submodule_header(f, path, line_prefix, one, two, dirty_submodule,
- meta, reset, &left, &right, &merge_bases);
+ show_submodule_header(o, path, one, two, dirty_submodule,
+ &left, &right, &merge_bases);
/* We need a valid left and right commit to display a difference */
if (!(left || is_null_oid(one)) ||
if (right)
new = two;
- fflush(f);
cp.git_cmd = 1;
cp.dir = path;
- cp.out = dup(fileno(f));
+ cp.out = -1;
cp.no_stdin = 1;
/* TODO: other options may need to be passed here. */
argv_array_pushl(&cp.args, "diff", "--submodule=diff", NULL);
+ argv_array_pushf(&cp.args, "--color=%s", want_color(o->use_color) ?
+ "always" : "never");
- argv_array_pushf(&cp.args, "--line-prefix=%s", line_prefix);
if (DIFF_OPT_TST(o, REVERSE_DIFF)) {
argv_array_pushf(&cp.args, "--src-prefix=%s%s/",
o->b_prefix, path);
argv_array_push(&cp.args, oid_to_hex(new));
prepare_submodule_repo_env(&cp.env_array);
- if (run_command(&cp))
- fprintf(f, "(diff failed)\n");
+ 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");
done:
- strbuf_release(&submodule_dir);
+ strbuf_release(&sb);
if (merge_bases)
free_commit_list(merge_bases);
if (left)
* Perform a check in the submodule to see if the remote and refspec work.
* Die if the submodule can't be pushed.
*/
-static void submodule_push_check(const char *path, const struct remote *remote,
+static void submodule_push_check(const char *path, const char *head,
+ const struct remote *remote,
const char **refspec, int refspec_nr)
{
struct child_process cp = CHILD_PROCESS_INIT;
argv_array_push(&cp.args, "submodule--helper");
argv_array_push(&cp.args, "push-check");
+ argv_array_push(&cp.args, head);
argv_array_push(&cp.args, remote->name);
for (i = 0; i < refspec_nr; i++)
* won't be propagated due to the remote being unconfigured (e.g. a URL
* instead of a remote name).
*/
- if (remote->origin != REMOTE_UNCONFIGURED)
+ if (remote->origin != REMOTE_UNCONFIGURED) {
+ char *head;
+ struct object_id head_oid;
+
+ head = resolve_refdup("HEAD", 0, head_oid.hash, NULL);
+ if (!head)
+ die(_("Failed to resolve HEAD as a valid ref."));
+
for (i = 0; i < needs_pushing.nr; i++)
submodule_push_check(needs_pushing.items[i].string,
- remote, refspec, refspec_nr);
+ head, remote,
+ refspec, refspec_nr);
+ free(head);
+ }
/* Actually push the submodules */
for (i = 0; i < needs_pushing.nr; i++) {
struct argv_array args = ARGV_ARRAY_INIT;
int ret;
- gitmodules_config();
/* No need to check if there are no submodules configured */
if (!submodule_from_path(NULL, NULL))
return 0;
oid_to_hex(&a->object.oid));
init_revisions(&revs, NULL);
rev_opts.submodule = path;
+ /* FIXME: can't handle linked worktrees in submodules yet */
+ revs.single_worktree = path != NULL;
setup_revisions(ARRAY_SIZE(rev_args)-1, rev_args, &revs, &rev_opts);
/* save all revisions from the above list that contain b */
strbuf_addstr(buf, git_dir);
}
if (!is_git_directory(buf->buf)) {
- gitmodules_config();
sub = submodule_from_path(&null_oid, submodule);
if (!sub) {
ret = -1;