13
#include "remote.h"
14
#include "refs.h"
15
#include "connect.h"
16
+#include "revision.h"
17
+#include "diffcore.h"
18
+#include "diff.h"
19
20
#define OPT_QUIET (1 << 0)
21
+#define OPT_CACHED (1 << 1)
22
+#define OPT_RECURSIVE (1 << 2)
23
24
typedef void (*each_submodule_fn)(const struct cache_entry *list_item,
25
void *cb_data);
250
}
251
}
252
253
+static char *compute_rev_name(const char *sub_path, const char* object_id)
254
+{
255
+ struct strbuf sb = STRBUF_INIT;
256
+ const char ***d;
257
+
258
+ static const char *describe_bare[] = { NULL };
259
+
260
+ static const char *describe_tags[] = { "--tags", NULL };
261
+
262
+ static const char *describe_contains[] = { "--contains", NULL };
263
+
264
+ static const char *describe_all_always[] = { "--all", "--always", NULL };
265
+
266
+ static const char **describe_argv[] = { describe_bare, describe_tags,
267
+ describe_contains,
268
+ describe_all_always, NULL };
269
+
270
+ for (d = describe_argv; *d; d++) {
271
+ struct child_process cp = CHILD_PROCESS_INIT;
272
+ prepare_submodule_repo_env(&cp.env_array);
273
+ cp.dir = sub_path;
274
+ cp.git_cmd = 1;
275
+ cp.no_stderr = 1;
276
+
277
+ argv_array_push(&cp.args, "describe");
278
+ argv_array_pushv(&cp.args, *d);
279
+ argv_array_push(&cp.args, object_id);
280
+
281
+ if (!capture_command(&cp, &sb, 0)) {
282
+ strbuf_strip_suffix(&sb, "\n");
283
+ return strbuf_detach(&sb, NULL);
284
+ }
285
+ }
286
+
287
+ strbuf_release(&sb);
288
+ return NULL;
289
+}
290
+
291
struct module_list {
292
const struct cache_entry **entries;
293
int alloc, nr;
547
return 0;
548
}
549
550
+struct status_cb {
551
+ const char *prefix;
552
+ unsigned int flags;
553
+};
554
+
555
+#define STATUS_CB_INIT { NULL, 0 }
556
+
557
+static void print_status(unsigned int flags, char state, const char *path,
558
+ const struct object_id *oid, const char *displaypath)
559
+{
560
+ if (flags & OPT_QUIET)
561
+ return;
562
+
563
+ printf("%c%s %s", state, oid_to_hex(oid), displaypath);
564
+
565
+ if (state == ' ' || state == '+')
566
+ printf(" (%s)", compute_rev_name(path, oid_to_hex(oid)));
567
+
568
+ printf("\n");
569
+}
570
+
571
+static int handle_submodule_head_ref(const char *refname,
572
+ const struct object_id *oid, int flags,
573
+ void *cb_data)
574
+{
575
+ struct object_id *output = cb_data;
576
+ if (oid)
577
+ oidcpy(output, oid);
578
+
579
+ return 0;
580
+}
581
+
582
+static void status_submodule(const char *path, const struct object_id *ce_oid,
583
+ unsigned int ce_flags, const char *prefix,
584
+ unsigned int flags)
585
+{
586
+ char *displaypath;
587
+ struct argv_array diff_files_args = ARGV_ARRAY_INIT;
588
+ struct rev_info rev;
589
+ int diff_files_result;
590
+
591
+ if (!submodule_from_path(&null_oid, path))
592
+ die(_("no submodule mapping found in .gitmodules for path '%s'"),
593
+ path);
594
+
595
+ displaypath = get_submodule_displaypath(path, prefix);
596
+
597
+ if ((CE_STAGEMASK & ce_flags) >> CE_STAGESHIFT) {
598
+ print_status(flags, 'U', path, &null_oid, displaypath);
599
+ goto cleanup;
600
+ }
601
+
602
+ if (!is_submodule_active(the_repository, path)) {
603
+ print_status(flags, '-', path, ce_oid, displaypath);
604
+ goto cleanup;
605
+ }
606
+
607
+ argv_array_pushl(&diff_files_args, "diff-files",
608
+ "--ignore-submodules=dirty", "--quiet", "--",
609
+ path, NULL);
610
+
611
+ git_config(git_diff_basic_config, NULL);
612
+ init_revisions(&rev, prefix);
613
+ rev.abbrev = 0;
614
+ diff_files_args.argc = setup_revisions(diff_files_args.argc,
615
+ diff_files_args.argv,
616
+ &rev, NULL);
617
+ diff_files_result = run_diff_files(&rev, 0);
618
+
619
+ if (!diff_result_code(&rev.diffopt, diff_files_result)) {
620
+ print_status(flags, ' ', path, ce_oid,
621
+ displaypath);
622
+ } else if (!(flags & OPT_CACHED)) {
623
+ struct object_id oid;
624
+
625
+ if (refs_head_ref(get_submodule_ref_store(path),
626
+ handle_submodule_head_ref, &oid))
627
+ die(_("could not resolve HEAD ref inside the"
628
+ "submodule '%s'"), path);
629
+
630
+ print_status(flags, '+', path, &oid, displaypath);
631
+ } else {
632
+ print_status(flags, '+', path, ce_oid, displaypath);
633
+ }
634
+
635
+ if (flags & OPT_RECURSIVE) {
636
+ struct child_process cpr = CHILD_PROCESS_INIT;
637
+
638
+ cpr.git_cmd = 1;
639
+ cpr.dir = path;
640
+ prepare_submodule_repo_env(&cpr.env_array);
641
+
642
+ argv_array_push(&cpr.args, "--super-prefix");
643
+ argv_array_pushf(&cpr.args, "%s/", displaypath);
644
+ argv_array_pushl(&cpr.args, "submodule--helper", "status",
645
+ "--recursive", NULL);
646
+
647
+ if (flags & OPT_CACHED)
648
+ argv_array_push(&cpr.args, "--cached");
649
+
650
+ if (flags & OPT_QUIET)
651
+ argv_array_push(&cpr.args, "--quiet");
652
+
653
+ if (run_command(&cpr))
654
+ die(_("failed to recurse into submodule '%s'"), path);
655
+ }
656
+
657
+cleanup:
658
+ argv_array_clear(&diff_files_args);
659
+ free(displaypath);
660
+}
661
+
662
+static void status_submodule_cb(const struct cache_entry *list_item,
663
+ void *cb_data)
664
+{
665
+ struct status_cb *info = cb_data;
666
+ status_submodule(list_item->name, &list_item->oid, list_item->ce_flags,
667
+ info->prefix, info->flags);
668
+}
669
+
670
+static int module_status(int argc, const char **argv, const char *prefix)
671
+{
672
+ struct status_cb info = STATUS_CB_INIT;
673
+ struct pathspec pathspec;
674
+ struct module_list list = MODULE_LIST_INIT;
675
+ int quiet = 0;
676
+
677
+ struct option module_status_options[] = {
678
+ OPT__QUIET(&quiet, N_("Suppress submodule status output")),
679
+ OPT_BIT(0, "cached", &info.flags, N_("Use commit stored in the index instead of the one stored in the submodule HEAD"), OPT_CACHED),
680
+ OPT_BIT(0, "recursive", &info.flags, N_("recurse into nested submodules"), OPT_RECURSIVE),
681
+ OPT_END()
682
+ };
683
+
684
+ const char *const git_submodule_helper_usage[] = {
685
+ N_("git submodule status [--quiet] [--cached] [--recursive] [<path>...]"),
686
+ NULL
687
+ };
688
+
689
+ argc = parse_options(argc, argv, prefix, module_status_options,
690
+ git_submodule_helper_usage, 0);
691
+
692
+ if (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0)
693
+ return 1;
694
+
695
+ info.prefix = prefix;
696
+ if (quiet)
697
+ info.flags |= OPT_QUIET;
698
+
699
+ for_each_listed_submodule(&list, status_submodule_cb, &info);
700
+
701
+ return 0;
702
+}
703
+
704
static int module_name(int argc, const char **argv, const char *prefix)
705
{
706
const struct submodule *sub;
1498
{"resolve-relative-url", resolve_relative_url, 0},
1499
{"resolve-relative-url-test", resolve_relative_url_test, 0},
1500
{"init", module_init, SUPPORT_SUPER_PREFIX},
1501
+ {"status", module_status, SUPPORT_SUPER_PREFIX},
1502
{"remote-branch", resolve_remote_submodule_branch, 0},
1503
{"push-check", push_check, 0},
1504
{"absorb-git-dirs", absorb_git_dirs, SUPPORT_SUPER_PREFIX},