@@ -38,9 +38,11 @@ static int receive_fsck_objects = -1;
38
38
static int transfer_fsck_objects = -1 ;
39
39
static int receive_unpack_limit = -1 ;
40
40
static int transfer_unpack_limit = -1 ;
41
+ static int advertise_atomic_push = 1 ;
41
42
static int unpack_limit = 100 ;
42
43
static int report_status ;
43
44
static int use_sideband ;
45
+ static int use_atomic ;
44
46
static int quiet ;
45
47
static int prefer_ofs_delta = 1 ;
46
48
static int auto_update_server_info ;
@@ -67,6 +69,7 @@ static const char *NONCE_SLOP = "SLOP";
67
69
static const char * nonce_status ;
68
70
static long nonce_stamp_slop ;
69
71
static unsigned long nonce_stamp_slop_limit ;
72
+ static struct ref_transaction * transaction ;
70
73
71
74
static enum deny_action parse_deny_action (const char * var , const char * value )
72
75
{
@@ -160,6 +163,11 @@ static int receive_pack_config(const char *var, const char *value, void *cb)
160
163
return 0 ;
161
164
}
162
165
166
+ if (strcmp (var , "receive.advertiseatomic" ) == 0 ) {
167
+ advertise_atomic_push = git_config_bool (var , value );
168
+ return 0 ;
169
+ }
170
+
163
171
return git_default_config (var , value , cb );
164
172
}
165
173
@@ -175,6 +183,8 @@ static void show_ref(const char *path, const unsigned char *sha1)
175
183
176
184
strbuf_addstr (& cap ,
177
185
"report-status delete-refs side-band-64k quiet" );
186
+ if (advertise_atomic_push )
187
+ strbuf_addstr (& cap , " atomic" );
178
188
if (prefer_ofs_delta )
179
189
strbuf_addstr (& cap , " ofs-delta" );
180
190
if (push_cert_nonce )
@@ -910,6 +920,7 @@ static const char *update(struct command *cmd, struct shallow_info *si)
910
920
}
911
921
912
922
if (is_null_sha1 (new_sha1 )) {
923
+ struct strbuf err = STRBUF_INIT ;
913
924
if (!parse_object (old_sha1 )) {
914
925
old_sha1 = NULL ;
915
926
if (ref_exists (name )) {
@@ -919,35 +930,36 @@ static const char *update(struct command *cmd, struct shallow_info *si)
919
930
cmd -> did_not_exist = 1 ;
920
931
}
921
932
}
922
- if (delete_ref (namespaced_name , old_sha1 , 0 )) {
923
- rp_error ("failed to delete %s" , name );
933
+ if (ref_transaction_delete (transaction ,
934
+ namespaced_name ,
935
+ old_sha1 ,
936
+ 0 , old_sha1 != NULL ,
937
+ "push" , & err )) {
938
+ rp_error ("%s" , err .buf );
939
+ strbuf_release (& err );
924
940
return "failed to delete" ;
925
941
}
942
+ strbuf_release (& err );
926
943
return NULL ; /* good */
927
944
}
928
945
else {
929
946
struct strbuf err = STRBUF_INIT ;
930
- struct ref_transaction * transaction ;
931
-
932
947
if (shallow_update && si -> shallow_ref [cmd -> index ] &&
933
948
update_shallow_ref (cmd , si ))
934
949
return "shallow error" ;
935
950
936
- transaction = ref_transaction_begin (& err );
937
- if (!transaction ||
938
- ref_transaction_update (transaction , namespaced_name ,
939
- new_sha1 , old_sha1 , 0 , 1 , "push" ,
940
- & err ) ||
941
- ref_transaction_commit (transaction , & err )) {
942
- ref_transaction_free (transaction );
943
-
951
+ if (ref_transaction_update (transaction ,
952
+ namespaced_name ,
953
+ new_sha1 , old_sha1 ,
954
+ 0 , 1 , "push" ,
955
+ & err )) {
944
956
rp_error ("%s" , err .buf );
945
957
strbuf_release (& err );
958
+
946
959
return "failed to update ref" ;
947
960
}
948
-
949
- ref_transaction_free (transaction );
950
961
strbuf_release (& err );
962
+
951
963
return NULL ; /* good */
952
964
}
953
965
}
@@ -1131,11 +1143,105 @@ static void reject_updates_to_hidden(struct command *commands)
1131
1143
}
1132
1144
}
1133
1145
1146
+ static int should_process_cmd (struct command * cmd )
1147
+ {
1148
+ return !cmd -> error_string && !cmd -> skip_update ;
1149
+ }
1150
+
1151
+ static void warn_if_skipped_connectivity_check (struct command * commands ,
1152
+ struct shallow_info * si )
1153
+ {
1154
+ struct command * cmd ;
1155
+ int checked_connectivity = 1 ;
1156
+
1157
+ for (cmd = commands ; cmd ; cmd = cmd -> next ) {
1158
+ if (should_process_cmd (cmd ) && si -> shallow_ref [cmd -> index ]) {
1159
+ error ("BUG: connectivity check has not been run on ref %s" ,
1160
+ cmd -> ref_name );
1161
+ checked_connectivity = 0 ;
1162
+ }
1163
+ }
1164
+ if (!checked_connectivity )
1165
+ die ("BUG: connectivity check skipped???" );
1166
+ }
1167
+
1168
+ static void execute_commands_non_atomic (struct command * commands ,
1169
+ struct shallow_info * si )
1170
+ {
1171
+ struct command * cmd ;
1172
+ struct strbuf err = STRBUF_INIT ;
1173
+
1174
+ for (cmd = commands ; cmd ; cmd = cmd -> next ) {
1175
+ if (!should_process_cmd (cmd ))
1176
+ continue ;
1177
+
1178
+ transaction = ref_transaction_begin (& err );
1179
+ if (!transaction ) {
1180
+ rp_error ("%s" , err .buf );
1181
+ strbuf_reset (& err );
1182
+ cmd -> error_string = "transaction failed to start" ;
1183
+ continue ;
1184
+ }
1185
+
1186
+ cmd -> error_string = update (cmd , si );
1187
+
1188
+ if (!cmd -> error_string
1189
+ && ref_transaction_commit (transaction , & err )) {
1190
+ rp_error ("%s" , err .buf );
1191
+ strbuf_reset (& err );
1192
+ cmd -> error_string = "failed to update ref" ;
1193
+ }
1194
+ ref_transaction_free (transaction );
1195
+ }
1196
+ strbuf_release (& err );
1197
+ }
1198
+
1199
+ static void execute_commands_atomic (struct command * commands ,
1200
+ struct shallow_info * si )
1201
+ {
1202
+ struct command * cmd ;
1203
+ struct strbuf err = STRBUF_INIT ;
1204
+ const char * reported_error = "atomic push failure" ;
1205
+
1206
+ transaction = ref_transaction_begin (& err );
1207
+ if (!transaction ) {
1208
+ rp_error ("%s" , err .buf );
1209
+ strbuf_reset (& err );
1210
+ reported_error = "transaction failed to start" ;
1211
+ goto failure ;
1212
+ }
1213
+
1214
+ for (cmd = commands ; cmd ; cmd = cmd -> next ) {
1215
+ if (!should_process_cmd (cmd ))
1216
+ continue ;
1217
+
1218
+ cmd -> error_string = update (cmd , si );
1219
+
1220
+ if (cmd -> error_string )
1221
+ goto failure ;
1222
+ }
1223
+
1224
+ if (ref_transaction_commit (transaction , & err )) {
1225
+ rp_error ("%s" , err .buf );
1226
+ reported_error = "atomic transaction failed" ;
1227
+ goto failure ;
1228
+ }
1229
+ goto cleanup ;
1230
+
1231
+ failure :
1232
+ for (cmd = commands ; cmd ; cmd = cmd -> next )
1233
+ if (!cmd -> error_string )
1234
+ cmd -> error_string = reported_error ;
1235
+
1236
+ cleanup :
1237
+ ref_transaction_free (transaction );
1238
+ strbuf_release (& err );
1239
+ }
1240
+
1134
1241
static void execute_commands (struct command * commands ,
1135
1242
const char * unpacker_error ,
1136
1243
struct shallow_info * si )
1137
1244
{
1138
- int checked_connectivity ;
1139
1245
struct command * cmd ;
1140
1246
unsigned char sha1 [20 ];
1141
1247
struct iterate_data data ;
@@ -1166,27 +1272,13 @@ static void execute_commands(struct command *commands,
1166
1272
free (head_name_to_free );
1167
1273
head_name = head_name_to_free = resolve_refdup ("HEAD" , 0 , sha1 , NULL );
1168
1274
1169
- checked_connectivity = 1 ;
1170
- for (cmd = commands ; cmd ; cmd = cmd -> next ) {
1171
- if (cmd -> error_string )
1172
- continue ;
1173
-
1174
- if (cmd -> skip_update )
1175
- continue ;
1176
-
1177
- cmd -> error_string = update (cmd , si );
1178
- if (shallow_update && !cmd -> error_string &&
1179
- si -> shallow_ref [cmd -> index ]) {
1180
- error ("BUG: connectivity check has not been run on ref %s" ,
1181
- cmd -> ref_name );
1182
- checked_connectivity = 0 ;
1183
- }
1184
- }
1275
+ if (use_atomic )
1276
+ execute_commands_atomic (commands , si );
1277
+ else
1278
+ execute_commands_non_atomic (commands , si );
1185
1279
1186
- if (shallow_update && !checked_connectivity )
1187
- error ("BUG: run 'git fsck' for safety.\n"
1188
- "If there are errors, try to remove "
1189
- "the reported refs above" );
1280
+ if (shallow_update )
1281
+ warn_if_skipped_connectivity_check (commands , si );
1190
1282
}
1191
1283
1192
1284
static struct command * * queue_command (struct command * * tail ,
@@ -1268,6 +1360,9 @@ static struct command *read_head_info(struct sha1_array *shallow)
1268
1360
use_sideband = LARGE_PACKET_MAX ;
1269
1361
if (parse_feature_request (feature_list , "quiet" ))
1270
1362
quiet = 1 ;
1363
+ if (advertise_atomic_push
1364
+ && parse_feature_request (feature_list , "atomic" ))
1365
+ use_atomic = 1 ;
1271
1366
}
1272
1367
1273
1368
if (!strcmp (line , "push-cert" )) {
0 commit comments