|
1 | 1 | using System;
|
| 2 | +using System.Linq; |
2 | 3 | using LibGit2Sharp.Core;
|
3 | 4 |
|
4 | 5 | namespace LibGit2Sharp
|
@@ -37,18 +38,47 @@ public static Branch Checkout(IRepository repository, string committishOrBranchS
|
37 | 38 | Ensure.ArgumentNotNullOrEmptyString(committishOrBranchSpec, "committishOrBranchSpec");
|
38 | 39 | Ensure.ArgumentNotNull(options, "options");
|
39 | 40 |
|
40 |
| - Reference reference; |
41 |
| - GitObject obj; |
| 41 | + Reference reference = null; |
| 42 | + GitObject obj = null; |
| 43 | + Branch branch = null; |
| 44 | + |
| 45 | + try |
| 46 | + { |
| 47 | + repository.RevParse(committishOrBranchSpec, out reference, out obj); |
| 48 | + } |
| 49 | + catch (NotFoundException) |
| 50 | + { |
| 51 | + // If committishOrBranchSpec is not a local branch but matches a tracking branch |
| 52 | + // in exactly one remote, use it. This is the "git checkout" command's default behavior. |
| 53 | + // https://git-scm.com/docs/git-checkout#Documentation/git-checkout.txt-emgitcheckoutemltbranchgt |
| 54 | + var remoteBranches = repository.Network.Remotes |
| 55 | + .SelectMany(r => repository.Branches.Where(b => |
| 56 | + b.IsRemote && |
| 57 | + b.CanonicalName == $"refs/remotes/{r.Name}/{committishOrBranchSpec}")) |
| 58 | + .ToList(); |
| 59 | + |
| 60 | + if (remoteBranches.Count == 1) |
| 61 | + { |
| 62 | + branch = repository.CreateBranch(committishOrBranchSpec, remoteBranches[0].Tip); |
| 63 | + repository.Branches.Update(branch, b => b.TrackedBranch = remoteBranches[0].CanonicalName); |
| 64 | + return Checkout(repository, branch, options); |
| 65 | + } |
| 66 | + |
| 67 | + if (remoteBranches.Count > 1) |
| 68 | + throw new AmbiguousSpecificationException( |
| 69 | + $"'{committishOrBranchSpec}' matched multiple ({remoteBranches.Count}) remote tracking branches"); |
| 70 | + |
| 71 | + throw; |
| 72 | + } |
42 | 73 |
|
43 |
| - repository.RevParse(committishOrBranchSpec, out reference, out obj); |
44 | 74 | if (reference != null && reference.IsLocalBranch)
|
45 | 75 | {
|
46 |
| - Branch branch = repository.Branches[reference.CanonicalName]; |
| 76 | + branch = repository.Branches[reference.CanonicalName]; |
47 | 77 | return Checkout(repository, branch, options);
|
48 | 78 | }
|
49 | 79 |
|
50 | 80 | Commit commit = obj.Peel<Commit>(true);
|
51 |
| - Checkout(repository, commit.Tree, options, committishOrBranchSpec); |
| 81 | + Checkout(repository, commit.Tree, options, committishOrBranchSpec); |
52 | 82 |
|
53 | 83 | return repository.Head;
|
54 | 84 | }
|
|
0 commit comments