10
#include "config.h"
11
#include "environment.h"
12
#include "gettext.h"
13
+#include "hex.h"
14
#include "refspec.h"
15
#include "run-command.h"
16
#include "remote.h"
545
return git_default_config(k, v, ctx, NULL);
546
}
547
548
+static int push_multiple(struct string_list *list,
549
+ const struct string_list *push_options,
550
+ int flags,
551
+ int tags,
552
+ const char **refspecs,
553
+ int refspec_nr)
554
+{
555
+ int result = 0;
556
+ size_t i;
557
+ struct strvec argv = STRVEC_INIT;
558
+
559
+ strvec_push(&argv, "push");
560
+
561
+ if (flags & TRANSPORT_PUSH_FORCE)
562
+ strvec_push(&argv, "--force");
563
+ if (flags & TRANSPORT_PUSH_DRY_RUN)
564
+ strvec_push(&argv, "--dry-run");
565
+ if (flags & TRANSPORT_PUSH_PORCELAIN)
566
+ strvec_push(&argv, "--porcelain");
567
+ if (flags & TRANSPORT_PUSH_PRUNE)
568
+ strvec_push(&argv, "--prune");
569
+ if (flags & TRANSPORT_PUSH_NO_HOOK)
570
+ strvec_push(&argv, "--no-verify");
571
+ if (flags & TRANSPORT_PUSH_FOLLOW_TAGS)
572
+ strvec_push(&argv, "--follow-tags");
573
+ if (flags & TRANSPORT_PUSH_SET_UPSTREAM)
574
+ strvec_push(&argv, "--set-upstream");
575
+ if (flags & TRANSPORT_PUSH_FORCE_IF_INCLUDES)
576
+ strvec_push(&argv, "--force-if-includes");
577
+ if (flags & TRANSPORT_PUSH_ALL)
578
+ strvec_push(&argv, "--all");
579
+ if (flags & TRANSPORT_PUSH_MIRROR)
580
+ strvec_push(&argv, "--mirror");
581
+
582
+ if (flags & TRANSPORT_PUSH_CERT_ALWAYS)
583
+ strvec_push(&argv, "--signed=yes");
584
+ else if (flags & TRANSPORT_PUSH_CERT_IF_ASKED)
585
+ strvec_push(&argv, "--signed=if-asked");
586
+ if (!thin)
587
+ strvec_push(&argv, "--no-thin");
588
+
589
+ if (deleterefs)
590
+ strvec_push(&argv, "--delete");
591
+
592
+ if (receivepack)
593
+ strvec_pushf(&argv, "--receive-pack=%s", receivepack);
594
+ if (verbosity >= 2)
595
+ strvec_push(&argv, "-v");
596
+ if (verbosity >= 1)
597
+ strvec_push(&argv, "-v");
598
+ else if (verbosity < 0)
599
+ strvec_push(&argv, "-q");
600
+ if (progress > 0)
601
+ strvec_push(&argv, "--progress");
602
+ else if (progress == 0)
603
+ strvec_push(&argv, "--no-progress");
604
+
605
+ if (family == TRANSPORT_FAMILY_IPV4)
606
+ strvec_push(&argv, "--ipv4");
607
+ else if (family == TRANSPORT_FAMILY_IPV6)
608
+ strvec_push(&argv, "--ipv6");
609
+
610
+ if (recurse_submodules == RECURSE_SUBMODULES_CHECK)
611
+ strvec_push(&argv, "--recurse-submodules=check");
612
+ else if (recurse_submodules == RECURSE_SUBMODULES_ON_DEMAND)
613
+ strvec_push(&argv, "--recurse-submodules=on-demand");
614
+ else if (recurse_submodules == RECURSE_SUBMODULES_ONLY)
615
+ strvec_push(&argv, "--recurse-submodules=only");
616
+ else if (recurse_submodules == RECURSE_SUBMODULES_OFF)
617
+ strvec_push(&argv, "--recurse-submodules=no");
618
+
619
+
620
+ if (tags)
621
+ strvec_push(&argv, "--tags");
622
+
623
+ for (i = 0; i < push_options->nr; i++)
624
+ strvec_pushf(&argv, "--push-option=%s",
625
+ push_options->items[i].string);
626
+
627
+ for (i = 0; i < cas.nr; i++) {
628
+ if (cas.entry[i].use_tracking) {
629
+ strvec_pushf(&argv, "--force-with-lease=%s",
630
+ cas.entry[i].refname);
631
+ } else if (!is_null_oid(&cas.entry[i].expect)) {
632
+ strvec_pushf(&argv, "--force-with-lease=%s:%s",
633
+ cas.entry[i].refname,
634
+ oid_to_hex(&cas.entry[i].expect));
635
+ } else {
636
+ strvec_push(&argv, "--force-with-lease");
637
+ }
638
+ }
639
+
640
+ for (i = 0; i < list->nr; i++) {
641
+ const char *name = list->items[i].string;
642
+ struct child_process cmd = CHILD_PROCESS_INIT;
643
+ int j;
644
+
645
+ strvec_pushv(&cmd.args, argv.v);
646
+ strvec_push(&cmd.args, name);
647
+
648
+ for (j = 0; j < refspec_nr; j++)
649
+ strvec_push(&cmd.args, refspecs[j]);
650
+
651
+ if (verbosity >= 0)
652
+ printf(_("Pushing to %s\n"), name);
653
+
654
+ cmd.git_cmd = 1;
655
+ if (run_command(&cmd)) {
656
+ error(_("could not push to %s"), name);
657
+ result = 1;
658
+ }
659
+ }
660
+
661
+ strvec_clear(&argv);
662
+ return result;
663
+}
664
+
665
int cmd_push(int argc,
666
const char **argv,
667
const char *prefix,
670
int flags = 0;
671
int tags = 0;
672
int push_cert = -1;
555
- int rc;
673
+ int rc = 0;
674
+ int base_flags;
675
const char *repo = NULL; /* default repository */
676
struct string_list push_options_cmdline = STRING_LIST_INIT_DUP;
677
+ struct string_list remote_group = STRING_LIST_INIT_DUP;
678
struct string_list *push_options;
679
const struct string_list_item *item;
560
- struct remote *remote;
680
681
struct option options[] = {
682
OPT__VERBOSITY(&verbosity),
739
else if (recurse_submodules == RECURSE_SUBMODULES_ONLY)
740
flags |= TRANSPORT_RECURSE_SUBMODULES_ONLY;
741
623
- if (tags)
624
- refspec_append(&rs, "refs/tags/*");
625
-
742
if (argc > 0)
743
repo = argv[0];
744
629
- remote = pushremote_get(repo);
630
- if (!remote) {
631
- if (repo)
632
- die(_("bad repository '%s'"), repo);
633
- die(_("No configured push destination.\n"
634
- "Either specify the URL from the command-line or configure a remote repository using\n"
635
- "\n"
636
- " git remote add <name> <url>\n"
637
- "\n"
638
- "and then push using the remote name\n"
639
- "\n"
640
- " git push <name>\n"));
641
- }
642
-
643
- if (argc > 0)
644
- set_refspecs(argv + 1, argc - 1, remote);
645
-
646
- if (remote->mirror)
647
- flags |= (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE);
648
-
649
- if (flags & TRANSPORT_PUSH_ALL) {
650
- if (argc >= 2)
651
- die(_("--all can't be combined with refspecs"));
652
- }
653
- if (flags & TRANSPORT_PUSH_MIRROR) {
654
- if (argc >= 2)
655
- die(_("--mirror can't be combined with refspecs"));
745
+ if (repo) {
746
+ if (!add_remote_or_group(repo, &remote_group)) {
747
+ /*
748
+ * Not a configured remote name or group name.
749
+ * Try treating it as a direct URL or path, e.g.
750
+ * git push /tmp/foo.git
751
+ * git push https://github.com/user/repo.git
752
+ * pushremote_get() creates an anonymous remote
753
+ * from the URL so the loop below can handle it
754
+ * identically to a named remote.
755
+ */
756
+ struct remote *r = pushremote_get(repo);
757
+ if (!r)
758
+ die(_("bad repository '%s'"), repo);
759
+ string_list_append(&remote_group, r->name);
760
+ }
761
+ } else {
762
+ struct remote *r = pushremote_get(NULL);
763
+ if (!r)
764
+ die(_("No configured push destination.\n"
765
+ "Either specify the URL from the command-line or configure a remote repository using\n"
766
+ "\n"
767
+ " git remote add <name> <url>\n"
768
+ "\n"
769
+ "and then push using the remote name\n"
770
+ "\n"
771
+ " git push <name>\n"
772
+ "\n"
773
+ "To push to multiple remotes at once, configure a remote group using\n"
774
+ "\n"
775
+ " git config remotes.<groupname> \"<remote1> <remote2>\"\n"
776
+ "\n"
777
+ "and then push using the group name\n"
778
+ "\n"
779
+ " git push <groupname>\n"));
780
+ string_list_append(&remote_group, r->name);
781
}
782
783
if (!is_empty_cas(&cas) && (flags & TRANSPORT_PUSH_FORCE_IF_INCLUDES))
787
if (strchr(item->string, '\n'))
788
die(_("push options must not have new line characters"));
789
665
- rc = do_push(flags, push_options, remote);
790
+ if (remote_group.nr == 1) {
791
+ /*
792
+ * Single remote (the common case): run do_push() directly
793
+ * in this process. The loop runs exactly once.
794
+ *
795
+ * Mirror detection and the --mirror/--all + refspec conflict
796
+ * checks are done here. rs is rebuilt so that per-remote push
797
+ * mappings (remote.NAME.push config) are resolved against the
798
+ * correct remote. inner_flags is a snapshot of flags so that a
799
+ * mirror remote cannot bleed TRANSPORT_PUSH_FORCE into any
800
+ * subsequent call.
801
+ */
802
+ base_flags = flags;
803
+ {
804
+ int inner_flags = base_flags;
805
+ struct remote *r = pushremote_get(remote_group.items[0].string);
806
+ if (!r)
807
+ die(_("no such remote or remote group: %s"),
808
+ remote_group.items[0].string);
809
+
810
+ if (r->mirror)
811
+ inner_flags |= (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE);
812
+
813
+ if (inner_flags & TRANSPORT_PUSH_ALL) {
814
+ if (argc >= 2)
815
+ die(_("--all can't be combined with refspecs"));
816
+ }
817
+ if (inner_flags & TRANSPORT_PUSH_MIRROR) {
818
+ if (argc >= 2)
819
+ die(_("--mirror can't be combined with refspecs"));
820
+ }
821
+
822
+ refspec_clear(&rs);
823
+ rs = (struct refspec) REFSPEC_INIT_PUSH;
824
+
825
+ if (tags)
826
+ refspec_append(&rs, "refs/tags/*");
827
+ if (argc > 0)
828
+ set_refspecs(argv + 1, argc - 1, r);
829
+
830
+ rc = do_push(inner_flags, push_options, r);
831
+ }
832
+ } else {
833
+ /*
834
+ * Multiple remotes: spawn one "git push <remote> [<refspecs>]"
835
+ * subprocess per remote, sequentially.
836
+ *
837
+ * Options that only make sense for a single transport connection
838
+ * are rejected here.
839
+ */
840
+ if (flags & TRANSPORT_PUSH_ATOMIC)
841
+ die(_("--atomic can only be used when pushing to one remote"));
842
+
843
+ rc = push_multiple(&remote_group, push_options, flags,
844
+ tags,
845
+ argc > 1 ? argv + 1 : NULL,
846
+ argc > 1 ? argc - 1 : 0);
847
+ }
848
+
849
string_list_clear(&push_options_cmdline, 0);
850
string_list_clear(&push_options_config, 0);
851
+ string_list_clear(&remote_group, 0);
852
clear_cas_option(&cas);
853
+
854
if (rc == -1)
855
usage_with_options(push_usage, options);
856
else