@@ -2854,12 +2854,117 @@ static int delete_ref_loose(struct ref_lock *lock, int flag, struct strbuf *err)
28542854 return 0 ;
28552855}
28562856
2857+ static int is_per_worktree_ref (const char * refname )
2858+ {
2859+ return !strcmp (refname , "HEAD" );
2860+ }
2861+
2862+ static int is_pseudoref_syntax (const char * refname )
2863+ {
2864+ const char * c ;
2865+
2866+ for (c = refname ; * c ; c ++ ) {
2867+ if (!isupper (* c ) && * c != '-' && * c != '_' )
2868+ return 0 ;
2869+ }
2870+
2871+ return 1 ;
2872+ }
2873+
2874+ enum ref_type ref_type (const char * refname )
2875+ {
2876+ if (is_per_worktree_ref (refname ))
2877+ return REF_TYPE_PER_WORKTREE ;
2878+ if (is_pseudoref_syntax (refname ))
2879+ return REF_TYPE_PSEUDOREF ;
2880+ return REF_TYPE_NORMAL ;
2881+ }
2882+
2883+ static int write_pseudoref (const char * pseudoref , const unsigned char * sha1 ,
2884+ const unsigned char * old_sha1 , struct strbuf * err )
2885+ {
2886+ const char * filename ;
2887+ int fd ;
2888+ static struct lock_file lock ;
2889+ struct strbuf buf = STRBUF_INIT ;
2890+ int ret = -1 ;
2891+
2892+ strbuf_addf (& buf , "%s\n" , sha1_to_hex (sha1 ));
2893+
2894+ filename = git_path ("%s" , pseudoref );
2895+ fd = hold_lock_file_for_update (& lock , filename , LOCK_DIE_ON_ERROR );
2896+ if (fd < 0 ) {
2897+ strbuf_addf (err , "Could not open '%s' for writing: %s" ,
2898+ filename , strerror (errno ));
2899+ return -1 ;
2900+ }
2901+
2902+ if (old_sha1 ) {
2903+ unsigned char actual_old_sha1 [20 ];
2904+
2905+ if (read_ref (pseudoref , actual_old_sha1 ))
2906+ die ("could not read ref '%s'" , pseudoref );
2907+ if (hashcmp (actual_old_sha1 , old_sha1 )) {
2908+ strbuf_addf (err , "Unexpected sha1 when writing %s" , pseudoref );
2909+ rollback_lock_file (& lock );
2910+ goto done ;
2911+ }
2912+ }
2913+
2914+ if (write_in_full (fd , buf .buf , buf .len ) != buf .len ) {
2915+ strbuf_addf (err , "Could not write to '%s'" , filename );
2916+ rollback_lock_file (& lock );
2917+ goto done ;
2918+ }
2919+
2920+ commit_lock_file (& lock );
2921+ ret = 0 ;
2922+ done :
2923+ strbuf_release (& buf );
2924+ return ret ;
2925+ }
2926+
2927+ static int delete_pseudoref (const char * pseudoref , const unsigned char * old_sha1 )
2928+ {
2929+ static struct lock_file lock ;
2930+ const char * filename ;
2931+
2932+ filename = git_path ("%s" , pseudoref );
2933+
2934+ if (old_sha1 && !is_null_sha1 (old_sha1 )) {
2935+ int fd ;
2936+ unsigned char actual_old_sha1 [20 ];
2937+
2938+ fd = hold_lock_file_for_update (& lock , filename ,
2939+ LOCK_DIE_ON_ERROR );
2940+ if (fd < 0 )
2941+ die_errno (_ ("Could not open '%s' for writing" ), filename );
2942+ if (read_ref (pseudoref , actual_old_sha1 ))
2943+ die ("could not read ref '%s'" , pseudoref );
2944+ if (hashcmp (actual_old_sha1 , old_sha1 )) {
2945+ warning ("Unexpected sha1 when deleting %s" , pseudoref );
2946+ rollback_lock_file (& lock );
2947+ return -1 ;
2948+ }
2949+
2950+ unlink (filename );
2951+ rollback_lock_file (& lock );
2952+ } else {
2953+ unlink (filename );
2954+ }
2955+
2956+ return 0 ;
2957+ }
2958+
28572959int delete_ref (const char * refname , const unsigned char * old_sha1 ,
28582960 unsigned int flags )
28592961{
28602962 struct ref_transaction * transaction ;
28612963 struct strbuf err = STRBUF_INIT ;
28622964
2965+ if (ref_type (refname ) == REF_TYPE_PSEUDOREF )
2966+ return delete_pseudoref (refname , old_sha1 );
2967+
28632968 transaction = ref_transaction_begin (& err );
28642969 if (!transaction ||
28652970 ref_transaction_delete (transaction , refname , old_sha1 ,
@@ -3961,17 +4066,25 @@ int update_ref(const char *msg, const char *refname,
39614066 const unsigned char * new_sha1 , const unsigned char * old_sha1 ,
39624067 unsigned int flags , enum action_on_err onerr )
39634068{
3964- struct ref_transaction * t ;
4069+ struct ref_transaction * t = NULL ;
39654070 struct strbuf err = STRBUF_INIT ;
4071+ int ret = 0 ;
39664072
3967- t = ref_transaction_begin (& err );
3968- if (!t ||
3969- ref_transaction_update (t , refname , new_sha1 , old_sha1 ,
3970- flags , msg , & err ) ||
3971- ref_transaction_commit (t , & err )) {
4073+ if (ref_type (refname ) == REF_TYPE_PSEUDOREF ) {
4074+ ret = write_pseudoref (refname , new_sha1 , old_sha1 , & err );
4075+ } else {
4076+ t = ref_transaction_begin (& err );
4077+ if (!t ||
4078+ ref_transaction_update (t , refname , new_sha1 , old_sha1 ,
4079+ flags , msg , & err ) ||
4080+ ref_transaction_commit (t , & err )) {
4081+ ret = 1 ;
4082+ ref_transaction_free (t );
4083+ }
4084+ }
4085+ if (ret ) {
39724086 const char * str = "update_ref failed for ref '%s': %s" ;
39734087
3974- ref_transaction_free (t );
39754088 switch (onerr ) {
39764089 case UPDATE_REFS_MSG_ON_ERR :
39774090 error (str , refname , err .buf );
@@ -3986,7 +4099,8 @@ int update_ref(const char *msg, const char *refname,
39864099 return 1 ;
39874100 }
39884101 strbuf_release (& err );
3989- ref_transaction_free (t );
4102+ if (t )
4103+ ref_transaction_free (t );
39904104 return 0 ;
39914105}
39924106
0 commit comments