зеркало из https://github.com/microsoft/git.git
Merge branch 'ss/submodule-summary-in-c'
Yet another subcommand of "git submodule" is getting rewritten in C. * ss/submodule-summary-in-c: submodule: port submodule subcommand 'summary' from shell to C t7421: introduce a test script for verifying 'summary' output submodule: rename helper functions to avoid ambiguity submodule: remove extra line feeds between callback struct and macro
This commit is contained in:
Коммит
bbdba3d883
|
@ -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,438 @@ 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,
|
||||
int missing_src, int missing_dst,
|
||||
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, *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 %d\n"), p->mod_dst);
|
||||
}
|
||||
}
|
||||
|
||||
if (S_ISGITLINK(p->mod_src)) {
|
||||
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, missing_src,
|
||||
missing_dst, 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 +2769,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},
|
||||
|
|
2
diff.c
2
diff.c
|
@ -3432,7 +3432,7 @@ static void builtin_diff(const char *name_a,
|
|||
if (o->submodule_format == DIFF_SUBMODULE_LOG &&
|
||||
(!one->mode || S_ISGITLINK(one->mode)) &&
|
||||
(!two->mode || S_ISGITLINK(two->mode))) {
|
||||
show_submodule_summary(o, one->path ? one->path : two->path,
|
||||
show_submodule_diff_summary(o, one->path ? one->path : two->path,
|
||||
&one->oid, &two->oid,
|
||||
two->dirty_submodule);
|
||||
return;
|
||||
|
|
186
git-submodule.sh
186
git-submodule.sh
|
@ -59,31 +59,6 @@ die_if_unmatched ()
|
|||
fi
|
||||
}
|
||||
|
||||
#
|
||||
# Print a submodule configuration setting
|
||||
#
|
||||
# $1 = submodule name
|
||||
# $2 = option name
|
||||
# $3 = default value
|
||||
#
|
||||
# Checks in the usual git-config places first (for overrides),
|
||||
# otherwise it falls back on .gitmodules. This allows you to
|
||||
# distribute project-wide defaults in .gitmodules, while still
|
||||
# customizing individual repositories if necessary. If the option is
|
||||
# not in .gitmodules either, print a default value.
|
||||
#
|
||||
get_submodule_config () {
|
||||
name="$1"
|
||||
option="$2"
|
||||
default="$3"
|
||||
value=$(git config submodule."$name"."$option")
|
||||
if test -z "$value"
|
||||
then
|
||||
value=$(git submodule--helper config submodule."$name"."$option")
|
||||
fi
|
||||
printf '%s' "${value:-$default}"
|
||||
}
|
||||
|
||||
isnumber()
|
||||
{
|
||||
n=$(($1 + 0)) 2>/dev/null && test "$n" = "$1"
|
||||
|
@ -831,166 +806,7 @@ cmd_summary() {
|
|||
shift
|
||||
done
|
||||
|
||||
test $summary_limit = 0 && return
|
||||
|
||||
if rev=$(git rev-parse -q --verify --default HEAD ${1+"$1"})
|
||||
then
|
||||
head=$rev
|
||||
test $# = 0 || shift
|
||||
elif test -z "$1" || test "$1" = "HEAD"
|
||||
then
|
||||
# before the first commit: compare with an empty tree
|
||||
head=$(git hash-object -w -t tree --stdin </dev/null)
|
||||
test -z "$1" || shift
|
||||
else
|
||||
head="HEAD"
|
||||
fi
|
||||
|
||||
if [ -n "$files" ]
|
||||
then
|
||||
test -n "$cached" &&
|
||||
die "$(gettext "The --cached option cannot be used with the --files option")"
|
||||
diff_cmd=diff-files
|
||||
head=
|
||||
fi
|
||||
|
||||
cd_to_toplevel
|
||||
eval "set $(git rev-parse --sq --prefix "$wt_prefix" -- "$@")"
|
||||
# Get modified modules cared by user
|
||||
modules=$(git $diff_cmd $cached --ignore-submodules=dirty --raw $head -- "$@" |
|
||||
sane_egrep '^:([0-7]* )?160000' |
|
||||
while read -r mod_src mod_dst sha1_src sha1_dst status sm_path
|
||||
do
|
||||
# Always show modules deleted or type-changed (blob<->module)
|
||||
if test "$status" = D || test "$status" = T
|
||||
then
|
||||
printf '%s\n' "$sm_path"
|
||||
continue
|
||||
fi
|
||||
# Respect the ignore setting for --for-status.
|
||||
if test -n "$for_status"
|
||||
then
|
||||
name=$(git submodule--helper name "$sm_path")
|
||||
ignore_config=$(get_submodule_config "$name" ignore none)
|
||||
test $status != A && test $ignore_config = all && continue
|
||||
fi
|
||||
# Also show added or modified modules which are checked out
|
||||
GIT_DIR="$sm_path/.git" git rev-parse --git-dir >/dev/null 2>&1 &&
|
||||
printf '%s\n' "$sm_path"
|
||||
done
|
||||
)
|
||||
|
||||
test -z "$modules" && return
|
||||
|
||||
git $diff_cmd $cached --ignore-submodules=dirty --raw $head -- $modules |
|
||||
sane_egrep '^:([0-7]* )?160000' |
|
||||
cut -c2- |
|
||||
while read -r mod_src mod_dst sha1_src sha1_dst status name
|
||||
do
|
||||
if test -z "$cached" &&
|
||||
is_zero_oid $sha1_dst
|
||||
then
|
||||
case "$mod_dst" in
|
||||
160000)
|
||||
sha1_dst=$(GIT_DIR="$name/.git" git rev-parse HEAD)
|
||||
;;
|
||||
100644 | 100755 | 120000)
|
||||
sha1_dst=$(git hash-object $name)
|
||||
;;
|
||||
000000)
|
||||
;; # removed
|
||||
*)
|
||||
# unexpected type
|
||||
eval_gettextln "unexpected mode \$mod_dst" >&2
|
||||
continue ;;
|
||||
esac
|
||||
fi
|
||||
missing_src=
|
||||
missing_dst=
|
||||
|
||||
test $mod_src = 160000 &&
|
||||
! GIT_DIR="$name/.git" git rev-parse -q --verify $sha1_src^0 >/dev/null &&
|
||||
missing_src=t
|
||||
|
||||
test $mod_dst = 160000 &&
|
||||
! GIT_DIR="$name/.git" git rev-parse -q --verify $sha1_dst^0 >/dev/null &&
|
||||
missing_dst=t
|
||||
|
||||
display_name=$(git submodule--helper relative-path "$name" "$wt_prefix")
|
||||
|
||||
total_commits=
|
||||
case "$missing_src,$missing_dst" in
|
||||
t,)
|
||||
errmsg="$(eval_gettext " Warn: \$display_name doesn't contain commit \$sha1_src")"
|
||||
;;
|
||||
,t)
|
||||
errmsg="$(eval_gettext " Warn: \$display_name doesn't contain commit \$sha1_dst")"
|
||||
;;
|
||||
t,t)
|
||||
errmsg="$(eval_gettext " Warn: \$display_name doesn't contain commits \$sha1_src and \$sha1_dst")"
|
||||
;;
|
||||
*)
|
||||
errmsg=
|
||||
total_commits=$(
|
||||
if test $mod_src = 160000 && test $mod_dst = 160000
|
||||
then
|
||||
range="$sha1_src...$sha1_dst"
|
||||
elif test $mod_src = 160000
|
||||
then
|
||||
range=$sha1_src
|
||||
else
|
||||
range=$sha1_dst
|
||||
fi
|
||||
GIT_DIR="$name/.git" \
|
||||
git rev-list --first-parent $range -- | wc -l
|
||||
)
|
||||
total_commits=" ($(($total_commits + 0)))"
|
||||
;;
|
||||
esac
|
||||
|
||||
sha1_abbr_src=$(GIT_DIR="$name/.git" git rev-parse --short $sha1_src 2>/dev/null ||
|
||||
echo $sha1_src | cut -c1-7)
|
||||
sha1_abbr_dst=$(GIT_DIR="$name/.git" git rev-parse --short $sha1_dst 2>/dev/null ||
|
||||
echo $sha1_dst | cut -c1-7)
|
||||
|
||||
if test $status = T
|
||||
then
|
||||
blob="$(gettext "blob")"
|
||||
submodule="$(gettext "submodule")"
|
||||
if test $mod_dst = 160000
|
||||
then
|
||||
echo "* $display_name $sha1_abbr_src($blob)->$sha1_abbr_dst($submodule)$total_commits:"
|
||||
else
|
||||
echo "* $display_name $sha1_abbr_src($submodule)->$sha1_abbr_dst($blob)$total_commits:"
|
||||
fi
|
||||
else
|
||||
echo "* $display_name $sha1_abbr_src...$sha1_abbr_dst$total_commits:"
|
||||
fi
|
||||
if test -n "$errmsg"
|
||||
then
|
||||
# Don't give error msg for modification whose dst is not submodule
|
||||
# i.e. deleted or changed to blob
|
||||
test $mod_dst = 160000 && echo "$errmsg"
|
||||
else
|
||||
if test $mod_src = 160000 && test $mod_dst = 160000
|
||||
then
|
||||
limit=
|
||||
test $summary_limit -gt 0 && limit="-$summary_limit"
|
||||
GIT_DIR="$name/.git" \
|
||||
git log $limit --pretty='format: %m %s' \
|
||||
--first-parent $sha1_src...$sha1_dst
|
||||
elif test $mod_dst = 160000
|
||||
then
|
||||
GIT_DIR="$name/.git" \
|
||||
git log --pretty='format: > %s' -1 $sha1_dst
|
||||
else
|
||||
GIT_DIR="$name/.git" \
|
||||
git log --pretty='format: < %s' -1 $sha1_src
|
||||
fi
|
||||
echo
|
||||
fi
|
||||
echo
|
||||
done
|
||||
git ${wt_prefix:+-C "$wt_prefix"} submodule--helper summary ${prefix:+--prefix "$prefix"} ${files:+--files} ${cached:+--cached} ${for_status:+--for-status} ${summary_limit:+-n $summary_limit} -- "$@"
|
||||
}
|
||||
#
|
||||
# List all submodules, prefixed with:
|
||||
|
|
10
submodule.c
10
submodule.c
|
@ -438,7 +438,7 @@ void handle_ignore_submodules_arg(struct diff_options *diffopt,
|
|||
*/
|
||||
}
|
||||
|
||||
static int prepare_submodule_summary(struct rev_info *rev, const char *path,
|
||||
static int prepare_submodule_diff_summary(struct rev_info *rev, const char *path,
|
||||
struct commit *left, struct commit *right,
|
||||
struct commit_list *merge_bases)
|
||||
{
|
||||
|
@ -459,7 +459,7 @@ static int prepare_submodule_summary(struct rev_info *rev, const char *path,
|
|||
return prepare_revision_walk(rev);
|
||||
}
|
||||
|
||||
static void print_submodule_summary(struct repository *r, struct rev_info *rev, struct diff_options *o)
|
||||
static void print_submodule_diff_summary(struct repository *r, struct rev_info *rev, struct diff_options *o)
|
||||
{
|
||||
static const char format[] = " %m %s";
|
||||
struct strbuf sb = STRBUF_INIT;
|
||||
|
@ -610,7 +610,7 @@ output_header:
|
|||
strbuf_release(&sb);
|
||||
}
|
||||
|
||||
void show_submodule_summary(struct diff_options *o, const char *path,
|
||||
void show_submodule_diff_summary(struct diff_options *o, const char *path,
|
||||
struct object_id *one, struct object_id *two,
|
||||
unsigned dirty_submodule)
|
||||
{
|
||||
|
@ -632,12 +632,12 @@ void show_submodule_summary(struct diff_options *o, const char *path,
|
|||
goto out;
|
||||
|
||||
/* Treat revision walker failure the same as missing commits */
|
||||
if (prepare_submodule_summary(&rev, path, left, right, merge_bases)) {
|
||||
if (prepare_submodule_diff_summary(&rev, path, left, right, merge_bases)) {
|
||||
diff_emit_submodule_error(o, "(revision walker failed)\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
print_submodule_summary(sub, &rev, o);
|
||||
print_submodule_diff_summary(sub, &rev, o);
|
||||
|
||||
out:
|
||||
if (merge_bases)
|
||||
|
|
|
@ -69,7 +69,7 @@ int parse_submodule_update_strategy(const char *value,
|
|||
struct submodule_update_strategy *dst);
|
||||
const char *submodule_strategy_to_string(const struct submodule_update_strategy *s);
|
||||
void handle_ignore_submodules_arg(struct diff_options *, const char *);
|
||||
void show_submodule_summary(struct diff_options *o, const char *path,
|
||||
void show_submodule_diff_summary(struct diff_options *o, const char *path,
|
||||
struct object_id *one, struct object_id *two,
|
||||
unsigned dirty_submodule);
|
||||
void show_submodule_inline_diff(struct diff_options *o, const char *path,
|
||||
|
|
|
@ -7,6 +7,12 @@ test_description='Summary support for submodules
|
|||
|
||||
This test script tries to verify the sanity of summary subcommand of git submodule.
|
||||
'
|
||||
|
||||
# NOTE: This test script uses 'git add' instead of 'git submodule add' to add
|
||||
# submodules to the superproject. Some submodule subcommands such as init and
|
||||
# deinit might not work as expected in this script. t7421 does not have this
|
||||
# caveat.
|
||||
#
|
||||
# NEEDSWORK: This test script is old fashioned and may need a big cleanup due to
|
||||
# various reasons, one of them being that there are lots of commands taking place
|
||||
# outside of 'test_expect_success' block, which is no longer in good-style.
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# Copyright (C) 2020 Shourya Shukla
|
||||
#
|
||||
|
||||
test_description='Summary support for submodules, adding them using git submodule add
|
||||
|
||||
This test script tries to verify the sanity of summary subcommand of git submodule
|
||||
while making sure to add submodules using `git submodule add` instead of
|
||||
`git add` as done in t7401.
|
||||
'
|
||||
|
||||
. ./test-lib.sh
|
||||
|
||||
test_expect_success 'summary test environment setup' '
|
||||
git init sm &&
|
||||
test_commit -C sm "add file" file file-content file-tag &&
|
||||
|
||||
git submodule add ./sm my-subm &&
|
||||
test_tick &&
|
||||
git commit -m "add submodule"
|
||||
'
|
||||
|
||||
test_expect_success 'submodule summary output for initialized submodule' '
|
||||
test_commit -C sm "add file2" file2 file2-content file2-tag &&
|
||||
git submodule update --remote &&
|
||||
test_tick &&
|
||||
git commit -m "update submodule" my-subm &&
|
||||
git submodule summary HEAD^ >actual &&
|
||||
rev1=$(git -C sm rev-parse --short HEAD^) &&
|
||||
rev2=$(git -C sm rev-parse --short HEAD) &&
|
||||
cat >expected <<-EOF &&
|
||||
* my-subm ${rev1}...${rev2} (1):
|
||||
> add file2
|
||||
|
||||
EOF
|
||||
test_cmp expected actual
|
||||
'
|
||||
|
||||
test_expect_success 'submodule summary output for deinitialized submodule' '
|
||||
git submodule deinit my-subm &&
|
||||
git submodule summary HEAD^ >actual &&
|
||||
test_must_be_empty actual &&
|
||||
git submodule update --init my-subm &&
|
||||
git submodule summary HEAD^ >actual &&
|
||||
rev1=$(git -C sm rev-parse --short HEAD^) &&
|
||||
rev2=$(git -C sm rev-parse --short HEAD) &&
|
||||
cat >expected <<-EOF &&
|
||||
* my-subm ${rev1}...${rev2} (1):
|
||||
> add file2
|
||||
|
||||
EOF
|
||||
test_cmp expected actual
|
||||
'
|
||||
|
||||
test_expect_success 'submodule summary output for submodules with changed paths' '
|
||||
git mv my-subm subm &&
|
||||
git commit -m "change submodule path" &&
|
||||
rev=$(git -C sm rev-parse --short HEAD^) &&
|
||||
git submodule summary HEAD^^ -- my-subm >actual 2>err &&
|
||||
grep "fatal:.*my-subm" err &&
|
||||
cat >expected <<-EOF &&
|
||||
* my-subm ${rev}...0000000:
|
||||
|
||||
EOF
|
||||
test_cmp expected actual
|
||||
'
|
||||
|
||||
test_done
|
Загрузка…
Ссылка в новой задаче