1
2
3
4
5
6
7
8
9
10 package org.eclipse.jgit.api;
11
12 import static org.junit.Assert.assertEquals;
13 import static org.junit.Assert.assertNotEquals;
14 import static org.junit.Assert.assertNotNull;
15 import static org.junit.Assert.assertNull;
16 import static org.junit.Assert.assertSame;
17 import static org.junit.Assert.assertTrue;
18 import static org.junit.Assert.fail;
19 import static org.junit.Assume.assumeTrue;
20
21 import java.io.File;
22 import java.util.Date;
23 import java.util.List;
24 import java.util.TimeZone;
25 import java.util.concurrent.atomic.AtomicInteger;
26
27 import org.eclipse.jgit.api.CherryPickResult.CherryPickStatus;
28 import org.eclipse.jgit.api.errors.CanceledException;
29 import org.eclipse.jgit.api.errors.EmptyCommitException;
30 import org.eclipse.jgit.api.errors.WrongRepositoryStateException;
31 import org.eclipse.jgit.diff.DiffEntry;
32 import org.eclipse.jgit.dircache.DirCache;
33 import org.eclipse.jgit.dircache.DirCacheBuilder;
34 import org.eclipse.jgit.dircache.DirCacheEntry;
35 import org.eclipse.jgit.junit.RepositoryTestCase;
36 import org.eclipse.jgit.junit.time.TimeUtil;
37 import org.eclipse.jgit.lib.CommitBuilder;
38 import org.eclipse.jgit.lib.ConfigConstants;
39 import org.eclipse.jgit.lib.Constants;
40 import org.eclipse.jgit.lib.FileMode;
41 import org.eclipse.jgit.lib.GpgSigner;
42 import org.eclipse.jgit.lib.ObjectId;
43 import org.eclipse.jgit.lib.PersonIdent;
44 import org.eclipse.jgit.lib.RefUpdate;
45 import org.eclipse.jgit.lib.RefUpdate.Result;
46 import org.eclipse.jgit.lib.ReflogEntry;
47 import org.eclipse.jgit.lib.Repository;
48 import org.eclipse.jgit.lib.StoredConfig;
49 import org.eclipse.jgit.revwalk.RevCommit;
50 import org.eclipse.jgit.storage.file.FileBasedConfig;
51 import org.eclipse.jgit.submodule.SubmoduleWalk;
52 import org.eclipse.jgit.transport.CredentialsProvider;
53 import org.eclipse.jgit.treewalk.TreeWalk;
54 import org.eclipse.jgit.treewalk.filter.TreeFilter;
55 import org.eclipse.jgit.util.FS;
56 import org.junit.Ignore;
57 import org.junit.Test;
58
59
60
61
62 public class CommitCommandTest extends RepositoryTestCase {
63
64 @Test
65 public void testExecutableRetention() throws Exception {
66 StoredConfig config = db.getConfig();
67 config.setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null,
68 ConfigConstants.CONFIG_KEY_FILEMODE, true);
69 config.save();
70
71 FS executableFs = new FS() {
72
73 @Override
74 public boolean supportsExecute() {
75 return true;
76 }
77
78 @Override
79 public boolean setExecute(File f, boolean canExec) {
80 return true;
81 }
82
83 @Override
84 public ProcessBuilder runInShell(String cmd, String[] args) {
85 return null;
86 }
87
88 @Override
89 public boolean retryFailedLockFileCommit() {
90 return false;
91 }
92
93 @Override
94 public FS newInstance() {
95 return this;
96 }
97
98 @Override
99 protected File discoverGitExe() {
100 return null;
101 }
102
103 @Override
104 public boolean canExecute(File f) {
105 return true;
106 }
107
108 @Override
109 public boolean isCaseSensitive() {
110 return true;
111 }
112 };
113
114 Git git = Git.open(db.getDirectory(), executableFs);
115 String path = "a.txt";
116 writeTrashFile(path, "content");
117 git.add().addFilepattern(path).call();
118 RevCommit commit1 = git.commit().setMessage("commit").call();
119 try (TreeWalk walk = TreeWalk.forPath(db, path, commit1.getTree())) {
120 assertNotNull(walk);
121 assertEquals(FileMode.EXECUTABLE_FILE, walk.getFileMode(0));
122 }
123
124 FS nonExecutableFs = new FS() {
125
126 @Override
127 public boolean supportsExecute() {
128 return false;
129 }
130
131 @Override
132 public boolean setExecute(File f, boolean canExec) {
133 return false;
134 }
135
136 @Override
137 public ProcessBuilder runInShell(String cmd, String[] args) {
138 return null;
139 }
140
141 @Override
142 public boolean retryFailedLockFileCommit() {
143 return false;
144 }
145
146 @Override
147 public FS newInstance() {
148 return this;
149 }
150
151 @Override
152 protected File discoverGitExe() {
153 return null;
154 }
155
156 @Override
157 public boolean canExecute(File f) {
158 return false;
159 }
160
161 @Override
162 public boolean isCaseSensitive() {
163 return true;
164 }
165 };
166
167 config = db.getConfig();
168 config.setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null,
169 ConfigConstants.CONFIG_KEY_FILEMODE, false);
170 config.save();
171
172 Git git2 = Git.open(db.getDirectory(), nonExecutableFs);
173 writeTrashFile(path, "content2");
174 RevCommit commit2 = git2.commit().setOnly(path).setMessage("commit2")
175 .call();
176 try (TreeWalk walk = TreeWalk.forPath(db, path, commit2.getTree())) {
177 assertNotNull(walk);
178 assertEquals(FileMode.EXECUTABLE_FILE, walk.getFileMode(0));
179 }
180 }
181
182 @Test
183 public void commitNewSubmodule() throws Exception {
184 try (Git git = new Git(db)) {
185 writeTrashFile("file.txt", "content");
186 git.add().addFilepattern("file.txt").call();
187 RevCommit commit = git.commit().setMessage("create file").call();
188
189 SubmoduleAddCommand command = new SubmoduleAddCommand(db);
190 String path = "sub";
191 command.setPath(path);
192 String uri = db.getDirectory().toURI().toString();
193 command.setURI(uri);
194 Repository repo = command.call();
195 assertNotNull(repo);
196 addRepoToClose(repo);
197
198 try (SubmoduleWalk generator = SubmoduleWalk.forIndex(db)) {
199 assertTrue(generator.next());
200 assertEquals(path, generator.getPath());
201 assertEquals(commit, generator.getObjectId());
202 assertEquals(uri, generator.getModulesUrl());
203 assertEquals(path, generator.getModulesPath());
204 assertEquals(uri, generator.getConfigUrl());
205 try (Repository subModRepo = generator.getRepository()) {
206 assertNotNull(subModRepo);
207 }
208 }
209 assertEquals(commit, repo.resolve(Constants.HEAD));
210
211 RevCommit submoduleCommit = git.commit().setMessage("submodule add")
212 .setOnly(path).call();
213 assertNotNull(submoduleCommit);
214 try (TreeWalk walk = new TreeWalk(db)) {
215 walk.addTree(commit.getTree());
216 walk.addTree(submoduleCommit.getTree());
217 walk.setFilter(TreeFilter.ANY_DIFF);
218 List<DiffEntry> diffs = DiffEntry.scan(walk);
219 assertEquals(1, diffs.size());
220 DiffEntry subDiff = diffs.get(0);
221 assertEquals(FileMode.MISSING, subDiff.getOldMode());
222 assertEquals(FileMode.GITLINK, subDiff.getNewMode());
223 assertEquals(ObjectId.zeroId(), subDiff.getOldId().toObjectId());
224 assertEquals(commit, subDiff.getNewId().toObjectId());
225 assertEquals(path, subDiff.getNewPath());
226 }
227 }
228 }
229
230 @Test
231 public void commitSubmoduleUpdate() throws Exception {
232 try (Git git = new Git(db)) {
233 writeTrashFile("file.txt", "content");
234 git.add().addFilepattern("file.txt").call();
235 RevCommit commit = git.commit().setMessage("create file").call();
236 writeTrashFile("file.txt", "content2");
237 git.add().addFilepattern("file.txt").call();
238 RevCommit commit2 = git.commit().setMessage("edit file").call();
239
240 SubmoduleAddCommand command = new SubmoduleAddCommand(db);
241 String path = "sub";
242 command.setPath(path);
243 String uri = db.getDirectory().toURI().toString();
244 command.setURI(uri);
245 Repository repo = command.call();
246 assertNotNull(repo);
247 addRepoToClose(repo);
248
249 try (SubmoduleWalk generator = SubmoduleWalk.forIndex(db)) {
250 assertTrue(generator.next());
251 assertEquals(path, generator.getPath());
252 assertEquals(commit2, generator.getObjectId());
253 assertEquals(uri, generator.getModulesUrl());
254 assertEquals(path, generator.getModulesPath());
255 assertEquals(uri, generator.getConfigUrl());
256 try (Repository subModRepo = generator.getRepository()) {
257 assertNotNull(subModRepo);
258 }
259 }
260 assertEquals(commit2, repo.resolve(Constants.HEAD));
261
262 RevCommit submoduleAddCommit = git.commit().setMessage("submodule add")
263 .setOnly(path).call();
264 assertNotNull(submoduleAddCommit);
265
266 RefUpdate update = repo.updateRef(Constants.HEAD);
267 update.setNewObjectId(commit);
268 assertEquals(Result.FORCED, update.forceUpdate());
269
270 RevCommit submoduleEditCommit = git.commit()
271 .setMessage("submodule add").setOnly(path).call();
272 assertNotNull(submoduleEditCommit);
273 try (TreeWalk walk = new TreeWalk(db)) {
274 walk.addTree(submoduleAddCommit.getTree());
275 walk.addTree(submoduleEditCommit.getTree());
276 walk.setFilter(TreeFilter.ANY_DIFF);
277 List<DiffEntry> diffs = DiffEntry.scan(walk);
278 assertEquals(1, diffs.size());
279 DiffEntry subDiff = diffs.get(0);
280 assertEquals(FileMode.GITLINK, subDiff.getOldMode());
281 assertEquals(FileMode.GITLINK, subDiff.getNewMode());
282 assertEquals(commit2, subDiff.getOldId().toObjectId());
283 assertEquals(commit, subDiff.getNewId().toObjectId());
284 assertEquals(path, subDiff.getNewPath());
285 assertEquals(path, subDiff.getOldPath());
286 }
287 }
288 }
289
290 @Ignore("very flaky when run with Hudson")
291 @Test
292 public void commitUpdatesSmudgedEntries() throws Exception {
293 try (Git git = new Git(db)) {
294 File file1 = writeTrashFile("file1.txt", "content1");
295 TimeUtil.setLastModifiedWithOffset(file1.toPath(), -5000L);
296 File file2 = writeTrashFile("file2.txt", "content2");
297 TimeUtil.setLastModifiedWithOffset(file2.toPath(), -5000L);
298 File file3 = writeTrashFile("file3.txt", "content3");
299 TimeUtil.setLastModifiedWithOffset(file3.toPath(), -5000L);
300
301 assertNotNull(git.add().addFilepattern("file1.txt")
302 .addFilepattern("file2.txt").addFilepattern("file3.txt").call());
303 RevCommit commit = git.commit().setMessage("add files").call();
304 assertNotNull(commit);
305
306 DirCache cache = DirCache.read(db.getIndexFile(), db.getFS());
307 int file1Size = cache.getEntry("file1.txt").getLength();
308 int file2Size = cache.getEntry("file2.txt").getLength();
309 int file3Size = cache.getEntry("file3.txt").getLength();
310 ObjectId file2Id = cache.getEntry("file2.txt").getObjectId();
311 ObjectId file3Id = cache.getEntry("file3.txt").getObjectId();
312 assertTrue(file1Size > 0);
313 assertTrue(file2Size > 0);
314 assertTrue(file3Size > 0);
315
316
317 cache = DirCache.lock(db.getIndexFile(), db.getFS());
318 cache.getEntry("file1.txt").setLength(0);
319 cache.getEntry("file2.txt").setLength(0);
320 cache.getEntry("file3.txt").setLength(0);
321 cache.write();
322 assertTrue(cache.commit());
323
324
325 cache = DirCache.read(db.getIndexFile(), db.getFS());
326 assertEquals(0, cache.getEntry("file1.txt").getLength());
327 assertEquals(0, cache.getEntry("file2.txt").getLength());
328 assertEquals(0, cache.getEntry("file3.txt").getLength());
329
330 TimeUtil.setLastModifiedWithOffset(db.getIndexFile().toPath(),
331 -5000L);
332
333 write(file1, "content4");
334
335 TimeUtil.setLastModifiedWithOffset(file1.toPath(), 2500L);
336 assertNotNull(git.commit().setMessage("edit file").setOnly("file1.txt")
337 .call());
338
339 cache = db.readDirCache();
340 assertEquals(file1Size, cache.getEntry("file1.txt").getLength());
341 assertEquals(file2Size, cache.getEntry("file2.txt").getLength());
342 assertEquals(file3Size, cache.getEntry("file3.txt").getLength());
343 assertEquals(file2Id, cache.getEntry("file2.txt").getObjectId());
344 assertEquals(file3Id, cache.getEntry("file3.txt").getObjectId());
345 }
346 }
347
348 @Ignore("very flaky when run with Hudson")
349 @Test
350 public void commitIgnoresSmudgedEntryWithDifferentId() throws Exception {
351 try (Git git = new Git(db)) {
352 File file1 = writeTrashFile("file1.txt", "content1");
353 TimeUtil.setLastModifiedWithOffset(file1.toPath(), -5000L);
354 File file2 = writeTrashFile("file2.txt", "content2");
355 TimeUtil.setLastModifiedWithOffset(file2.toPath(), -5000L);
356
357 assertNotNull(git.add().addFilepattern("file1.txt")
358 .addFilepattern("file2.txt").call());
359 RevCommit commit = git.commit().setMessage("add files").call();
360 assertNotNull(commit);
361
362 DirCache cache = DirCache.read(db.getIndexFile(), db.getFS());
363 int file1Size = cache.getEntry("file1.txt").getLength();
364 int file2Size = cache.getEntry("file2.txt").getLength();
365 assertTrue(file1Size > 0);
366 assertTrue(file2Size > 0);
367
368 writeTrashFile("file2.txt", "content3");
369 assertNotNull(git.add().addFilepattern("file2.txt").call());
370 writeTrashFile("file2.txt", "content4");
371
372
373 cache = DirCache.lock(db.getIndexFile(), db.getFS());
374 cache.getEntry("file1.txt").setLength(0);
375 cache.getEntry("file2.txt").setLength(0);
376 cache.write();
377 assertTrue(cache.commit());
378
379
380 cache = db.readDirCache();
381 assertEquals(0, cache.getEntry("file1.txt").getLength());
382 assertEquals(0, cache.getEntry("file2.txt").getLength());
383
384 TimeUtil.setLastModifiedWithOffset(db.getIndexFile().toPath(),
385 -5000L);
386
387 write(file1, "content5");
388 TimeUtil.setLastModifiedWithOffset(file1.toPath(), 1000L);
389
390 assertNotNull(git.commit().setMessage("edit file").setOnly("file1.txt")
391 .call());
392
393 cache = db.readDirCache();
394 assertEquals(file1Size, cache.getEntry("file1.txt").getLength());
395 assertEquals(0, cache.getEntry("file2.txt").getLength());
396 }
397 }
398
399 @Test
400 public void commitAfterSquashMerge() throws Exception {
401 try (Git git = new Git(db)) {
402 writeTrashFile("file1", "file1");
403 git.add().addFilepattern("file1").call();
404 RevCommit first = git.commit().setMessage("initial commit").call();
405
406 assertTrue(new File(db.getWorkTree(), "file1").exists());
407 createBranch(first, "refs/heads/branch1");
408 checkoutBranch("refs/heads/branch1");
409
410 writeTrashFile("file2", "file2");
411 git.add().addFilepattern("file2").call();
412 git.commit().setMessage("second commit").call();
413 assertTrue(new File(db.getWorkTree(), "file2").exists());
414
415 checkoutBranch("refs/heads/master");
416
417 MergeResult result = git.merge()
418 .include(db.exactRef("refs/heads/branch1"))
419 .setSquash(true)
420 .call();
421
422 assertTrue(new File(db.getWorkTree(), "file1").exists());
423 assertTrue(new File(db.getWorkTree(), "file2").exists());
424 assertEquals(MergeResult.MergeStatus.FAST_FORWARD_SQUASHED,
425 result.getMergeStatus());
426
427
428 RevCommit squashedCommit = git.commit().call();
429
430 assertEquals(1, squashedCommit.getParentCount());
431 assertNull(db.readSquashCommitMsg());
432 assertEquals("commit: Squashed commit of the following:", db
433 .getReflogReader(Constants.HEAD).getLastEntry().getComment());
434 assertEquals("commit: Squashed commit of the following:", db
435 .getReflogReader(db.getBranch()).getLastEntry().getComment());
436 }
437 }
438
439 @Test
440 public void testReflogs() throws Exception {
441 try (Git git = new Git(db)) {
442 writeTrashFile("f", "1");
443 git.add().addFilepattern("f").call();
444 git.commit().setMessage("c1").call();
445 writeTrashFile("f", "2");
446 git.commit().setMessage("c2").setAll(true).setReflogComment(null)
447 .call();
448 writeTrashFile("f", "3");
449 git.commit().setMessage("c3").setAll(true)
450 .setReflogComment("testRl").call();
451
452 db.getReflogReader(Constants.HEAD).getReverseEntries();
453
454 assertEquals("testRl;commit (initial): c1;", reflogComments(
455 db.getReflogReader(Constants.HEAD).getReverseEntries()));
456 assertEquals("testRl;commit (initial): c1;", reflogComments(
457 db.getReflogReader(db.getBranch()).getReverseEntries()));
458 }
459 }
460
461 private static String reflogComments(List<ReflogEntry> entries) {
462 StringBuilder b = new StringBuilder();
463 for (ReflogEntry e : entries) {
464 b.append(e.getComment()).append(";");
465 }
466 return b.toString();
467 }
468
469 @Test(expected = WrongRepositoryStateException.class)
470 public void commitAmendOnInitialShouldFail() throws Exception {
471 try (Git git = new Git(db)) {
472 git.commit().setAmend(true).setMessage("initial commit").call();
473 }
474 }
475
476 @Test
477 public void commitAmendWithoutAuthorShouldSetOriginalAuthorAndAuthorTime()
478 throws Exception {
479 try (Git git = new Git(db)) {
480 writeTrashFile("file1", "file1");
481 git.add().addFilepattern("file1").call();
482
483 final String authorName = "First Author";
484 final String authorEmail = "author@example.org";
485 final Date authorDate = new Date(1349621117000L);
486 PersonIdent firstAuthor = new PersonIdent(authorName, authorEmail,
487 authorDate, TimeZone.getTimeZone("UTC"));
488 git.commit().setMessage("initial commit").setAuthor(firstAuthor).call();
489
490 RevCommit amended = git.commit().setAmend(true)
491 .setMessage("amend commit").call();
492
493 PersonIdent amendedAuthor = amended.getAuthorIdent();
494 assertEquals(authorName, amendedAuthor.getName());
495 assertEquals(authorEmail, amendedAuthor.getEmailAddress());
496 assertEquals(authorDate.getTime(), amendedAuthor.getWhen().getTime());
497 }
498 }
499
500 @Test
501 public void commitAmendWithAuthorShouldUseIt() throws Exception {
502 try (Git git = new Git(db)) {
503 writeTrashFile("file1", "file1");
504 git.add().addFilepattern("file1").call();
505 git.commit().setMessage("initial commit").call();
506
507 RevCommit amended = git.commit().setAmend(true)
508 .setAuthor("New Author", "newauthor@example.org")
509 .setMessage("amend commit").call();
510
511 PersonIdent amendedAuthor = amended.getAuthorIdent();
512 assertEquals("New Author", amendedAuthor.getName());
513 assertEquals("newauthor@example.org", amendedAuthor.getEmailAddress());
514 }
515 }
516
517 @Test
518 public void commitEmptyCommits() throws Exception {
519 try (Git git = new Git(db)) {
520
521 writeTrashFile("file1", "file1");
522 git.add().addFilepattern("file1").call();
523 RevCommit initial = git.commit().setMessage("initial commit")
524 .call();
525
526 RevCommit emptyFollowUp = git.commit()
527 .setAuthor("New Author", "newauthor@example.org")
528 .setMessage("no change").call();
529
530 assertNotEquals(initial.getId(), emptyFollowUp.getId());
531 assertEquals(initial.getTree().getId(),
532 emptyFollowUp.getTree().getId());
533
534 try {
535 git.commit().setAuthor("New Author", "newauthor@example.org")
536 .setMessage("again no change").setAllowEmpty(false)
537 .call();
538 fail("Didn't get the expected EmptyCommitException");
539 } catch (EmptyCommitException e) {
540
541 }
542
543
544 git.commit().setAuthor("New Author", "newauthor@example.org")
545 .setMessage("again no change").setOnly("file1")
546 .setAllowEmpty(true).call();
547 }
548 }
549
550 @Test
551 public void commitOnlyShouldCommitUnmergedPathAndNotAffectOthers()
552 throws Exception {
553 DirCache index = db.lockDirCache();
554 DirCacheBuilder builder = index.builder();
555 addUnmergedEntry("unmerged1", builder);
556 addUnmergedEntry("unmerged2", builder);
557 DirCacheEntry other = new DirCacheEntry("other");
558 other.setFileMode(FileMode.REGULAR_FILE);
559 builder.add(other);
560 builder.commit();
561
562 writeTrashFile("unmerged1", "unmerged1 data");
563 writeTrashFile("unmerged2", "unmerged2 data");
564 writeTrashFile("other", "other data");
565
566 assertEquals("[other, mode:100644]"
567 + "[unmerged1, mode:100644, stage:1]"
568 + "[unmerged1, mode:100644, stage:2]"
569 + "[unmerged1, mode:100644, stage:3]"
570 + "[unmerged2, mode:100644, stage:1]"
571 + "[unmerged2, mode:100644, stage:2]"
572 + "[unmerged2, mode:100644, stage:3]",
573 indexState(0));
574
575 try (Git git = new Git(db)) {
576 RevCommit commit = git.commit().setOnly("unmerged1")
577 .setMessage("Only one file").call();
578
579 assertEquals("[other, mode:100644]" + "[unmerged1, mode:100644]"
580 + "[unmerged2, mode:100644, stage:1]"
581 + "[unmerged2, mode:100644, stage:2]"
582 + "[unmerged2, mode:100644, stage:3]",
583 indexState(0));
584
585 try (TreeWalk walk = TreeWalk.forPath(db, "unmerged1", commit.getTree())) {
586 assertEquals(FileMode.REGULAR_FILE, walk.getFileMode(0));
587 }
588 }
589 }
590
591 @Test
592 public void commitOnlyShouldHandleIgnored() throws Exception {
593 try (Git git = new Git(db)) {
594 writeTrashFile("subdir/foo", "Hello World");
595 writeTrashFile("subdir/bar", "Hello World");
596 writeTrashFile(".gitignore", "bar");
597 git.add().addFilepattern("subdir").call();
598 git.commit().setOnly("subdir").setMessage("first commit").call();
599 assertEquals("[subdir/foo, mode:100644, content:Hello World]",
600 indexState(CONTENT));
601 }
602 }
603
604 private void nonNormalizedIndexTest(boolean executable) throws Exception {
605 String mode = executable ? "100755" : "100644";
606 try (Git git = new Git(db)) {
607
608 FileBasedConfig config = db.getConfig();
609 config.setString("core", null, "autocrlf", "false");
610 config.save();
611 File testFile = writeTrashFile("file.txt", "line 1\r\nline 2\r\n");
612 if (executable) {
613 FS.DETECTED.setExecute(testFile, true);
614 }
615 git.add().addFilepattern("file.txt").call();
616 git.commit().setMessage("Initial").call();
617 assertEquals(
618 "[file.txt, mode:" + mode
619 + ", content:line 1\r\nline 2\r\n]",
620 indexState(CONTENT));
621 config.setString("core", null, "autocrlf", "true");
622 config.save();
623 writeTrashFile("file.txt", "line 1\r\nline 1.5\r\nline 2\r\n");
624 testFile = writeTrashFile("file2.txt", "new\r\nfile\r\n");
625 if (executable) {
626 FS.DETECTED.setExecute(testFile, true);
627 }
628 git.add().addFilepattern("file.txt").addFilepattern("file2.txt")
629 .call();
630 git.commit().setMessage("Second").call();
631 assertEquals(
632 "[file.txt, mode:" + mode
633 + ", content:line 1\r\nline 1.5\r\nline 2\r\n]"
634 + "[file2.txt, mode:" + mode
635 + ", content:new\nfile\n]",
636 indexState(CONTENT));
637 writeTrashFile("file2.txt", "new\r\nfile\r\ncontent\r\n");
638 git.add().addFilepattern("file2.txt").call();
639 git.commit().setMessage("Third").call();
640 assertEquals(
641 "[file.txt, mode:" + mode
642 + ", content:line 1\r\nline 1.5\r\nline 2\r\n]"
643 + "[file2.txt, mode:" + mode
644 + ", content:new\nfile\ncontent\n]",
645 indexState(CONTENT));
646 }
647 }
648
649 @Test
650 public void commitWithAutoCrlfAndNonNormalizedIndex() throws Exception {
651 nonNormalizedIndexTest(false);
652 }
653
654 @Test
655 public void commitExecutableWithAutoCrlfAndNonNormalizedIndex()
656 throws Exception {
657 assumeTrue(FS.DETECTED.supportsExecute());
658 nonNormalizedIndexTest(true);
659 }
660
661 @Test
662 public void testDeletionConflictWithAutoCrlf() throws Exception {
663 try (Git git = new Git(db)) {
664
665 FileBasedConfig config = db.getConfig();
666 config.setString("core", null, "autocrlf", "false");
667 config.save();
668 File file = writeTrashFile("file.txt", "foo\r\n");
669 git.add().addFilepattern("file.txt").call();
670 git.commit().setMessage("Initial").call();
671
672 git.checkout().setCreateBranch(true).setName("side").call();
673 assertTrue(file.delete());
674 git.rm().addFilepattern("file.txt").call();
675 git.commit().setMessage("Side").call();
676
677 config.setString("core", null, "autocrlf", "true");
678 config.save();
679
680 git.checkout().setName("master").call();
681 writeTrashFile("file.txt", "foob\r\n");
682 git.add().addFilepattern("file.txt").call();
683 assertEquals("[file.txt, mode:100644, content:foob\r\n]",
684 indexState(CONTENT));
685 writeTrashFile("g", "file2.txt", "anything");
686 git.add().addFilepattern("g/file2.txt");
687 RevCommit master = git.commit().setMessage("Second").call();
688
689 git.checkout().setName("side").call();
690
691 CherryPickResult pick = git.cherryPick().include(master).call();
692 assertEquals("Expected a cherry-pick conflict",
693 CherryPickStatus.CONFLICTING, pick.getStatus());
694
695 git.add().addFilepattern("g/file2.txt").call();
696
697 writeTrashFile("file.txt", "foob\r\n");
698 git.add().addFilepattern("file.txt").call();
699 git.commit().setMessage("Cherry").call();
700
701
702 assertEquals(
703 "[file.txt, mode:100644, content:foob\n]"
704 + "[g/file2.txt, mode:100644, content:anything]",
705 indexState(CONTENT));
706 }
707 }
708
709 private void testConflictWithAutoCrlf(String baseLf, String lf)
710 throws Exception {
711 try (Git git = new Git(db)) {
712
713 FileBasedConfig config = db.getConfig();
714 config.setString("core", null, "autocrlf", "false");
715 config.save();
716 writeTrashFile("file.txt", "foo" + baseLf);
717 git.add().addFilepattern("file.txt").call();
718 git.commit().setMessage("Initial").call();
719
720 git.checkout().setCreateBranch(true).setName("side").call();
721 writeTrashFile("file.txt", "bar\r\n");
722 git.add().addFilepattern("file.txt").call();
723 RevCommit side = git.commit().setMessage("Side").call();
724
725 git.checkout().setName("master");
726 writeTrashFile("file.txt", "foob" + lf);
727 git.add().addFilepattern("file.txt").call();
728 git.commit().setMessage("Second").call();
729
730 config.setString("core", null, "autocrlf", "true");
731 config.save();
732
733 CherryPickResult pick = git.cherryPick().include(side).call();
734 assertEquals("Expected a cherry-pick conflict",
735 CherryPickStatus.CONFLICTING, pick.getStatus());
736 writeTrashFile("file.txt", "foobar\r\n");
737 git.add().addFilepattern("file.txt").call();
738 git.commit().setMessage("Second").call();
739 assertEquals("[file.txt, mode:100644, content:foobar" + lf + "]",
740 indexState(CONTENT));
741 }
742 }
743
744 @Test
745 public void commitConflictWithAutoCrlfBaseCrLfOursLf() throws Exception {
746 testConflictWithAutoCrlf("\r\n", "\n");
747 }
748
749 @Test
750 public void commitConflictWithAutoCrlfBaseLfOursLf() throws Exception {
751 testConflictWithAutoCrlf("\n", "\n");
752 }
753
754 @Test
755 public void commitConflictWithAutoCrlfBasCrLfOursCrLf() throws Exception {
756 testConflictWithAutoCrlf("\r\n", "\r\n");
757 }
758
759 @Test
760 public void commitConflictWithAutoCrlfBaseLfOursCrLf() throws Exception {
761 testConflictWithAutoCrlf("\n", "\r\n");
762 }
763
764 private static void addUnmergedEntry(String file, DirCacheBuilder builder) {
765 DirCacheEntry stage1 = new DirCacheEntry(file, DirCacheEntry.STAGE_1);
766 DirCacheEntry stage2 = new DirCacheEntry(file, DirCacheEntry.STAGE_2);
767 DirCacheEntry stage3 = new DirCacheEntry(file, DirCacheEntry.STAGE_3);
768 stage1.setFileMode(FileMode.REGULAR_FILE);
769 stage2.setFileMode(FileMode.REGULAR_FILE);
770 stage3.setFileMode(FileMode.REGULAR_FILE);
771 builder.add(stage1);
772 builder.add(stage2);
773 builder.add(stage3);
774 }
775
776 @Test
777 public void callSignerWithProperSigningKey() throws Exception {
778 try (Git git = new Git(db)) {
779 writeTrashFile("file1", "file1");
780 git.add().addFilepattern("file1").call();
781
782 String[] signingKey = new String[1];
783 PersonIdent[] signingCommitters = new PersonIdent[1];
784 AtomicInteger callCount = new AtomicInteger();
785 GpgSigner.setDefault(new GpgSigner() {
786 @Override
787 public void sign(CommitBuilder commit, String gpgSigningKey,
788 PersonIdent signingCommitter, CredentialsProvider credentialsProvider) {
789 signingKey[0] = gpgSigningKey;
790 signingCommitters[0] = signingCommitter;
791 callCount.incrementAndGet();
792 }
793
794 @Override
795 public boolean canLocateSigningKey(String gpgSigningKey,
796 PersonIdent signingCommitter,
797 CredentialsProvider credentialsProvider)
798 throws CanceledException {
799 return false;
800 }
801 });
802
803
804
805 git.commit().setCommitter(committer).setSign(Boolean.TRUE)
806 .setMessage("initial commit")
807 .call();
808 assertNull(signingKey[0]);
809 assertEquals(1, callCount.get());
810 assertSame(committer, signingCommitters[0]);
811
812 writeTrashFile("file2", "file2");
813 git.add().addFilepattern("file2").call();
814
815
816 String expectedConfigSigningKey = "config-" + System.nanoTime();
817 StoredConfig config = git.getRepository().getConfig();
818 config.setString("user", null, "signingKey",
819 expectedConfigSigningKey);
820 config.save();
821
822 git.commit().setCommitter(committer).setSign(Boolean.TRUE)
823 .setMessage("initial commit")
824 .call();
825 assertEquals(expectedConfigSigningKey, signingKey[0]);
826 assertEquals(2, callCount.get());
827 assertSame(committer, signingCommitters[0]);
828
829 writeTrashFile("file3", "file3");
830 git.add().addFilepattern("file3").call();
831
832
833 String expectedSigningKey = "my-" + System.nanoTime();
834 git.commit().setCommitter(committer).setSign(Boolean.TRUE)
835 .setSigningKey(expectedSigningKey)
836 .setMessage("initial commit").call();
837 assertEquals(expectedSigningKey, signingKey[0]);
838 assertEquals(3, callCount.get());
839 assertSame(committer, signingCommitters[0]);
840 }
841 }
842
843 @Test
844 public void callSignerOnlyWhenSigning() throws Exception {
845 try (Git git = new Git(db)) {
846 writeTrashFile("file1", "file1");
847 git.add().addFilepattern("file1").call();
848
849 AtomicInteger callCount = new AtomicInteger();
850 GpgSigner.setDefault(new GpgSigner() {
851 @Override
852 public void sign(CommitBuilder commit, String gpgSigningKey,
853 PersonIdent signingCommitter, CredentialsProvider credentialsProvider) {
854 callCount.incrementAndGet();
855 }
856
857 @Override
858 public boolean canLocateSigningKey(String gpgSigningKey,
859 PersonIdent signingCommitter,
860 CredentialsProvider credentialsProvider)
861 throws CanceledException {
862 return false;
863 }
864 });
865
866
867
868 git.commit().setMessage("initial commit").call();
869 assertEquals(0, callCount.get());
870
871 writeTrashFile("file2", "file2");
872 git.add().addFilepattern("file2").call();
873
874
875 git.commit().setSign(Boolean.TRUE).setMessage("commit").call();
876 assertEquals(1, callCount.get());
877
878 writeTrashFile("file3", "file3");
879 git.add().addFilepattern("file3").call();
880
881
882 StoredConfig config = git.getRepository().getConfig();
883 config.setBoolean("commit", null, "gpgSign", true);
884 config.save();
885
886 git.commit().setMessage("commit").call();
887 assertEquals(2, callCount.get());
888
889 writeTrashFile("file4", "file4");
890 git.add().addFilepattern("file4").call();
891
892
893 git.commit().setSign(Boolean.FALSE).setMessage("commit").call();
894 assertEquals(2, callCount.get());
895 }
896 }
897 }