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 addRepoToClose(db2);
296
297 Git.wrap(db2).checkout().setCreateBranch(true).setName("test")
298 .setStartPoint("origin/test")
299 .setUpstreamMode(SetupUpstreamMode.TRACK).call();
300
301 assertEquals("refs/heads/test",
302 db2.exactRef(Constants.HEAD).getTarget().getName());
303 StoredConfig config = db2.getConfig();
304 assertEquals("origin", config.getString(
305 ConfigConstants.CONFIG_BRANCH_SECTION, "test",
306 ConfigConstants.CONFIG_KEY_REMOTE));
307 assertEquals("refs/heads/test", config.getString(
308 ConfigConstants.CONFIG_BRANCH_SECTION, "test",
309 ConfigConstants.CONFIG_KEY_MERGE));
310 }
311
312 @Test
313 public void testCheckoutRemoteTrackingWithoutLocalBranch() throws Exception {
314 Repository db2 = createRepositoryWithRemote();
315 addRepoToClose(db2);
316
317
318
319 Git.wrap(db2).checkout().setName("remotes/origin/test").call();
320 assertEquals("[Test.txt, mode:100644, content:Some change]",
321 indexState(db2, CONTENT));
322 }
323
324
325
326 @Test
327 public void testCheckoutOfFileWithInexistentParentDir() throws Exception {
328 File a = writeTrashFile("dir/a.txt", "A");
329 writeTrashFile("dir/b.txt", "A");
330 git.add().addFilepattern("dir/a.txt").addFilepattern("dir/b.txt")
331 .call();
332 git.commit().setMessage("Added dir").call();
333
334 File dir = new File(db.getWorkTree(), "dir");
335 FileUtils.delete(dir, FileUtils.RECURSIVE);
336
337 git.checkout().addPath("dir/a.txt").call();
338 assertTrue(a.exists());
339 }
340
341 @Test
342 public void testCheckoutOfDirectoryShouldBeRecursive() throws Exception {
343 File a = writeTrashFile("dir/a.txt", "A");
344 File b = writeTrashFile("dir/sub/b.txt", "B");
345 git.add().addFilepattern("dir").call();
346 git.commit().setMessage("Added dir").call();
347
348 write(a, "modified");
349 write(b, "modified");
350 git.checkout().addPath("dir").call();
351
352 assertThat(read(a), is("A"));
353 assertThat(read(b), is("B"));
354 }
355
356 @Test
357 public void testCheckoutAllPaths() throws Exception {
358 File a = writeTrashFile("dir/a.txt", "A");
359 File b = writeTrashFile("dir/sub/b.txt", "B");
360 git.add().addFilepattern("dir").call();
361 git.commit().setMessage("Added dir").call();
362
363 write(a, "modified");
364 write(b, "modified");
365 git.checkout().setAllPaths(true).call();
366
367 assertThat(read(a), is("A"));
368 assertThat(read(b), is("B"));
369 }
370
371 @Test
372 public void testCheckoutWithStartPoint() throws Exception {
373 File a = writeTrashFile("a.txt", "A");
374 git.add().addFilepattern("a.txt").call();
375 RevCommit first = git.commit().setMessage("Added a").call();
376
377 write(a, "other");
378 git.commit().setAll(true).setMessage("Other").call();
379
380 git.checkout().setCreateBranch(true).setName("a")
381 .setStartPoint(first.getId().getName()).call();
382
383 assertThat(read(a), is("A"));
384 }
385
386 @Test
387 public void testCheckoutWithStartPointOnlyCertainFiles() throws Exception {
388 File a = writeTrashFile("a.txt", "A");
389 File b = writeTrashFile("b.txt", "B");
390 git.add().addFilepattern("a.txt").addFilepattern("b.txt").call();
391 RevCommit first = git.commit().setMessage("First").call();
392
393 write(a, "other");
394 write(b, "other");
395 git.commit().setAll(true).setMessage("Other").call();
396
397 git.checkout().setCreateBranch(true).setName("a")
398 .setStartPoint(first.getId().getName()).addPath("a.txt").call();
399
400 assertThat(read(a), is("A"));
401 assertThat(read(b), is("other"));
402 }
403
404 @Test
405 public void testDetachedHeadOnCheckout() throws JGitInternalException,
406 IOException, GitAPIException {
407 CheckoutCommand co = git.checkout();
408 co.setName("master").call();
409
410 String commitId = db.exactRef(R_HEADS + MASTER).getObjectId().name();
411 co = git.checkout();
412 co.setName(commitId).call();
413
414 assertHeadDetached();
415 }
416
417 @Test
418 public void testUpdateSmudgedEntries() throws Exception {
419 git.branchCreate().setName("test2").call();
420 RefUpdate rup = db.updateRef(Constants.HEAD);
421 rup.link("refs/heads/test2");
422
423 File file = new File(db.getWorkTree(), "Test.txt");
424 long size = file.length();
425 Instant mTime = TimeUtil.setLastModifiedWithOffset(file.toPath(),
426 -5000L);
427
428 DirCache cache = DirCache.lock(db.getIndexFile(), db.getFS());
429 DirCacheEntry entry = cache.getEntry("Test.txt");
430 assertNotNull(entry);
431 entry.setLength(0);
432 entry.setLastModified(EPOCH);
433 cache.write();
434 assertTrue(cache.commit());
435
436 cache = DirCache.read(db.getIndexFile(), db.getFS());
437 entry = cache.getEntry("Test.txt");
438 assertNotNull(entry);
439 assertEquals(0, entry.getLength());
440 assertEquals(EPOCH, entry.getLastModifiedInstant());
441
442 Files.setLastModifiedTime(db.getIndexFile().toPath(),
443 FileTime.from(FS.DETECTED
444 .lastModifiedInstant(db.getIndexFile())
445 .minusMillis(5000L)));
446
447 assertNotNull(git.checkout().setName("test").call());
448
449 cache = DirCache.read(db.getIndexFile(), db.getFS());
450 entry = cache.getEntry("Test.txt");
451 assertNotNull(entry);
452 assertEquals(size, entry.getLength());
453 assertEquals(mTime, entry.getLastModifiedInstant());
454 }
455
456 @Test
457 public void testCheckoutOrphanBranch() throws Exception {
458 CheckoutCommand co = newOrphanBranchCommand();
459 assertCheckoutRef(co.call());
460
461 File HEAD = new File(trash, ".git/HEAD");
462 String headRef = read(HEAD);
463 assertEquals("ref: refs/heads/orphanbranch\n", headRef);
464 assertEquals(2, trash.list().length);
465
466 File heads = new File(trash, ".git/refs/heads");
467 assertEquals(2, heads.listFiles().length);
468
469 this.assertNoHead();
470 this.assertRepositoryCondition(1);
471 assertEquals(CheckoutResult.NOT_TRIED_RESULT, co.getResult());
472 }
473
474 private Repository createRepositoryWithRemote() throws IOException,
475 URISyntaxException, MalformedURLException, GitAPIException,
476 InvalidRemoteException, TransportException {
477
478 Repository db2 = createWorkRepository();
479 try (Git git2 = new Git(db2)) {
480
481 final StoredConfig config = db2.getConfig();
482 RemoteConfig remoteConfig = new RemoteConfig(config, "origin");
483 URIish uri = new URIish(db.getDirectory().toURI().toURL());
484 remoteConfig.addURI(uri);
485 remoteConfig.update(config);
486 config.save();
487
488
489 git2.fetch().setRemote("origin")
490 .setRefSpecs("+refs/heads/*:refs/remotes/origin/*").call();
491 return db2;
492 }
493 }
494
495 private CheckoutCommand newOrphanBranchCommand() {
496 return git.checkout().setOrphan(true)
497 .setName("orphanbranch");
498 }
499
500 private static void assertCheckoutRef(Ref ref) {
501 assertNotNull(ref);
502 assertEquals("refs/heads/orphanbranch", ref.getTarget().getName());
503 }
504
505 private void assertNoHead() throws IOException {
506 assertNull(db.resolve("HEAD"));
507 }
508
509 private void assertHeadDetached() throws IOException {
510 Ref head = db.exactRef(Constants.HEAD);
511 assertFalse(head.isSymbolic());
512 assertSame(head, head.getTarget());
513 }
514
515 private void assertRepositoryCondition(int files) throws GitAPIException {
516 org.eclipse.jgit.api.Status status = this.git.status().call();
517 assertFalse(status.isClean());
518 assertEquals(files, status.getAdded().size());
519 }
520
521 @Test
522 public void testCreateOrphanBranchWithStartCommit() throws Exception {
523 CheckoutCommand co = newOrphanBranchCommand();
524 Ref ref = co.setStartPoint(initialCommit).call();
525 assertCheckoutRef(ref);
526 assertEquals(2, trash.list().length);
527 this.assertNoHead();
528 this.assertRepositoryCondition(1);
529 }
530
531 @Test
532 public void testCreateOrphanBranchWithStartPoint() throws Exception {
533 CheckoutCommand co = newOrphanBranchCommand();
534 Ref ref = co.setStartPoint("HEAD^").call();
535 assertCheckoutRef(ref);
536
537 assertEquals(2, trash.list().length);
538 this.assertNoHead();
539 this.assertRepositoryCondition(1);
540 }
541
542 @Test
543 public void testInvalidRefName() throws Exception {
544 try {
545 git.checkout().setOrphan(true).setName("../invalidname").call();
546 fail("Should have failed");
547 } catch (InvalidRefNameException e) {
548
549 }
550 }
551
552 @Test
553 public void testNullRefName() throws Exception {
554 try {
555 git.checkout().setOrphan(true).setName(null).call();
556 fail("Should have failed");
557 } catch (InvalidRefNameException e) {
558
559 }
560 }
561
562 @Test
563 public void testAlreadyExists() throws Exception {
564 this.git.checkout().setCreateBranch(true).setName("orphanbranch")
565 .call();
566 this.git.checkout().setName("master").call();
567
568 try {
569 newOrphanBranchCommand().call();
570 fail("Should have failed");
571 } catch (RefAlreadyExistsException e) {
572
573 }
574 }
575
576
577
578 @Test
579 public void testCheckoutAutoCrlfTrue() throws Exception {
580 int nrOfAutoCrlfTestFiles = 200;
581
582 FileBasedConfig c = db.getConfig();
583 c.setString("core", null, "autocrlf", "true");
584 c.save();
585
586 AddCommand add = git.add();
587 for (int i = 100; i < 100 + nrOfAutoCrlfTestFiles; i++) {
588 writeTrashFile("Test_" + i + ".txt", "Hello " + i
589 + " world\nX\nYU\nJK\n");
590 add.addFilepattern("Test_" + i + ".txt");
591 }
592 fsTick(null);
593 add.call();
594 RevCommit c1 = git.commit().setMessage("add some lines").call();
595
596 add = git.add();
597 for (int i = 100; i < 100 + nrOfAutoCrlfTestFiles; i++) {
598 writeTrashFile("Test_" + i + ".txt", "Hello " + i
599 + " world\nX\nY\n");
600 add.addFilepattern("Test_" + i + ".txt");
601 }
602 fsTick(null);
603 add.call();
604 git.commit().setMessage("add more").call();
605
606 git.checkout().setName(c1.getName()).call();
607
608 boolean foundUnsmudged = false;
609 DirCache dc = db.readDirCache();
610 for (int i = 100; i < 100 + nrOfAutoCrlfTestFiles; i++) {
611 DirCacheEntry entry = dc.getEntry(
612 "Test_" + i + ".txt");
613 if (!entry.isSmudged()) {
614 foundUnsmudged = true;
615 assertEquals("unexpected file length in git index", 28,
616 entry.getLength());
617 }
618 }
619 org.junit.Assume.assumeTrue(foundUnsmudged);
620 }
621
622 @Test
623 public void testSmudgeFilter_modifyExisting() throws IOException, GitAPIException {
624 File script = writeTempFile("sed s/o/e/g");
625 StoredConfig config = git.getRepository().getConfig();
626 config.setString("filter", "lfs", "smudge",
627 "sh " + slashify(script.getPath()));
628 config.save();
629
630 writeTrashFile(".gitattributes", "*.txt filter=lfs");
631 git.add().addFilepattern(".gitattributes").call();
632 git.commit().setMessage("add filter").call();
633
634 writeTrashFile("src/a.tmp", "x");
635
636
637 writeTrashFile("src/a.txt", "x\n");
638 git.add().addFilepattern("src/a.tmp").addFilepattern("src/a.txt")
639 .call();
640 RevCommit content1 = git.commit().setMessage("add content").call();
641
642 writeTrashFile("src/a.tmp", "foo");
643 writeTrashFile("src/a.txt", "foo\n");
644 git.add().addFilepattern("src/a.tmp").addFilepattern("src/a.txt")
645 .call();
646 RevCommit content2 = git.commit().setMessage("changed content").call();
647
648 git.checkout().setName(content1.getName()).call();
649 git.checkout().setName(content2.getName()).call();
650
651 assertEquals(
652 "[.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]",
653 indexState(CONTENT));
654 assertEquals(Sets.of("src/a.txt"), git.status().call().getModified());
655 assertEquals("foo", read("src/a.tmp"));
656 assertEquals("fee\n", read("src/a.txt"));
657 }
658
659 @Test
660 public void testSmudgeFilter_createNew()
661 throws IOException, GitAPIException {
662 File script = writeTempFile("sed s/o/e/g");
663 StoredConfig config = git.getRepository().getConfig();
664 config.setString("filter", "lfs", "smudge",
665 "sh " + slashify(script.getPath()));
666 config.save();
667
668 writeTrashFile("foo", "foo");
669 git.add().addFilepattern("foo").call();
670 RevCommit initial = git.commit().setMessage("initial").call();
671
672 writeTrashFile(".gitattributes", "*.txt filter=lfs");
673 git.add().addFilepattern(".gitattributes").call();
674 git.commit().setMessage("add filter").call();
675
676 writeTrashFile("src/a.tmp", "foo");
677
678
679 writeTrashFile("src/a.txt", "foo\n");
680 git.add().addFilepattern("src/a.tmp").addFilepattern("src/a.txt")
681 .call();
682 RevCommit content = git.commit().setMessage("added content").call();
683
684 git.checkout().setName(initial.getName()).call();
685 git.checkout().setName(content.getName()).call();
686
687 assertEquals(
688 "[.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]",
689 indexState(CONTENT));
690 assertEquals("foo", read("src/a.tmp"));
691 assertEquals("fee\n", read("src/a.txt"));
692 }
693
694 @Test
695 public void testSmudgeFilter_deleteFileAndRestoreFromCommit()
696 throws IOException, GitAPIException {
697 File script = writeTempFile("sed s/o/e/g");
698 StoredConfig config = git.getRepository().getConfig();
699 config.setString("filter", "lfs", "smudge",
700 "sh " + slashify(script.getPath()));
701 config.save();
702
703 writeTrashFile("foo", "foo");
704 git.add().addFilepattern("foo").call();
705 git.commit().setMessage("initial").call();
706
707 writeTrashFile(".gitattributes", "*.txt filter=lfs");
708 git.add().addFilepattern(".gitattributes").call();
709 git.commit().setMessage("add filter").call();
710
711 writeTrashFile("src/a.tmp", "foo");
712
713
714 writeTrashFile("src/a.txt", "foo\n");
715 git.add().addFilepattern("src/a.tmp").addFilepattern("src/a.txt")
716 .call();
717 RevCommit content = git.commit().setMessage("added content").call();
718
719 deleteTrashFile("src/a.txt");
720 git.checkout().setStartPoint(content.getName()).addPath("src/a.txt")
721 .call();
722
723 assertEquals(
724 "[.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]",
725 indexState(CONTENT));
726 assertEquals("foo", read("src/a.tmp"));
727 assertEquals("fee\n", read("src/a.txt"));
728 }
729
730 @Test
731 public void testSmudgeFilter_deleteFileAndRestoreFromIndex()
732 throws IOException, GitAPIException {
733 File script = writeTempFile("sed s/o/e/g");
734 StoredConfig config = git.getRepository().getConfig();
735 config.setString("filter", "lfs", "smudge",
736 "sh " + slashify(script.getPath()));
737 config.save();
738
739 writeTrashFile("foo", "foo");
740 git.add().addFilepattern("foo").call();
741 git.commit().setMessage("initial").call();
742
743 writeTrashFile(".gitattributes", "*.txt filter=lfs");
744 git.add().addFilepattern(".gitattributes").call();
745 git.commit().setMessage("add filter").call();
746
747 writeTrashFile("src/a.tmp", "foo");
748
749
750 writeTrashFile("src/a.txt", "foo\n");
751 git.add().addFilepattern("src/a.tmp").addFilepattern("src/a.txt")
752 .call();
753 git.commit().setMessage("added content").call();
754
755 deleteTrashFile("src/a.txt");
756 git.checkout().addPath("src/a.txt").call();
757
758 assertEquals(
759 "[.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]",
760 indexState(CONTENT));
761 assertEquals("foo", read("src/a.tmp"));
762 assertEquals("fee\n", read("src/a.txt"));
763 }
764
765 @Test
766 public void testSmudgeFilter_deleteFileAndCreateBranchAndRestoreFromCommit()
767 throws IOException, GitAPIException {
768 File script = writeTempFile("sed s/o/e/g");
769 StoredConfig config = git.getRepository().getConfig();
770 config.setString("filter", "lfs", "smudge",
771 "sh " + slashify(script.getPath()));
772 config.save();
773
774 writeTrashFile("foo", "foo");
775 git.add().addFilepattern("foo").call();
776 git.commit().setMessage("initial").call();
777
778 writeTrashFile(".gitattributes", "*.txt filter=lfs");
779 git.add().addFilepattern(".gitattributes").call();
780 git.commit().setMessage("add filter").call();
781
782 writeTrashFile("src/a.tmp", "foo");
783
784
785 writeTrashFile("src/a.txt", "foo\n");
786 git.add().addFilepattern("src/a.tmp").addFilepattern("src/a.txt")
787 .call();
788 RevCommit content = git.commit().setMessage("added content").call();
789
790 deleteTrashFile("src/a.txt");
791 git.checkout().setName("newBranch").setCreateBranch(true)
792 .setStartPoint(content).addPath("src/a.txt").call();
793
794 assertEquals(
795 "[.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]",
796 indexState(CONTENT));
797 assertEquals("foo", read("src/a.tmp"));
798 assertEquals("fee\n", read("src/a.txt"));
799 }
800
801 @Test
802 public void testSmudgeAndClean() throws Exception {
803 File clean_filter = writeTempFile("sed s/V1/@version/g");
804 File smudge_filter = writeTempFile("sed s/@version/V1/g");
805
806 try (Git git2 = new Git(db)) {
807 StoredConfig config = git.getRepository().getConfig();
808 config.setString("filter", "lfs", "smudge",
809 "sh " + slashify(smudge_filter.getPath()));
810 config.setString("filter", "lfs", "clean",
811 "sh " + slashify(clean_filter.getPath()));
812 config.setBoolean("filter", "lfs", "useJGitBuiltin", true);
813 config.save();
814 writeTrashFile(".gitattributes", "filterTest.txt filter=lfs");
815 git2.add().addFilepattern(".gitattributes").call();
816 git2.commit().setMessage("add attributes").call();
817
818 fsTick(writeTrashFile("filterTest.txt", "hello world, V1\n"));
819 git2.add().addFilepattern("filterTest.txt").call();
820 RevCommit one = git2.commit().setMessage("add filterText.txt").call();
821 assertEquals(
822 "[.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]",
823 indexState(CONTENT));
824
825 fsTick(writeTrashFile("filterTest.txt", "bon giorno world, V1\n"));
826 git2.add().addFilepattern("filterTest.txt").call();
827 RevCommit two = git2.commit().setMessage("modified filterTest.txt").call();
828
829 assertTrue(git2.status().call().isClean());
830 assertEquals(
831 "[.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]",
832 indexState(CONTENT));
833
834 git2.checkout().setName(one.getName()).call();
835 assertTrue(git2.status().call().isClean());
836 assertEquals(
837 "[.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]",
838 indexState(CONTENT));
839 assertEquals("hello world, V1\n", read("filterTest.txt"));
840
841 git2.checkout().setName(two.getName()).call();
842 assertTrue(git2.status().call().isClean());
843 assertEquals(
844 "[.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]",
845 indexState(CONTENT));
846 assertEquals("bon giorno world, V1\n", read("filterTest.txt"));
847 }
848 }
849
850 @Test
851 public void testNonDeletableFilesOnWindows()
852 throws GitAPIException, IOException {
853
854 org.junit.Assume.assumeTrue(SystemReader.getInstance().isWindows());
855 writeTrashFile("toBeModified.txt", "a");
856 writeTrashFile("toBeDeleted.txt", "a");
857 git.add().addFilepattern(".").call();
858 RevCommit addFiles = git.commit().setMessage("add more files").call();
859
860 git.rm().setCached(false).addFilepattern("Test.txt")
861 .addFilepattern("toBeDeleted.txt").call();
862 writeTrashFile("toBeModified.txt", "b");
863 writeTrashFile("toBeCreated.txt", "a");
864 git.add().addFilepattern(".").call();
865 RevCommit crudCommit = git.commit().setMessage("delete, modify, add")
866 .call();
867 git.checkout().setName(addFiles.getName()).call();
868 try ( FileInputStream fis=new FileInputStream(new File(db.getWorkTree(), "Test.txt")) ) {
869 CheckoutCommand coCommand = git.checkout();
870 coCommand.setName(crudCommit.getName()).call();
871 CheckoutResult result = coCommand.getResult();
872 assertEquals(Status.NONDELETED, result.getStatus());
873 assertEquals("[toBeDeleted.txt]",
874 result.getRemovedList().toString());
875 assertEquals("[toBeCreated.txt, toBeModified.txt]",
876 result.getModifiedList().toString());
877 assertEquals("[Test.txt]", result.getUndeletedList().toString());
878 assertTrue(result.getConflictList().isEmpty());
879 }
880 }
881
882 private File writeTempFile(String body) throws IOException {
883 File f = File.createTempFile("CheckoutCommandTest_", "");
884 JGitTestUtil.write(f, body);
885 return f;
886 }
887 }