1
- using System ;
1
+ using System ;
2
2
using LibGit2Sharp . Tests . TestHelpers ;
3
3
using Xunit ;
4
4
using Xunit . Extensions ;
5
+ using System . IO ;
5
6
6
7
namespace LibGit2Sharp . Tests
7
8
{
8
9
public class CheckoutFixture : BaseFixture
9
10
{
11
+ private static readonly string originalFilePath = "a.txt" ;
12
+ private static readonly string originalFileContent = "Hello" ;
13
+ private static readonly string otherBranchName = "other" ;
14
+
10
15
[ Theory ]
11
16
[ InlineData ( "i-do-numbers" ) ]
12
17
[ InlineData ( "diff-test-cases" ) ]
@@ -18,6 +23,10 @@ public void CanCheckoutAnExistingBranch(string branchName)
18
23
Branch master = repo . Branches [ "master" ] ;
19
24
Assert . True ( master . IsCurrentRepositoryHead ) ;
20
25
26
+ // Hard reset to ensure that working directory, index, and HEAD match
27
+ repo . Reset ( ResetOptions . Hard ) ;
28
+ Assert . False ( repo . Index . RetrieveStatus ( ) . IsDirty ) ;
29
+
21
30
Branch branch = repo . Branches [ branchName ] ;
22
31
Assert . NotNull ( branch ) ;
23
32
@@ -29,6 +38,9 @@ public void CanCheckoutAnExistingBranch(string branchName)
29
38
Assert . Equal ( repo . Head , test ) ;
30
39
31
40
Assert . False ( master . IsCurrentRepositoryHead ) ;
41
+
42
+ // Working directory should not be dirty
43
+ Assert . False ( repo . Index . RetrieveStatus ( ) . IsDirty ) ;
32
44
}
33
45
}
34
46
@@ -43,6 +55,10 @@ public void CanCheckoutAnExistingBranchByName(string branchName)
43
55
Branch master = repo . Branches [ "master" ] ;
44
56
Assert . True ( master . IsCurrentRepositoryHead ) ;
45
57
58
+ // Hard reset to ensure that working directory, index, and HEAD match
59
+ repo . Reset ( ResetOptions . Hard ) ;
60
+ Assert . False ( repo . Index . RetrieveStatus ( ) . IsDirty ) ;
61
+
46
62
Branch test = repo . Checkout ( branchName ) ;
47
63
Assert . False ( repo . Info . IsHeadDetached ) ;
48
64
@@ -51,6 +67,9 @@ public void CanCheckoutAnExistingBranchByName(string branchName)
51
67
Assert . Equal ( repo . Head , test ) ;
52
68
53
69
Assert . False ( master . IsCurrentRepositoryHead ) ;
70
+
71
+ // Working directory should not be dirty
72
+ Assert . False ( repo . Index . RetrieveStatus ( ) . IsDirty ) ;
54
73
}
55
74
}
56
75
@@ -65,12 +84,17 @@ public void CanCheckoutAnArbitraryCommit(string commitPointer)
65
84
Branch master = repo . Branches [ "master" ] ;
66
85
Assert . True ( master . IsCurrentRepositoryHead ) ;
67
86
87
+ // Hard reset to ensure that working directory, index, and HEAD match
88
+ repo . Reset ( ResetOptions . Hard ) ;
89
+ Assert . False ( repo . Index . RetrieveStatus ( ) . IsDirty ) ;
90
+
68
91
Branch detachedHead = repo . Checkout ( commitPointer ) ;
69
92
70
93
Assert . Equal ( repo . Head , detachedHead ) ;
71
94
Assert . Equal ( repo . Lookup ( commitPointer ) . Sha , detachedHead . Tip . Sha ) ;
72
95
Assert . True ( repo . Head . IsCurrentRepositoryHead ) ;
73
96
Assert . True ( repo . Info . IsHeadDetached ) ;
97
+ Assert . False ( repo . Index . RetrieveStatus ( ) . IsDirty ) ;
74
98
75
99
Assert . True ( detachedHead . IsCurrentRepositoryHead ) ;
76
100
Assert . False ( detachedHead . IsRemote ) ;
@@ -82,6 +106,158 @@ public void CanCheckoutAnArbitraryCommit(string commitPointer)
82
106
}
83
107
}
84
108
109
+ [ Fact ]
110
+ public void CheckoutAddsMissingFilesInWorkingDirectory ( )
111
+ {
112
+ SelfCleaningDirectory scd = BuildSelfCleaningDirectory ( ) ;
113
+
114
+ using ( var repo = Repository . Init ( scd . DirectoryPath ) )
115
+ {
116
+ PopulateBasicRepository ( repo ) ;
117
+
118
+ // Remove the file in master branch
119
+ // Verify it exists after checking out otherBranch.
120
+ string fileFullPath = Path . Combine ( repo . Info . WorkingDirectory , originalFilePath ) ;
121
+ repo . Index . Remove ( fileFullPath ) ;
122
+ repo . Commit ( "2nd commit" , Constants . Signature , Constants . Signature ) ;
123
+
124
+ // Checkout other_branch
125
+ Branch otherBranch = repo . Branches [ otherBranchName ] ;
126
+ Assert . NotNull ( otherBranch ) ;
127
+ otherBranch . Checkout ( ) ;
128
+
129
+ // Verify working directory is updated
130
+ Assert . False ( repo . Index . RetrieveStatus ( ) . IsDirty ) ;
131
+ Assert . Equal ( originalFileContent , File . ReadAllText ( fileFullPath ) ) ;
132
+ }
133
+ }
134
+
135
+ [ Fact ]
136
+ public void CheckoutRemovesExtraFilesInWorkingDirectory ( )
137
+ {
138
+ SelfCleaningDirectory scd = BuildSelfCleaningDirectory ( ) ;
139
+
140
+ using ( var repo = Repository . Init ( scd . DirectoryPath ) )
141
+ {
142
+ PopulateBasicRepository ( repo ) ;
143
+
144
+ // Add extra file in master branch
145
+ // Verify it is removed after checking out otherBranch.
146
+ string newFileFullPath = Path . Combine ( repo . Info . WorkingDirectory , "b.txt" ) ;
147
+ File . WriteAllText ( newFileFullPath , "hello from master branch!\n " ) ;
148
+ repo . Index . Stage ( newFileFullPath ) ;
149
+ repo . Commit ( "2nd commit" , Constants . Signature , Constants . Signature ) ;
150
+
151
+ // Checkout other_branch
152
+ Branch otherBranch = repo . Branches [ otherBranchName ] ;
153
+ Assert . NotNull ( otherBranch ) ;
154
+ otherBranch . Checkout ( ) ;
155
+
156
+ // Verify working directory is updated
157
+ Assert . False ( repo . Index . RetrieveStatus ( ) . IsDirty ) ;
158
+ Assert . False ( File . Exists ( newFileFullPath ) ) ;
159
+ }
160
+ }
161
+
162
+ [ Fact ]
163
+ public void CheckoutUpdatesModifiedFilesInWorkingDirectory ( )
164
+ {
165
+ SelfCleaningDirectory scd = BuildSelfCleaningDirectory ( ) ;
166
+
167
+ using ( var repo = Repository . Init ( scd . DirectoryPath ) )
168
+ {
169
+ PopulateBasicRepository ( repo ) ;
170
+
171
+ // Modify file in master branch.
172
+ // Verify contents match initial commit after checking out other branch.
173
+ string fullPath = Path . Combine ( repo . Info . WorkingDirectory , originalFilePath ) ;
174
+ File . WriteAllText ( fullPath , "Update : hello from master branch!\n " ) ;
175
+ repo . Index . Stage ( fullPath ) ;
176
+ repo . Commit ( "2nd commit" , Constants . Signature , Constants . Signature ) ;
177
+
178
+ // Checkout other_branch
179
+ Branch otherBranch = repo . Branches [ otherBranchName ] ;
180
+ Assert . NotNull ( otherBranch ) ;
181
+ otherBranch . Checkout ( ) ;
182
+
183
+ // Verify working directory is updated
184
+ Assert . False ( repo . Index . RetrieveStatus ( ) . IsDirty ) ;
185
+ Assert . Equal ( originalFileContent , File . ReadAllText ( fullPath ) ) ;
186
+ }
187
+ }
188
+
189
+ [ Fact ]
190
+ public void CanForcefullyCheckoutWithStagedChanges ( )
191
+ {
192
+ TemporaryCloneOfTestRepo path = BuildTemporaryCloneOfTestRepo ( StandardTestRepoWorkingDirPath ) ;
193
+
194
+ using ( var repo = new Repository ( path . RepositoryPath ) )
195
+ {
196
+ string fileFullPath = Path . Combine ( repo . Info . WorkingDirectory , originalFilePath ) ;
197
+ Branch master = repo . Branches [ "master" ] ;
198
+ Assert . True ( master . IsCurrentRepositoryHead ) ;
199
+
200
+ // Hard reset to ensure that working directory, index, and HEAD match
201
+ repo . Reset ( ResetOptions . Hard ) ;
202
+ Assert . False ( repo . Index . RetrieveStatus ( ) . IsDirty ) ;
203
+
204
+ // Add local change
205
+ string fullPath = Path . Combine ( repo . Info . WorkingDirectory , fileFullPath ) ;
206
+ File . WriteAllText ( fullPath , originalFileContent ) ;
207
+ repo . Index . Stage ( fullPath ) ;
208
+
209
+ // Verify working directory is now dirty
210
+ Assert . True ( repo . Index . RetrieveStatus ( ) . IsDirty ) ;
211
+
212
+ // And that the new file exists
213
+ Assert . True ( File . Exists ( fileFullPath ) ) ;
214
+
215
+ // Checkout with the force option
216
+ Branch targetBranch = repo . Branches [ "i-do-numbers" ] ;
217
+ targetBranch . Checkout ( CheckoutOptions . Force , null ) ;
218
+
219
+ // Assert that target branch is checked out
220
+ Assert . True ( targetBranch . IsCurrentRepositoryHead ) ;
221
+
222
+ // And that staged change (add) is no longer preset
223
+ Assert . False ( File . Exists ( fileFullPath ) ) ;
224
+ }
225
+ }
226
+
227
+ [ Fact ]
228
+ public void CheckingOutWithMergeConflictsThrows ( )
229
+ {
230
+ SelfCleaningDirectory scd = BuildSelfCleaningDirectory ( ) ;
231
+
232
+ using ( var repo = Repository . Init ( scd . DirectoryPath ) )
233
+ {
234
+ string fullPath = Path . Combine ( repo . Info . WorkingDirectory , "a.txt" ) ;
235
+ File . WriteAllText ( fullPath , "Hello\n " ) ;
236
+ repo . Index . Stage ( fullPath ) ;
237
+ repo . Commit ( "Initial commit" , Constants . Signature , Constants . Signature ) ;
238
+
239
+ // Create 2nd branch
240
+ repo . CreateBranch ( "branch2" ) ;
241
+
242
+ // Update file in main
243
+ File . WriteAllText ( fullPath , "Hello from master!\n " ) ;
244
+ repo . Index . Stage ( fullPath ) ;
245
+ repo . Commit ( "2nd commit" , Constants . Signature , Constants . Signature ) ;
246
+
247
+ // Checkout branch2
248
+ repo . Checkout ( "branch2" ) ;
249
+ File . WriteAllText ( fullPath , "Hello From branch2!\n " ) ;
250
+
251
+ // Assert that checking out master throws
252
+ // when there are unstaged commits
253
+ Assert . Throws < MergeConflictException > ( ( ) => repo . Checkout ( "master" ) ) ;
254
+
255
+ // And when there are staged commits
256
+ repo . Index . Stage ( fullPath ) ;
257
+ Assert . Throws < MergeConflictException > ( ( ) => repo . Checkout ( "master" ) ) ;
258
+ }
259
+ }
260
+
85
261
[ Fact ]
86
262
public void CheckingOutInABareRepoThrows ( )
87
263
{
@@ -111,5 +287,53 @@ public void CheckingOutABranchWithBadParamsThrows()
111
287
Assert . Throws < ArgumentNullException > ( ( ) => repo . Checkout ( default ( string ) ) ) ;
112
288
}
113
289
}
290
+
291
+ [ Fact ]
292
+ public void CheckingOutThroughBranchCallsCheckoutProgress ( )
293
+ {
294
+ SelfCleaningDirectory scd = BuildSelfCleaningDirectory ( ) ;
295
+
296
+ using ( var repo = Repository . Init ( scd . DirectoryPath ) )
297
+ {
298
+ PopulateBasicRepository ( repo ) ;
299
+ bool wasCalled = false ;
300
+
301
+ Branch branch = repo . Branches [ otherBranchName ] ;
302
+ branch . Checkout ( CheckoutOptions . None , ( path , completed , total ) => wasCalled = true ) ;
303
+
304
+ Assert . True ( wasCalled ) ;
305
+ }
306
+ }
307
+
308
+ [ Fact ]
309
+ public void CheckingOutThroughRepositoryCallsCheckoutProgress ( )
310
+ {
311
+ SelfCleaningDirectory scd = BuildSelfCleaningDirectory ( ) ;
312
+
313
+ using ( var repo = Repository . Init ( scd . DirectoryPath ) )
314
+ {
315
+ PopulateBasicRepository ( repo ) ;
316
+ bool wasCalled = false ;
317
+
318
+ repo . Checkout ( otherBranchName , CheckoutOptions . None , ( path , completed , total ) => wasCalled = true ) ;
319
+
320
+ Assert . True ( wasCalled ) ;
321
+ }
322
+ }
323
+
324
+ /// <summary>
325
+ /// Helper method to populate a simple repository with
326
+ /// a single file and two branches.
327
+ /// </summary>
328
+ /// <param name="repo">Repository to populate</param>
329
+ private void PopulateBasicRepository ( Repository repo )
330
+ {
331
+ string fullPathFileA = Path . Combine ( repo . Info . WorkingDirectory , "a.txt" ) ;
332
+ File . WriteAllText ( fullPathFileA , originalFileContent ) ;
333
+ repo . Index . Stage ( fullPathFileA ) ;
334
+ repo . Commit ( "Initial commit" , Constants . Signature , Constants . Signature ) ;
335
+
336
+ repo . CreateBranch ( otherBranchName ) ;
337
+ }
114
338
}
115
339
}
0 commit comments