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