99 "github.com/MakeNowJust/heredoc"
1010 "github.com/cli/cli/api"
1111 "github.com/cli/cli/context"
12+ gitpkg "github.com/cli/cli/git"
1213 "github.com/cli/cli/internal/ghrepo"
1314 "github.com/cli/cli/pkg/cmdutil"
1415 "github.com/cli/cli/pkg/iostreams"
@@ -91,24 +92,20 @@ func syncRun(opts *SyncOptions) error {
9192}
9293
9394func syncLocalRepo (opts * SyncOptions ) error {
94- var err error
9595 var srcRepo ghrepo.Interface
9696
97- dirtyRepo , err := opts .Git .IsDirty ()
98- if err != nil {
99- return err
100- }
101- if dirtyRepo {
102- return fmt .Errorf ("can't sync because there are local changes, please commit or stash them" )
103- }
104-
10597 if opts .SrcArg != "" {
98+ var err error
10699 srcRepo , err = ghrepo .FromFullName (opts .SrcArg )
100+ if err != nil {
101+ return err
102+ }
107103 } else {
104+ var err error
108105 srcRepo , err = opts .BaseRepo ()
109- }
110- if err != nil {
111- return err
106+ if err != nil {
107+ return err
108+ }
112109 }
113110
114111 // Find remote that matches the srcRepo
@@ -117,14 +114,9 @@ func syncLocalRepo(opts *SyncOptions) error {
117114 if err != nil {
118115 return err
119116 }
120- for _ , r := range remotes {
121- if r .RepoName () == srcRepo .RepoName () &&
122- r .RepoOwner () == srcRepo .RepoOwner () &&
123- r .RepoHost () == srcRepo .RepoHost () {
124- remote = r .Name
125- }
126- }
127- if remote == "" {
117+ if r , err := remotes .FindByRepo (srcRepo .RepoOwner (), srcRepo .RepoName ()); err == nil {
118+ remote = r .Name
119+ } else {
128120 return fmt .Errorf ("can't find corresponding remote for %s" , ghrepo .FullName (srcRepo ))
129121 }
130122
@@ -238,6 +230,7 @@ var mismatchRemotesError = errors.New("branch remote does not match specified so
238230func executeLocalRepoSync (srcRepo ghrepo.Interface , remote string , opts * SyncOptions ) error {
239231 git := opts .Git
240232 branch := opts .Branch
233+ useForce := opts .Force
241234
242235 if err := git .Fetch (remote , fmt .Sprintf ("refs/heads/%s" , branch )); err != nil {
243236 return err
@@ -253,47 +246,49 @@ func executeLocalRepoSync(srcRepo ghrepo.Interface, remote string, opts *SyncOpt
253246 return mismatchRemotesError
254247 }
255248
256- fastForward , err := git .IsAncestor (branch , fmt . Sprintf ( "%s/%s" , remote , branch ) )
249+ fastForward , err := git .IsAncestor (branch , "FETCH_HEAD" )
257250 if err != nil {
258251 return err
259252 }
260253
261- if ! fastForward && ! opts . Force {
254+ if ! fastForward && ! useForce {
262255 return divergingError
263256 }
257+ if fastForward && useForce {
258+ useForce = false
259+ }
264260 }
265261
266- startBranch , err := git .CurrentBranch ()
267- if err != nil {
262+ currentBranch , err := git .CurrentBranch ()
263+ if err != nil && ! errors . Is ( err , gitpkg . ErrNotOnAnyBranch ) {
268264 return err
269265 }
270- if startBranch != branch {
271- if hasLocalBranch {
272- if err := git .CheckoutLocal (branch ); err != nil {
266+ if currentBranch == branch {
267+ if isDirty , err := git .IsDirty (); err == nil && isDirty {
268+ return fmt .Errorf ("can't sync because there are local changes; please stash them before trying again" )
269+ } else if err != nil {
270+ return err
271+ }
272+ if useForce {
273+ if err := git .ResetHard ("FETCH_HEAD" ); err != nil {
273274 return err
274275 }
275276 } else {
276- if err := git .CheckoutRemote ( remote , branch ); err != nil {
277+ if err := git .MergeFastForward ( "FETCH_HEAD" ); err != nil {
277278 return err
278279 }
279280 }
280- }
281- if hasLocalBranch {
282- if opts .Force {
283- if err := git .ResetHard (fmt .Sprintf ("refs/remotes/%s/%s" , remote , branch )); err != nil {
281+ } else {
282+ if hasLocalBranch {
283+ if err := git .UpdateBranch (branch , "FETCH_HEAD" ); err != nil {
284284 return err
285285 }
286286 } else {
287- if err := git .MergeFastForward ( fmt .Sprintf ("refs/remotes/ %s/%s" , remote , branch )); err != nil {
287+ if err := git .CreateBranch ( branch , "FETCH_HEAD" , fmt .Sprintf ("%s/%s" , remote , branch )); err != nil {
288288 return err
289289 }
290290 }
291291 }
292- if startBranch != branch {
293- if err := git .CheckoutLocal (startBranch ); err != nil {
294- return err
295- }
296- }
297292
298293 return nil
299294}
0 commit comments