1
2
3
4
5
6
7
8
9
10 package org.eclipse.jgit.diff;
11
12 import static org.eclipse.jgit.diff.DiffEntry.DEV_NULL;
13 import static org.eclipse.jgit.util.FileUtils.delete;
14 import static org.hamcrest.CoreMatchers.is;
15 import static org.hamcrest.CoreMatchers.notNullValue;
16 import static org.hamcrest.MatcherAssert.assertThat;
17 import static org.junit.Assert.assertEquals;
18 import static org.junit.Assert.assertFalse;
19 import static org.junit.Assert.assertTrue;
20
21 import java.io.File;
22 import java.util.List;
23
24 import org.eclipse.jgit.api.Git;
25 import org.eclipse.jgit.diff.DiffEntry.ChangeType;
26 import org.eclipse.jgit.dircache.DirCache;
27 import org.eclipse.jgit.dircache.DirCacheEditor;
28 import org.eclipse.jgit.dircache.DirCacheEditor.PathEdit;
29 import org.eclipse.jgit.dircache.DirCacheEntry;
30 import org.eclipse.jgit.internal.storage.file.FileRepository;
31 import org.eclipse.jgit.junit.JGitTestUtil;
32 import org.eclipse.jgit.junit.RepositoryTestCase;
33 import org.eclipse.jgit.lib.FileMode;
34 import org.eclipse.jgit.lib.Repository;
35 import org.eclipse.jgit.revwalk.RevCommit;
36 import org.eclipse.jgit.treewalk.EmptyTreeIterator;
37 import org.eclipse.jgit.treewalk.FileTreeIterator;
38 import org.eclipse.jgit.treewalk.TreeWalk;
39 import org.eclipse.jgit.treewalk.filter.PathFilterGroup;
40 import org.eclipse.jgit.treewalk.filter.TreeFilter;
41 import org.eclipse.jgit.util.FileUtils;
42 import org.junit.Test;
43
44 public class DiffEntryTest extends RepositoryTestCase {
45
46 @Test
47 public void shouldListAddedFileInInitialCommit() throws Exception {
48
49 writeTrashFile("a.txt", "content");
50 try (Git git = new Git(db);
51 TreeWalk walk = new TreeWalk(db)) {
52 git.add().addFilepattern("a.txt").call();
53 RevCommit c = git.commit().setMessage("initial commit").call();
54
55
56 walk.addTree(new EmptyTreeIterator());
57 walk.addTree(c.getTree());
58 List<DiffEntry> result = DiffEntry.scan(walk);
59
60
61 assertThat(result, notNullValue());
62 assertThat(Integer.valueOf(result.size()), is(Integer.valueOf(1)));
63
64 DiffEntry entry = result.get(0);
65 assertThat(entry.getChangeType(), is(ChangeType.ADD));
66 assertThat(entry.getNewPath(), is("a.txt"));
67 assertThat(entry.getOldPath(), is(DEV_NULL));
68 }
69 }
70
71 @Test
72 public void shouldListAddedFileBetweenTwoCommits() throws Exception {
73
74 try (Git git = new Git(db);
75 TreeWalk walk = new TreeWalk(db)) {
76 RevCommit c1 = git.commit().setMessage("initial commit").call();
77 writeTrashFile("a.txt", "content");
78 git.add().addFilepattern("a.txt").call();
79 RevCommit c2 = git.commit().setMessage("second commit").call();
80
81
82 walk.addTree(c1.getTree());
83 walk.addTree(c2.getTree());
84 List<DiffEntry> result = DiffEntry.scan(walk);
85
86
87 assertThat(result, notNullValue());
88 assertThat(Integer.valueOf(result.size()), is(Integer.valueOf(1)));
89
90 DiffEntry entry = result.get(0);
91 assertThat(entry.getChangeType(), is(ChangeType.ADD));
92 assertThat(entry.getNewPath(), is("a.txt"));
93 assertThat(entry.getOldPath(), is(DEV_NULL));
94 }
95 }
96
97 @Test
98 public void shouldListModificationBetweenTwoCommits() throws Exception {
99
100 try (Git git = new Git(db);
101 TreeWalk walk = new TreeWalk(db)) {
102 File file = writeTrashFile("a.txt", "content");
103 git.add().addFilepattern("a.txt").call();
104 RevCommit c1 = git.commit().setMessage("initial commit").call();
105 write(file, "new content");
106 RevCommit c2 = git.commit().setAll(true).setMessage("second commit")
107 .call();
108
109
110 walk.addTree(c1.getTree());
111 walk.addTree(c2.getTree());
112 List<DiffEntry> result = DiffEntry.scan(walk);
113
114
115 assertThat(result, notNullValue());
116 assertThat(Integer.valueOf(result.size()), is(Integer.valueOf(1)));
117
118 DiffEntry entry = result.get(0);
119 assertThat(entry.getChangeType(), is(ChangeType.MODIFY));
120 assertThat(entry.getNewPath(), is("a.txt"));
121 }
122 }
123
124 @Test
125 public void shouldListDeletionBetweenTwoCommits() throws Exception {
126
127 try (Git git = new Git(db);
128 TreeWalk walk = new TreeWalk(db)) {
129 File file = writeTrashFile("a.txt", "content");
130 git.add().addFilepattern("a.txt").call();
131 RevCommit c1 = git.commit().setMessage("initial commit").call();
132 delete(file);
133 RevCommit c2 = git.commit().setAll(true).setMessage("delete a.txt")
134 .call();
135
136
137 walk.addTree(c1.getTree());
138 walk.addTree(c2.getTree());
139 List<DiffEntry> result = DiffEntry.scan(walk);
140
141
142 assertThat(result, notNullValue());
143 assertThat(Integer.valueOf(result.size()), is(Integer.valueOf(1)));
144
145 DiffEntry entry = result.get(0);
146 assertThat(entry.getOldPath(), is("a.txt"));
147 assertThat(entry.getNewPath(), is(DEV_NULL));
148 assertThat(entry.getChangeType(), is(ChangeType.DELETE));
149 }
150 }
151
152 @Test
153 public void shouldListModificationInDirWithoutModifiedTrees()
154 throws Exception {
155
156 try (Git git = new Git(db);
157 TreeWalk walk = new TreeWalk(db)) {
158 File tree = new File(new File(db.getWorkTree(), "a"), "b");
159 FileUtils.mkdirs(tree);
160 File file = new File(tree, "c.txt");
161 FileUtils.createNewFile(file);
162 write(file, "content");
163 git.add().addFilepattern("a").call();
164 RevCommit c1 = git.commit().setMessage("initial commit").call();
165 write(file, "new line");
166 RevCommit c2 = git.commit().setAll(true).setMessage("second commit")
167 .call();
168
169
170 walk.addTree(c1.getTree());
171 walk.addTree(c2.getTree());
172 walk.setRecursive(true);
173 List<DiffEntry> result = DiffEntry.scan(walk);
174
175
176 assertThat(result, notNullValue());
177 assertThat(Integer.valueOf(result.size()), is(Integer.valueOf(1)));
178
179 DiffEntry entry = result.get(0);
180 assertThat(entry.getChangeType(), is(ChangeType.MODIFY));
181 assertThat(entry.getNewPath(), is("a/b/c.txt"));
182 }
183 }
184
185 @Test
186 public void shouldListModificationInDirWithModifiedTrees() throws Exception {
187
188 try (Git git = new Git(db);
189 TreeWalk walk = new TreeWalk(db)) {
190 File tree = new File(new File(db.getWorkTree(), "a"), "b");
191 FileUtils.mkdirs(tree);
192 File file = new File(tree, "c.txt");
193 FileUtils.createNewFile(file);
194 write(file, "content");
195 git.add().addFilepattern("a").call();
196 RevCommit c1 = git.commit().setMessage("initial commit").call();
197 write(file, "new line");
198 RevCommit c2 = git.commit().setAll(true).setMessage("second commit")
199 .call();
200
201
202 walk.addTree(c1.getTree());
203 walk.addTree(c2.getTree());
204 List<DiffEntry> result = DiffEntry.scan(walk, true);
205
206
207 assertThat(result, notNullValue());
208 assertThat(Integer.valueOf(result.size()), is(Integer.valueOf(3)));
209
210 DiffEntry entry = result.get(0);
211 assertThat(entry.getChangeType(), is(ChangeType.MODIFY));
212 assertThat(entry.getNewPath(), is("a"));
213
214 entry = result.get(1);
215 assertThat(entry.getChangeType(), is(ChangeType.MODIFY));
216 assertThat(entry.getNewPath(), is("a/b"));
217
218 entry = result.get(2);
219 assertThat(entry.getChangeType(), is(ChangeType.MODIFY));
220 assertThat(entry.getNewPath(), is("a/b/c.txt"));
221 }
222 }
223
224 @Test
225 public void shouldListChangesInWorkingTree() throws Exception {
226
227 writeTrashFile("a.txt", "content");
228 try (Git git = new Git(db);
229 TreeWalk walk = new TreeWalk(db)) {
230 git.add().addFilepattern("a.txt").call();
231 RevCommit c = git.commit().setMessage("initial commit").call();
232 writeTrashFile("b.txt", "new line");
233
234
235 walk.addTree(c.getTree());
236 walk.addTree(new FileTreeIterator(db));
237 List<DiffEntry> result = DiffEntry.scan(walk, true);
238
239
240 assertThat(Integer.valueOf(result.size()), is(Integer.valueOf(1)));
241 DiffEntry entry = result.get(0);
242
243 assertThat(entry.getChangeType(), is(ChangeType.ADD));
244 assertThat(entry.getNewPath(), is("b.txt"));
245 }
246 }
247
248 @Test
249 public void shouldMarkEntriesWhenGivenMarkTreeFilter() throws Exception {
250
251 try (Git git = new Git(db);
252 TreeWalk walk = new TreeWalk(db)) {
253 RevCommit c1 = git.commit().setMessage("initial commit").call();
254 FileUtils.mkdir(new File(db.getWorkTree(), "b"));
255 writeTrashFile("a.txt", "a");
256 writeTrashFile("b/1.txt", "b1");
257 writeTrashFile("b/2.txt", "b2");
258 writeTrashFile("c.txt", "c");
259 git.add().addFilepattern("a.txt").addFilepattern("b")
260 .addFilepattern("c.txt").call();
261 RevCommit c2 = git.commit().setMessage("second commit").call();
262 TreeFilter filterA = PathFilterGroup.createFromStrings("a.txt");
263 TreeFilter filterB = PathFilterGroup.createFromStrings("b");
264 TreeFilter filterB2 = PathFilterGroup.createFromStrings("b/2.txt");
265
266
267 walk.addTree(c1.getTree());
268 walk.addTree(c2.getTree());
269 List<DiffEntry> result = DiffEntry.scan(walk, true, new TreeFilter[] {
270 filterA, filterB, filterB2 });
271
272
273 assertThat(result, notNullValue());
274 assertEquals(5, result.size());
275
276 DiffEntry entryA = result.get(0);
277 DiffEntry entryB = result.get(1);
278 DiffEntry entryB1 = result.get(2);
279 DiffEntry entryB2 = result.get(3);
280 DiffEntry entryC = result.get(4);
281
282 assertThat(entryA.getNewPath(), is("a.txt"));
283 assertTrue(entryA.isMarked(0));
284 assertFalse(entryA.isMarked(1));
285 assertFalse(entryA.isMarked(2));
286 assertEquals(1, entryA.getTreeFilterMarks());
287
288 assertThat(entryB.getNewPath(), is("b"));
289 assertFalse(entryB.isMarked(0));
290 assertTrue(entryB.isMarked(1));
291 assertTrue(entryB.isMarked(2));
292 assertEquals(6, entryB.getTreeFilterMarks());
293
294 assertThat(entryB1.getNewPath(), is("b/1.txt"));
295 assertFalse(entryB1.isMarked(0));
296 assertTrue(entryB1.isMarked(1));
297 assertFalse(entryB1.isMarked(2));
298 assertEquals(2, entryB1.getTreeFilterMarks());
299
300 assertThat(entryB2.getNewPath(), is("b/2.txt"));
301 assertFalse(entryB2.isMarked(0));
302 assertTrue(entryB2.isMarked(1));
303 assertTrue(entryB2.isMarked(2));
304 assertEquals(6, entryB2.getTreeFilterMarks());
305
306 assertThat(entryC.getNewPath(), is("c.txt"));
307 assertFalse(entryC.isMarked(0));
308 assertFalse(entryC.isMarked(1));
309 assertFalse(entryC.isMarked(2));
310 assertEquals(0, entryC.getTreeFilterMarks());
311 }
312 }
313
314 @Test(expected = IllegalArgumentException.class)
315 public void shouldThrowIAEWhenTreeWalkHasLessThanTwoTrees()
316 throws Exception {
317
318
319
320 try (TreeWalk walk = new TreeWalk(db)) {
321 walk.addTree(new EmptyTreeIterator());
322 DiffEntry.scan(walk);
323 }
324 }
325
326 @Test(expected = IllegalArgumentException.class)
327 public void shouldThrowIAEWhenTreeWalkHasMoreThanTwoTrees()
328 throws Exception {
329
330
331
332 try (TreeWalk walk = new TreeWalk(db)) {
333 walk.addTree(new EmptyTreeIterator());
334 walk.addTree(new EmptyTreeIterator());
335 walk.addTree(new EmptyTreeIterator());
336 DiffEntry.scan(walk);
337 }
338 }
339
340 @Test(expected = IllegalArgumentException.class)
341 public void shouldThrowIAEWhenScanShouldIncludeTreesAndWalkIsRecursive()
342 throws Exception {
343
344
345
346 try (TreeWalk walk = new TreeWalk(db)) {
347 walk.addTree(new EmptyTreeIterator());
348 walk.addTree(new EmptyTreeIterator());
349 walk.setRecursive(true);
350 DiffEntry.scan(walk, true);
351 }
352 }
353
354 @Test
355 public void shouldReportFileModeChange() throws Exception {
356 writeTrashFile("a.txt", "content");
357 try (Git git = new Git(db);
358 TreeWalk walk = new TreeWalk(db)) {
359 git.add().addFilepattern("a.txt").call();
360 RevCommit c1 = git.commit().setMessage("initial commit").call();
361 DirCache cache = db.lockDirCache();
362 DirCacheEditor editor = cache.editor();
363 walk.addTree(c1.getTree());
364 walk.setRecursive(true);
365 assertTrue(walk.next());
366
367 editor.add(new PathEdit("a.txt") {
368 @Override
369 public void apply(DirCacheEntry ent) {
370 ent.setFileMode(FileMode.EXECUTABLE_FILE);
371 ent.setObjectId(walk.getObjectId(0));
372 }
373 });
374 assertTrue(editor.commit());
375 RevCommit c2 = git.commit().setMessage("second commit").call();
376 walk.reset();
377 walk.addTree(c1.getTree());
378 walk.addTree(c2.getTree());
379 List<DiffEntry> diffs = DiffEntry.scan(walk, false);
380 assertEquals(1, diffs.size());
381 DiffEntry diff = diffs.get(0);
382 assertEquals(ChangeType.MODIFY,diff.getChangeType());
383 assertEquals(diff.getOldId(), diff.getNewId());
384 assertEquals("a.txt", diff.getOldPath());
385 assertEquals(diff.getOldPath(), diff.getNewPath());
386 assertEquals(FileMode.EXECUTABLE_FILE, diff.getNewMode());
387 assertEquals(FileMode.REGULAR_FILE, diff.getOldMode());
388 }
389 }
390
391 @Test
392 public void shouldReportSubmoduleReplacedByFileMove() throws Exception {
393
394 FileRepository submoduleStandalone = createWorkRepository();
395 JGitTestUtil.writeTrashFile(submoduleStandalone, "fileInSubmodule",
396 "submodule");
397 Git submoduleStandaloneGit = Git.wrap(submoduleStandalone);
398 submoduleStandaloneGit.add().addFilepattern("fileInSubmodule").call();
399 submoduleStandaloneGit.commit().setMessage("add file to submodule")
400 .call();
401
402 Repository submodule_db = Git.wrap(db).submoduleAdd()
403 .setPath("modules/submodule")
404 .setURI(submoduleStandalone.getDirectory().toURI().toString())
405 .call();
406 File submodule_trash = submodule_db.getWorkTree();
407 addRepoToClose(submodule_db);
408 writeTrashFile("fileInRoot", "root");
409 Git rootGit = Git.wrap(db);
410 rootGit.add().addFilepattern("fileInRoot").call();
411 rootGit.commit().setMessage("add submodule and root file").call();
412
413 writeTrashFile("fileInRoot", "changed");
414 rootGit.add().addFilepattern("fileInRoot").call();
415 RevCommit firstCommit = rootGit.commit().setMessage("change root file")
416 .call();
417
418 rootGit.rm().setCached(true).addFilepattern("modules/submodule").call();
419 recursiveDelete(submodule_trash);
420 JGitTestUtil.deleteTrashFile(db, "fileInRoot");
421
422 writeTrashFile("modules/submodule/fileInRoot", "changed");
423 rootGit.rm().addFilepattern("fileInRoot").addFilepattern("modules/")
424 .call();
425 rootGit.add().addFilepattern("modules/").call();
426 RevCommit secondCommit = rootGit.commit()
427 .setMessage("remove submodule and move root file")
428 .call();
429
430
431 try (TreeWalk walk = new TreeWalk(db)) {
432 walk.addTree(firstCommit.getTree());
433 walk.addTree(secondCommit.getTree());
434 walk.setRecursive(true);
435 List<DiffEntry> diffs = DiffEntry.scan(walk);
436 assertEquals(3, diffs.size());
437 DiffEntry e = diffs.get(0);
438 assertEquals(DiffEntry.ChangeType.DELETE, e.getChangeType());
439 assertEquals("fileInRoot", e.getOldPath());
440 e = diffs.get(1);
441 assertEquals(DiffEntry.ChangeType.DELETE, e.getChangeType());
442 assertEquals("modules/submodule", e.getOldPath());
443 assertEquals(FileMode.GITLINK, e.getOldMode());
444 e = diffs.get(2);
445 assertEquals(DiffEntry.ChangeType.ADD, e.getChangeType());
446 assertEquals("modules/submodule/fileInRoot", e.getNewPath());
447 }
448
449 }
450 }