1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44 package org.eclipse.jgit.api;
45
46 import static org.hamcrest.CoreMatchers.is;
47 import static org.hamcrest.MatcherAssert.assertThat;
48 import static org.junit.Assert.assertEquals;
49 import static org.junit.Assert.assertFalse;
50 import static org.junit.Assert.assertNotNull;
51 import static org.junit.Assert.assertNull;
52 import static org.junit.Assert.assertSame;
53 import static org.junit.Assert.assertTrue;
54 import static org.junit.Assert.fail;
55
56 import java.io.File;
57 import java.io.FileInputStream;
58 import java.io.IOException;
59 import java.net.MalformedURLException;
60 import java.net.URISyntaxException;
61
62 import org.eclipse.jgit.api.CheckoutResult.Status;
63 import org.eclipse.jgit.api.CreateBranchCommand.SetupUpstreamMode;
64 import org.eclipse.jgit.api.errors.GitAPIException;
65 import org.eclipse.jgit.api.errors.InvalidRefNameException;
66 import org.eclipse.jgit.api.errors.InvalidRemoteException;
67 import org.eclipse.jgit.api.errors.JGitInternalException;
68 import org.eclipse.jgit.api.errors.RefAlreadyExistsException;
69 import org.eclipse.jgit.api.errors.RefNotFoundException;
70 import org.eclipse.jgit.api.errors.TransportException;
71 import org.eclipse.jgit.dircache.DirCache;
72 import org.eclipse.jgit.dircache.DirCacheEntry;
73 import org.eclipse.jgit.junit.RepositoryTestCase;
74 import org.eclipse.jgit.lib.ConfigConstants;
75 import org.eclipse.jgit.lib.Constants;
76 import org.eclipse.jgit.lib.Ref;
77 import org.eclipse.jgit.lib.RefUpdate;
78 import org.eclipse.jgit.lib.Repository;
79 import org.eclipse.jgit.lib.StoredConfig;
80 import org.eclipse.jgit.revwalk.RevCommit;
81 import org.eclipse.jgit.storage.file.FileBasedConfig;
82 import org.eclipse.jgit.transport.RefSpec;
83 import org.eclipse.jgit.transport.RemoteConfig;
84 import org.eclipse.jgit.transport.URIish;
85 import org.eclipse.jgit.util.FileUtils;
86 import org.junit.Before;
87 import org.junit.Test;
88
89 public class CheckoutCommandTest extends RepositoryTestCase {
90 private Git git;
91
92 RevCommit initialCommit;
93
94 RevCommit secondCommit;
95
96 @Override
97 @Before
98 public void setUp() throws Exception {
99 super.setUp();
100 git = new Git(db);
101
102 writeTrashFile("Test.txt", "Hello world");
103 git.add().addFilepattern("Test.txt").call();
104 initialCommit = git.commit().setMessage("Initial commit").call();
105
106
107 git.branchCreate().setName("test").call();
108 RefUpdate rup = db.updateRef(Constants.HEAD);
109 rup.link("refs/heads/test");
110
111
112 writeTrashFile("Test.txt", "Some change");
113 git.add().addFilepattern("Test.txt").call();
114 secondCommit = git.commit().setMessage("Second commit").call();
115 }
116
117 @Test
118 public void testSimpleCheckout() throws Exception {
119 git.checkout().setName("test").call();
120 }
121
122 @Test
123 public void testCheckout() throws Exception {
124 git.checkout().setName("test").call();
125 assertEquals("[Test.txt, mode:100644, content:Some change]",
126 indexState(CONTENT));
127 Ref result = git.checkout().setName("master").call();
128 assertEquals("[Test.txt, mode:100644, content:Hello world]",
129 indexState(CONTENT));
130 assertEquals("refs/heads/master", result.getName());
131 assertEquals("refs/heads/master", git.getRepository().getFullBranch());
132 }
133
134 @Test
135 public void testCreateBranchOnCheckout() throws Exception {
136 git.checkout().setCreateBranch(true).setName("test2").call();
137 assertNotNull(db.getRef("test2"));
138 }
139
140 @Test
141 public void testCheckoutToNonExistingBranch() throws GitAPIException {
142 try {
143 git.checkout().setName("badbranch").call();
144 fail("Should have failed");
145 } catch (RefNotFoundException e) {
146
147 }
148 }
149
150 @Test
151 public void testCheckoutWithConflict() {
152 CheckoutCommand co = git.checkout();
153 try {
154 writeTrashFile("Test.txt", "Another change");
155 assertEquals(Status.NOT_TRIED, co.getResult().getStatus());
156 co.setName("master").call();
157 fail("Should have failed");
158 } catch (Exception e) {
159 assertEquals(Status.CONFLICTS, co.getResult().getStatus());
160 assertTrue(co.getResult().getConflictList().contains("Test.txt"));
161 }
162 }
163
164 @Test
165 public void testCheckoutWithNonDeletedFiles() throws Exception {
166 File testFile = writeTrashFile("temp", "");
167 FileInputStream fis = new FileInputStream(testFile);
168 try {
169 FileUtils.delete(testFile);
170 return;
171 } catch (IOException e) {
172
173
174 } finally {
175 fis.close();
176 }
177 FileUtils.delete(testFile);
178 CheckoutCommand co = git.checkout();
179
180 testFile = new File(db.getWorkTree(), "Test.txt");
181 assertTrue(testFile.exists());
182 FileUtils.delete(testFile);
183 assertFalse(testFile.exists());
184 git.add().addFilepattern("Test.txt");
185 git.commit().setMessage("Delete Test.txt").setAll(true).call();
186 git.checkout().setName("master").call();
187 assertTrue(testFile.exists());
188
189 fis = new FileInputStream(testFile);
190 try {
191 assertEquals(Status.NOT_TRIED, co.getResult().getStatus());
192 co.setName("test").call();
193 assertTrue(testFile.exists());
194 assertEquals(Status.NONDELETED, co.getResult().getStatus());
195 assertTrue(co.getResult().getUndeletedList().contains("Test.txt"));
196 } finally {
197 fis.close();
198 }
199 }
200
201 @Test
202 public void testCheckoutCommit() throws Exception {
203 Ref result = git.checkout().setName(initialCommit.name()).call();
204 assertEquals("[Test.txt, mode:100644, content:Hello world]",
205 indexState(CONTENT));
206 assertNull(result);
207 assertEquals(initialCommit.name(), git.getRepository().getFullBranch());
208 }
209
210 @Test
211 public void testCheckoutLightweightTag() throws Exception {
212 git.tag().setAnnotated(false).setName("test-tag")
213 .setObjectId(initialCommit).call();
214 Ref result = git.checkout().setName("test-tag").call();
215
216 assertNull(result);
217 assertEquals(initialCommit.getId(), db.resolve(Constants.HEAD));
218 assertHeadDetached();
219 }
220
221 @Test
222 public void testCheckoutAnnotatedTag() throws Exception {
223 git.tag().setAnnotated(true).setName("test-tag")
224 .setObjectId(initialCommit).call();
225 Ref result = git.checkout().setName("test-tag").call();
226
227 assertNull(result);
228 assertEquals(initialCommit.getId(), db.resolve(Constants.HEAD));
229 assertHeadDetached();
230 }
231
232 @Test
233 public void testCheckoutRemoteTrackingWithUpstream() throws Exception {
234 Repository db2 = createRepositoryWithRemote();
235
236 Git.wrap(db2).checkout().setCreateBranch(true).setName("test")
237 .setStartPoint("origin/test")
238 .setUpstreamMode(SetupUpstreamMode.TRACK).call();
239
240 assertEquals("refs/heads/test", db2.getRef(Constants.HEAD).getTarget()
241 .getName());
242 StoredConfig config = db2.getConfig();
243 assertEquals("origin", config.getString(
244 ConfigConstants.CONFIG_BRANCH_SECTION, "test",
245 ConfigConstants.CONFIG_KEY_REMOTE));
246 assertEquals("refs/heads/test", config.getString(
247 ConfigConstants.CONFIG_BRANCH_SECTION, "test",
248 ConfigConstants.CONFIG_KEY_MERGE));
249 }
250
251 @Test
252 public void testCheckoutRemoteTrackingWithoutLocalBranch() throws Exception {
253 Repository db2 = createRepositoryWithRemote();
254
255
256
257 Git.wrap(db2).checkout().setName("remotes/origin/test").call();
258 assertEquals("[Test.txt, mode:100644, content:Some change]",
259 indexState(db2, CONTENT));
260 }
261
262
263
264 @Test
265 public void testCheckoutOfFileWithInexistentParentDir() throws Exception {
266 File a = writeTrashFile("dir/a.txt", "A");
267 writeTrashFile("dir/b.txt", "A");
268 git.add().addFilepattern("dir/a.txt").addFilepattern("dir/b.txt")
269 .call();
270 git.commit().setMessage("Added dir").call();
271
272 File dir = new File(db.getWorkTree(), "dir");
273 FileUtils.delete(dir, FileUtils.RECURSIVE);
274
275 git.checkout().addPath("dir/a.txt").call();
276 assertTrue(a.exists());
277 }
278
279 @Test
280 public void testCheckoutOfDirectoryShouldBeRecursive() throws Exception {
281 File a = writeTrashFile("dir/a.txt", "A");
282 File b = writeTrashFile("dir/sub/b.txt", "B");
283 git.add().addFilepattern("dir").call();
284 git.commit().setMessage("Added dir").call();
285
286 write(a, "modified");
287 write(b, "modified");
288 git.checkout().addPath("dir").call();
289
290 assertThat(read(a), is("A"));
291 assertThat(read(b), is("B"));
292 }
293
294 @Test
295 public void testCheckoutAllPaths() throws Exception {
296 File a = writeTrashFile("dir/a.txt", "A");
297 File b = writeTrashFile("dir/sub/b.txt", "B");
298 git.add().addFilepattern("dir").call();
299 git.commit().setMessage("Added dir").call();
300
301 write(a, "modified");
302 write(b, "modified");
303 git.checkout().setAllPaths(true).call();
304
305 assertThat(read(a), is("A"));
306 assertThat(read(b), is("B"));
307 }
308
309 @Test
310 public void testCheckoutWithStartPoint() throws Exception {
311 File a = writeTrashFile("a.txt", "A");
312 git.add().addFilepattern("a.txt").call();
313 RevCommit first = git.commit().setMessage("Added a").call();
314
315 write(a, "other");
316 git.commit().setAll(true).setMessage("Other").call();
317
318 git.checkout().setCreateBranch(true).setName("a")
319 .setStartPoint(first.getId().getName()).call();
320
321 assertThat(read(a), is("A"));
322 }
323
324 @Test
325 public void testCheckoutWithStartPointOnlyCertainFiles() throws Exception {
326 File a = writeTrashFile("a.txt", "A");
327 File b = writeTrashFile("b.txt", "B");
328 git.add().addFilepattern("a.txt").addFilepattern("b.txt").call();
329 RevCommit first = git.commit().setMessage("First").call();
330
331 write(a, "other");
332 write(b, "other");
333 git.commit().setAll(true).setMessage("Other").call();
334
335 git.checkout().setCreateBranch(true).setName("a")
336 .setStartPoint(first.getId().getName()).addPath("a.txt").call();
337
338 assertThat(read(a), is("A"));
339 assertThat(read(b), is("other"));
340 }
341
342 @Test
343 public void testDetachedHeadOnCheckout() throws JGitInternalException,
344 IOException, GitAPIException {
345 CheckoutCommand co = git.checkout();
346 co.setName("master").call();
347
348 String commitId = db.getRef(Constants.MASTER).getObjectId().name();
349 co = git.checkout();
350 co.setName(commitId).call();
351
352 assertHeadDetached();
353 }
354
355 @Test
356 public void testUpdateSmudgedEntries() throws Exception {
357 git.branchCreate().setName("test2").call();
358 RefUpdate rup = db.updateRef(Constants.HEAD);
359 rup.link("refs/heads/test2");
360
361 File file = new File(db.getWorkTree(), "Test.txt");
362 long size = file.length();
363 long mTime = file.lastModified() - 5000L;
364 assertTrue(file.setLastModified(mTime));
365
366 DirCache cache = DirCache.lock(db.getIndexFile(), db.getFS());
367 DirCacheEntry entry = cache.getEntry("Test.txt");
368 assertNotNull(entry);
369 entry.setLength(0);
370 entry.setLastModified(0);
371 cache.write();
372 assertTrue(cache.commit());
373
374 cache = DirCache.read(db.getIndexFile(), db.getFS());
375 entry = cache.getEntry("Test.txt");
376 assertNotNull(entry);
377 assertEquals(0, entry.getLength());
378 assertEquals(0, entry.getLastModified());
379
380 db.getIndexFile().setLastModified(
381 db.getIndexFile().lastModified() - 5000);
382
383 assertNotNull(git.checkout().setName("test").call());
384
385 cache = DirCache.read(db.getIndexFile(), db.getFS());
386 entry = cache.getEntry("Test.txt");
387 assertNotNull(entry);
388 assertEquals(size, entry.getLength());
389 assertEquals(mTime, entry.getLastModified());
390 }
391
392 @Test
393 public void testCheckoutOrphanBranch() throws Exception {
394 CheckoutCommand co = newOrphanBranchCommand();
395 assertCheckoutRef(co.call());
396
397 File HEAD = new File(trash, ".git/HEAD");
398 String headRef = read(HEAD);
399 assertEquals("ref: refs/heads/orphanbranch\n", headRef);
400 assertEquals(2, trash.list().length);
401
402 File heads = new File(trash, ".git/refs/heads");
403 assertEquals(2, heads.listFiles().length);
404
405 this.assertNoHead();
406 this.assertRepositoryCondition(1);
407 assertEquals(CheckoutResult.NOT_TRIED_RESULT, co.getResult());
408 }
409
410 private Repository createRepositoryWithRemote() throws IOException,
411 URISyntaxException, MalformedURLException, GitAPIException,
412 InvalidRemoteException, TransportException {
413
414 Repository db2 = createWorkRepository();
415 Git git2 = new Git(db2);
416
417
418 final StoredConfig config = db2.getConfig();
419 RemoteConfig remoteConfig = new RemoteConfig(config, "origin");
420 URIish uri = new URIish(db.getDirectory().toURI().toURL());
421 remoteConfig.addURI(uri);
422 remoteConfig.update(config);
423 config.save();
424
425
426 RefSpec spec = new RefSpec("+refs/heads/*:refs/remotes/origin/*");
427 git2.fetch().setRemote("origin").setRefSpecs(spec).call();
428 return db2;
429 }
430
431 private CheckoutCommand newOrphanBranchCommand() {
432 return git.checkout().setOrphan(true)
433 .setName("orphanbranch");
434 }
435
436 private static void assertCheckoutRef(Ref ref) {
437 assertNotNull(ref);
438 assertEquals("refs/heads/orphanbranch", ref.getTarget().getName());
439 }
440
441 private void assertNoHead() throws IOException {
442 assertNull(db.resolve("HEAD"));
443 }
444
445 private void assertHeadDetached() throws IOException {
446 Ref head = db.getRef(Constants.HEAD);
447 assertFalse(head.isSymbolic());
448 assertSame(head, head.getTarget());
449 }
450
451 private void assertRepositoryCondition(int files) throws GitAPIException {
452 org.eclipse.jgit.api.Status status = this.git.status().call();
453 assertFalse(status.isClean());
454 assertEquals(files, status.getAdded().size());
455 }
456
457 @Test
458 public void testCreateOrphanBranchWithStartCommit() throws Exception {
459 CheckoutCommand co = newOrphanBranchCommand();
460 Ref ref = co.setStartPoint(initialCommit).call();
461 assertCheckoutRef(ref);
462 assertEquals(2, trash.list().length);
463 this.assertNoHead();
464 this.assertRepositoryCondition(1);
465 }
466
467 @Test
468 public void testCreateOrphanBranchWithStartPoint() throws Exception {
469 CheckoutCommand co = newOrphanBranchCommand();
470 Ref ref = co.setStartPoint("HEAD^").call();
471 assertCheckoutRef(ref);
472
473 assertEquals(2, trash.list().length);
474 this.assertNoHead();
475 this.assertRepositoryCondition(1);
476 }
477
478 @Test
479 public void testInvalidRefName() throws Exception {
480 try {
481 git.checkout().setOrphan(true).setName("../invalidname").call();
482 fail("Should have failed");
483 } catch (InvalidRefNameException e) {
484
485 }
486 }
487
488 @Test
489 public void testNullRefName() throws Exception {
490 try {
491 git.checkout().setOrphan(true).setName(null).call();
492 fail("Should have failed");
493 } catch (InvalidRefNameException e) {
494
495 }
496 }
497
498 @Test
499 public void testAlreadyExists() throws Exception {
500 this.git.checkout().setCreateBranch(true).setName("orphanbranch")
501 .call();
502 this.git.checkout().setName("master").call();
503
504 try {
505 newOrphanBranchCommand().call();
506 fail("Should have failed");
507 } catch (RefAlreadyExistsException e) {
508
509 }
510 }
511
512
513
514 @Test
515 public void testCheckoutAutoCrlfTrue() throws Exception {
516 int nrOfAutoCrlfTestFiles = 200;
517
518 FileBasedConfig c = db.getConfig();
519 c.setString("core", null, "autocrlf", "true");
520 c.save();
521
522 AddCommand add = git.add();
523 for (int i = 100; i < 100 + nrOfAutoCrlfTestFiles; i++) {
524 writeTrashFile("Test_" + i + ".txt", "Hello " + i
525 + " world\nX\nYU\nJK\n");
526 add.addFilepattern("Test_" + i + ".txt");
527 }
528 fsTick(null);
529 add.call();
530 RevCommit c1 = git.commit().setMessage("add some lines").call();
531
532 add = git.add();
533 for (int i = 100; i < 100 + nrOfAutoCrlfTestFiles; i++) {
534 writeTrashFile("Test_" + i + ".txt", "Hello " + i
535 + " world\nX\nY\n");
536 add.addFilepattern("Test_" + i + ".txt");
537 }
538 fsTick(null);
539 add.call();
540 git.commit().setMessage("add more").call();
541
542 git.checkout().setName(c1.getName()).call();
543
544 boolean foundUnsmudged = false;
545 DirCache dc = db.readDirCache();
546 for (int i = 100; i < 100 + nrOfAutoCrlfTestFiles; i++) {
547 DirCacheEntry entry = dc.getEntry(
548 "Test_" + i + ".txt");
549 if (!entry.isSmudged()) {
550 foundUnsmudged = true;
551 assertEquals("unexpected file length in git index", 28,
552 entry.getLength());
553 }
554 }
555 org.junit.Assume.assumeTrue(foundUnsmudged);
556 }
557 }