1
1
use super :: Error ;
2
- use crate :: bstr:: BStr ;
2
+ use crate :: bstr:: { BStr , ByteSlice } ;
3
3
use crate :: Repository ;
4
4
use git_odb:: Find ;
5
5
use git_ref:: transaction:: { LogChange , RefLog } ;
6
+ use git_ref:: FullNameRef ;
7
+ use std:: borrow:: Cow ;
8
+ use std:: convert:: TryInto ;
6
9
7
10
pub fn write_remote_to_local_config_file (
8
11
remote : & mut crate :: Remote < ' _ > ,
@@ -42,19 +45,19 @@ pub fn update_head(
42
45
repo : & Repository ,
43
46
remote_refs : & [ git_protocol:: fetch:: Ref ] ,
44
47
reflog_message : & BStr ,
48
+ remote_name : & str ,
45
49
) -> Result < ( ) , Error > {
46
50
use git_ref:: transaction:: { PreviousValue , RefEdit } ;
47
51
use git_ref:: Target ;
48
- use std:: convert:: TryInto ;
49
52
let ( head_peeled_id, head_ref) = match remote_refs. iter ( ) . find_map ( |r| {
50
53
Some ( match r {
51
54
git_protocol:: fetch:: Ref :: Symbolic {
52
55
full_ref_name,
53
56
target,
54
57
object,
55
- } if full_ref_name == "HEAD" => ( Some ( object) , Some ( target) ) ,
58
+ } if full_ref_name == "HEAD" => ( Some ( object. as_ref ( ) ) , Some ( target) ) ,
56
59
git_protocol:: fetch:: Ref :: Direct { full_ref_name, object } if full_ref_name == "HEAD" => {
57
- ( Some ( object) , None )
60
+ ( Some ( object. as_ref ( ) ) , None )
58
61
}
59
62
git_protocol:: fetch:: Ref :: Unborn { full_ref_name, target } if full_ref_name == "HEAD" => {
60
63
( None , Some ( target) )
@@ -106,7 +109,7 @@ pub fn update_head(
106
109
expected : PreviousValue :: Any ,
107
110
new : Target :: Peeled ( head_peeled_id. to_owned ( ) ) ,
108
111
} ,
109
- name : referent,
112
+ name : referent. clone ( ) ,
110
113
deref : false ,
111
114
} ) ;
112
115
} ;
@@ -126,12 +129,14 @@ pub fn update_head(
126
129
change : git_ref:: transaction:: Change :: Update {
127
130
log,
128
131
expected : PreviousValue :: Any ,
129
- new : Target :: Peeled ( * head_peeled_id) ,
132
+ new : Target :: Peeled ( head_peeled_id. to_owned ( ) ) ,
130
133
} ,
131
134
name : head,
132
135
deref : false ,
133
136
} ) ?;
134
137
}
138
+
139
+ setup_branch_config ( repo, referent. as_ref ( ) , head_peeled_id, remote_name) ?;
135
140
}
136
141
None => {
137
142
repo. edit_reference ( RefEdit {
@@ -151,3 +156,55 @@ pub fn update_head(
151
156
} ;
152
157
Ok ( ( ) )
153
158
}
159
+
160
+ /// Setup the remote configuration for `branch` so that it points to itself, but on the remote, if an only if currently saved refspec
161
+ /// is able to match it.
162
+ /// For that we reload the remote of `remote_name` and use its ref_specs for match.
163
+ fn setup_branch_config (
164
+ repo : & Repository ,
165
+ branch : & FullNameRef ,
166
+ branch_id : Option < & git_hash:: oid > ,
167
+ remote_name : & str ,
168
+ ) -> Result < ( ) , Error > {
169
+ let short_name = match branch. category_and_short_name ( ) {
170
+ Some ( ( cat, shortened) ) if cat == git_ref:: Category :: LocalBranch => match shortened. to_str ( ) {
171
+ Ok ( s) => s,
172
+ Err ( _) => return Ok ( ( ) ) ,
173
+ } ,
174
+ _ => return Ok ( ( ) ) ,
175
+ } ;
176
+ let remote = repo
177
+ . find_remote ( remote_name)
178
+ . expect ( "remote was just created and must be visible in config" ) ;
179
+ let group = git_refspec:: MatchGroup :: from_fetch_specs ( remote. fetch_specs . iter ( ) . map ( |s| s. to_ref ( ) ) ) ;
180
+ let null = git_hash:: ObjectId :: null ( repo. object_hash ( ) ) ;
181
+ let res = group. match_remotes (
182
+ Some ( git_refspec:: match_group:: Item {
183
+ full_ref_name : branch. as_bstr ( ) ,
184
+ target : branch_id. unwrap_or ( & null) ,
185
+ object : None ,
186
+ } )
187
+ . into_iter ( ) ,
188
+ ) ;
189
+ if !res. mappings . is_empty ( ) {
190
+ let mut metadata = git_config:: file:: Metadata :: from ( git_config:: Source :: Local ) ;
191
+ let config_path = remote. repo . git_dir ( ) . join ( "config" ) ;
192
+ metadata. path = Some ( config_path. clone ( ) ) ;
193
+ let mut config =
194
+ git_config:: File :: from_paths_metadata ( Some ( metadata) , Default :: default ( ) ) ?. expect ( "one file to load" ) ;
195
+
196
+ let mut section = config
197
+ . new_section ( "branch" , Some ( Cow :: Owned ( short_name. into ( ) ) ) )
198
+ . expect ( "section header name is always valid per naming rules, our input branch name is valid" ) ;
199
+ section. push (
200
+ "remote" . try_into ( ) . expect ( "valid at compile time" ) ,
201
+ Some ( remote_name. into ( ) ) ,
202
+ ) ;
203
+ section. push (
204
+ "merge" . try_into ( ) . expect ( "valid at compile time" ) ,
205
+ Some ( branch. as_bstr ( ) ) ,
206
+ ) ;
207
+ std:: fs:: write ( config_path, config. to_bstring ( ) ) ?;
208
+ }
209
+ Ok ( ( ) )
210
+ }
0 commit comments