1
2
3
4
5
6
7
8
9
10
11 package org.eclipse.jgit.api;
12
13 import static java.time.Instant.EPOCH;
14 import static org.eclipse.jgit.lib.Constants.MASTER;
15 import static org.eclipse.jgit.lib.Constants.R_HEADS;
16 import static org.hamcrest.CoreMatchers.is;
17 import static org.hamcrest.MatcherAssert.assertThat;
18 import static org.junit.Assert.assertEquals;
19 import static org.junit.Assert.assertFalse;
20 import static org.junit.Assert.assertNotNull;
21 import static org.junit.Assert.assertNull;
22 import static org.junit.Assert.assertSame;
23 import static org.junit.Assert.assertTrue;
24 import static org.junit.Assert.fail;
25
26 import java.io.File;
27 import java.io.FileInputStream;
28 import java.io.IOException;
29 import java.net.MalformedURLException;
30 import java.net.URISyntaxException;
31 import java.nio.file.Files;
32 import java.nio.file.attribute.FileTime;
33 import java.time.Instant;
34
35 import org.eclipse.jgit.api.CheckoutResult.Status;
36 import org.eclipse.jgit.api.CreateBranchCommand.SetupUpstreamMode;
37 import org.eclipse.jgit.api.errors.CheckoutConflictException;
38 import org.eclipse.jgit.api.errors.GitAPIException;
39 import org.eclipse.jgit.api.errors.InvalidRefNameException;
40 import org.eclipse.jgit.api.errors.InvalidRemoteException;
41 import org.eclipse.jgit.api.errors.JGitInternalException;
42 import org.eclipse.jgit.api.errors.RefAlreadyExistsException;
43 import org.eclipse.jgit.api.errors.RefNotFoundException;
44 import org.eclipse.jgit.api.errors.TransportException;
45 import org.eclipse.jgit.dircache.DirCache;
46 import org.eclipse.jgit.dircache.DirCacheEntry;
47 import org.eclipse.jgit.junit.JGitTestUtil;
48 import org.eclipse.jgit.junit.RepositoryTestCase;
49 import org.eclipse.jgit.junit.time.TimeUtil;
50 import org.eclipse.jgit.lfs.BuiltinLFS;
51 import org.eclipse.jgit.lib.ConfigConstants;
52 import org.eclipse.jgit.lib.Constants;
53 import org.eclipse.jgit.lib.Ref;
54 import org.eclipse.jgit.lib.RefUpdate;
55 import org.eclipse.jgit.lib.Repository;
56 import org.eclipse.jgit.lib.Sets;
57 import org.eclipse.jgit.lib.StoredConfig;
58 import org.eclipse.jgit.revwalk.RevCommit;
59 import org.eclipse.jgit.storage.file.FileBasedConfig;
60 import org.eclipse.jgit.transport.RemoteConfig;
61 import org.eclipse.jgit.transport.URIish;
62 import org.eclipse.jgit.util.FS;
63 import org.eclipse.jgit.util.FileUtils;
64 import org.eclipse.jgit.util.SystemReader;
65 import org.junit.Before;
66 import org.junit.Test;
67
68 public class CheckoutCommandTest extends RepositoryTestCase {
69 private Git git;
70
71 RevCommit initialCommit;
72
73 RevCommit secondCommit;
74
75 @Override
76 @Before
77 public void setUp() throws Exception {
78 BuiltinLFS.register();
79 super.setUp();
80 git = new Git(db);
81
82 writeTrashFile("Test.txt", "Hello world");
83 git.add().addFilepattern("Test.txt").call();
84 initialCommit = git.commit().setMessage("Initial commit").call();
85
86
87 git.branchCreate().setName("test").call();
88 RefUpdate rup = db.updateRef(Constants.HEAD);
89 rup.link("refs/heads/test");
90
91
92 writeTrashFile("Test.txt", "Some change");
93 git.add().addFilepattern("Test.txt").call();
94 secondCommit = git.commit().setMessage("Second commit").call();
95 }
96
97 @Test
98 public void testSimpleCheckout() throws Exception {
99 git.checkout().setName("test").call();
100 }
101
102 @Test
103 public void testCheckout() throws Exception {
104 git.checkout().setName("test").call();
105 assertEquals("[Test.txt, mode:100644, content:Some change]",
106 indexState(CONTENT));
107 Ref result = git.checkout().setName("master").call();
108 assertEquals("[Test.txt, mode:100644, content:Hello world]",
109 indexState(CONTENT));
110 assertEquals("refs/heads/master", result.getName());
111 assertEquals("refs/heads/master", git.getRepository().getFullBranch());
112 }
113
114 @Test
115 public void testCheckoutForced() throws Exception {
116 writeTrashFile("Test.txt", "Garbage");
117 try {
118 git.checkout().setName("master").call().getObjectId();
119 fail("Expected CheckoutConflictException didn't occur");
120 } catch (CheckoutConflictException e) {
121
122 }
123 assertEquals(initialCommit.getId(), git.checkout().setName("master")
124 .setForced(true).call().getObjectId());
125 }
126
127 @Test
128 public void testCheckoutForced_deleteFileAndRestore() throws Exception {
129 File testFile = new File(db.getWorkTree(), "Test.txt");
130 assertTrue(testFile.exists());
131
132 assertEquals("test", git.getRepository().getBranch());
133 FileUtils.delete(testFile);
134 assertFalse(testFile.exists());
135
136 assertEquals(initialCommit.getId(), git.checkout().setName("master")
137 .setForced(true).call().getObjectId());
138 assertTrue(testFile.exists());
139
140 assertEquals("master", git.getRepository().getBranch());
141 FileUtils.delete(testFile);
142 assertFalse(testFile.exists());
143
144 assertEquals(initialCommit.getId(), git.checkout().setName("master")
145 .setForced(true).call().getObjectId());
146 assertTrue(testFile.exists());
147 }
148
149 @Test
150 public void testCheckoutForcedNoChangeNotInIndex() throws Exception {
151 git.checkout().setCreateBranch(true).setName("test2").call();
152 File f = writeTrashFile("NewFile.txt", "New file");
153 git.add().addFilepattern("NewFile.txt").call();
154 git.commit().setMessage("New file created").call();
155 git.checkout().setName("test").call();
156 assertFalse("NewFile.txt should not exist", f.exists());
157 writeTrashFile("NewFile.txt", "New file");
158 git.add().addFilepattern("NewFile.txt").call();
159 git.commit().setMessage("New file created again with same content")
160 .call();
161
162
163 git.rm().addFilepattern("NewFile.txt").setCached(true).call();
164 assertTrue("NewFile.txt should exist", f.isFile());
165 git.checkout().setForced(true).setName("test2").call();
166 assertTrue("NewFile.txt should exist", f.isFile());
167 assertEquals(Constants.R_HEADS + "test2", git.getRepository()
168 .exactRef(Constants.HEAD).getTarget().getName());
169 assertTrue("Force checkout should have undone git rm --cached",
170 git.status().call().isClean());
171 }
172
173 @Test
174 public void testCheckoutNoChangeNotInIndex() throws Exception {
175 git.checkout().setCreateBranch(true).setName("test2").call();
176 File f = writeTrashFile("NewFile.txt", "New file");
177 git.add().addFilepattern("NewFile.txt").call();
178 git.commit().setMessage("New file created").call();
179 git.checkout().setName("test").call();
180 assertFalse("NewFile.txt should not exist", f.exists());
181 writeTrashFile("NewFile.txt", "New file");
182 git.add().addFilepattern("NewFile.txt").call();
183 git.commit().setMessage("New file created again with same content")
184 .call();
185
186
187 git.rm().addFilepattern("NewFile.txt").setCached(true).call();
188 assertTrue("NewFile.txt should exist", f.isFile());
189 git.checkout().setName("test2").call();
190 assertTrue("NewFile.txt should exist", f.isFile());
191 assertEquals(Constants.R_HEADS + "test2", git.getRepository()
192 .exactRef(Constants.HEAD).getTarget().getName());
193 org.eclipse.jgit.api.Status status = git.status().call();
194 assertEquals("[NewFile.txt]", status.getRemoved().toString());
195 assertEquals("[NewFile.txt]", status.getUntracked().toString());
196 }
197
198 @Test
199 public void testCreateBranchOnCheckout() throws Exception {
200 git.checkout().setCreateBranch(true).setName("test2").call();
201 assertNotNull(db.exactRef("refs/heads/test2"));
202 }
203
204 @Test
205 public void testCheckoutToNonExistingBranch() throws GitAPIException {
206 try {
207 git.checkout().setName("badbranch").call();
208 fail("Should have failed");
209 } catch (RefNotFoundException e) {
210
211 }
212 }
213
214 @Test
215 public void testCheckoutWithConflict() throws Exception {
216 CheckoutCommand co = git.checkout();
217 try {
218 writeTrashFile("Test.txt", "Another change");
219 assertEquals(Status.NOT_TRIED, co.getResult().getStatus());
220 co.setName("master").call();
221 fail("Should have failed");
222 } catch (Exception e) {
223 assertEquals(Status.CONFLICTS, co.getResult().getStatus());
224 assertTrue(co.getResult().getConflictList().contains("Test.txt"));
225 }
226 git.checkout().setName("master").setForced(true).call();
227 assertThat(read("Test.txt"), is("Hello world"));
228 }
229
230 @Test
231 public void testCheckoutWithNonDeletedFiles() throws Exception {
232 File testFile = writeTrashFile("temp", "");
233 try (FileInputStream fis = new FileInputStream(testFile)) {
234 FileUtils.delete(testFile);
235 return;
236 } catch (IOException e) {
237
238
239 }
240 FileUtils.delete(testFile);
241 CheckoutCommand co = git.checkout();
242
243 testFile = new File(db.getWorkTree(), "Test.txt");
244 assertTrue(testFile.exists());
245 FileUtils.delete(testFile);
246 assertFalse(testFile.exists());
247 git.add().addFilepattern("Test.txt");
248 git.commit().setMessage("Delete Test.txt").setAll(true).call();
249 git.checkout().setName("master").call();
250 assertTrue(testFile.exists());
251
252 try (FileInputStream fis = new FileInputStream(testFile)) {
253 assertEquals(Status.NOT_TRIED, co.getResult().getStatus());
254 co.setName("test").call();
255 assertTrue(testFile.exists());
256 assertEquals(Status.NONDELETED, co.getResult().getStatus());
257 assertTrue(co.getResult().getUndeletedList().contains("Test.txt"));
258 }
259 }
260
261 @Test
262 public void testCheckoutCommit() throws Exception {
263 Ref result = git.checkout().setName(initialCommit.name()).call();
264 assertEquals("[Test.txt, mode:100644, content:Hello world]",
265 indexState(CONTENT));
266 assertNull(result);
267 assertEquals(initialCommit.name(), git.getRepository().getFullBranch());
268 }
269
270 @Test
271 public void testCheckoutLightweightTag() throws Exception {
272 git.tag().setAnnotated(false).setName("test-tag")
273 .setObjectId(initialCommit).call();
274 Ref result = git.checkout().setName("test-tag").call();
275
276 assertNull(result);
277 assertEquals(initialCommit.getId(), db.resolve(Constants.HEAD));
278 assertHeadDetached();
279 }
280
281 @Test
282 public void testCheckoutAnnotatedTag() throws Exception {
283 git.tag().setAnnotated(true).setName("test-tag")
284 .setObjectId(initialCommit).call();
285 Ref result = git.checkout().setName("test-tag").call();
286
287 assertNull(result);
288 assertEquals(initialCommit.getId(), db.resolve(Constants.HEAD));
289 assertHeadDetached();
290 }
291
292 @Test
293 public void testCheckoutRemoteTrackingWithUpstream() throws Exception {
294 Repository db2 = createRepositoryWithRemote();
295
296 Git.wrap(db2).checkout().setCreateBranch(true).setName("test")
297 .setStartPoint("origin/test")
298 .setUpstreamMode(SetupUpstreamMode.TRACK).call();
299
300 assertEquals("refs/heads/test",
301 db2.exactRef(Constants.HEAD).getTarget().getName());
302 StoredConfig config = db2.getConfig();
303 assertEquals("origin", config.getString(
304 ConfigConstants.CONFIG_BRANCH_SECTION, "test",
305 ConfigConstants.CONFIG_KEY_REMOTE));
306 assertEquals("refs/heads/test", config.getString(
307 ConfigConstants.CONFIG_BRANCH_SECTION, "test",
308 ConfigConstants.CONFIG_KEY_MERGE));
309 }
310
311 @Test
312 public void testCheckoutRemoteTrackingWithoutLocalBranch() throws Exception {
313 Repository db2 = createRepositoryWithRemote();
314
315
316
317 Git.wrap(db2).checkout().setName("remotes/origin/test").call();
318 assertEquals("[Test.txt, mode:100644, content:Some change]",
319 indexState(db2, CONTENT));
320 }
321
322
323
324 @Test
325 public void testCheckoutOfFileWithInexistentParentDir() throws Exception {
326 File a = writeTrashFile("dir/a.txt", "A");
327 writeTrashFile("dir/b.txt", "A");
328 git.add().addFilepattern("dir/a.txt").addFilepattern("dir/b.txt")
329 .call();
330 git.commit().setMessage("Added dir").call();
331
332 File dir = new File(db.getWorkTree(), "dir");
333 FileUtils.delete(dir, FileUtils.RECURSIVE);
334
335 git.checkout().addPath("dir/a.txt").call();
336 assertTrue(a.exists());
337 }
338
339 @Test
340 public void testCheckoutOfDirectoryShouldBeRecursive() throws Exception {
341 File a = writeTrashFile("dir/a.txt", "A");
342 File b = writeTrashFile("dir/sub/b.txt", "B");
343 git.add().addFilepattern("dir").call();
344 git.commit().setMessage("Added dir").call();
345
346 write(a, "modified");
347 write(b, "modified");
348 git.checkout().addPath("dir").call();
349
350 assertThat(read(a), is("A"));
351 assertThat(read(b), is("B"));
352 }
353
354 @Test
355 public void testCheckoutAllPaths() throws Exception {
356 File a = writeTrashFile("dir/a.txt", "A");
357 File b = writeTrashFile("dir/sub/b.txt", "B");
358 git.add().addFilepattern("dir").call();
359 git.commit().setMessage("Added dir").call();
360
361 write(a, "modified");
362 write(b, "modified");
363 git.checkout().setAllPaths(true).call();
364
365 assertThat(read(a), is("A"));
366 assertThat(read(b), is("B"));
367 }
368
369 @Test
370 public void testCheckoutWithStartPoint() throws Exception {
371 File a = writeTrashFile("a.txt", "A");
372 git.add().addFilepattern("a.txt").call();
373 RevCommit first = git.commit().setMessage("Added a").call();
374
375 write(a, "other");
376 git.commit().setAll(true).setMessage("Other").call();
377
378 git.checkout().setCreateBranch(true).setName("a")
379 .setStartPoint(first.getId().getName()).call();
380
381 assertThat(read(a), is("A"));
382 }
383
384 @Test
385 public void testCheckoutWithStartPointOnlyCertainFiles() throws Exception {
386 File a = writeTrashFile("a.txt", "A");
387 File b = writeTrashFile("b.txt", "B");
388 git.add().addFilepattern("a.txt").addFilepattern("b.txt").call();
389 RevCommit first = git.commit().setMessage("First").call();
390
391 write(a, "other");
392 write(b, "other");
393 git.commit().setAll(true).setMessage("Other").call();
394
395 git.checkout().setCreateBranch(true).setName("a")
396 .setStartPoint(first.getId().getName()).addPath("a.txt").call();
397
398 assertThat(read(a), is("A"));
399 assertThat(read(b), is("other"));
400 }
401
402 @Test
403 public void testDetachedHeadOnCheckout() throws JGitInternalException,
404 IOException, GitAPIException {
405 CheckoutCommand co = git.checkout();
406 co.setName("master").call();
407
408 String commitId = db.exactRef(R_HEADS + MASTER).getObjectId().name();
409 co = git.checkout();
410 co.setName(commitId).call();
411
412 assertHeadDetached();
413 }
414
415 @Test
416 public void testUpdateSmudgedEntries() throws Exception {
417 git.branchCreate().setName("test2").call();
418 RefUpdate rup = db.updateRef(Constants.HEAD);
419 rup.link("refs/heads/test2");
420
421 File file = new File(db.getWorkTree(), "Test.txt");
422 long size = file.length();
423 Instant mTime = TimeUtil.setLastModifiedWithOffset(file.toPath(),
424 -5000L);
425
426 DirCache cache = DirCache.lock(db.getIndexFile(), db.getFS());
427 DirCacheEntry entry = cache.getEntry("Test.txt");
428 assertNotNull(entry);
429 entry.setLength(0);
430 entry.setLastModified(EPOCH);
431 cache.write();
432 assertTrue(cache.commit());
433
434 cache = DirCache.read(db.getIndexFile(), db.getFS());
435 entry = cache.getEntry("Test.txt");
436 assertNotNull(entry);
437 assertEquals(0, entry.getLength());
438 assertEquals(EPOCH, entry.getLastModifiedInstant());
439
440 Files.setLastModifiedTime(db.getIndexFile().toPath(),
441 FileTime.from(FS.DETECTED
442 .lastModifiedInstant(db.getIndexFile())
443 .minusMillis(5000L)));
444
445 assertNotNull(git.checkout().setName("test").call());
446
447 cache = DirCache.read(db.getIndexFile(), db.getFS());
448 entry = cache.getEntry("Test.txt");
449 assertNotNull(entry);
450 assertEquals(size, entry.getLength());
451 assertEquals(mTime, entry.getLastModifiedInstant());
452 }
453
454 @Test
455 public void testCheckoutOrphanBranch() throws Exception {
456 CheckoutCommand co = newOrphanBranchCommand();
457 assertCheckoutRef(co.call());
458
459 File HEAD = new File(trash, ".git/HEAD");
460 String headRef = read(HEAD);
461 assertEquals("ref: refs/heads/orphanbranch\n", headRef);
462 assertEquals(2, trash.list().length);
463
464 File heads = new File(trash, ".git/refs/heads");
465 assertEquals(2, heads.listFiles().length);
466
467 this.assertNoHead();
468 this.assertRepositoryCondition(1);
469 assertEquals(CheckoutResult.NOT_TRIED_RESULT, co.getResult());
470 }
471
472 private Repository createRepositoryWithRemote() throws IOException,
473 URISyntaxException, MalformedURLException, GitAPIException,
474 InvalidRemoteException, TransportException {
475
476 Repository db2 = createWorkRepository();
477 try (Git git2 = new Git(db2)) {
478
479 final StoredConfig config = db2.getConfig();
480 RemoteConfig remoteConfig = new RemoteConfig(config, "origin");
481 URIish uri = new URIish(db.getDirectory().toURI().toURL());
482 remoteConfig.addURI(uri);
483 remoteConfig.update(config);
484 config.save();
485
486
487 git2.fetch().setRemote("origin")
488 .setRefSpecs("+refs/heads/*:refs/remotes/origin/*").call();
489 return db2;
490 }
491 }
492
493 private CheckoutCommand newOrphanBranchCommand() {
494 return git.checkout().setOrphan(true)
495 .setName("orphanbranch");
496 }
497
498 private static void assertCheckoutRef(Ref ref) {
499 assertNotNull(ref);
500 assertEquals("refs/heads/orphanbranch", ref.getTarget().getName());
501 }
502
503 private void assertNoHead() throws IOException {
504 assertNull(db.resolve("HEAD"));
505 }
506
507 private void assertHeadDetached() throws IOException {
508 Ref head = db.exactRef(Constants.HEAD);
509 assertFalse(head.isSymbolic());
510 assertSame(head, head.getTarget());
511 }
512
513 private void assertRepositoryCondition(int files) throws GitAPIException {
514 org.eclipse.jgit.api.Status status = this.git.status().call();
515 assertFalse(status.isClean());
516 assertEquals(files, status.getAdded().size());
517 }
518
519 @Test
520 public void testCreateOrphanBranchWithStartCommit() throws Exception {
521 CheckoutCommand co = newOrphanBranchCommand();
522 Ref ref = co.setStartPoint(initialCommit).call();
523 assertCheckoutRef(ref);
524 assertEquals(2, trash.list().length);
525 this.assertNoHead();
526 this.assertRepositoryCondition(1);
527 }
528
529 @Test
530 public void testCreateOrphanBranchWithStartPoint() throws Exception {
531 CheckoutCommand co = newOrphanBranchCommand();
532 Ref ref = co.setStartPoint("HEAD^").call();
533 assertCheckoutRef(ref);
534
535 assertEquals(2, trash.list().length);
536 this.assertNoHead();
537 this.assertRepositoryCondition(1);
538 }
539
540 @Test
541 public void testInvalidRefName() throws Exception {
542 try {
543 git.checkout().setOrphan(true).setName("../invalidname").call();
544 fail("Should have failed");
545 } catch (InvalidRefNameException e) {
546
547 }
548 }
549
550 @Test
551 public void testNullRefName() throws Exception {
552 try {
553 git.checkout().setOrphan(true).setName(null).call();
554 fail("Should have failed");
555 } catch (InvalidRefNameException e) {
556
557 }
558 }
559
560 @Test
561 public void testAlreadyExists() throws Exception {
562 this.git.checkout().setCreateBranch(true).setName("orphanbranch")
563 .call();
564 this.git.checkout().setName("master").call();
565
566 try {
567 newOrphanBranchCommand().call();
568 fail("Should have failed");
569 } catch (RefAlreadyExistsException e) {
570
571 }
572 }
573
574
575
576 @Test
577 public void testCheckoutAutoCrlfTrue() throws Exception {
578 int nrOfAutoCrlfTestFiles = 200;
579
580 FileBasedConfig c = db.getConfig();
581 c.setString("core", null, "autocrlf", "true");
582 c.save();
583
584 AddCommand add = git.add();
585 for (int i = 100; i < 100 + nrOfAutoCrlfTestFiles; i++) {
586 writeTrashFile("Test_" + i + ".txt", "Hello " + i
587 + " world\nX\nYU\nJK\n");
588 add.addFilepattern("Test_" + i + ".txt");
589 }
590 fsTick(null);
591 add.call();
592 RevCommit c1 = git.commit().setMessage("add some lines").call();
593
594 add = git.add();
595 for (int i = 100; i < 100 + nrOfAutoCrlfTestFiles; i++) {
596 writeTrashFile("Test_" + i + ".txt", "Hello " + i
597 + " world\nX\nY\n");
598 add.addFilepattern("Test_" + i + ".txt");
599 }
600 fsTick(null);
601 add.call();
602 git.commit().setMessage("add more").call();
603
604 git.checkout().setName(c1.getName()).call();
605
606 boolean foundUnsmudged = false;
607 DirCache dc = db.readDirCache();
608 for (int i = 100; i < 100 + nrOfAutoCrlfTestFiles; i++) {
609 DirCacheEntry entry = dc.getEntry(
610 "Test_" + i + ".txt");
611 if (!entry.isSmudged()) {
612 foundUnsmudged = true;
613 assertEquals("unexpected file length in git index", 28,
614 entry.getLength());
615 }
616 }
617 org.junit.Assume.assumeTrue(foundUnsmudged);
618 }
619
620 @Test
621 public void testSmudgeFilter_modifyExisting() throws IOException, GitAPIException {
622 File script = writeTempFile("sed s/o/e/g");
623 StoredConfig config = git.getRepository().getConfig();
624 config.setString("filter", "lfs", "smudge",
625 "sh " + slashify(script.getPath()));
626 config.save();
627
628 writeTrashFile(".gitattributes", "*.txt filter=lfs");
629 git.add().addFilepattern(".gitattributes").call();
630 git.commit().setMessage("add filter").call();
631
632 writeTrashFile("src/a.tmp", "x");
633
634
635 writeTrashFile("src/a.txt", "x\n");
636 git.add().addFilepattern("src/a.tmp").addFilepattern("src/a.txt")
637 .call();
638 RevCommit content1 = git.commit().setMessage("add content").call();
639
640 writeTrashFile("src/a.tmp", "foo");
641 writeTrashFile("src/a.txt", "foo\n");
642 git.add().addFilepattern("src/a.tmp").addFilepattern("src/a.txt")
643 .call();
644 RevCommit content2 = git.commit().setMessage("changed content").call();
645
646 git.checkout().setName(content1.getName()).call();
647 git.checkout().setName(content2.getName()).call();
648
649 assertEquals(
650 "[.gitattributes, mode:100644, content:*.txt filter=lfs][Test.txt, mode:100644, content:Some change][src/a.tmp, mode:100644, content:foo][src/a.txt, mode:100644, content:foo\n]",
651 indexState(CONTENT));
652 assertEquals(Sets.of("src/a.txt"), git.status().call().getModified());
653 assertEquals("foo", read("src/a.tmp"));
654 assertEquals("fee\n", read("src/a.txt"));
655 }
656
657 @Test
658 public void testSmudgeFilter_createNew()
659 throws IOException, GitAPIException {
660 File script = writeTempFile("sed s/o/e/g");
661 StoredConfig config = git.getRepository().getConfig();
662 config.setString("filter", "lfs", "smudge",
663 "sh " + slashify(script.getPath()));
664 config.save();
665
666 writeTrashFile("foo", "foo");
667 git.add().addFilepattern("foo").call();
668 RevCommit initial = git.commit().setMessage("initial").call();
669
670 writeTrashFile(".gitattributes", "*.txt filter=lfs");
671 git.add().addFilepattern(".gitattributes").call();
672 git.commit().setMessage("add filter").call();
673
674 writeTrashFile("src/a.tmp", "foo");
675
676
677 writeTrashFile("src/a.txt", "foo\n");
678 git.add().addFilepattern("src/a.tmp").addFilepattern("src/a.txt")
679 .call();
680 RevCommit content = git.commit().setMessage("added content").call();
681
682 git.checkout().setName(initial.getName()).call();
683 git.checkout().setName(content.getName()).call();
684
685 assertEquals(
686 "[.gitattributes, mode:100644, content:*.txt filter=lfs][Test.txt, mode:100644, content:Some change][foo, mode:100644, content:foo][src/a.tmp, mode:100644, content:foo][src/a.txt, mode:100644, content:foo\n]",
687 indexState(CONTENT));
688 assertEquals("foo", read("src/a.tmp"));
689 assertEquals("fee\n", read("src/a.txt"));
690 }
691
692 @Test
693 public void testSmudgeFilter_deleteFileAndRestoreFromCommit()
694 throws IOException, GitAPIException {
695 File script = writeTempFile("sed s/o/e/g");
696 StoredConfig config = git.getRepository().getConfig();
697 config.setString("filter", "lfs", "smudge",
698 "sh " + slashify(script.getPath()));
699 config.save();
700
701 writeTrashFile("foo", "foo");
702 git.add().addFilepattern("foo").call();
703 git.commit().setMessage("initial").call();
704
705 writeTrashFile(".gitattributes", "*.txt filter=lfs");
706 git.add().addFilepattern(".gitattributes").call();
707 git.commit().setMessage("add filter").call();
708
709 writeTrashFile("src/a.tmp", "foo");
710
711
712 writeTrashFile("src/a.txt", "foo\n");
713 git.add().addFilepattern("src/a.tmp").addFilepattern("src/a.txt")
714 .call();
715 RevCommit content = git.commit().setMessage("added content").call();
716
717 deleteTrashFile("src/a.txt");
718 git.checkout().setStartPoint(content.getName()).addPath("src/a.txt")
719 .call();
720
721 assertEquals(
722 "[.gitattributes, mode:100644, content:*.txt filter=lfs][Test.txt, mode:100644, content:Some change][foo, mode:100644, content:foo][src/a.tmp, mode:100644, content:foo][src/a.txt, mode:100644, content:foo\n]",
723 indexState(CONTENT));
724 assertEquals("foo", read("src/a.tmp"));
725 assertEquals("fee\n", read("src/a.txt"));
726 }
727
728 @Test
729 public void testSmudgeFilter_deleteFileAndRestoreFromIndex()
730 throws IOException, GitAPIException {
731 File script = writeTempFile("sed s/o/e/g");
732 StoredConfig config = git.getRepository().getConfig();
733 config.setString("filter", "lfs", "smudge",
734 "sh " + slashify(script.getPath()));
735 config.save();
736
737 writeTrashFile("foo", "foo");
738 git.add().addFilepattern("foo").call();
739 git.commit().setMessage("initial").call();
740
741 writeTrashFile(".gitattributes", "*.txt filter=lfs");
742 git.add().addFilepattern(".gitattributes").call();
743 git.commit().setMessage("add filter").call();
744
745 writeTrashFile("src/a.tmp", "foo");
746
747
748 writeTrashFile("src/a.txt", "foo\n");
749 git.add().addFilepattern("src/a.tmp").addFilepattern("src/a.txt")
750 .call();
751 git.commit().setMessage("added content").call();
752
753 deleteTrashFile("src/a.txt");
754 git.checkout().addPath("src/a.txt").call();
755
756 assertEquals(
757 "[.gitattributes, mode:100644, content:*.txt filter=lfs][Test.txt, mode:100644, content:Some change][foo, mode:100644, content:foo][src/a.tmp, mode:100644, content:foo][src/a.txt, mode:100644, content:foo\n]",
758 indexState(CONTENT));
759 assertEquals("foo", read("src/a.tmp"));
760 assertEquals("fee\n", read("src/a.txt"));
761 }
762
763 @Test
764 public void testSmudgeFilter_deleteFileAndCreateBranchAndRestoreFromCommit()
765 throws IOException, GitAPIException {
766 File script = writeTempFile("sed s/o/e/g");
767 StoredConfig config = git.getRepository().getConfig();
768 config.setString("filter", "lfs", "smudge",
769 "sh " + slashify(script.getPath()));
770 config.save();
771
772 writeTrashFile("foo", "foo");
773 git.add().addFilepattern("foo").call();
774 git.commit().setMessage("initial").call();
775
776 writeTrashFile(".gitattributes", "*.txt filter=lfs");
777 git.add().addFilepattern(".gitattributes").call();
778 git.commit().setMessage("add filter").call();
779
780 writeTrashFile("src/a.tmp", "foo");
781
782
783 writeTrashFile("src/a.txt", "foo\n");
784 git.add().addFilepattern("src/a.tmp").addFilepattern("src/a.txt")
785 .call();
786 RevCommit content = git.commit().setMessage("added content").call();
787
788 deleteTrashFile("src/a.txt");
789 git.checkout().setName("newBranch").setCreateBranch(true)
790 .setStartPoint(content).addPath("src/a.txt").call();
791
792 assertEquals(
793 "[.gitattributes, mode:100644, content:*.txt filter=lfs][Test.txt, mode:100644, content:Some change][foo, mode:100644, content:foo][src/a.tmp, mode:100644, content:foo][src/a.txt, mode:100644, content:foo\n]",
794 indexState(CONTENT));
795 assertEquals("foo", read("src/a.tmp"));
796 assertEquals("fee\n", read("src/a.txt"));
797 }
798
799 @Test
800 public void testSmudgeAndClean() throws Exception {
801 File clean_filter = writeTempFile("sed s/V1/@version/g");
802 File smudge_filter = writeTempFile("sed s/@version/V1/g");
803
804 try (Git git2 = new Git(db)) {
805 StoredConfig config = git.getRepository().getConfig();
806 config.setString("filter", "lfs", "smudge",
807 "sh " + slashify(smudge_filter.getPath()));
808 config.setString("filter", "lfs", "clean",
809 "sh " + slashify(clean_filter.getPath()));
810 config.setBoolean("filter", "lfs", "useJGitBuiltin", true);
811 config.save();
812 writeTrashFile(".gitattributes", "filterTest.txt filter=lfs");
813 git2.add().addFilepattern(".gitattributes").call();
814 git2.commit().setMessage("add attributes").call();
815
816 fsTick(writeTrashFile("filterTest.txt", "hello world, V1\n"));
817 git2.add().addFilepattern("filterTest.txt").call();
818 RevCommit one = git2.commit().setMessage("add filterText.txt").call();
819 assertEquals(
820 "[.gitattributes, mode:100644, content:filterTest.txt filter=lfs][Test.txt, mode:100644, content:Some change][filterTest.txt, mode:100644, content:version https://git-lfs.github.com/spec/v1\noid sha256:7bd5d32e5c494354aa4c2473a1306d0ce7b52cc3bffeb342c03cd517ef8cf8da\nsize 16\n]",
821 indexState(CONTENT));
822
823 fsTick(writeTrashFile("filterTest.txt", "bon giorno world, V1\n"));
824 git2.add().addFilepattern("filterTest.txt").call();
825 RevCommit two = git2.commit().setMessage("modified filterTest.txt").call();
826
827 assertTrue(git2.status().call().isClean());
828 assertEquals(
829 "[.gitattributes, mode:100644, content:filterTest.txt filter=lfs][Test.txt, mode:100644, content:Some change][filterTest.txt, mode:100644, content:version https://git-lfs.github.com/spec/v1\noid sha256:087148cccf53b0049c56475c1595113c9da4b638997c3489af8ac7108d51ef13\nsize 21\n]",
830 indexState(CONTENT));
831
832 git2.checkout().setName(one.getName()).call();
833 assertTrue(git2.status().call().isClean());
834 assertEquals(
835 "[.gitattributes, mode:100644, content:filterTest.txt filter=lfs][Test.txt, mode:100644, content:Some change][filterTest.txt, mode:100644, content:version https://git-lfs.github.com/spec/v1\noid sha256:7bd5d32e5c494354aa4c2473a1306d0ce7b52cc3bffeb342c03cd517ef8cf8da\nsize 16\n]",
836 indexState(CONTENT));
837 assertEquals("hello world, V1\n", read("filterTest.txt"));
838
839 git2.checkout().setName(two.getName()).call();
840 assertTrue(git2.status().call().isClean());
841 assertEquals(
842 "[.gitattributes, mode:100644, content:filterTest.txt filter=lfs][Test.txt, mode:100644, content:Some change][filterTest.txt, mode:100644, content:version https://git-lfs.github.com/spec/v1\noid sha256:087148cccf53b0049c56475c1595113c9da4b638997c3489af8ac7108d51ef13\nsize 21\n]",
843 indexState(CONTENT));
844 assertEquals("bon giorno world, V1\n", read("filterTest.txt"));
845 }
846 }
847
848 @Test
849 public void testNonDeletableFilesOnWindows()
850 throws GitAPIException, IOException {
851
852 org.junit.Assume.assumeTrue(SystemReader.getInstance().isWindows());
853 writeTrashFile("toBeModified.txt", "a");
854 writeTrashFile("toBeDeleted.txt", "a");
855 git.add().addFilepattern(".").call();
856 RevCommit addFiles = git.commit().setMessage("add more files").call();
857
858 git.rm().setCached(false).addFilepattern("Test.txt")
859 .addFilepattern("toBeDeleted.txt").call();
860 writeTrashFile("toBeModified.txt", "b");
861 writeTrashFile("toBeCreated.txt", "a");
862 git.add().addFilepattern(".").call();
863 RevCommit crudCommit = git.commit().setMessage("delete, modify, add")
864 .call();
865 git.checkout().setName(addFiles.getName()).call();
866 try ( FileInputStream fis=new FileInputStream(new File(db.getWorkTree(), "Test.txt")) ) {
867 CheckoutCommand coCommand = git.checkout();
868 coCommand.setName(crudCommit.getName()).call();
869 CheckoutResult result = coCommand.getResult();
870 assertEquals(Status.NONDELETED, result.getStatus());
871 assertEquals("[Test.txt, toBeDeleted.txt]",
872 result.getRemovedList().toString());
873 assertEquals("[toBeCreated.txt, toBeModified.txt]",
874 result.getModifiedList().toString());
875 assertEquals("[Test.txt]", result.getUndeletedList().toString());
876 assertTrue(result.getConflictList().isEmpty());
877 }
878 }
879
880 private File writeTempFile(String body) throws IOException {
881 File f = File.createTempFile("CheckoutCommandTest_", "");
882 JGitTestUtil.write(f, body);
883 return f;
884 }
885 }