View Javadoc
1   /*
2    * Copyright (C) 2010, Stefan Lay <stefan.lay@sap.com>
3    * Copyright (C) 2010, Christian Halstrick <christian.halstrick@sap.com>
4    * and other copyright owners as documented in the project's IP log.
5    *
6    * This program and the accompanying materials are made available
7    * under the terms of the Eclipse Distribution License v1.0 which
8    * accompanies this distribution, is reproduced below, and is
9    * available at http://www.eclipse.org/org/documents/edl-v10.php
10   *
11   * All rights reserved.
12   *
13   * Redistribution and use in source and binary forms, with or
14   * without modification, are permitted provided that the following
15   * conditions are met:
16   *
17   * - Redistributions of source code must retain the above copyright
18   *   notice, this list of conditions and the following disclaimer.
19   *
20   * - Redistributions in binary form must reproduce the above
21   *   copyright notice, this list of conditions and the following
22   *   disclaimer in the documentation and/or other materials provided
23   *   with the distribution.
24   *
25   * - Neither the name of the Eclipse Foundation, Inc. nor the
26   *   names of its contributors may be used to endorse or promote
27   *   products derived from this software without specific prior
28   *   written permission.
29   *
30   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
31   * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
32   * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
33   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
34   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
35   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
36   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
37   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
38   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
39   * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
40   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
41   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
42   * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
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  			// expected
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 		// is supposed to do nothing
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 		// is supposed to do nothing
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 		// prepare conflict
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 		// now the test begins
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 	// the same three cases as in testAddWithParameterUpdate
459 	// file a exists in workdir and in index -> added
460 	// file b exists not in workdir but in index -> unchanged
461 	// file c exists in workdir but not in index -> added
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 		// new unstaged file sub/c.txt
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 		// file sub/a.txt is modified
495 		writer = new PrintWriter(file);
496 		writer.print("modified content");
497 		writer.close();
498 
499 		// file sub/b.txt is deleted
500 		FileUtils.delete(file2);
501 
502 		git.add().addFilepattern("sub").call();
503 		// change in sub/a.txt is staged
504 		// deletion of sub/b.txt is not staged
505 		// sub/c.txt is staged
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 	// file a exists in workdir and in index -> added
514 	// file b exists not in workdir but in index -> deleted
515 	// file c exists in workdir but not in index -> unchanged
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 		// new unstaged file sub/c.txt
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 		// file sub/a.txt is modified
549 		writer = new PrintWriter(file);
550 		writer.print("modified content");
551 		writer.close();
552 
553 		FileUtils.delete(file2);
554 
555 		// change in sub/a.txt is staged
556 		// deletion of sub/b.txt is staged
557 		// sub/c.txt is not staged
558 		git.add().addFilepattern("sub").setUpdate(true).call();
559 		// change in sub/a.txt is staged
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 }