@@ -63,6 +63,7 @@ static int enable_auto_gc = 1;
63
63
static int tags = TAGS_DEFAULT , unshallow , update_shallow , deepen ;
64
64
static int max_jobs = -1 , submodule_fetch_jobs_config = -1 ;
65
65
static int fetch_parallel_config = 1 ;
66
+ static int atomic_fetch ;
66
67
static enum transport_family family ;
67
68
static const char * depth ;
68
69
static const char * deepen_since ;
@@ -144,6 +145,8 @@ static struct option builtin_fetch_options[] = {
144
145
N_ ("set upstream for git pull/fetch" )),
145
146
OPT_BOOL ('a' , "append" , & append ,
146
147
N_ ("append to .git/FETCH_HEAD instead of overwriting" )),
148
+ OPT_BOOL (0 , "atomic" , & atomic_fetch ,
149
+ N_ ("use atomic transaction to update references" )),
147
150
OPT_STRING (0 , "upload-pack" , & upload_pack , N_ ("path" ),
148
151
N_ ("path to upload pack on remote end" )),
149
152
OPT__FORCE (& force , N_ ("force overwrite of local reference" ), 0 ),
@@ -583,45 +586,62 @@ static struct ref *get_ref_map(struct remote *remote,
583
586
584
587
static int s_update_ref (const char * action ,
585
588
struct ref * ref ,
589
+ struct ref_transaction * transaction ,
586
590
int check_old )
587
591
{
588
592
char * msg ;
589
593
char * rla = getenv ("GIT_REFLOG_ACTION" );
590
- struct ref_transaction * transaction ;
594
+ struct ref_transaction * our_transaction = NULL ;
591
595
struct strbuf err = STRBUF_INIT ;
592
- int ret , df_conflict = 0 ;
596
+ int ret ;
593
597
594
598
if (dry_run )
595
599
return 0 ;
596
600
if (!rla )
597
601
rla = default_rla .buf ;
598
602
msg = xstrfmt ("%s: %s" , rla , action );
599
603
600
- transaction = ref_transaction_begin (& err );
601
- if (!transaction ||
602
- ref_transaction_update (transaction , ref -> name ,
603
- & ref -> new_oid ,
604
- check_old ? & ref -> old_oid : NULL ,
605
- 0 , msg , & err ))
606
- goto fail ;
604
+ /*
605
+ * If no transaction was passed to us, we manage the transaction
606
+ * ourselves. Otherwise, we trust the caller to handle the transaction
607
+ * lifecycle.
608
+ */
609
+ if (!transaction ) {
610
+ transaction = our_transaction = ref_transaction_begin (& err );
611
+ if (!transaction ) {
612
+ ret = STORE_REF_ERROR_OTHER ;
613
+ goto out ;
614
+ }
615
+ }
607
616
608
- ret = ref_transaction_commit (transaction , & err );
617
+ ret = ref_transaction_update (transaction , ref -> name , & ref -> new_oid ,
618
+ check_old ? & ref -> old_oid : NULL ,
619
+ 0 , msg , & err );
609
620
if (ret ) {
610
- df_conflict = ( ret == TRANSACTION_NAME_CONFLICT ) ;
611
- goto fail ;
621
+ ret = STORE_REF_ERROR_OTHER ;
622
+ goto out ;
612
623
}
613
624
614
- ref_transaction_free (transaction );
615
- strbuf_release (& err );
616
- free (msg );
617
- return 0 ;
618
- fail :
619
- ref_transaction_free (transaction );
620
- error ("%s" , err .buf );
625
+ if (our_transaction ) {
626
+ switch (ref_transaction_commit (our_transaction , & err )) {
627
+ case 0 :
628
+ break ;
629
+ case TRANSACTION_NAME_CONFLICT :
630
+ ret = STORE_REF_ERROR_DF_CONFLICT ;
631
+ goto out ;
632
+ default :
633
+ ret = STORE_REF_ERROR_OTHER ;
634
+ goto out ;
635
+ }
636
+ }
637
+
638
+ out :
639
+ ref_transaction_free (our_transaction );
640
+ if (ret )
641
+ error ("%s" , err .buf );
621
642
strbuf_release (& err );
622
643
free (msg );
623
- return df_conflict ? STORE_REF_ERROR_DF_CONFLICT
624
- : STORE_REF_ERROR_OTHER ;
644
+ return ret ;
625
645
}
626
646
627
647
static int refcol_width = 10 ;
@@ -759,6 +779,7 @@ static void format_display(struct strbuf *display, char code,
759
779
}
760
780
761
781
static int update_local_ref (struct ref * ref ,
782
+ struct ref_transaction * transaction ,
762
783
const char * remote ,
763
784
const struct ref * remote_ref ,
764
785
struct strbuf * display ,
@@ -799,7 +820,7 @@ static int update_local_ref(struct ref *ref,
799
820
starts_with (ref -> name , "refs/tags/" )) {
800
821
if (force || ref -> force ) {
801
822
int r ;
802
- r = s_update_ref ("updating tag" , ref , 0 );
823
+ r = s_update_ref ("updating tag" , ref , transaction , 0 );
803
824
format_display (display , r ? '!' : 't' , _ ("[tag update]" ),
804
825
r ? _ ("unable to update local ref" ) : NULL ,
805
826
remote , pretty_ref , summary_width );
@@ -836,7 +857,7 @@ static int update_local_ref(struct ref *ref,
836
857
what = _ ("[new ref]" );
837
858
}
838
859
839
- r = s_update_ref (msg , ref , 0 );
860
+ r = s_update_ref (msg , ref , transaction , 0 );
840
861
format_display (display , r ? '!' : '*' , what ,
841
862
r ? _ ("unable to update local ref" ) : NULL ,
842
863
remote , pretty_ref , summary_width );
@@ -858,7 +879,7 @@ static int update_local_ref(struct ref *ref,
858
879
strbuf_add_unique_abbrev (& quickref , & current -> object .oid , DEFAULT_ABBREV );
859
880
strbuf_addstr (& quickref , ".." );
860
881
strbuf_add_unique_abbrev (& quickref , & ref -> new_oid , DEFAULT_ABBREV );
861
- r = s_update_ref ("fast-forward" , ref , 1 );
882
+ r = s_update_ref ("fast-forward" , ref , transaction , 1 );
862
883
format_display (display , r ? '!' : ' ' , quickref .buf ,
863
884
r ? _ ("unable to update local ref" ) : NULL ,
864
885
remote , pretty_ref , summary_width );
@@ -870,7 +891,7 @@ static int update_local_ref(struct ref *ref,
870
891
strbuf_add_unique_abbrev (& quickref , & current -> object .oid , DEFAULT_ABBREV );
871
892
strbuf_addstr (& quickref , "..." );
872
893
strbuf_add_unique_abbrev (& quickref , & ref -> new_oid , DEFAULT_ABBREV );
873
- r = s_update_ref ("forced-update" , ref , 1 );
894
+ r = s_update_ref ("forced-update" , ref , transaction , 1 );
874
895
format_display (display , r ? '!' : '+' , quickref .buf ,
875
896
r ? _ ("unable to update local ref" ) : _ ("forced update" ),
876
897
remote , pretty_ref , summary_width );
@@ -897,6 +918,89 @@ static int iterate_ref_map(void *cb_data, struct object_id *oid)
897
918
return 0 ;
898
919
}
899
920
921
+ struct fetch_head {
922
+ FILE * fp ;
923
+ struct strbuf buf ;
924
+ };
925
+
926
+ static int open_fetch_head (struct fetch_head * fetch_head )
927
+ {
928
+ const char * filename = git_path_fetch_head (the_repository );
929
+
930
+ if (write_fetch_head ) {
931
+ fetch_head -> fp = fopen (filename , "a" );
932
+ if (!fetch_head -> fp )
933
+ return error_errno (_ ("cannot open %s" ), filename );
934
+ strbuf_init (& fetch_head -> buf , 0 );
935
+ } else {
936
+ fetch_head -> fp = NULL ;
937
+ }
938
+
939
+ return 0 ;
940
+ }
941
+
942
+ static void append_fetch_head (struct fetch_head * fetch_head ,
943
+ const struct object_id * old_oid ,
944
+ enum fetch_head_status fetch_head_status ,
945
+ const char * note ,
946
+ const char * url , size_t url_len )
947
+ {
948
+ char old_oid_hex [GIT_MAX_HEXSZ + 1 ];
949
+ const char * merge_status_marker ;
950
+ size_t i ;
951
+
952
+ if (!fetch_head -> fp )
953
+ return ;
954
+
955
+ switch (fetch_head_status ) {
956
+ case FETCH_HEAD_NOT_FOR_MERGE :
957
+ merge_status_marker = "not-for-merge" ;
958
+ break ;
959
+ case FETCH_HEAD_MERGE :
960
+ merge_status_marker = "" ;
961
+ break ;
962
+ default :
963
+ /* do not write anything to FETCH_HEAD */
964
+ return ;
965
+ }
966
+
967
+ strbuf_addf (& fetch_head -> buf , "%s\t%s\t%s" ,
968
+ oid_to_hex_r (old_oid_hex , old_oid ), merge_status_marker , note );
969
+ for (i = 0 ; i < url_len ; ++ i )
970
+ if ('\n' == url [i ])
971
+ strbuf_addstr (& fetch_head -> buf , "\\n" );
972
+ else
973
+ strbuf_addch (& fetch_head -> buf , url [i ]);
974
+ strbuf_addch (& fetch_head -> buf , '\n' );
975
+
976
+ /*
977
+ * When using an atomic fetch, we do not want to update FETCH_HEAD if
978
+ * any of the reference updates fails. We thus have to write all
979
+ * updates to a buffer first and only commit it as soon as all
980
+ * references have been successfully updated.
981
+ */
982
+ if (!atomic_fetch ) {
983
+ strbuf_write (& fetch_head -> buf , fetch_head -> fp );
984
+ strbuf_reset (& fetch_head -> buf );
985
+ }
986
+ }
987
+
988
+ static void commit_fetch_head (struct fetch_head * fetch_head )
989
+ {
990
+ if (!fetch_head -> fp || !atomic_fetch )
991
+ return ;
992
+ strbuf_write (& fetch_head -> buf , fetch_head -> fp );
993
+ }
994
+
995
+ static void close_fetch_head (struct fetch_head * fetch_head )
996
+ {
997
+ if (!fetch_head -> fp )
998
+ return ;
999
+
1000
+ fclose (fetch_head -> fp );
1001
+ strbuf_release (& fetch_head -> buf );
1002
+ }
1003
+
900
1004
static const char warn_show_forced_updates [] =
901
1005
N_ ("Fetch normally indicates which branches had a forced update,\n"
902
1006
"but that check has been disabled. To re-enable, use '--show-forced-updates'\n"
@@ -909,22 +1013,20 @@ N_("It took %.2f seconds to check forced updates. You can use\n"
909
1013
static int store_updated_refs (const char * raw_url , const char * remote_name ,
910
1014
int connectivity_checked , struct ref * ref_map )
911
1015
{
912
- FILE * fp ;
1016
+ struct fetch_head fetch_head ;
913
1017
struct commit * commit ;
914
1018
int url_len , i , rc = 0 ;
915
- struct strbuf note = STRBUF_INIT ;
1019
+ struct strbuf note = STRBUF_INIT , err = STRBUF_INIT ;
1020
+ struct ref_transaction * transaction = NULL ;
916
1021
const char * what , * kind ;
917
1022
struct ref * rm ;
918
1023
char * url ;
919
- const char * filename = (!write_fetch_head
920
- ? "/dev/null"
921
- : git_path_fetch_head (the_repository ));
922
1024
int want_status ;
923
1025
int summary_width = transport_summary_width (ref_map );
924
1026
925
- fp = fopen ( filename , "a" );
926
- if (! fp )
927
- return error_errno ( _ ( "cannot open %s" ), filename ) ;
1027
+ rc = open_fetch_head ( & fetch_head );
1028
+ if (rc )
1029
+ return -1 ;
928
1030
929
1031
if (raw_url )
930
1032
url = transport_anonymize_url (raw_url );
@@ -941,6 +1043,14 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
941
1043
}
942
1044
}
943
1045
1046
+ if (atomic_fetch ) {
1047
+ transaction = ref_transaction_begin (& err );
1048
+ if (!transaction ) {
1049
+ error ("%s" , err .buf );
1050
+ goto abort ;
1051
+ }
1052
+ }
1053
+
944
1054
prepare_format_display (ref_map );
945
1055
946
1056
/*
@@ -953,7 +1063,6 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
953
1063
want_status ++ ) {
954
1064
for (rm = ref_map ; rm ; rm = rm -> next ) {
955
1065
struct ref * ref = NULL ;
956
- const char * merge_status_marker = "" ;
957
1066
958
1067
if (rm -> status == REF_STATUS_REJECT_SHALLOW ) {
959
1068
if (want_status == FETCH_HEAD_MERGE )
@@ -1011,31 +1120,15 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
1011
1120
strbuf_addf (& note , "%s " , kind );
1012
1121
strbuf_addf (& note , "'%s' of " , what );
1013
1122
}
1014
- switch (rm -> fetch_head_status ) {
1015
- case FETCH_HEAD_NOT_FOR_MERGE :
1016
- merge_status_marker = "not-for-merge" ;
1017
- /* fall-through */
1018
- case FETCH_HEAD_MERGE :
1019
- fprintf (fp , "%s\t%s\t%s" ,
1020
- oid_to_hex (& rm -> old_oid ),
1021
- merge_status_marker ,
1022
- note .buf );
1023
- for (i = 0 ; i < url_len ; ++ i )
1024
- if ('\n' == url [i ])
1025
- fputs ("\\n" , fp );
1026
- else
1027
- fputc (url [i ], fp );
1028
- fputc ('\n' , fp );
1029
- break ;
1030
- default :
1031
- /* do not write anything to FETCH_HEAD */
1032
- break ;
1033
- }
1123
+
1124
+ append_fetch_head (& fetch_head , & rm -> old_oid ,
1125
+ rm -> fetch_head_status ,
1126
+ note .buf , url , url_len );
1034
1127
1035
1128
strbuf_reset (& note );
1036
1129
if (ref ) {
1037
- rc |= update_local_ref (ref , what , rm , & note ,
1038
- summary_width );
1130
+ rc |= update_local_ref (ref , transaction , what ,
1131
+ rm , & note , summary_width );
1039
1132
free (ref );
1040
1133
} else if (write_fetch_head || dry_run ) {
1041
1134
/*
@@ -1060,6 +1153,17 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
1060
1153
}
1061
1154
}
1062
1155
1156
+ if (!rc && transaction ) {
1157
+ rc = ref_transaction_commit (transaction , & err );
1158
+ if (rc ) {
1159
+ error ("%s" , err .buf );
1160
+ goto abort ;
1161
+ }
1162
+ }
1163
+
1164
+ if (!rc )
1165
+ commit_fetch_head (& fetch_head );
1166
+
1063
1167
if (rc & STORE_REF_ERROR_DF_CONFLICT )
1064
1168
error (_ ("some local refs could not be updated; try running\n"
1065
1169
" 'git remote prune %s' to remove any old, conflicting "
@@ -1076,8 +1180,10 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
1076
1180
1077
1181
abort :
1078
1182
strbuf_release (& note );
1183
+ strbuf_release (& err );
1184
+ ref_transaction_free (transaction );
1079
1185
free (url );
1080
- fclose ( fp );
1186
+ close_fetch_head ( & fetch_head );
1081
1187
return rc ;
1082
1188
}
1083
1189
@@ -1887,6 +1993,10 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
1887
1993
die (_ ("--filter can only be used with the remote "
1888
1994
"configured in extensions.partialclone" ));
1889
1995
1996
+ if (atomic_fetch )
1997
+ die (_ ("--atomic can only be used when fetching "
1998
+ "from one remote" ));
1999
+
1890
2000
if (stdin_refspecs )
1891
2001
die (_ ("--stdin can only be used when fetching "
1892
2002
"from one remote" ));
0 commit comments