Move push matching and reporting logic into transport.c
For native-protocol pushes (and other protocols as they are converted to the new method), this moves the refspec match, tracking update, and report message out of send-pack() and into transport_push(), where it can be shared completely with other protocols. This also makes fetch and push more similar in terms of what code is in what file. Signed-off-by: Daniel Barkalow <barkalow@iabervon.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Daniel Barkalow committed
Mar 8, 2009 at 21:06 UTC
64fcef2daa03f6093b480142c6ab2a4173b0b43e
4 files changed
+343
-92
builtin-send-pack.c
+74
-69
@@ -11,7 +11,6 @@ static const char send_pack_usage[] =
11
" --all and explicit <ref> specification are mutually exclusive.";
12
13
static struct send_pack_args args = {
14
- /* .receivepack = */ "git-receive-pack",
14
};
15
16
static int feed_object(const unsigned char *sha1, int fd, int negative)
@@ -31,7 +30,7 @@ static int feed_object(const unsigned char *sha1, int fd, int negative)
30
/*
31
* Make a pack stream and spit it out into file descriptor fd
32
*/
34
-static int pack_objects(int fd, struct ref *refs, struct extra_have_objects *extra)
33
+static int pack_objects(int fd, struct ref *refs, struct extra_have_objects *extra, struct send_pack_args *args)
34
{
35
/*
36
* The child becomes pack-objects --revs; we feed
@@ -49,7 +48,7 @@ static int pack_objects(int fd, struct ref *refs, struct extra_have_objects *ext
48
struct child_process po;
49
int i;
50
52
- if (args.use_thin_pack)
51
+ if (args->use_thin_pack)
52
argv[4] = "--thin";
53
memset(&po, 0, sizeof(po));
54
po.argv = argv;
@@ -83,8 +82,6 @@ static int pack_objects(int fd, struct ref *refs, struct extra_have_objects *ext
82
return 0;
83
}
84
86
-static struct ref *remote_refs, **remote_tail;
87
-
85
static int receive_status(int in, struct ref *refs)
86
{
87
struct ref *hint;
@@ -300,27 +297,19 @@ static int refs_pushed(struct ref *ref)
297
return 0;
298
}
299
303
-static int do_send_pack(int in, int out, struct remote *remote, const char *dest, int nr_refspec, const char **refspec)
300
+int send_pack(struct send_pack_args *args,
301
+ int fd[], struct child_process *conn,
302
+ struct ref *remote_refs,
303
+ struct extra_have_objects *extra_have)
304
{
305
- struct ref *ref, *local_refs;
305
+ int in = fd[0];
306
+ int out = fd[1];
307
+ struct ref *ref;
308
int new_refs;
309
int ask_for_status_report = 0;
310
int allow_deleting_refs = 0;
311
int expect_status_report = 0;
310
- int flags = MATCH_REFS_NONE;
312
int ret;
312
- struct extra_have_objects extra_have;
313
-
314
- memset(&extra_have, 0, sizeof(extra_have));
315
- if (args.send_all)
316
- flags |= MATCH_REFS_ALL;
317
- if (args.send_mirror)
318
- flags |= MATCH_REFS_MIRROR;
319
-
320
- /* No funny business with the matcher */
321
- remote_tail = get_remote_heads(in, &remote_refs, 0, NULL, REF_NORMAL,
322
- &extra_have);
323
- local_refs = get_local_heads();
313
314
/* Does the other end support the reporting? */
315
if (server_supports("report-status"))
@@ -328,19 +317,9 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest
317
if (server_supports("delete-refs"))
318
allow_deleting_refs = 1;
319
331
- /* match them up */
332
- if (!remote_tail)
333
- remote_tail = &remote_refs;
334
- if (match_refs(local_refs, remote_refs, &remote_tail,
335
- nr_refspec, refspec, flags)) {
336
- close(out);
337
- return -1;
338
- }
339
-
320
if (!remote_refs) {
321
fprintf(stderr, "No refs in common and none specified; doing nothing.\n"
322
"Perhaps you should specify a branch such as 'master'.\n");
343
- close(out);
323
return 0;
324
}
325
@@ -352,7 +331,7 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest
331
332
if (ref->peer_ref)
333
hashcpy(ref->new_sha1, ref->peer_ref->new_sha1);
355
- else if (!args.send_mirror)
334
+ else if (!args->send_mirror)
335
continue;
336
337
ref->deletion = is_null_sha1(ref->new_sha1);
@@ -391,7 +370,7 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest
370
(!has_sha1_file(ref->old_sha1)
371
|| !ref_newer(ref->new_sha1, ref->old_sha1));
372
394
- if (ref->nonfastforward && !ref->force && !args.force_update) {
373
+ if (ref->nonfastforward && !ref->force && !args->force_update) {
374
ref->status = REF_STATUS_REJECT_NONFASTFORWARD;
375
continue;
376
}
@@ -399,7 +378,7 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest
378
if (!ref->deletion)
379
new_refs++;
380
402
- if (!args.dry_run) {
381
+ if (!args->dry_run) {
382
char *old_hex = sha1_to_hex(ref->old_sha1);
383
char *new_hex = sha1_to_hex(ref->new_sha1);
384
@@ -420,27 +399,19 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest
399
}
400
401
packet_flush(out);
423
- if (new_refs && !args.dry_run) {
424
- if (pack_objects(out, remote_refs, &extra_have) < 0)
402
+ if (new_refs && !args->dry_run) {
403
+ if (pack_objects(out, remote_refs, extra_have, args) < 0) {
404
+ for (ref = remote_refs; ref; ref = ref->next)
405
+ ref->status = REF_STATUS_NONE;
406
return -1;
407
+ }
408
}
427
- else
428
- close(out);
409
410
if (expect_status_report)
411
ret = receive_status(in, remote_refs);
412
else
413
ret = 0;
414
435
- print_push_status(dest, remote_refs);
436
-
437
- if (!args.dry_run && remote) {
438
- for (ref = remote_refs; ref; ref = ref->next)
439
- update_tracking_ref(remote, ref);
440
- }
441
-
442
- if (!refs_pushed(remote_refs))
443
- fprintf(stderr, "Everything up-to-date\n");
415
if (ret < 0)
416
return ret;
417
for (ref = remote_refs; ref; ref = ref->next) {
@@ -489,11 +460,19 @@ static void verify_remote_names(int nr_heads, const char **heads)
460
461
int cmd_send_pack(int argc, const char **argv, const char *prefix)
462
{
492
- int i, nr_heads = 0;
493
- const char **heads = NULL;
463
+ int i, nr_refspecs = 0;
464
+ const char **refspecs = NULL;
465
const char *remote_name = NULL;
466
struct remote *remote = NULL;
467
const char *dest = NULL;
468
+ int fd[2];
469
+ struct child_process *conn;
470
+ struct extra_have_objects extra_have;
471
+ struct ref *remote_refs, **remote_tail, *local_refs;
472
+ int ret;
473
+ int send_all = 0;
474
+ const char *receivepack = "git-receive-pack";
475
+ int flags;
476
477
argv++;
478
for (i = 1; i < argc; i++, argv++) {
@@ -501,11 +480,11 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
480
481
if (*arg == '-') {
482
if (!prefixcmp(arg, "--receive-pack=")) {
504
- args.receivepack = arg + 15;
483
+ receivepack = arg + 15;
484
continue;
485
}
486
if (!prefixcmp(arg, "--exec=")) {
508
- args.receivepack = arg + 7;
487
+ receivepack = arg + 7;
488
continue;
489
}
490
if (!prefixcmp(arg, "--remote=")) {
@@ -513,7 +492,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
492
continue;
493
}
494
if (!strcmp(arg, "--all")) {
516
- args.send_all = 1;
495
+ send_all = 1;
496
continue;
497
}
498
if (!strcmp(arg, "--dry-run")) {
@@ -542,8 +521,8 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
521
dest = arg;
522
continue;
523
}
545
- heads = (const char **) argv;
546
- nr_heads = argc - i;
524
+ refspecs = (const char **) argv;
525
+ nr_refspecs = argc - i;
526
break;
527
}
528
if (!dest)
@@ -552,8 +531,8 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
531
* --all and --mirror are incompatible; neither makes sense
532
* with any refspecs.
533
*/
555
- if ((heads && (args.send_all || args.send_mirror)) ||
556
- (args.send_all && args.send_mirror))
534
+ if ((refspecs && (send_all || args.send_mirror)) ||
535
+ (send_all && args.send_mirror))
536
usage(send_pack_usage);
537
538
if (remote_name) {
@@ -564,24 +543,50 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
543
}
544
}
545
567
- return send_pack(&args, dest, remote, nr_heads, heads);
568
-}
546
+ conn = git_connect(fd, dest, receivepack, args.verbose ? CONNECT_VERBOSE : 0);
547
570
-int send_pack(struct send_pack_args *my_args,
571
- const char *dest, struct remote *remote,
572
- int nr_heads, const char **heads)
573
-{
574
- int fd[2], ret;
575
- struct child_process *conn;
548
+ memset(&extra_have, 0, sizeof(extra_have));
549
+
550
+ get_remote_heads(fd[0], &remote_refs, 0, NULL, REF_NORMAL,
551
+ &extra_have);
552
+
553
+ verify_remote_names(nr_refspecs, refspecs);
554
+
555
+ local_refs = get_local_heads();
556
577
- memcpy(&args, my_args, sizeof(args));
557
+ flags = MATCH_REFS_NONE;
558
+
559
+ if (send_all)
560
+ flags |= MATCH_REFS_ALL;
561
+ if (args.send_mirror)
562
+ flags |= MATCH_REFS_MIRROR;
563
+
564
+ /* match them up */
565
+ remote_tail = &remote_refs;
566
+ while (*remote_tail)
567
+ remote_tail = &((*remote_tail)->next);
568
+ if (match_refs(local_refs, remote_refs, &remote_tail,
569
+ nr_refspecs, refspecs, flags)) {
570
+ return -1;
571
+ }
572
579
- verify_remote_names(nr_heads, heads);
573
+ ret = send_pack(&args, fd, conn, remote_refs, &extra_have);
574
581
- conn = git_connect(fd, dest, args.receivepack, args.verbose ? CONNECT_VERBOSE : 0);
582
- ret = do_send_pack(fd[0], fd[1], remote, dest, nr_heads, heads);
575
+ close(fd[1]);
576
close(fd[0]);
584
- /* do_send_pack always closes fd[1] */
577
+
578
ret |= finish_connect(conn);
586
- return !!ret;
579
+
580
+ print_push_status(dest, remote_refs);
581
+
582
+ if (!args.dry_run && remote) {
583
+ struct ref *ref;
584
+ for (ref = remote_refs; ref; ref = ref->next)
585
+ update_tracking_ref(remote, ref);
586
+ }
587
+
588
+ if (!ret && !refs_pushed(remote_refs))
589
+ fprintf(stderr, "Everything up-to-date\n");
590
+
591
+ return ret;
592
}
send-pack.h
+2
-4
@@ -2,9 +2,7 @@
2
#define SEND_PACK_H
3
4
struct send_pack_args {
5
- const char *receivepack;
5
unsigned verbose:1,
7
- send_all:1,
6
send_mirror:1,
7
force_update:1,
8
use_thin_pack:1,
@@ -12,7 +10,7 @@ struct send_pack_args {
10
};
11
12
int send_pack(struct send_pack_args *args,
15
- const char *dest, struct remote *remote,
16
- int nr_heads, const char **heads);
13
+ int fd[], struct child_process *conn,
14
+ struct ref *remote_refs, struct extra_have_objects *extra_have);
15
16
#endif
transport.c
+265
-18
@@ -138,7 +138,7 @@ static void insert_packed_refs(const char *packed_refs, struct ref **list)
138
}
139
}
140
141
-static struct ref *get_refs_via_rsync(struct transport *transport)
141
+static struct ref *get_refs_via_rsync(struct transport *transport, int for_push)
142
{
143
struct strbuf buf = STRBUF_INIT, temp_dir = STRBUF_INIT;
144
struct ref dummy, *tail = &dummy;
@@ -146,6 +146,9 @@ static struct ref *get_refs_via_rsync(struct transport *transport)
146
const char *args[5];
147
int temp_dir_len;
148
149
+ if (for_push)
150
+ return NULL;
151
+
152
/* copy the refs to the temporary directory */
153
154
strbuf_addstr(&temp_dir, git_path("rsync-refs-XXXXXX"));
@@ -422,7 +425,7 @@ static int curl_transport_push(struct transport *transport, int refspec_nr, cons
425
return !!err;
426
}
427
425
-static struct ref *get_refs_via_curl(struct transport *transport)
428
+static struct ref *get_refs_via_curl(struct transport *transport, int for_push)
429
{
430
struct strbuf buffer = STRBUF_INIT;
431
char *data, *start, *mid;
@@ -439,6 +442,9 @@ static struct ref *get_refs_via_curl(struct transport *transport)
442
443
struct walker *walker;
444
445
+ if (for_push)
446
+ return NULL;
447
+
448
if (!transport->data)
449
transport->data = get_http_walker(transport->url,
450
transport->remote);
@@ -525,12 +531,15 @@ struct bundle_transport_data {
531
struct bundle_header header;
532
};
533
528
-static struct ref *get_refs_from_bundle(struct transport *transport)
534
+static struct ref *get_refs_from_bundle(struct transport *transport, int for_push)
535
{
536
struct bundle_transport_data *data = transport->data;
537
struct ref *result = NULL;
538
int i;
539
540
+ if (for_push)
541
+ return NULL;
542
+
543
if (data->fd > 0)
544
close(data->fd);
545
data->fd = read_bundle_header(transport->url, &data->header);
@@ -571,6 +580,7 @@ struct git_transport_data {
580
int fd[2];
581
const char *uploadpack;
582
const char *receivepack;
583
+ struct extra_have_objects extra_have;
584
};
585
586
static int set_git_option(struct transport *connection,
@@ -602,20 +612,23 @@ static int set_git_option(struct transport *connection,
612
return 1;
613
}
614
605
-static int connect_setup(struct transport *transport)
615
+static int connect_setup(struct transport *transport, int for_push, int verbose)
616
{
617
struct git_transport_data *data = transport->data;
608
- data->conn = git_connect(data->fd, transport->url, data->uploadpack, 0);
618
+ data->conn = git_connect(data->fd, transport->url,
619
+ for_push ? data->receivepack : data->uploadpack,
620
+ verbose ? CONNECT_VERBOSE : 0);
621
return 0;
622
}
623
612
-static struct ref *get_refs_via_connect(struct transport *transport)
624
+static struct ref *get_refs_via_connect(struct transport *transport, int for_push)
625
{
626
struct git_transport_data *data = transport->data;
627
struct ref *refs;
628
617
- connect_setup(transport);
618
- get_remote_heads(data->fd[0], &refs, 0, NULL, 0, NULL);
629
+ connect_setup(transport, for_push, 0);
630
+ get_remote_heads(data->fd[0], &refs, 0, NULL,
631
+ for_push ? REF_NORMAL : 0, &data->extra_have);
632
633
return refs;
634
}
@@ -647,7 +660,7 @@ static int fetch_refs_via_pack(struct transport *transport,
660
origh[i] = heads[i] = xstrdup(to_fetch[i]->name);
661
662
if (!data->conn) {
650
- connect_setup(transport);
663
+ connect_setup(transport, 0, 0);
664
get_remote_heads(data->fd[0], &refs_tmp, 0, NULL, 0, NULL);
665
}
666
@@ -670,20 +683,216 @@ static int fetch_refs_via_pack(struct transport *transport,
683
return (refs ? 0 : -1);
684
}
685
673
-static int git_transport_push(struct transport *transport, int refspec_nr, const char **refspec, int flags)
686
+static int refs_pushed(struct ref *ref)
687
+{
688
+ for (; ref; ref = ref->next) {
689
+ switch(ref->status) {
690
+ case REF_STATUS_NONE:
691
+ case REF_STATUS_UPTODATE:
692
+ break;
693
+ default:
694
+ return 1;
695
+ }
696
+ }
697
+ return 0;
698
+}
699
+
700
+static void update_tracking_ref(struct remote *remote, struct ref *ref, int verbose)
701
+{
702
+ struct refspec rs;
703
+
704
+ if (ref->status != REF_STATUS_OK && ref->status != REF_STATUS_UPTODATE)
705
+ return;
706
+
707
+ rs.src = ref->name;
708
+ rs.dst = NULL;
709
+
710
+ if (!remote_find_tracking(remote, &rs)) {
711
+ if (verbose)
712
+ fprintf(stderr, "updating local tracking ref '%s'\n", rs.dst);
713
+ if (ref->deletion) {
714
+ delete_ref(rs.dst, NULL, 0);
715
+ } else
716
+ update_ref("update by push", rs.dst,
717
+ ref->new_sha1, NULL, 0, 0);
718
+ free(rs.dst);
719
+ }
720
+}
721
+
722
+#define SUMMARY_WIDTH (2 * DEFAULT_ABBREV + 3)
723
+
724
+static void print_ref_status(char flag, const char *summary, struct ref *to, struct ref *from, const char *msg)
725
+{
726
+ fprintf(stderr, " %c %-*s ", flag, SUMMARY_WIDTH, summary);
727
+ if (from)
728
+ fprintf(stderr, "%s -> %s", prettify_ref(from), prettify_ref(to));
729
+ else
730
+ fputs(prettify_ref(to), stderr);
731
+ if (msg) {
732
+ fputs(" (", stderr);
733
+ fputs(msg, stderr);
734
+ fputc(')', stderr);
735
+ }
736
+ fputc('\n', stderr);
737
+}
738
+
739
+static const char *status_abbrev(unsigned char sha1[20])
740
+{
741
+ return find_unique_abbrev(sha1, DEFAULT_ABBREV);
742
+}
743
+
744
+static void print_ok_ref_status(struct ref *ref)
745
+{
746
+ if (ref->deletion)
747
+ print_ref_status('-', "[deleted]", ref, NULL, NULL);
748
+ else if (is_null_sha1(ref->old_sha1))
749
+ print_ref_status('*',
750
+ (!prefixcmp(ref->name, "refs/tags/") ? "[new tag]" :
751
+ "[new branch]"),
752
+ ref, ref->peer_ref, NULL);
753
+ else {
754
+ char quickref[84];
755
+ char type;
756
+ const char *msg;
757
+
758
+ strcpy(quickref, status_abbrev(ref->old_sha1));
759
+ if (ref->nonfastforward) {
760
+ strcat(quickref, "...");
761
+ type = '+';
762
+ msg = "forced update";
763
+ } else {
764
+ strcat(quickref, "..");
765
+ type = ' ';
766
+ msg = NULL;
767
+ }
768
+ strcat(quickref, status_abbrev(ref->new_sha1));
769
+
770
+ print_ref_status(type, quickref, ref, ref->peer_ref, msg);
771
+ }
772
+}
773
+
774
+static int print_one_push_status(struct ref *ref, const char *dest, int count)
775
+{
776
+ if (!count)
777
+ fprintf(stderr, "To %s\n", dest);
778
+
779
+ switch(ref->status) {
780
+ case REF_STATUS_NONE:
781
+ print_ref_status('X', "[no match]", ref, NULL, NULL);
782
+ break;
783
+ case REF_STATUS_REJECT_NODELETE:
784
+ print_ref_status('!', "[rejected]", ref, NULL,
785
+ "remote does not support deleting refs");
786
+ break;
787
+ case REF_STATUS_UPTODATE:
788
+ print_ref_status('=', "[up to date]", ref,
789
+ ref->peer_ref, NULL);
790
+ break;
791
+ case REF_STATUS_REJECT_NONFASTFORWARD:
792
+ print_ref_status('!', "[rejected]", ref, ref->peer_ref,
793
+ "non-fast forward");
794
+ break;
795
+ case REF_STATUS_REMOTE_REJECT:
796
+ print_ref_status('!', "[remote rejected]", ref,
797
+ ref->deletion ? NULL : ref->peer_ref,
798
+ ref->remote_status);
799
+ break;
800
+ case REF_STATUS_EXPECTING_REPORT:
801
+ print_ref_status('!', "[remote failure]", ref,
802
+ ref->deletion ? NULL : ref->peer_ref,
803
+ "remote failed to report status");
804
+ break;
805
+ case REF_STATUS_OK:
806
+ print_ok_ref_status(ref);
807
+ break;
808
+ }
809
+
810
+ return 1;
811
+}
812
+
813
+static void print_push_status(const char *dest, struct ref *refs, int verbose)
814
+{
815
+ struct ref *ref;
816
+ int n = 0;
817
+
818
+ if (verbose) {
819
+ for (ref = refs; ref; ref = ref->next)
820
+ if (ref->status == REF_STATUS_UPTODATE)
821
+ n += print_one_push_status(ref, dest, n);
822
+ }
823
+
824
+ for (ref = refs; ref; ref = ref->next)
825
+ if (ref->status == REF_STATUS_OK)
826
+ n += print_one_push_status(ref, dest, n);
827
+
828
+ for (ref = refs; ref; ref = ref->next) {
829
+ if (ref->status != REF_STATUS_NONE &&
830
+ ref->status != REF_STATUS_UPTODATE &&
831
+ ref->status != REF_STATUS_OK)
832
+ n += print_one_push_status(ref, dest, n);
833
+ }
834
+}
835
+
836
+static void verify_remote_names(int nr_heads, const char **heads)
837
+{
838
+ int i;
839
+
840
+ for (i = 0; i < nr_heads; i++) {
841
+ const char *local = heads[i];
842
+ const char *remote = strrchr(heads[i], ':');
843
+
844
+ if (*local == '+')
845
+ local++;
846
+
847
+ /* A matching refspec is okay. */
848
+ if (remote == local && remote[1] == '\0')
849
+ continue;
850
+
851
+ remote = remote ? (remote + 1) : local;
852
+ switch (check_ref_format(remote)) {
853
+ case 0: /* ok */
854
+ case CHECK_REF_FORMAT_ONELEVEL:
855
+ /* ok but a single level -- that is fine for
856
+ * a match pattern.
857
+ */
858
+ case CHECK_REF_FORMAT_WILDCARD:
859
+ /* ok but ends with a pattern-match character */
860
+ continue;
861
+ }
862
+ die("remote part of refspec is not a valid name in %s",
863
+ heads[i]);
864
+ }
865
+}
866
+
867
+static int git_transport_push(struct transport *transport, struct ref *remote_refs, int flags)
868
{
869
struct git_transport_data *data = transport->data;
870
struct send_pack_args args;
871
+ int ret;
872
+
873
+ if (!data->conn) {
874
+ struct ref *tmp_refs;
875
+ connect_setup(transport, 1, 0);
876
+
877
+ get_remote_heads(data->fd[0], &tmp_refs, 0, NULL, REF_NORMAL,
878
+ NULL);
879
+ }
880
678
- args.receivepack = data->receivepack;
679
- args.send_all = !!(flags & TRANSPORT_PUSH_ALL);
881
args.send_mirror = !!(flags & TRANSPORT_PUSH_MIRROR);
882
args.force_update = !!(flags & TRANSPORT_PUSH_FORCE);
883
args.use_thin_pack = data->thin;
884
args.verbose = !!(flags & TRANSPORT_PUSH_VERBOSE);
885
args.dry_run = !!(flags & TRANSPORT_PUSH_DRY_RUN);
886
686
- return send_pack(&args, transport->url, transport->remote, refspec_nr, refspec);
887
+ ret = send_pack(&args, data->fd, data->conn, remote_refs,
888
+ &data->extra_have);
889
+
890
+ close(data->fd[1]);
891
+ close(data->fd[0]);
892
+ ret |= finish_connect(data->conn);
893
+ data->conn = NULL;
894
+
895
+ return ret;
896
}
897
898
static int disconnect_git(struct transport *transport)
@@ -753,7 +962,7 @@ struct transport *transport_get(struct remote *remote, const char *url)
962
ret->set_option = set_git_option;
963
ret->get_refs_list = get_refs_via_connect;
964
ret->fetch = fetch_refs_via_pack;
756
- ret->push = git_transport_push;
965
+ ret->push_refs = git_transport_push;
966
ret->disconnect = disconnect_git;
967
968
data->thin = 1;
@@ -780,15 +989,53 @@ int transport_set_option(struct transport *transport,
989
int transport_push(struct transport *transport,
990
int refspec_nr, const char **refspec, int flags)
991
{
783
- if (!transport->push)
784
- return 1;
785
- return transport->push(transport, refspec_nr, refspec, flags);
992
+ verify_remote_names(refspec_nr, refspec);
993
+
994
+ if (transport->push)
995
+ return transport->push(transport, refspec_nr, refspec, flags);
996
+ if (transport->push_refs) {
997
+ struct ref *remote_refs =
998
+ transport->get_refs_list(transport, 1);
999
+ struct ref **remote_tail;
1000
+ struct ref *local_refs = get_local_heads();
1001
+ int match_flags = MATCH_REFS_NONE;
1002
+ int verbose = flags & TRANSPORT_PUSH_VERBOSE;
1003
+ int ret;
1004
+
1005
+ if (flags & TRANSPORT_PUSH_ALL)
1006
+ match_flags |= MATCH_REFS_ALL;
1007
+ if (flags & TRANSPORT_PUSH_MIRROR)
1008
+ match_flags |= MATCH_REFS_MIRROR;
1009
+
1010
+ remote_tail = &remote_refs;
1011
+ while (*remote_tail)
1012
+ remote_tail = &((*remote_tail)->next);
1013
+ if (match_refs(local_refs, remote_refs, &remote_tail,
1014
+ refspec_nr, refspec, match_flags)) {
1015
+ return -1;
1016
+ }
1017
+
1018
+ ret = transport->push_refs(transport, remote_refs, flags);
1019
+
1020
+ print_push_status(transport->url, remote_refs, verbose);
1021
+
1022
+ if (!(flags & TRANSPORT_PUSH_DRY_RUN)) {
1023
+ struct ref *ref;
1024
+ for (ref = remote_refs; ref; ref = ref->next)
1025
+ update_tracking_ref(transport->remote, ref, verbose);
1026
+ }
1027
+
1028
+ if (!ret && !refs_pushed(remote_refs))
1029
+ fprintf(stderr, "Everything up-to-date\n");
1030
+ return ret;
1031
+ }
1032
+ return 1;
1033
}
1034
1035
const struct ref *transport_get_remote_refs(struct transport *transport)
1036
{
1037
if (!transport->remote_refs)
791
- transport->remote_refs = transport->get_refs_list(transport);
1038
+ transport->remote_refs = transport->get_refs_list(transport, 0);
1039
return transport->remote_refs;
1040
}
1041
transport.h
+2
-1
@@ -18,8 +18,9 @@ struct transport {
18
int (*set_option)(struct transport *connection, const char *name,
19
const char *value);
20
21
- struct ref *(*get_refs_list)(struct transport *transport);
21
+ struct ref *(*get_refs_list)(struct transport *transport, int for_push);
22
int (*fetch)(struct transport *transport, int refs_nr, const struct ref **refs);
23
+ int (*push_refs)(struct transport *transport, struct ref *refs, int flags);
24
int (*push)(struct transport *connection, int refspec_nr, const char **refspec, int flags);
25
26
int (*disconnect)(struct transport *connection);