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.junit.Assert.assertEquals;
47 import static org.junit.Assert.assertNotNull;
48 import static org.junit.Assert.fail;
49
50 import java.io.File;
51 import java.io.FileInputStream;
52 import java.io.IOException;
53 import java.io.PrintWriter;
54
55 import org.eclipse.jgit.api.errors.GitAPIException;
56 import org.eclipse.jgit.api.errors.NoFilepatternException;
57 import org.eclipse.jgit.dircache.DirCache;
58 import org.eclipse.jgit.dircache.DirCacheBuilder;
59 import org.eclipse.jgit.dircache.DirCacheEntry;
60 import org.eclipse.jgit.junit.RepositoryTestCase;
61 import org.eclipse.jgit.lib.ConfigConstants;
62 import org.eclipse.jgit.lib.Constants;
63 import org.eclipse.jgit.lib.FileMode;
64 import org.eclipse.jgit.lib.ObjectId;
65 import org.eclipse.jgit.lib.ObjectInserter;
66 import org.eclipse.jgit.lib.StoredConfig;
67 import org.eclipse.jgit.revwalk.RevCommit;
68 import org.eclipse.jgit.treewalk.TreeWalk;
69 import org.eclipse.jgit.util.FS;
70 import org.eclipse.jgit.util.FileUtils;
71 import org.junit.Test;
72
73 public class AddCommandTest extends RepositoryTestCase {
74
75 @Test
76 public void testAddNothing() throws GitAPIException {
77 Git git = new Git(db);
78
79 try {
80 git.add().call();
81 fail("Expected IllegalArgumentException");
82 } catch (NoFilepatternException e) {
83
84 }
85
86 }
87
88 @Test
89 public void testAddNonExistingSingleFile() throws GitAPIException {
90 Git git = new Git(db);
91
92 DirCache dc = git.add().addFilepattern("a.txt").call();
93 assertEquals(0, dc.getEntryCount());
94
95 }
96
97 @Test
98 public void testAddExistingSingleFile() throws IOException, GitAPIException {
99 File file = new File(db.getWorkTree(), "a.txt");
100 FileUtils.createNewFile(file);
101 PrintWriter writer = new PrintWriter(file);
102 writer.print("content");
103 writer.close();
104
105 Git git = new Git(db);
106
107 git.add().addFilepattern("a.txt").call();
108
109 assertEquals(
110 "[a.txt, mode:100644, content:content]",
111 indexState(CONTENT));
112 }
113
114 @Test
115 public void testAddExistingSingleSmallFileWithNewLine() throws IOException,
116 GitAPIException {
117 File file = new File(db.getWorkTree(), "a.txt");
118 FileUtils.createNewFile(file);
119 PrintWriter writer = new PrintWriter(file);
120 writer.print("row1\r\nrow2");
121 writer.close();
122
123 Git git = new Git(db);
124 db.getConfig().setString("core", null, "autocrlf", "false");
125 git.add().addFilepattern("a.txt").call();
126 assertEquals("[a.txt, mode:100644, content:row1\r\nrow2]",
127 indexState(CONTENT));
128 db.getConfig().setString("core", null, "autocrlf", "true");
129 git.add().addFilepattern("a.txt").call();
130 assertEquals("[a.txt, mode:100644, content:row1\nrow2]",
131 indexState(CONTENT));
132 db.getConfig().setString("core", null, "autocrlf", "input");
133 git.add().addFilepattern("a.txt").call();
134 assertEquals("[a.txt, mode:100644, content:row1\nrow2]",
135 indexState(CONTENT));
136 }
137
138 @Test
139 public void testAddExistingSingleMediumSizeFileWithNewLine()
140 throws IOException, GitAPIException {
141 File file = new File(db.getWorkTree(), "a.txt");
142 FileUtils.createNewFile(file);
143 StringBuilder data = new StringBuilder();
144 for (int i = 0; i < 1000; ++i) {
145 data.append("row1\r\nrow2");
146 }
147 String crData = data.toString();
148 PrintWriter writer = new PrintWriter(file);
149 writer.print(crData);
150 writer.close();
151 String lfData = data.toString().replaceAll("\r", "");
152 Git git = new Git(db);
153 db.getConfig().setString("core", null, "autocrlf", "false");
154 git.add().addFilepattern("a.txt").call();
155 assertEquals("[a.txt, mode:100644, content:" + data + "]",
156 indexState(CONTENT));
157 db.getConfig().setString("core", null, "autocrlf", "true");
158 git.add().addFilepattern("a.txt").call();
159 assertEquals("[a.txt, mode:100644, content:" + lfData + "]",
160 indexState(CONTENT));
161 db.getConfig().setString("core", null, "autocrlf", "input");
162 git.add().addFilepattern("a.txt").call();
163 assertEquals("[a.txt, mode:100644, content:" + lfData + "]",
164 indexState(CONTENT));
165 }
166
167 @Test
168 public void testAddExistingSingleBinaryFile() throws IOException,
169 GitAPIException {
170 File file = new File(db.getWorkTree(), "a.txt");
171 FileUtils.createNewFile(file);
172 PrintWriter writer = new PrintWriter(file);
173 writer.print("row1\r\nrow2\u0000");
174 writer.close();
175
176 Git git = new Git(db);
177 db.getConfig().setString("core", null, "autocrlf", "false");
178 git.add().addFilepattern("a.txt").call();
179 assertEquals("[a.txt, mode:100644, content:row1\r\nrow2\u0000]",
180 indexState(CONTENT));
181 db.getConfig().setString("core", null, "autocrlf", "true");
182 git.add().addFilepattern("a.txt").call();
183 assertEquals("[a.txt, mode:100644, content:row1\r\nrow2\u0000]",
184 indexState(CONTENT));
185 db.getConfig().setString("core", null, "autocrlf", "input");
186 git.add().addFilepattern("a.txt").call();
187 assertEquals("[a.txt, mode:100644, content:row1\r\nrow2\u0000]",
188 indexState(CONTENT));
189 }
190
191 @Test
192 public void testAddExistingSingleFileInSubDir() throws IOException,
193 GitAPIException {
194 FileUtils.mkdir(new File(db.getWorkTree(), "sub"));
195 File file = new File(db.getWorkTree(), "sub/a.txt");
196 FileUtils.createNewFile(file);
197 PrintWriter writer = new PrintWriter(file);
198 writer.print("content");
199 writer.close();
200
201 Git git = new Git(db);
202
203 git.add().addFilepattern("sub/a.txt").call();
204
205 assertEquals(
206 "[sub/a.txt, mode:100644, content:content]",
207 indexState(CONTENT));
208 }
209
210 @Test
211 public void testAddExistingSingleFileTwice() throws IOException,
212 GitAPIException {
213 File file = new File(db.getWorkTree(), "a.txt");
214 FileUtils.createNewFile(file);
215 PrintWriter writer = new PrintWriter(file);
216 writer.print("content");
217 writer.close();
218
219 Git git = new Git(db);
220 DirCache dc = git.add().addFilepattern("a.txt").call();
221
222 dc.getEntry(0).getObjectId();
223
224 writer = new PrintWriter(file);
225 writer.print("other content");
226 writer.close();
227
228 dc = git.add().addFilepattern("a.txt").call();
229
230 assertEquals(
231 "[a.txt, mode:100644, content:other content]",
232 indexState(CONTENT));
233 }
234
235 @Test
236 public void testAddExistingSingleFileTwiceWithCommit() throws Exception {
237 File file = new File(db.getWorkTree(), "a.txt");
238 FileUtils.createNewFile(file);
239 PrintWriter writer = new PrintWriter(file);
240 writer.print("content");
241 writer.close();
242
243 Git git = new Git(db);
244 DirCache dc = git.add().addFilepattern("a.txt").call();
245
246 dc.getEntry(0).getObjectId();
247
248 git.commit().setMessage("commit a.txt").call();
249
250 writer = new PrintWriter(file);
251 writer.print("other content");
252 writer.close();
253
254 dc = git.add().addFilepattern("a.txt").call();
255
256 assertEquals(
257 "[a.txt, mode:100644, content:other content]",
258 indexState(CONTENT));
259 }
260
261 @Test
262 public void testAddRemovedFile() throws Exception {
263 File file = new File(db.getWorkTree(), "a.txt");
264 FileUtils.createNewFile(file);
265 PrintWriter writer = new PrintWriter(file);
266 writer.print("content");
267 writer.close();
268
269 Git git = new Git(db);
270 DirCache dc = git.add().addFilepattern("a.txt").call();
271
272 dc.getEntry(0).getObjectId();
273 FileUtils.delete(file);
274
275
276 dc = git.add().addFilepattern("a.txt").call();
277
278 assertEquals(
279 "[a.txt, mode:100644, content:content]",
280 indexState(CONTENT));
281 }
282
283 @Test
284 public void testAddRemovedCommittedFile() throws Exception {
285 File file = new File(db.getWorkTree(), "a.txt");
286 FileUtils.createNewFile(file);
287 PrintWriter writer = new PrintWriter(file);
288 writer.print("content");
289 writer.close();
290
291 Git git = new Git(db);
292 DirCache dc = git.add().addFilepattern("a.txt").call();
293
294 git.commit().setMessage("commit a.txt").call();
295
296 dc.getEntry(0).getObjectId();
297 FileUtils.delete(file);
298
299
300 dc = git.add().addFilepattern("a.txt").call();
301
302 assertEquals(
303 "[a.txt, mode:100644, content:content]",
304 indexState(CONTENT));
305 }
306
307 @Test
308 public void testAddWithConflicts() throws Exception {
309
310
311 File file = new File(db.getWorkTree(), "a.txt");
312 FileUtils.createNewFile(file);
313 PrintWriter writer = new PrintWriter(file);
314 writer.print("content");
315 writer.close();
316
317 File file2 = new File(db.getWorkTree(), "b.txt");
318 FileUtils.createNewFile(file2);
319 writer = new PrintWriter(file2);
320 writer.print("content b");
321 writer.close();
322
323 ObjectInserter newObjectInserter = db.newObjectInserter();
324 DirCache dc = db.lockDirCache();
325 DirCacheBuilder builder = dc.builder();
326
327 addEntryToBuilder("b.txt", file2, newObjectInserter, builder, 0);
328 addEntryToBuilder("a.txt", file, newObjectInserter, builder, 1);
329
330 writer = new PrintWriter(file);
331 writer.print("other content");
332 writer.close();
333 addEntryToBuilder("a.txt", file, newObjectInserter, builder, 3);
334
335 writer = new PrintWriter(file);
336 writer.print("our content");
337 writer.close();
338 addEntryToBuilder("a.txt", file, newObjectInserter, builder, 2)
339 .getObjectId();
340
341 builder.commit();
342
343 assertEquals(
344 "[a.txt, mode:100644, stage:1, content:content]" +
345 "[a.txt, mode:100644, stage:2, content:our content]" +
346 "[a.txt, mode:100644, stage:3, content:other content]" +
347 "[b.txt, mode:100644, content:content b]",
348 indexState(CONTENT));
349
350
351
352 Git git = new Git(db);
353 dc = git.add().addFilepattern("a.txt").call();
354
355 assertEquals(
356 "[a.txt, mode:100644, content:our content]" +
357 "[b.txt, mode:100644, content:content b]",
358 indexState(CONTENT));
359 }
360
361 @Test
362 public void testAddTwoFiles() throws Exception {
363 File file = new File(db.getWorkTree(), "a.txt");
364 FileUtils.createNewFile(file);
365 PrintWriter writer = new PrintWriter(file);
366 writer.print("content");
367 writer.close();
368
369 File file2 = new File(db.getWorkTree(), "b.txt");
370 FileUtils.createNewFile(file2);
371 writer = new PrintWriter(file2);
372 writer.print("content b");
373 writer.close();
374
375 Git git = new Git(db);
376 git.add().addFilepattern("a.txt").addFilepattern("b.txt").call();
377 assertEquals(
378 "[a.txt, mode:100644, content:content]" +
379 "[b.txt, mode:100644, content:content b]",
380 indexState(CONTENT));
381 }
382
383 @Test
384 public void testAddFolder() throws Exception {
385 FileUtils.mkdir(new File(db.getWorkTree(), "sub"));
386 File file = new File(db.getWorkTree(), "sub/a.txt");
387 FileUtils.createNewFile(file);
388 PrintWriter writer = new PrintWriter(file);
389 writer.print("content");
390 writer.close();
391
392 File file2 = new File(db.getWorkTree(), "sub/b.txt");
393 FileUtils.createNewFile(file2);
394 writer = new PrintWriter(file2);
395 writer.print("content b");
396 writer.close();
397
398 Git git = new Git(db);
399 git.add().addFilepattern("sub").call();
400 assertEquals(
401 "[sub/a.txt, mode:100644, content:content]" +
402 "[sub/b.txt, mode:100644, content:content b]",
403 indexState(CONTENT));
404 }
405
406 @Test
407 public void testAddIgnoredFile() throws Exception {
408 FileUtils.mkdir(new File(db.getWorkTree(), "sub"));
409 File file = new File(db.getWorkTree(), "sub/a.txt");
410 FileUtils.createNewFile(file);
411 PrintWriter writer = new PrintWriter(file);
412 writer.print("content");
413 writer.close();
414
415 File ignoreFile = new File(db.getWorkTree(), ".gitignore");
416 FileUtils.createNewFile(ignoreFile);
417 writer = new PrintWriter(ignoreFile);
418 writer.print("sub/b.txt");
419 writer.close();
420
421 File file2 = new File(db.getWorkTree(), "sub/b.txt");
422 FileUtils.createNewFile(file2);
423 writer = new PrintWriter(file2);
424 writer.print("content b");
425 writer.close();
426
427 Git git = new Git(db);
428 git.add().addFilepattern("sub").call();
429
430 assertEquals(
431 "[sub/a.txt, mode:100644, content:content]",
432 indexState(CONTENT));
433 }
434
435 @Test
436 public void testAddWholeRepo() throws Exception {
437 FileUtils.mkdir(new File(db.getWorkTree(), "sub"));
438 File file = new File(db.getWorkTree(), "sub/a.txt");
439 FileUtils.createNewFile(file);
440 PrintWriter writer = new PrintWriter(file);
441 writer.print("content");
442 writer.close();
443
444 File file2 = new File(db.getWorkTree(), "sub/b.txt");
445 FileUtils.createNewFile(file2);
446 writer = new PrintWriter(file2);
447 writer.print("content b");
448 writer.close();
449
450 Git git = new Git(db);
451 git.add().addFilepattern(".").call();
452 assertEquals(
453 "[sub/a.txt, mode:100644, content:content]" +
454 "[sub/b.txt, mode:100644, content:content b]",
455 indexState(CONTENT));
456 }
457
458
459
460
461
462 @Test
463 public void testAddWithoutParameterUpdate() throws Exception {
464 FileUtils.mkdir(new File(db.getWorkTree(), "sub"));
465 File file = new File(db.getWorkTree(), "sub/a.txt");
466 FileUtils.createNewFile(file);
467 PrintWriter writer = new PrintWriter(file);
468 writer.print("content");
469 writer.close();
470
471 File file2 = new File(db.getWorkTree(), "sub/b.txt");
472 FileUtils.createNewFile(file2);
473 writer = new PrintWriter(file2);
474 writer.print("content b");
475 writer.close();
476
477 Git git = new Git(db);
478 git.add().addFilepattern("sub").call();
479
480 assertEquals(
481 "[sub/a.txt, mode:100644, content:content]" +
482 "[sub/b.txt, mode:100644, content:content b]",
483 indexState(CONTENT));
484
485 git.commit().setMessage("commit").call();
486
487
488 File file3 = new File(db.getWorkTree(), "sub/c.txt");
489 FileUtils.createNewFile(file3);
490 writer = new PrintWriter(file3);
491 writer.print("content c");
492 writer.close();
493
494
495 writer = new PrintWriter(file);
496 writer.print("modified content");
497 writer.close();
498
499
500 FileUtils.delete(file2);
501
502 git.add().addFilepattern("sub").call();
503
504
505
506 assertEquals(
507 "[sub/a.txt, mode:100644, content:modified content]" +
508 "[sub/b.txt, mode:100644, content:content b]" +
509 "[sub/c.txt, mode:100644, content:content c]",
510 indexState(CONTENT));
511 }
512
513
514
515
516 @Test
517 public void testAddWithParameterUpdate() throws Exception {
518 FileUtils.mkdir(new File(db.getWorkTree(), "sub"));
519 File file = new File(db.getWorkTree(), "sub/a.txt");
520 FileUtils.createNewFile(file);
521 PrintWriter writer = new PrintWriter(file);
522 writer.print("content");
523 writer.close();
524
525 File file2 = new File(db.getWorkTree(), "sub/b.txt");
526 FileUtils.createNewFile(file2);
527 writer = new PrintWriter(file2);
528 writer.print("content b");
529 writer.close();
530
531 Git git = new Git(db);
532 git.add().addFilepattern("sub").call();
533
534 assertEquals(
535 "[sub/a.txt, mode:100644, content:content]" +
536 "[sub/b.txt, mode:100644, content:content b]",
537 indexState(CONTENT));
538
539 git.commit().setMessage("commit").call();
540
541
542 File file3 = new File(db.getWorkTree(), "sub/c.txt");
543 FileUtils.createNewFile(file3);
544 writer = new PrintWriter(file3);
545 writer.print("content c");
546 writer.close();
547
548
549 writer = new PrintWriter(file);
550 writer.print("modified content");
551 writer.close();
552
553 FileUtils.delete(file2);
554
555
556
557
558 git.add().addFilepattern("sub").setUpdate(true).call();
559
560 assertEquals(
561 "[sub/a.txt, mode:100644, content:modified content]",
562 indexState(CONTENT));
563 }
564
565 @Test
566 public void testAssumeUnchanged() throws Exception {
567 Git git = new Git(db);
568 String path = "a.txt";
569 writeTrashFile(path, "content");
570 git.add().addFilepattern(path).call();
571 String path2 = "b.txt";
572 writeTrashFile(path2, "content");
573 git.add().addFilepattern(path2).call();
574 git.commit().setMessage("commit").call();
575 assertEquals("[a.txt, mode:100644, content:"
576 + "content, assume-unchanged:false]"
577 + "[b.txt, mode:100644, content:content, "
578 + "assume-unchanged:false]", indexState(CONTENT
579 | ASSUME_UNCHANGED));
580 assumeUnchanged(path2);
581 assertEquals("[a.txt, mode:100644, content:content, "
582 + "assume-unchanged:false][b.txt, mode:100644, "
583 + "content:content, assume-unchanged:true]", indexState(CONTENT
584 | ASSUME_UNCHANGED));
585 writeTrashFile(path, "more content");
586 writeTrashFile(path2, "more content");
587
588 git.add().addFilepattern(".").call();
589
590 assertEquals("[a.txt, mode:100644, content:more content,"
591 + " assume-unchanged:false][b.txt, mode:100644,"
592 + "" + ""
593 + " content:content, assume-unchanged:true]",
594 indexState(CONTENT
595 | ASSUME_UNCHANGED));
596 }
597
598 @Test
599 public void testExecutableRetention() throws Exception {
600 StoredConfig config = db.getConfig();
601 config.setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null,
602 ConfigConstants.CONFIG_KEY_FILEMODE, true);
603 config.save();
604
605 FS executableFs = new FS() {
606
607 public boolean supportsExecute() {
608 return true;
609 }
610
611 public boolean setExecute(File f, boolean canExec) {
612 return true;
613 }
614
615 public ProcessBuilder runInShell(String cmd, String[] args) {
616 return null;
617 }
618
619 public boolean retryFailedLockFileCommit() {
620 return false;
621 }
622
623 public FS newInstance() {
624 return this;
625 }
626
627 protected File discoverGitExe() {
628 return null;
629 }
630
631 public boolean canExecute(File f) {
632 return true;
633 }
634
635 @Override
636 public boolean isCaseSensitive() {
637 return false;
638 }
639 };
640
641 Git git = Git.open(db.getDirectory(), executableFs);
642 String path = "a.txt";
643 writeTrashFile(path, "content");
644 git.add().addFilepattern(path).call();
645 RevCommit commit1 = git.commit().setMessage("commit").call();
646 TreeWalk walk = TreeWalk.forPath(db, path, commit1.getTree());
647 assertNotNull(walk);
648 assertEquals(FileMode.EXECUTABLE_FILE, walk.getFileMode(0));
649
650 FS nonExecutableFs = new FS() {
651
652 public boolean supportsExecute() {
653 return false;
654 }
655
656 public boolean setExecute(File f, boolean canExec) {
657 return false;
658 }
659
660 public ProcessBuilder runInShell(String cmd, String[] args) {
661 return null;
662 }
663
664 public boolean retryFailedLockFileCommit() {
665 return false;
666 }
667
668 public FS newInstance() {
669 return this;
670 }
671
672 protected File discoverGitExe() {
673 return null;
674 }
675
676 public boolean canExecute(File f) {
677 return false;
678 }
679
680 @Override
681 public boolean isCaseSensitive() {
682 return false;
683 }
684 };
685
686 config = db.getConfig();
687 config.setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null,
688 ConfigConstants.CONFIG_KEY_FILEMODE, false);
689 config.save();
690
691 Git git2 = Git.open(db.getDirectory(), nonExecutableFs);
692 writeTrashFile(path, "content2");
693 git2.add().addFilepattern(path).call();
694 RevCommit commit2 = git2.commit().setMessage("commit2").call();
695 walk = TreeWalk.forPath(db, path, commit2.getTree());
696 assertNotNull(walk);
697 assertEquals(FileMode.EXECUTABLE_FILE, walk.getFileMode(0));
698 }
699
700 private static DirCacheEntry addEntryToBuilder(String path, File file,
701 ObjectInserter newObjectInserter, DirCacheBuilder builder, int stage)
702 throws IOException {
703 FileInputStream inputStream = new FileInputStream(file);
704 ObjectId id = newObjectInserter.insert(
705 Constants.OBJ_BLOB, file.length(), inputStream);
706 inputStream.close();
707 DirCacheEntry entry = new DirCacheEntry(path, stage);
708 entry.setObjectId(id);
709 entry.setFileMode(FileMode.REGULAR_FILE);
710 entry.setLastModified(file.lastModified());
711 entry.setLength((int) file.length());
712
713 builder.add(entry);
714 return entry;
715 }
716
717 private void assumeUnchanged(String path) throws IOException {
718 final DirCache dirc = db.lockDirCache();
719 final DirCacheEntry ent = dirc.getEntry(path);
720 if (ent != null)
721 ent.setAssumeValid(true);
722 dirc.write();
723 if (!dirc.commit())
724 throw new IOException("could not commit");
725 }
726
727 }