@@ -640,17 +640,13 @@ static struct ref *get_ref_map(struct remote *remote,
640640 return ref_map ;
641641}
642642
643- #define STORE_REF_ERROR_OTHER 1
644- #define STORE_REF_ERROR_DF_CONFLICT 2
645-
646643static int s_update_ref (const char * action ,
647644 struct ref * ref ,
648645 struct ref_transaction * transaction ,
649646 int check_old )
650647{
651648 char * msg ;
652649 char * rla = getenv ("GIT_REFLOG_ACTION" );
653- struct ref_transaction * our_transaction = NULL ;
654650 struct strbuf err = STRBUF_INIT ;
655651 int ret ;
656652
@@ -660,43 +656,10 @@ static int s_update_ref(const char *action,
660656 rla = default_rla .buf ;
661657 msg = xstrfmt ("%s: %s" , rla , action );
662658
663- /*
664- * If no transaction was passed to us, we manage the transaction
665- * ourselves. Otherwise, we trust the caller to handle the transaction
666- * lifecycle.
667- */
668- if (!transaction ) {
669- transaction = our_transaction = ref_store_transaction_begin (get_main_ref_store (the_repository ),
670- 0 , & err );
671- if (!transaction ) {
672- ret = STORE_REF_ERROR_OTHER ;
673- goto out ;
674- }
675- }
676-
677659 ret = ref_transaction_update (transaction , ref -> name , & ref -> new_oid ,
678660 check_old ? & ref -> old_oid : NULL ,
679661 NULL , NULL , 0 , msg , & err );
680- if (ret ) {
681- ret = STORE_REF_ERROR_OTHER ;
682- goto out ;
683- }
684-
685- if (our_transaction ) {
686- switch (ref_transaction_commit (our_transaction , & err )) {
687- case 0 :
688- break ;
689- case REF_TRANSACTION_ERROR_NAME_CONFLICT :
690- ret = STORE_REF_ERROR_DF_CONFLICT ;
691- goto out ;
692- default :
693- ret = STORE_REF_ERROR_OTHER ;
694- goto out ;
695- }
696- }
697662
698- out :
699- ref_transaction_free (our_transaction );
700663 if (ret )
701664 error ("%s" , err .buf );
702665 strbuf_release (& err );
@@ -1139,7 +1102,6 @@ N_("it took %.2f seconds to check forced updates; you can use\n"
11391102 "to avoid this check\n" );
11401103
11411104static int store_updated_refs (struct display_state * display_state ,
1142- const char * remote_name ,
11431105 int connectivity_checked ,
11441106 struct ref_transaction * transaction , struct ref * ref_map ,
11451107 struct fetch_head * fetch_head ,
@@ -1277,11 +1239,6 @@ static int store_updated_refs(struct display_state *display_state,
12771239 }
12781240 }
12791241
1280- if (rc & STORE_REF_ERROR_DF_CONFLICT )
1281- error (_ ("some local refs could not be updated; try running\n"
1282- " 'git remote prune %s' to remove any old, conflicting "
1283- "branches" ), remote_name );
1284-
12851242 if (advice_enabled (ADVICE_FETCH_SHOW_FORCED_UPDATES )) {
12861243 if (!config -> show_forced_updates ) {
12871244 warning (_ (warn_show_forced_updates ));
@@ -1365,9 +1322,8 @@ static int fetch_and_consume_refs(struct display_state *display_state,
13651322 }
13661323
13671324 trace2_region_enter ("fetch" , "consume_refs" , the_repository );
1368- ret = store_updated_refs (display_state , transport -> remote -> name ,
1369- connectivity_checked , transaction , ref_map ,
1370- fetch_head , config );
1325+ ret = store_updated_refs (display_state , connectivity_checked ,
1326+ transaction , ref_map , fetch_head , config );
13711327 trace2_region_leave ("fetch" , "consume_refs" , the_repository );
13721328
13731329out :
@@ -1687,6 +1643,37 @@ static int set_head(const struct ref *remote_refs, struct remote *remote)
16871643 return result ;
16881644}
16891645
1646+ struct ref_rejection_data {
1647+ int * retcode ;
1648+ int conflict_msg_shown ;
1649+ const char * remote_name ;
1650+ };
1651+
1652+ static void ref_transaction_rejection_handler (const char * refname ,
1653+ const struct object_id * old_oid UNUSED ,
1654+ const struct object_id * new_oid UNUSED ,
1655+ const char * old_target UNUSED ,
1656+ const char * new_target UNUSED ,
1657+ enum ref_transaction_error err ,
1658+ void * cb_data )
1659+ {
1660+ struct ref_rejection_data * data = (struct ref_rejection_data * )cb_data ;
1661+
1662+ if (err == REF_TRANSACTION_ERROR_NAME_CONFLICT && !data -> conflict_msg_shown ) {
1663+ error (_ ("some local refs could not be updated; try running\n"
1664+ " 'git remote prune %s' to remove any old, conflicting "
1665+ "branches" ), data -> remote_name );
1666+ data -> conflict_msg_shown = 1 ;
1667+ } else {
1668+ char * reason = ref_transaction_error_msg (err );
1669+
1670+ error (_ ("fetching ref %s failed: %s" ), refname , reason );
1671+ free (reason );
1672+ }
1673+
1674+ * data -> retcode = 1 ;
1675+ }
1676+
16901677static int do_fetch (struct transport * transport ,
16911678 struct refspec * rs ,
16921679 const struct fetch_config * config )
@@ -1807,6 +1794,24 @@ static int do_fetch(struct transport *transport,
18071794 retcode = 1 ;
18081795 }
18091796
1797+ /*
1798+ * If not atomic, we can still use batched updates, which would be much
1799+ * more performant. We don't initiate the transaction before pruning,
1800+ * since pruning must be an independent step, to avoid F/D conflicts.
1801+ *
1802+ * TODO: if reference transactions gain logical conflict resolution, we
1803+ * can delete and create refs (with F/D conflicts) in the same transaction
1804+ * and this can be moved about the 'prune_refs()' block.
1805+ */
1806+ if (!transaction ) {
1807+ transaction = ref_store_transaction_begin (get_main_ref_store (the_repository ),
1808+ REF_TRANSACTION_ALLOW_FAILURE , & err );
1809+ if (!transaction ) {
1810+ retcode = -1 ;
1811+ goto cleanup ;
1812+ }
1813+ }
1814+
18101815 if (fetch_and_consume_refs (& display_state , transport , transaction , ref_map ,
18111816 & fetch_head , config )) {
18121817 retcode = 1 ;
@@ -1838,16 +1843,31 @@ static int do_fetch(struct transport *transport,
18381843 free_refs (tags_ref_map );
18391844 }
18401845
1841- if (transaction ) {
1842- if (retcode )
1843- goto cleanup ;
1846+ if (retcode )
1847+ goto cleanup ;
18441848
1845- retcode = ref_transaction_commit (transaction , & err );
1849+ retcode = ref_transaction_commit (transaction , & err );
1850+ if (retcode ) {
1851+ /*
1852+ * Explicitly handle transaction cleanup to avoid
1853+ * aborting an already closed transaction.
1854+ */
1855+ ref_transaction_free (transaction );
1856+ transaction = NULL ;
1857+ goto cleanup ;
1858+ }
1859+
1860+ if (!atomic_fetch ) {
1861+ struct ref_rejection_data data = {
1862+ .retcode = & retcode ,
1863+ .conflict_msg_shown = 0 ,
1864+ .remote_name = transport -> remote -> name ,
1865+ };
1866+
1867+ ref_transaction_for_each_rejected_update (transaction ,
1868+ ref_transaction_rejection_handler ,
1869+ & data );
18461870 if (retcode ) {
1847- /*
1848- * Explicitly handle transaction cleanup to avoid
1849- * aborting an already closed transaction.
1850- */
18511871 ref_transaction_free (transaction );
18521872 transaction = NULL ;
18531873 goto cleanup ;
0 commit comments