summaryrefslogtreecommitdiff
path: root/builtin
diff options
context:
space:
mode:
Diffstat (limited to 'builtin')
-rw-r--r--builtin/checkout.c4
-rw-r--r--builtin/fast-export.c2
-rw-r--r--builtin/init-db.c26
-rw-r--r--builtin/log.c2
-rw-r--r--builtin/merge.c2
-rw-r--r--builtin/repack.c12
-rw-r--r--builtin/reset.c2
-rw-r--r--builtin/rev-parse.c2
-rw-r--r--builtin/show-branch.c2
-rw-r--r--builtin/stash.c2
-rw-r--r--builtin/submodule--helper.c431
-rw-r--r--builtin/worktree.c38
12 files changed, 501 insertions, 24 deletions
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 6ec82097a2..0951f8fee5 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -651,7 +651,7 @@ static void setup_branch_path(struct branch_info *branch)
* If this is a ref, resolve it; otherwise, look up the OID for our
* expression. Failure here is okay.
*/
- if (!dwim_ref(branch->name, strlen(branch->name), &branch->oid, &branch->refname))
+ if (!dwim_ref(branch->name, strlen(branch->name), &branch->oid, &branch->refname, 0))
repo_get_oid_committish(the_repository, branch->name, &branch->oid);
strbuf_branchname(&buf, branch->name, INTERPRET_BRANCH_LOCAL);
@@ -1345,7 +1345,7 @@ static void die_expecting_a_branch(const struct branch_info *branch_info)
struct object_id oid;
char *to_free;
- if (dwim_ref(branch_info->name, strlen(branch_info->name), &oid, &to_free) == 1) {
+ if (dwim_ref(branch_info->name, strlen(branch_info->name), &oid, &to_free, 0) == 1) {
const char *ref = to_free;
if (skip_prefix(ref, "refs/tags/", &ref))
diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index 9f37895d4c..1b8fca3ee0 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -943,7 +943,7 @@ static void get_tags_and_duplicates(struct rev_cmdline_info *info)
if (e->flags & UNINTERESTING)
continue;
- if (dwim_ref(e->name, strlen(e->name), &oid, &full_name) != 1)
+ if (dwim_ref(e->name, strlen(e->name), &oid, &full_name, 0) != 1)
continue;
if (refspecs.nr) {
diff --git a/builtin/init-db.c b/builtin/init-db.c
index bbc9bc78f9..cd3e760541 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -9,6 +9,7 @@
#include "builtin.h"
#include "exec-cmd.h"
#include "parse-options.h"
+#include "worktree.h"
#ifndef DEFAULT_GIT_TEMPLATE_DIR
#define DEFAULT_GIT_TEMPLATE_DIR "/usr/share/git-core/templates"
@@ -364,6 +365,7 @@ static void separate_git_dir(const char *git_dir, const char *git_link)
if (rename(src, git_dir))
die_errno(_("unable to move %s to %s"), src, git_dir);
+ repair_worktrees(NULL, NULL);
}
write_file(git_link, "gitdir: %s", git_dir);
@@ -640,6 +642,30 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
if (!git_dir)
git_dir = DEFAULT_GIT_DIR_ENVIRONMENT;
+ /*
+ * When --separate-git-dir is used inside a linked worktree, take
+ * care to ensure that the common .git/ directory is relocated, not
+ * the worktree-specific .git/worktrees/<id>/ directory.
+ */
+ if (real_git_dir) {
+ int err;
+ const char *p;
+ struct strbuf sb = STRBUF_INIT;
+
+ p = read_gitfile_gently(git_dir, &err);
+ if (p && get_common_dir(&sb, p)) {
+ struct strbuf mainwt = STRBUF_INIT;
+
+ strbuf_addbuf(&mainwt, &sb);
+ strbuf_strip_suffix(&mainwt, "/.git");
+ if (chdir(mainwt.buf) < 0)
+ die_errno(_("cannot chdir to %s"), mainwt.buf);
+ strbuf_release(&mainwt);
+ git_dir = strbuf_detach(&sb, NULL);
+ }
+ strbuf_release(&sb);
+ }
+
if (is_bare_repository_cfg < 0)
is_bare_repository_cfg = guess_repository_type(git_dir);
diff --git a/builtin/log.c b/builtin/log.c
index b58f8da09e..4ec7f57cf4 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -1061,7 +1061,7 @@ static char *find_branch_name(struct rev_info *rev)
return NULL;
ref = rev->cmdline.rev[positive].name;
tip_oid = &rev->cmdline.rev[positive].item->oid;
- if (dwim_ref(ref, strlen(ref), &branch_oid, &full_ref) &&
+ if (dwim_ref(ref, strlen(ref), &branch_oid, &full_ref, 0) &&
skip_prefix(full_ref, "refs/heads/", &v) &&
oideq(tip_oid, &branch_oid))
branch = xstrdup(v);
diff --git a/builtin/merge.c b/builtin/merge.c
index b9a89ba858..032a8f5434 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -500,7 +500,7 @@ static void merge_name(const char *remote, struct strbuf *msg)
if (!remote_head)
die(_("'%s' does not point to a commit"), remote);
- if (dwim_ref(remote, strlen(remote), &branch_head, &found_ref) > 0) {
+ if (dwim_ref(remote, strlen(remote), &branch_head, &found_ref, 0) > 0) {
if (starts_with(found_ref, "refs/heads/")) {
strbuf_addf(msg, "%s\t\tbranch '%s' of .\n",
oid_to_hex(&branch_head), remote);
diff --git a/builtin/repack.c b/builtin/repack.c
index 04c5ceaf7e..01e7767c79 100644
--- a/builtin/repack.c
+++ b/builtin/repack.c
@@ -133,7 +133,11 @@ static void get_non_kept_pack_filenames(struct string_list *fname_list,
static void remove_redundant_pack(const char *dir_name, const char *base_name)
{
struct strbuf buf = STRBUF_INIT;
- strbuf_addf(&buf, "%s/%s.pack", dir_name, base_name);
+ struct multi_pack_index *m = get_local_multi_pack_index(the_repository);
+ strbuf_addf(&buf, "%s.pack", base_name);
+ if (m && midx_contains_pack(m, buf.buf))
+ clear_midx_file(the_repository);
+ strbuf_insertf(&buf, 0, "%s/", dir_name);
unlink_pack_path(buf.buf, 1);
strbuf_release(&buf);
}
@@ -286,7 +290,6 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
int keep_unreachable = 0;
struct string_list keep_pack_list = STRING_LIST_INIT_NODUP;
int no_update_server_info = 0;
- int midx_cleared = 0;
struct pack_objects_args po_args = {NULL};
struct option builtin_repack_options[] = {
@@ -439,11 +442,6 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
for (ext = 0; ext < ARRAY_SIZE(exts); ext++) {
char *fname, *fname_old;
- if (!midx_cleared) {
- clear_midx_file(the_repository);
- midx_cleared = 1;
- }
-
fname = mkpathdup("%s/pack-%s%s", packdir,
item->string, exts[ext].name);
if (!file_exists(fname)) {
diff --git a/builtin/reset.c b/builtin/reset.c
index 8ae69d6f2b..c635b062c3 100644
--- a/builtin/reset.c
+++ b/builtin/reset.c
@@ -423,7 +423,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
char *ref = NULL;
int err;
- dwim_ref(rev, strlen(rev), &dummy, &ref);
+ dwim_ref(rev, strlen(rev), &dummy, &ref, 0);
if (ref && !starts_with(ref, "refs/"))
ref = NULL;
diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c
index 669dd2fd6f..ed200c8af1 100644
--- a/builtin/rev-parse.c
+++ b/builtin/rev-parse.c
@@ -136,7 +136,7 @@ static void show_rev(int type, const struct object_id *oid, const char *name)
struct object_id discard;
char *full;
- switch (dwim_ref(name, strlen(name), &discard, &full)) {
+ switch (dwim_ref(name, strlen(name), &discard, &full, 0)) {
case 0:
/*
* Not found -- not a ref. We could
diff --git a/builtin/show-branch.c b/builtin/show-branch.c
index 7eae5f3801..d6d2dabeca 100644
--- a/builtin/show-branch.c
+++ b/builtin/show-branch.c
@@ -741,7 +741,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
die(Q_("only %d entry can be shown at one time.",
"only %d entries can be shown at one time.",
MAX_REVS), MAX_REVS);
- if (!dwim_ref(*av, strlen(*av), &oid, &ref))
+ if (!dwim_ref(*av, strlen(*av), &oid, &ref, 0))
die(_("no such ref %s"), *av);
/* Has the base been specified? */
diff --git a/builtin/stash.c b/builtin/stash.c
index 4bdfaf8397..3f811f3050 100644
--- a/builtin/stash.c
+++ b/builtin/stash.c
@@ -185,7 +185,7 @@ static int get_stash_info(struct stash_info *info, int argc, const char **argv)
end_of_rev = strchrnul(revision, '@');
strbuf_add(&symbolic, revision, end_of_rev - revision);
- ret = dwim_ref(symbolic.buf, symbolic.len, &dummy, &expanded_ref);
+ ret = dwim_ref(symbolic.buf, symbolic.len, &dummy, &expanded_ref, 0);
strbuf_release(&symbolic);
switch (ret) {
case 0: /* Not found, but valid ref */
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index a59d8e4bda..de5ad73bb8 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -612,7 +612,6 @@ struct init_cb {
const char *prefix;
unsigned int flags;
};
-
#define INIT_CB_INIT { NULL, 0 }
static void init_submodule(const char *path, const char *prefix,
@@ -742,7 +741,6 @@ struct status_cb {
const char *prefix;
unsigned int flags;
};
-
#define STATUS_CB_INIT { NULL, 0 }
static void print_status(unsigned int flags, char state, const char *path,
@@ -929,11 +927,437 @@ static int module_name(int argc, const char **argv, const char *prefix)
return 0;
}
+struct module_cb {
+ unsigned int mod_src;
+ unsigned int mod_dst;
+ struct object_id oid_src;
+ struct object_id oid_dst;
+ char status;
+ const char *sm_path;
+};
+#define MODULE_CB_INIT { 0, 0, NULL, NULL, '\0', NULL }
+
+struct module_cb_list {
+ struct module_cb **entries;
+ int alloc, nr;
+};
+#define MODULE_CB_LIST_INIT { NULL, 0, 0 }
+
+struct summary_cb {
+ int argc;
+ const char **argv;
+ const char *prefix;
+ unsigned int cached: 1;
+ unsigned int for_status: 1;
+ unsigned int files: 1;
+ int summary_limit;
+};
+#define SUMMARY_CB_INIT { 0, NULL, NULL, 0, 0, 0, 0 }
+
+enum diff_cmd {
+ DIFF_INDEX,
+ DIFF_FILES
+};
+
+static char *verify_submodule_committish(const char *sm_path,
+ const char *committish)
+{
+ struct child_process cp_rev_parse = CHILD_PROCESS_INIT;
+ struct strbuf result = STRBUF_INIT;
+
+ cp_rev_parse.git_cmd = 1;
+ cp_rev_parse.dir = sm_path;
+ prepare_submodule_repo_env(&cp_rev_parse.env_array);
+ strvec_pushl(&cp_rev_parse.args, "rev-parse", "-q", "--short", NULL);
+ strvec_pushf(&cp_rev_parse.args, "%s^0", committish);
+ strvec_push(&cp_rev_parse.args, "--");
+
+ if (capture_command(&cp_rev_parse, &result, 0))
+ return NULL;
+
+ strbuf_trim_trailing_newline(&result);
+ return strbuf_detach(&result, NULL);
+}
+
+static void print_submodule_summary(struct summary_cb *info, char *errmsg,
+ int total_commits, const char *displaypath,
+ const char *src_abbrev, const char *dst_abbrev,
+ struct module_cb *p)
+{
+ if (p->status == 'T') {
+ if (S_ISGITLINK(p->mod_dst))
+ printf(_("* %s %s(blob)->%s(submodule)"),
+ displaypath, src_abbrev, dst_abbrev);
+ else
+ printf(_("* %s %s(submodule)->%s(blob)"),
+ displaypath, src_abbrev, dst_abbrev);
+ } else {
+ printf("* %s %s...%s",
+ displaypath, src_abbrev, dst_abbrev);
+ }
+
+ if (total_commits < 0)
+ printf(":\n");
+ else
+ printf(" (%d):\n", total_commits);
+
+ if (errmsg) {
+ printf(_("%s"), errmsg);
+ } else if (total_commits > 0) {
+ struct child_process cp_log = CHILD_PROCESS_INIT;
+
+ cp_log.git_cmd = 1;
+ cp_log.dir = p->sm_path;
+ prepare_submodule_repo_env(&cp_log.env_array);
+ strvec_pushl(&cp_log.args, "log", NULL);
+
+ if (S_ISGITLINK(p->mod_src) && S_ISGITLINK(p->mod_dst)) {
+ if (info->summary_limit > 0)
+ strvec_pushf(&cp_log.args, "-%d",
+ info->summary_limit);
+
+ strvec_pushl(&cp_log.args, "--pretty= %m %s",
+ "--first-parent", NULL);
+ strvec_pushf(&cp_log.args, "%s...%s",
+ src_abbrev, dst_abbrev);
+ } else if (S_ISGITLINK(p->mod_dst)) {
+ strvec_pushl(&cp_log.args, "--pretty= > %s",
+ "-1", dst_abbrev, NULL);
+ } else {
+ strvec_pushl(&cp_log.args, "--pretty= < %s",
+ "-1", src_abbrev, NULL);
+ }
+ run_command(&cp_log);
+ }
+ printf("\n");
+}
+
+static void generate_submodule_summary(struct summary_cb *info,
+ struct module_cb *p)
+{
+ char *displaypath, *src_abbrev = NULL, *dst_abbrev;
+ int missing_src = 0, missing_dst = 0;
+ char *errmsg = NULL;
+ int total_commits = -1;
+
+ if (!info->cached && oideq(&p->oid_dst, &null_oid)) {
+ if (S_ISGITLINK(p->mod_dst)) {
+ struct ref_store *refs = get_submodule_ref_store(p->sm_path);
+ if (refs)
+ refs_head_ref(refs, handle_submodule_head_ref, &p->oid_dst);
+ } else if (S_ISLNK(p->mod_dst) || S_ISREG(p->mod_dst)) {
+ struct stat st;
+ int fd = open(p->sm_path, O_RDONLY);
+
+ if (fd < 0 || fstat(fd, &st) < 0 ||
+ index_fd(&the_index, &p->oid_dst, fd, &st, OBJ_BLOB,
+ p->sm_path, 0))
+ error(_("couldn't hash object from '%s'"), p->sm_path);
+ } else {
+ /* for a submodule removal (mode:0000000), don't warn */
+ if (p->mod_dst)
+ warning(_("unexpected mode %o\n"), p->mod_dst);
+ }
+ }
+
+ if (S_ISGITLINK(p->mod_src)) {
+ if (p->status != 'D')
+ src_abbrev = verify_submodule_committish(p->sm_path,
+ oid_to_hex(&p->oid_src));
+ if (!src_abbrev) {
+ missing_src = 1;
+ /*
+ * As `rev-parse` failed, we fallback to getting
+ * the abbreviated hash using oid_src. We do
+ * this as we might still need the abbreviated
+ * hash in cases like a submodule type change, etc.
+ */
+ src_abbrev = xstrndup(oid_to_hex(&p->oid_src), 7);
+ }
+ } else {
+ /*
+ * The source does not point to a submodule.
+ * So, we fallback to getting the abbreviation using
+ * oid_src as we might still need the abbreviated
+ * hash in cases like submodule add, etc.
+ */
+ src_abbrev = xstrndup(oid_to_hex(&p->oid_src), 7);
+ }
+
+ if (S_ISGITLINK(p->mod_dst)) {
+ dst_abbrev = verify_submodule_committish(p->sm_path,
+ oid_to_hex(&p->oid_dst));
+ if (!dst_abbrev) {
+ missing_dst = 1;
+ /*
+ * As `rev-parse` failed, we fallback to getting
+ * the abbreviated hash using oid_dst. We do
+ * this as we might still need the abbreviated
+ * hash in cases like a submodule type change, etc.
+ */
+ dst_abbrev = xstrndup(oid_to_hex(&p->oid_dst), 7);
+ }
+ } else {
+ /*
+ * The destination does not point to a submodule.
+ * So, we fallback to getting the abbreviation using
+ * oid_dst as we might still need the abbreviated
+ * hash in cases like a submodule removal, etc.
+ */
+ dst_abbrev = xstrndup(oid_to_hex(&p->oid_dst), 7);
+ }
+
+ displaypath = get_submodule_displaypath(p->sm_path, info->prefix);
+
+ if (!missing_src && !missing_dst) {
+ struct child_process cp_rev_list = CHILD_PROCESS_INIT;
+ struct strbuf sb_rev_list = STRBUF_INIT;
+
+ strvec_pushl(&cp_rev_list.args, "rev-list",
+ "--first-parent", "--count", NULL);
+ if (S_ISGITLINK(p->mod_src) && S_ISGITLINK(p->mod_dst))
+ strvec_pushf(&cp_rev_list.args, "%s...%s",
+ src_abbrev, dst_abbrev);
+ else
+ strvec_push(&cp_rev_list.args, S_ISGITLINK(p->mod_src) ?
+ src_abbrev : dst_abbrev);
+ strvec_push(&cp_rev_list.args, "--");
+
+ cp_rev_list.git_cmd = 1;
+ cp_rev_list.dir = p->sm_path;
+ prepare_submodule_repo_env(&cp_rev_list.env_array);
+
+ if (!capture_command(&cp_rev_list, &sb_rev_list, 0))
+ total_commits = atoi(sb_rev_list.buf);
+
+ strbuf_release(&sb_rev_list);
+ } else {
+ /*
+ * Don't give error msg for modification whose dst is not
+ * submodule, i.e., deleted or changed to blob
+ */
+ if (S_ISGITLINK(p->mod_dst)) {
+ struct strbuf errmsg_str = STRBUF_INIT;
+ if (missing_src && missing_dst) {
+ strbuf_addf(&errmsg_str, " Warn: %s doesn't contain commits %s and %s\n",
+ displaypath, oid_to_hex(&p->oid_src),
+ oid_to_hex(&p->oid_dst));
+ } else {
+ strbuf_addf(&errmsg_str, " Warn: %s doesn't contain commit %s\n",
+ displaypath, missing_src ?
+ oid_to_hex(&p->oid_src) :
+ oid_to_hex(&p->oid_dst));
+ }
+ errmsg = strbuf_detach(&errmsg_str, NULL);
+ }
+ }
+
+ print_submodule_summary(info, errmsg, total_commits,
+ displaypath, src_abbrev,
+ dst_abbrev, p);
+
+ free(displaypath);
+ free(src_abbrev);
+ free(dst_abbrev);
+}
+
+static void prepare_submodule_summary(struct summary_cb *info,
+ struct module_cb_list *list)
+{
+ int i;
+ for (i = 0; i < list->nr; i++) {
+ const struct submodule *sub;
+ struct module_cb *p = list->entries[i];
+ struct strbuf sm_gitdir = STRBUF_INIT;
+
+ if (p->status == 'D' || p->status == 'T') {
+ generate_submodule_summary(info, p);
+ continue;
+ }
+
+ if (info->for_status && p->status != 'A' &&
+ (sub = submodule_from_path(the_repository,
+ &null_oid, p->sm_path))) {
+ char *config_key = NULL;
+ const char *value;
+ int ignore_all = 0;
+
+ config_key = xstrfmt("submodule.%s.ignore",
+ sub->name);
+ if (!git_config_get_string_tmp(config_key, &value))
+ ignore_all = !strcmp(value, "all");
+ else if (sub->ignore)
+ ignore_all = !strcmp(sub->ignore, "all");
+
+ free(config_key);
+ if (ignore_all)
+ continue;
+ }
+
+ /* Also show added or modified modules which are checked out */
+ strbuf_addstr(&sm_gitdir, p->sm_path);
+ if (is_nonbare_repository_dir(&sm_gitdir))
+ generate_submodule_summary(info, p);
+ strbuf_release(&sm_gitdir);
+ }
+}
+
+static void submodule_summary_callback(struct diff_queue_struct *q,
+ struct diff_options *options,
+ void *data)
+{
+ int i;
+ struct module_cb_list *list = data;
+ for (i = 0; i < q->nr; i++) {
+ struct diff_filepair *p = q->queue[i];
+ struct module_cb *temp;
+
+ if (!S_ISGITLINK(p->one->mode) && !S_ISGITLINK(p->two->mode))
+ continue;
+ temp = (struct module_cb*)malloc(sizeof(struct module_cb));
+ temp->mod_src = p->one->mode;
+ temp->mod_dst = p->two->mode;
+ temp->oid_src = p->one->oid;
+ temp->oid_dst = p->two->oid;
+ temp->status = p->status;
+ temp->sm_path = xstrdup(p->one->path);
+
+ ALLOC_GROW(list->entries, list->nr + 1, list->alloc);
+ list->entries[list->nr++] = temp;
+ }
+}
+
+static const char *get_diff_cmd(enum diff_cmd diff_cmd)
+{
+ switch (diff_cmd) {
+ case DIFF_INDEX: return "diff-index";
+ case DIFF_FILES: return "diff-files";
+ default: BUG("bad diff_cmd value %d", diff_cmd);
+ }
+}
+
+static int compute_summary_module_list(struct object_id *head_oid,
+ struct summary_cb *info,
+ enum diff_cmd diff_cmd)
+{
+ struct strvec diff_args = STRVEC_INIT;
+ struct rev_info rev;
+ struct module_cb_list list = MODULE_CB_LIST_INIT;
+
+ strvec_push(&diff_args, get_diff_cmd(diff_cmd));
+ if (info->cached)
+ strvec_push(&diff_args, "--cached");
+ strvec_pushl(&diff_args, "--ignore-submodules=dirty", "--raw", NULL);
+ if (head_oid)
+ strvec_push(&diff_args, oid_to_hex(head_oid));
+ strvec_push(&diff_args, "--");
+ if (info->argc)
+ strvec_pushv(&diff_args, info->argv);
+
+ git_config(git_diff_basic_config, NULL);
+ init_revisions(&rev, info->prefix);
+ rev.abbrev = 0;
+ precompose_argv(diff_args.nr, diff_args.v);
+ setup_revisions(diff_args.nr, diff_args.v, &rev, NULL);
+ rev.diffopt.output_format = DIFF_FORMAT_NO_OUTPUT | DIFF_FORMAT_CALLBACK;
+ rev.diffopt.format_callback = submodule_summary_callback;
+ rev.diffopt.format_callback_data = &list;
+
+ if (!info->cached) {
+ if (diff_cmd == DIFF_INDEX)
+ setup_work_tree();
+ if (read_cache_preload(&rev.diffopt.pathspec) < 0) {
+ perror("read_cache_preload");
+ return -1;
+ }
+ } else if (read_cache() < 0) {
+ perror("read_cache");
+ return -1;
+ }
+
+ if (diff_cmd == DIFF_INDEX)
+ run_diff_index(&rev, info->cached);
+ else
+ run_diff_files(&rev, 0);
+ prepare_submodule_summary(info, &list);
+ strvec_clear(&diff_args);
+ return 0;
+}
+
+static int module_summary(int argc, const char **argv, const char *prefix)
+{
+ struct summary_cb info = SUMMARY_CB_INIT;
+ int cached = 0;
+ int for_status = 0;
+ int files = 0;
+ int summary_limit = -1;
+ enum diff_cmd diff_cmd = DIFF_INDEX;
+ struct object_id head_oid;
+ int ret;
+
+ struct option module_summary_options[] = {
+ OPT_BOOL(0, "cached", &cached,
+ N_("use the commit stored in the index instead of the submodule HEAD")),
+ OPT_BOOL(0, "files", &files,
+ N_("to compare the commit in the index with that in the submodule HEAD")),
+ OPT_BOOL(0, "for-status", &for_status,
+ N_("skip submodules with 'ignore_config' value set to 'all'")),
+ OPT_INTEGER('n', "summary-limit", &summary_limit,
+ N_("limit the summary size")),
+ OPT_END()
+ };
+
+ const char *const git_submodule_helper_usage[] = {
+ N_("git submodule--helper summary [<options>] [commit] [--] [<path>]"),
+ NULL
+ };
+
+ argc = parse_options(argc, argv, prefix, module_summary_options,
+ git_submodule_helper_usage, 0);
+
+ if (!summary_limit)
+ return 0;
+
+ if (!get_oid(argc ? argv[0] : "HEAD", &head_oid)) {
+ if (argc) {
+ argv++;
+ argc--;
+ }
+ } else if (!argc || !strcmp(argv[0], "HEAD")) {
+ /* before the first commit: compare with an empty tree */
+ oidcpy(&head_oid, the_hash_algo->empty_tree);
+ if (argc) {
+ argv++;
+ argc--;
+ }
+ } else {
+ if (get_oid("HEAD", &head_oid))
+ die(_("could not fetch a revision for HEAD"));
+ }
+
+ if (files) {
+ if (cached)
+ die(_("--cached and --files are mutually exclusive"));
+ diff_cmd = DIFF_FILES;
+ }
+
+ info.argc = argc;
+ info.argv = argv;
+ info.prefix = prefix;
+ info.cached = !!cached;
+ info.files = !!files;
+ info.for_status = !!for_status;
+ info.summary_limit = summary_limit;
+
+ ret = compute_summary_module_list((diff_cmd == DIFF_INDEX) ? &head_oid : NULL,
+ &info, diff_cmd);
+ return ret;
+}
+
struct sync_cb {
const char *prefix;
unsigned int flags;
};
-
#define SYNC_CB_INIT { NULL, 0 }
static void sync_submodule(const char *path, const char *prefix,
@@ -2344,6 +2768,7 @@ static struct cmd_struct commands[] = {
{"print-default-remote", print_default_remote, 0},
{"sync", module_sync, SUPPORT_SUPER_PREFIX},
{"deinit", module_deinit, 0},
+ {"summary", module_summary, SUPPORT_SUPER_PREFIX},
{"remote-branch", resolve_remote_submodule_branch, 0},
{"push-check", push_check, 0},
{"absorb-git-dirs", absorb_git_dirs, SUPPORT_SUPER_PREFIX},
diff --git a/builtin/worktree.c b/builtin/worktree.c
index 378f332b5d..bb70fde97e 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -924,7 +924,6 @@ static int move_worktree(int ac, const char **av, const char *prefix)
static void check_clean_worktree(struct worktree *wt,
const char *original_path)
{
- struct strvec child_env = STRVEC_INIT;
struct child_process cp;
char buf[1];
int ret;
@@ -935,15 +934,14 @@ static void check_clean_worktree(struct worktree *wt,
*/
validate_no_submodules(wt);
- strvec_pushf(&child_env, "%s=%s/.git",
+ child_process_init(&cp);
+ strvec_pushf(&cp.env_array, "%s=%s/.git",
GIT_DIR_ENVIRONMENT, wt->path);
- strvec_pushf(&child_env, "%s=%s",
+ strvec_pushf(&cp.env_array, "%s=%s",
GIT_WORK_TREE_ENVIRONMENT, wt->path);
- memset(&cp, 0, sizeof(cp));
strvec_pushl(&cp.args, "status",
"--porcelain", "--ignore-submodules=none",
NULL);
- cp.env = child_env.v;
cp.git_cmd = 1;
cp.dir = wt->path;
cp.out = -1;
@@ -1030,6 +1028,34 @@ static int remove_worktree(int ac, const char **av, const char *prefix)
return ret;
}
+static void report_repair(int iserr, const char *path, const char *msg, void *cb_data)
+{
+ if (!iserr) {
+ printf_ln(_("repair: %s: %s"), msg, path);
+ } else {
+ int *exit_status = (int *)cb_data;
+ fprintf_ln(stderr, _("error: %s: %s"), msg, path);
+ *exit_status = 1;
+ }
+}
+
+static int repair(int ac, const char **av, const char *prefix)
+{
+ const char **p;
+ const char *self[] = { ".", NULL };
+ struct option options[] = {
+ OPT_END()
+ };
+ int rc = 0;
+
+ ac = parse_options(ac, av, prefix, options, worktree_usage, 0);
+ repair_worktrees(report_repair, &rc);
+ p = ac > 0 ? av : self;
+ for (; *p; p++)
+ repair_worktree_at_path(*p, report_repair, &rc);
+ return rc;
+}
+
int cmd_worktree(int ac, const char **av, const char *prefix)
{
struct option options[] = {
@@ -1056,5 +1082,7 @@ int cmd_worktree(int ac, const char **av, const char *prefix)
return move_worktree(ac - 1, av + 1, prefix);
if (!strcmp(av[1], "remove"))
return remove_worktree(ac - 1, av + 1, prefix);
+ if (!strcmp(av[1], "repair"))
+ return repair(ac - 1, av + 1, prefix);
usage_with_options(worktree_usage, options);
}