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