View Javadoc
1   /*
2    * Copyright (C) 2011-2012, GitHub Inc.
3    * and other copyright owners as documented in the project's IP log.
4    *
5    * This program and the accompanying materials are made available
6    * under the terms of the Eclipse Distribution License v1.0 which
7    * accompanies this distribution, is reproduced below, and is
8    * available at http://www.eclipse.org/org/documents/edl-v10.php
9    *
10   * All rights reserved.
11   *
12   * Redistribution and use in source and binary forms, with or
13   * without modification, are permitted provided that the following
14   * conditions are met:
15   *
16   * - Redistributions of source code must retain the above copyright
17   *   notice, this list of conditions and the following disclaimer.
18   *
19   * - Redistributions in binary form must reproduce the above
20   *   copyright notice, this list of conditions and the following
21   *   disclaimer in the documentation and/or other materials provided
22   *   with the distribution.
23   *
24   * - Neither the name of the Eclipse Foundation, Inc. nor the
25   *   names of its contributors may be used to endorse or promote
26   *   products derived from this software without specific prior
27   *   written permission.
28   *
29   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
30   * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
31   * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
32   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
34   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
35   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
36   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
37   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
38   * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
40   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
41   * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42   */
43  package org.eclipse.jgit.api;
44  
45  import static org.junit.Assert.assertEquals;
46  import static org.junit.Assert.assertNotNull;
47  import static org.junit.Assert.assertNull;
48  import static org.junit.Assert.assertTrue;
49  import static org.junit.Assert.assertNotEquals;
50  import static org.junit.Assert.fail;
51  
52  import java.io.File;
53  import java.util.Date;
54  import java.util.List;
55  import java.util.TimeZone;
56  
57  import org.eclipse.jgit.api.errors.EmtpyCommitException;
58  import org.eclipse.jgit.api.errors.WrongRepositoryStateException;
59  import org.eclipse.jgit.diff.DiffEntry;
60  import org.eclipse.jgit.dircache.DirCache;
61  import org.eclipse.jgit.dircache.DirCacheBuilder;
62  import org.eclipse.jgit.dircache.DirCacheEntry;
63  import org.eclipse.jgit.junit.RepositoryTestCase;
64  import org.eclipse.jgit.lib.ConfigConstants;
65  import org.eclipse.jgit.lib.Constants;
66  import org.eclipse.jgit.lib.FileMode;
67  import org.eclipse.jgit.lib.ObjectId;
68  import org.eclipse.jgit.lib.PersonIdent;
69  import org.eclipse.jgit.lib.RefUpdate;
70  import org.eclipse.jgit.lib.RefUpdate.Result;
71  import org.eclipse.jgit.lib.Repository;
72  import org.eclipse.jgit.lib.StoredConfig;
73  import org.eclipse.jgit.revwalk.RevCommit;
74  import org.eclipse.jgit.submodule.SubmoduleWalk;
75  import org.eclipse.jgit.treewalk.TreeWalk;
76  import org.eclipse.jgit.treewalk.filter.TreeFilter;
77  import org.eclipse.jgit.util.FS;
78  import org.junit.Test;
79  
80  /**
81   * Unit tests of {@link CommitCommand}.
82   */
83  public class CommitCommandTest extends RepositoryTestCase {
84  
85  	@Test
86  	public void testExecutableRetention() throws Exception {
87  		StoredConfig config = db.getConfig();
88  		config.setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null,
89  				ConfigConstants.CONFIG_KEY_FILEMODE, true);
90  		config.save();
91  
92  		FS executableFs = new FS() {
93  
94  			public boolean supportsExecute() {
95  				return true;
96  			}
97  
98  			public boolean setExecute(File f, boolean canExec) {
99  				return true;
100 			}
101 
102 			public ProcessBuilder runInShell(String cmd, String[] args) {
103 				return null;
104 			}
105 
106 			public boolean retryFailedLockFileCommit() {
107 				return false;
108 			}
109 
110 			public FS newInstance() {
111 				return this;
112 			}
113 
114 			protected File discoverGitExe() {
115 				return null;
116 			}
117 
118 			public boolean canExecute(File f) {
119 				return true;
120 			}
121 
122 			@Override
123 			public boolean isCaseSensitive() {
124 				return true;
125 			}
126 		};
127 
128 		Git git = Git.open(db.getDirectory(), executableFs);
129 		String path = "a.txt";
130 		writeTrashFile(path, "content");
131 		git.add().addFilepattern(path).call();
132 		RevCommit commit1 = git.commit().setMessage("commit").call();
133 		TreeWalk walk = TreeWalk.forPath(db, path, commit1.getTree());
134 		assertNotNull(walk);
135 		assertEquals(FileMode.EXECUTABLE_FILE, walk.getFileMode(0));
136 
137 		FS nonExecutableFs = new FS() {
138 
139 			public boolean supportsExecute() {
140 				return false;
141 			}
142 
143 			public boolean setExecute(File f, boolean canExec) {
144 				return false;
145 			}
146 
147 			public ProcessBuilder runInShell(String cmd, String[] args) {
148 				return null;
149 			}
150 
151 			public boolean retryFailedLockFileCommit() {
152 				return false;
153 			}
154 
155 			public FS newInstance() {
156 				return this;
157 			}
158 
159 			protected File discoverGitExe() {
160 				return null;
161 			}
162 
163 			public boolean canExecute(File f) {
164 				return false;
165 			}
166 
167 			@Override
168 			public boolean isCaseSensitive() {
169 				return true;
170 			}
171 		};
172 
173 		config = db.getConfig();
174 		config.setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null,
175 				ConfigConstants.CONFIG_KEY_FILEMODE, false);
176 		config.save();
177 
178 		Git git2 = Git.open(db.getDirectory(), nonExecutableFs);
179 		writeTrashFile(path, "content2");
180 		RevCommit commit2 = git2.commit().setOnly(path).setMessage("commit2")
181 				.call();
182 		walk = TreeWalk.forPath(db, path, commit2.getTree());
183 		assertNotNull(walk);
184 		assertEquals(FileMode.EXECUTABLE_FILE, walk.getFileMode(0));
185 	}
186 
187 	@Test
188 	public void commitNewSubmodule() throws Exception {
189 		try (Git git = new Git(db)) {
190 			writeTrashFile("file.txt", "content");
191 			git.add().addFilepattern("file.txt").call();
192 			RevCommit commit = git.commit().setMessage("create file").call();
193 
194 			SubmoduleAddCommand command = new SubmoduleAddCommand(db);
195 			String path = "sub";
196 			command.setPath(path);
197 			String uri = db.getDirectory().toURI().toString();
198 			command.setURI(uri);
199 			Repository repo = command.call();
200 			assertNotNull(repo);
201 			addRepoToClose(repo);
202 
203 			SubmoduleWalk generator = SubmoduleWalk.forIndex(db);
204 			assertTrue(generator.next());
205 			assertEquals(path, generator.getPath());
206 			assertEquals(commit, generator.getObjectId());
207 			assertEquals(uri, generator.getModulesUrl());
208 			assertEquals(path, generator.getModulesPath());
209 			assertEquals(uri, generator.getConfigUrl());
210 			Repository subModRepo = generator.getRepository();
211 			assertNotNull(subModRepo);
212 			subModRepo.close();
213 			assertEquals(commit, repo.resolve(Constants.HEAD));
214 
215 			RevCommit submoduleCommit = git.commit().setMessage("submodule add")
216 					.setOnly(path).call();
217 			assertNotNull(submoduleCommit);
218 			try (TreeWalk walk = new TreeWalk(db)) {
219 				walk.addTree(commit.getTree());
220 				walk.addTree(submoduleCommit.getTree());
221 				walk.setFilter(TreeFilter.ANY_DIFF);
222 				List<DiffEntry> diffs = DiffEntry.scan(walk);
223 				assertEquals(1, diffs.size());
224 				DiffEntry subDiff = diffs.get(0);
225 				assertEquals(FileMode.MISSING, subDiff.getOldMode());
226 				assertEquals(FileMode.GITLINK, subDiff.getNewMode());
227 				assertEquals(ObjectId.zeroId(), subDiff.getOldId().toObjectId());
228 				assertEquals(commit, subDiff.getNewId().toObjectId());
229 				assertEquals(path, subDiff.getNewPath());
230 			}
231 		}
232 	}
233 
234 	@Test
235 	public void commitSubmoduleUpdate() throws Exception {
236 		try (Git git = new Git(db)) {
237 			writeTrashFile("file.txt", "content");
238 			git.add().addFilepattern("file.txt").call();
239 			RevCommit commit = git.commit().setMessage("create file").call();
240 			writeTrashFile("file.txt", "content2");
241 			git.add().addFilepattern("file.txt").call();
242 			RevCommit commit2 = git.commit().setMessage("edit file").call();
243 
244 			SubmoduleAddCommand command = new SubmoduleAddCommand(db);
245 			String path = "sub";
246 			command.setPath(path);
247 			String uri = db.getDirectory().toURI().toString();
248 			command.setURI(uri);
249 			Repository repo = command.call();
250 			assertNotNull(repo);
251 			addRepoToClose(repo);
252 
253 			SubmoduleWalk generator = SubmoduleWalk.forIndex(db);
254 			assertTrue(generator.next());
255 			assertEquals(path, generator.getPath());
256 			assertEquals(commit2, generator.getObjectId());
257 			assertEquals(uri, generator.getModulesUrl());
258 			assertEquals(path, generator.getModulesPath());
259 			assertEquals(uri, generator.getConfigUrl());
260 			Repository subModRepo = generator.getRepository();
261 			assertNotNull(subModRepo);
262 			subModRepo.close();
263 			assertEquals(commit2, repo.resolve(Constants.HEAD));
264 
265 			RevCommit submoduleAddCommit = git.commit().setMessage("submodule add")
266 					.setOnly(path).call();
267 			assertNotNull(submoduleAddCommit);
268 
269 			RefUpdate update = repo.updateRef(Constants.HEAD);
270 			update.setNewObjectId(commit);
271 			assertEquals(Result.FORCED, update.forceUpdate());
272 
273 			RevCommit submoduleEditCommit = git.commit()
274 					.setMessage("submodule add").setOnly(path).call();
275 			assertNotNull(submoduleEditCommit);
276 			try (TreeWalk walk = new TreeWalk(db)) {
277 				walk.addTree(submoduleAddCommit.getTree());
278 				walk.addTree(submoduleEditCommit.getTree());
279 				walk.setFilter(TreeFilter.ANY_DIFF);
280 				List<DiffEntry> diffs = DiffEntry.scan(walk);
281 				assertEquals(1, diffs.size());
282 				DiffEntry subDiff = diffs.get(0);
283 				assertEquals(FileMode.GITLINK, subDiff.getOldMode());
284 				assertEquals(FileMode.GITLINK, subDiff.getNewMode());
285 				assertEquals(commit2, subDiff.getOldId().toObjectId());
286 				assertEquals(commit, subDiff.getNewId().toObjectId());
287 				assertEquals(path, subDiff.getNewPath());
288 				assertEquals(path, subDiff.getOldPath());
289 			}
290 		}
291 	}
292 
293 	@Test
294 	public void commitUpdatesSmudgedEntries() throws Exception {
295 		try (Git git = new Git(db)) {
296 			File file1 = writeTrashFile("file1.txt", "content1");
297 			assertTrue(file1.setLastModified(file1.lastModified() - 5000));
298 			File file2 = writeTrashFile("file2.txt", "content2");
299 			assertTrue(file2.setLastModified(file2.lastModified() - 5000));
300 			File file3 = writeTrashFile("file3.txt", "content3");
301 			assertTrue(file3.setLastModified(file3.lastModified() - 5000));
302 
303 			assertNotNull(git.add().addFilepattern("file1.txt")
304 					.addFilepattern("file2.txt").addFilepattern("file3.txt").call());
305 			RevCommit commit = git.commit().setMessage("add files").call();
306 			assertNotNull(commit);
307 
308 			DirCache cache = DirCache.read(db.getIndexFile(), db.getFS());
309 			int file1Size = cache.getEntry("file1.txt").getLength();
310 			int file2Size = cache.getEntry("file2.txt").getLength();
311 			int file3Size = cache.getEntry("file3.txt").getLength();
312 			ObjectId file2Id = cache.getEntry("file2.txt").getObjectId();
313 			ObjectId file3Id = cache.getEntry("file3.txt").getObjectId();
314 			assertTrue(file1Size > 0);
315 			assertTrue(file2Size > 0);
316 			assertTrue(file3Size > 0);
317 
318 			// Smudge entries
319 			cache = DirCache.lock(db.getIndexFile(), db.getFS());
320 			cache.getEntry("file1.txt").setLength(0);
321 			cache.getEntry("file2.txt").setLength(0);
322 			cache.getEntry("file3.txt").setLength(0);
323 			cache.write();
324 			assertTrue(cache.commit());
325 
326 			// Verify entries smudged
327 			cache = DirCache.read(db.getIndexFile(), db.getFS());
328 			assertEquals(0, cache.getEntry("file1.txt").getLength());
329 			assertEquals(0, cache.getEntry("file2.txt").getLength());
330 			assertEquals(0, cache.getEntry("file3.txt").getLength());
331 
332 			long indexTime = db.getIndexFile().lastModified();
333 			db.getIndexFile().setLastModified(indexTime - 5000);
334 
335 			write(file1, "content4");
336 			assertTrue(file1.setLastModified(file1.lastModified() + 2500));
337 			assertNotNull(git.commit().setMessage("edit file").setOnly("file1.txt")
338 					.call());
339 
340 			cache = db.readDirCache();
341 			assertEquals(file1Size, cache.getEntry("file1.txt").getLength());
342 			assertEquals(file2Size, cache.getEntry("file2.txt").getLength());
343 			assertEquals(file3Size, cache.getEntry("file3.txt").getLength());
344 			assertEquals(file2Id, cache.getEntry("file2.txt").getObjectId());
345 			assertEquals(file3Id, cache.getEntry("file3.txt").getObjectId());
346 		}
347 	}
348 
349 	@Test
350 	public void commitIgnoresSmudgedEntryWithDifferentId() throws Exception {
351 		try (Git git = new Git(db)) {
352 			File file1 = writeTrashFile("file1.txt", "content1");
353 			assertTrue(file1.setLastModified(file1.lastModified() - 5000));
354 			File file2 = writeTrashFile("file2.txt", "content2");
355 			assertTrue(file2.setLastModified(file2.lastModified() - 5000));
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 			// Smudge entries
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 			// Verify entries smudged
380 			cache = db.readDirCache();
381 			assertEquals(0, cache.getEntry("file1.txt").getLength());
382 			assertEquals(0, cache.getEntry("file2.txt").getLength());
383 
384 			long indexTime = db.getIndexFile().lastModified();
385 			db.getIndexFile().setLastModified(indexTime - 5000);
386 
387 			write(file1, "content5");
388 			assertTrue(file1.setLastModified(file1.lastModified() + 1000));
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 			// comment not set, should be inferred from SQUASH_MSG
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(expected = WrongRepositoryStateException.class)
440 	public void commitAmendOnInitialShouldFail() throws Exception {
441 		try (Git git = new Git(db)) {
442 			git.commit().setAmend(true).setMessage("initial commit").call();
443 		}
444 	}
445 
446 	@Test
447 	public void commitAmendWithoutAuthorShouldSetOriginalAuthorAndAuthorTime()
448 			throws Exception {
449 		try (Git git = new Git(db)) {
450 			writeTrashFile("file1", "file1");
451 			git.add().addFilepattern("file1").call();
452 
453 			final String authorName = "First Author";
454 			final String authorEmail = "author@example.org";
455 			final Date authorDate = new Date(1349621117000L);
456 			PersonIdent firstAuthor = new PersonIdent(authorName, authorEmail,
457 					authorDate, TimeZone.getTimeZone("UTC"));
458 			git.commit().setMessage("initial commit").setAuthor(firstAuthor).call();
459 
460 			RevCommit amended = git.commit().setAmend(true)
461 					.setMessage("amend commit").call();
462 
463 			PersonIdent amendedAuthor = amended.getAuthorIdent();
464 			assertEquals(authorName, amendedAuthor.getName());
465 			assertEquals(authorEmail, amendedAuthor.getEmailAddress());
466 			assertEquals(authorDate.getTime(), amendedAuthor.getWhen().getTime());
467 		}
468 	}
469 
470 	@Test
471 	public void commitAmendWithAuthorShouldUseIt() throws Exception {
472 		try (Git git = new Git(db)) {
473 			writeTrashFile("file1", "file1");
474 			git.add().addFilepattern("file1").call();
475 			git.commit().setMessage("initial commit").call();
476 
477 			RevCommit amended = git.commit().setAmend(true)
478 					.setAuthor("New Author", "newauthor@example.org")
479 					.setMessage("amend commit").call();
480 
481 			PersonIdent amendedAuthor = amended.getAuthorIdent();
482 			assertEquals("New Author", amendedAuthor.getName());
483 			assertEquals("newauthor@example.org", amendedAuthor.getEmailAddress());
484 		}
485 	}
486 
487 	@Test
488 	public void commitEmptyCommits() throws Exception {
489 		try (Git git = new Git(db)) {
490 
491 			writeTrashFile("file1", "file1");
492 			git.add().addFilepattern("file1").call();
493 			RevCommit initial = git.commit().setMessage("initial commit")
494 					.call();
495 
496 			RevCommit emptyFollowUp = git.commit()
497 					.setAuthor("New Author", "newauthor@example.org")
498 					.setMessage("no change").call();
499 
500 			assertNotEquals(initial.getId(), emptyFollowUp.getId());
501 			assertEquals(initial.getTree().getId(),
502 					emptyFollowUp.getTree().getId());
503 
504 			try {
505 				git.commit().setAuthor("New Author", "newauthor@example.org")
506 						.setMessage("again no change").setAllowEmpty(false)
507 						.call();
508 				fail("Didn't get the expected EmtpyCommitException");
509 			} catch (EmtpyCommitException e) {
510 				// expect this exception
511 			}
512 		}
513 	}
514 
515 	@Test
516 	public void commitOnlyShouldCommitUnmergedPathAndNotAffectOthers()
517 			throws Exception {
518 		DirCache index = db.lockDirCache();
519 		DirCacheBuilder builder = index.builder();
520 		addUnmergedEntry("unmerged1", builder);
521 		addUnmergedEntry("unmerged2", builder);
522 		DirCacheEntry other = new DirCacheEntry("other");
523 		other.setFileMode(FileMode.REGULAR_FILE);
524 		builder.add(other);
525 		builder.commit();
526 
527 		writeTrashFile("unmerged1", "unmerged1 data");
528 		writeTrashFile("unmerged2", "unmerged2 data");
529 		writeTrashFile("other", "other data");
530 
531 		assertEquals("[other, mode:100644]"
532 				+ "[unmerged1, mode:100644, stage:1]"
533 				+ "[unmerged1, mode:100644, stage:2]"
534 				+ "[unmerged1, mode:100644, stage:3]"
535 				+ "[unmerged2, mode:100644, stage:1]"
536 				+ "[unmerged2, mode:100644, stage:2]"
537 				+ "[unmerged2, mode:100644, stage:3]",
538 				indexState(0));
539 
540 		try (Git git = new Git(db)) {
541 			RevCommit commit = git.commit().setOnly("unmerged1")
542 					.setMessage("Only one file").call();
543 
544 			assertEquals("[other, mode:100644]" + "[unmerged1, mode:100644]"
545 					+ "[unmerged2, mode:100644, stage:1]"
546 					+ "[unmerged2, mode:100644, stage:2]"
547 					+ "[unmerged2, mode:100644, stage:3]",
548 					indexState(0));
549 
550 			try (TreeWalk walk = TreeWalk.forPath(db, "unmerged1", commit.getTree())) {
551 				assertEquals(FileMode.REGULAR_FILE, walk.getFileMode(0));
552 			}
553 		}
554 	}
555 
556 	@Test
557 	public void commitOnlyShouldHandleIgnored() throws Exception {
558 		try (Git git = new Git(db)) {
559 			writeTrashFile("subdir/foo", "Hello World");
560 			writeTrashFile("subdir/bar", "Hello World");
561 			writeTrashFile(".gitignore", "bar");
562 			git.add().addFilepattern("subdir").call();
563 			git.commit().setOnly("subdir").setMessage("first commit").call();
564 		}
565 	}
566 
567 	private static void addUnmergedEntry(String file, DirCacheBuilder builder) {
568 		DirCacheEntry stage1 = new DirCacheEntry(file, DirCacheEntry.STAGE_1);
569 		DirCacheEntry stage2 = new DirCacheEntry(file, DirCacheEntry.STAGE_2);
570 		DirCacheEntry stage3 = new DirCacheEntry(file, DirCacheEntry.STAGE_3);
571 		stage1.setFileMode(FileMode.REGULAR_FILE);
572 		stage2.setFileMode(FileMode.REGULAR_FILE);
573 		stage3.setFileMode(FileMode.REGULAR_FILE);
574 		builder.add(stage1);
575 		builder.add(stage2);
576 		builder.add(stage3);
577 	}
578 }