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 package org.eclipse.jgit.api;
44
45 import static org.eclipse.jgit.api.ResetCommand.ResetType.HARD;
46 import static org.junit.Assert.assertEquals;
47 import static org.junit.Assert.assertFalse;
48 import static org.junit.Assert.assertNotNull;
49 import static org.junit.Assert.assertNull;
50 import static org.junit.Assert.assertTrue;
51 import static org.junit.Assert.fail;
52
53 import java.io.File;
54 import java.io.IOException;
55 import java.io.PrintWriter;
56
57 import org.eclipse.jgit.api.ResetCommand.ResetType;
58 import org.eclipse.jgit.api.errors.GitAPIException;
59 import org.eclipse.jgit.api.errors.JGitInternalException;
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.errors.AmbiguousObjectException;
64 import org.eclipse.jgit.junit.RepositoryTestCase;
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.Ref;
69 import org.eclipse.jgit.revwalk.RevCommit;
70 import org.eclipse.jgit.revwalk.RevWalk;
71 import org.eclipse.jgit.treewalk.TreeWalk;
72 import org.eclipse.jgit.util.FileUtils;
73 import org.junit.Assert;
74 import org.junit.Test;
75
76 public class ResetCommandTest extends RepositoryTestCase {
77
78 private Git git;
79
80 private RevCommit initialCommit;
81
82 private RevCommit secondCommit;
83
84 private File indexFile;
85
86 private File untrackedFile;
87
88 private DirCacheEntry prestage;
89
90 public void setupRepository() throws IOException, JGitInternalException,
91 GitAPIException {
92
93
94 git = new Git(db);
95 initialCommit = git.commit().setMessage("initial commit").call();
96
97
98 File dir = new File(db.getWorkTree(), "dir");
99 FileUtils.mkdir(dir);
100 File nestedFile = new File(dir, "b.txt");
101 FileUtils.createNewFile(nestedFile);
102
103 PrintWriter nesterFileWriter = new PrintWriter(nestedFile);
104 nesterFileWriter.print("content");
105 nesterFileWriter.flush();
106
107
108 indexFile = new File(db.getWorkTree(), "a.txt");
109 FileUtils.createNewFile(indexFile);
110 PrintWriter writer = new PrintWriter(indexFile);
111 writer.print("content");
112 writer.flush();
113
114
115 git.add().addFilepattern("dir").addFilepattern("a.txt").call();
116 secondCommit = git.commit().setMessage("adding a.txt and dir/b.txt")
117 .call();
118
119 prestage = DirCache.read(db.getIndexFile(), db.getFS()).getEntry(
120 indexFile.getName());
121
122
123 writer.print("new content");
124 writer.close();
125 nesterFileWriter.print("new content");
126 nesterFileWriter.close();
127 git.add().addFilepattern("a.txt").addFilepattern("dir").call();
128
129
130 untrackedFile = new File(db.getWorkTree(),
131 "notAddedToIndex.txt");
132 FileUtils.createNewFile(untrackedFile);
133 PrintWriter writer2 = new PrintWriter(untrackedFile);
134 writer2.print("content");
135 writer2.close();
136 }
137
138 @Test
139 public void testHardReset() throws JGitInternalException,
140 AmbiguousObjectException, IOException, GitAPIException {
141 setupRepository();
142 ObjectId prevHead = db.resolve(Constants.HEAD);
143 assertSameAsHead(git.reset().setMode(ResetType.HARD)
144 .setRef(initialCommit.getName()).call());
145
146 ObjectId head = db.resolve(Constants.HEAD);
147 assertEquals(initialCommit, head);
148
149 assertFalse(indexFile.exists());
150 assertTrue(untrackedFile.exists());
151
152 String fileInIndexPath = indexFile.getAbsolutePath();
153 assertFalse(inHead(fileInIndexPath));
154 assertFalse(inIndex(indexFile.getName()));
155 assertReflog(prevHead, head);
156 assertEquals(prevHead, db.readOrigHead());
157 }
158
159 @Test
160 public void testHardResetReflogDisabled() throws Exception {
161 setupRepository();
162 ObjectId prevHead = db.resolve(Constants.HEAD);
163 ResetCommand reset = git.reset();
164 assertSameAsHead(reset.setMode(ResetType.HARD)
165 .setRef(initialCommit.getName()).disableRefLog(true).call());
166 assertTrue("reflog should be disabled", reset.isReflogDisabled());
167
168 ObjectId head = db.resolve(Constants.HEAD);
169 assertEquals(initialCommit, head);
170
171 assertFalse(indexFile.exists());
172 assertTrue(untrackedFile.exists());
173
174 String fileInIndexPath = indexFile.getAbsolutePath();
175 assertFalse(inHead(fileInIndexPath));
176 assertFalse(inIndex(indexFile.getName()));
177 assertReflogDisabled(head);
178 assertEquals(prevHead, db.readOrigHead());
179 }
180
181 @Test
182 public void testHardResetWithConflicts_DoOverWriteUntrackedFile()
183 throws JGitInternalException,
184 AmbiguousObjectException, IOException, GitAPIException {
185 setupRepository();
186 git.rm().setCached(true).addFilepattern("a.txt").call();
187 assertTrue(new File(db.getWorkTree(), "a.txt").exists());
188 git.reset().setMode(ResetType.HARD).setRef(Constants.HEAD)
189 .call();
190 assertTrue(new File(db.getWorkTree(), "a.txt").exists());
191 assertEquals("content", read(new File(db.getWorkTree(), "a.txt")));
192 }
193
194 @Test
195 public void testHardResetWithConflicts_DoDeleteFileFolderConflicts()
196 throws JGitInternalException,
197 AmbiguousObjectException, IOException, GitAPIException {
198 setupRepository();
199 writeTrashFile("d/c.txt", "x");
200 git.add().addFilepattern("d/c.txt").call();
201 FileUtils.delete(new File(db.getWorkTree(), "d"), FileUtils.RECURSIVE);
202 writeTrashFile("d", "y");
203
204 git.reset().setMode(ResetType.HARD).setRef(Constants.HEAD)
205 .call();
206 assertFalse(new File(db.getWorkTree(), "d").exists());
207 }
208
209 @Test
210 public void testResetToNonexistingHEAD() throws JGitInternalException,
211 AmbiguousObjectException, IOException, GitAPIException {
212
213
214 git = new Git(db);
215 writeTrashFile("f", "content");
216
217 try {
218 git.reset().setRef(Constants.HEAD).call();
219 fail("Expected JGitInternalException didn't occur");
220 } catch (JGitInternalException e) {
221
222 }
223 }
224
225 @Test
226 public void testSoftReset() throws JGitInternalException,
227 AmbiguousObjectException, IOException, GitAPIException {
228 setupRepository();
229 ObjectId prevHead = db.resolve(Constants.HEAD);
230 assertSameAsHead(git.reset().setMode(ResetType.SOFT)
231 .setRef(initialCommit.getName()).call());
232
233 ObjectId head = db.resolve(Constants.HEAD);
234 assertEquals(initialCommit, head);
235
236 assertTrue(untrackedFile.exists());
237 assertTrue(indexFile.exists());
238
239 String fileInIndexPath = indexFile.getAbsolutePath();
240 assertFalse(inHead(fileInIndexPath));
241 assertTrue(inIndex(indexFile.getName()));
242 assertReflog(prevHead, head);
243 assertEquals(prevHead, db.readOrigHead());
244 }
245
246 @Test
247 public void testMixedReset() throws JGitInternalException,
248 AmbiguousObjectException, IOException, GitAPIException {
249 setupRepository();
250 ObjectId prevHead = db.resolve(Constants.HEAD);
251 assertSameAsHead(git.reset().setMode(ResetType.MIXED)
252 .setRef(initialCommit.getName()).call());
253
254 ObjectId head = db.resolve(Constants.HEAD);
255 assertEquals(initialCommit, head);
256
257 assertTrue(untrackedFile.exists());
258 assertTrue(indexFile.exists());
259
260 String fileInIndexPath = indexFile.getAbsolutePath();
261 assertFalse(inHead(fileInIndexPath));
262 assertFalse(inIndex(indexFile.getName()));
263
264 assertReflog(prevHead, head);
265 assertEquals(prevHead, db.readOrigHead());
266 }
267
268 @Test
269 public void testMixedResetRetainsSizeAndModifiedTime() throws Exception {
270 git = new Git(db);
271
272 writeTrashFile("a.txt", "a").setLastModified(
273 System.currentTimeMillis() - 60 * 1000);
274 assertNotNull(git.add().addFilepattern("a.txt").call());
275 assertNotNull(git.commit().setMessage("a commit").call());
276
277 writeTrashFile("b.txt", "b").setLastModified(
278 System.currentTimeMillis() - 60 * 1000);
279 assertNotNull(git.add().addFilepattern("b.txt").call());
280 RevCommit commit2 = git.commit().setMessage("b commit").call();
281 assertNotNull(commit2);
282
283 DirCache cache = db.readDirCache();
284
285 DirCacheEntry aEntry = cache.getEntry("a.txt");
286 assertNotNull(aEntry);
287 assertTrue(aEntry.getLength() > 0);
288 assertTrue(aEntry.getLastModified() > 0);
289
290 DirCacheEntry bEntry = cache.getEntry("b.txt");
291 assertNotNull(bEntry);
292 assertTrue(bEntry.getLength() > 0);
293 assertTrue(bEntry.getLastModified() > 0);
294
295 assertSameAsHead(git.reset().setMode(ResetType.MIXED)
296 .setRef(commit2.getName()).call());
297
298 cache = db.readDirCache();
299
300 DirCacheEntry mixedAEntry = cache.getEntry("a.txt");
301 assertNotNull(mixedAEntry);
302 assertEquals(aEntry.getLastModified(), mixedAEntry.getLastModified());
303 assertEquals(aEntry.getLastModified(), mixedAEntry.getLastModified());
304
305 DirCacheEntry mixedBEntry = cache.getEntry("b.txt");
306 assertNotNull(mixedBEntry);
307 assertEquals(bEntry.getLastModified(), mixedBEntry.getLastModified());
308 assertEquals(bEntry.getLastModified(), mixedBEntry.getLastModified());
309 }
310
311 @Test
312 public void testMixedResetWithUnmerged() throws Exception {
313 git = new Git(db);
314
315 String file = "a.txt";
316 writeTrashFile(file, "data");
317 String file2 = "b.txt";
318 writeTrashFile(file2, "data");
319
320 git.add().addFilepattern(file).addFilepattern(file2).call();
321 git.commit().setMessage("commit").call();
322
323 DirCache index = db.lockDirCache();
324 DirCacheBuilder builder = index.builder();
325 builder.add(createEntry(file, FileMode.REGULAR_FILE, 1, ""));
326 builder.add(createEntry(file, FileMode.REGULAR_FILE, 2, ""));
327 builder.add(createEntry(file, FileMode.REGULAR_FILE, 3, ""));
328 assertTrue(builder.commit());
329
330 assertEquals("[a.txt, mode:100644, stage:1]"
331 + "[a.txt, mode:100644, stage:2]"
332 + "[a.txt, mode:100644, stage:3]",
333 indexState(0));
334
335 assertSameAsHead(git.reset().setMode(ResetType.MIXED).call());
336
337 assertEquals("[a.txt, mode:100644]" + "[b.txt, mode:100644]",
338 indexState(0));
339 }
340
341 @Test
342 public void testPathsReset() throws Exception {
343 setupRepository();
344
345 DirCacheEntry preReset = DirCache.read(db.getIndexFile(), db.getFS())
346 .getEntry(indexFile.getName());
347 assertNotNull(preReset);
348
349 git.add().addFilepattern(untrackedFile.getName()).call();
350
351
352
353 assertSameAsHead(git.reset().addPath(indexFile.getName())
354 .addPath(untrackedFile.getName()).call());
355
356 DirCacheEntry postReset = DirCache.read(db.getIndexFile(), db.getFS())
357 .getEntry(indexFile.getName());
358 assertNotNull(postReset);
359 Assert.assertNotSame(preReset.getObjectId(), postReset.getObjectId());
360 Assert.assertEquals(prestage.getObjectId(), postReset.getObjectId());
361
362
363 ObjectId head = db.resolve(Constants.HEAD);
364 assertEquals(secondCommit, head);
365
366 assertTrue(untrackedFile.exists());
367 assertTrue(indexFile.exists());
368 assertTrue(inHead(indexFile.getName()));
369 assertTrue(inIndex(indexFile.getName()));
370 assertFalse(inIndex(untrackedFile.getName()));
371 }
372
373 @Test
374 public void testPathsResetOnDirs() throws Exception {
375 setupRepository();
376
377 DirCacheEntry preReset = DirCache.read(db.getIndexFile(), db.getFS())
378 .getEntry("dir/b.txt");
379 assertNotNull(preReset);
380
381 git.add().addFilepattern(untrackedFile.getName()).call();
382
383
384 assertSameAsHead(git.reset().addPath("dir").call());
385
386 DirCacheEntry postReset = DirCache.read(db.getIndexFile(), db.getFS())
387 .getEntry("dir/b.txt");
388 assertNotNull(postReset);
389 Assert.assertNotSame(preReset.getObjectId(), postReset.getObjectId());
390
391
392 ObjectId head = db.resolve(Constants.HEAD);
393 assertEquals(secondCommit, head);
394
395 assertTrue(untrackedFile.exists());
396 assertTrue(inHead("dir/b.txt"));
397 assertTrue(inIndex("dir/b.txt"));
398 }
399
400 @Test
401 public void testPathsResetWithRef() throws Exception {
402 setupRepository();
403
404 DirCacheEntry preReset = DirCache.read(db.getIndexFile(), db.getFS())
405 .getEntry(indexFile.getName());
406 assertNotNull(preReset);
407
408 git.add().addFilepattern(untrackedFile.getName()).call();
409
410
411
412
413 assertSameAsHead(git.reset().setRef(initialCommit.getName())
414 .addPath(indexFile.getName()).addPath(untrackedFile.getName())
415 .call());
416
417
418 ObjectId head = db.resolve(Constants.HEAD);
419 assertEquals(secondCommit, head);
420
421 assertTrue(untrackedFile.exists());
422 assertTrue(indexFile.exists());
423 assertTrue(inHead(indexFile.getName()));
424 assertFalse(inIndex(indexFile.getName()));
425 assertFalse(inIndex(untrackedFile.getName()));
426 }
427
428 @Test
429 public void testPathsResetWithUnmerged() throws Exception {
430 setupRepository();
431
432 String file = "a.txt";
433 writeTrashFile(file, "data");
434
435 git.add().addFilepattern(file).call();
436 git.commit().setMessage("commit").call();
437
438 DirCache index = db.lockDirCache();
439 DirCacheBuilder builder = index.builder();
440 builder.add(createEntry(file, FileMode.REGULAR_FILE, 1, ""));
441 builder.add(createEntry(file, FileMode.REGULAR_FILE, 2, ""));
442 builder.add(createEntry(file, FileMode.REGULAR_FILE, 3, ""));
443 builder.add(createEntry("b.txt", FileMode.REGULAR_FILE));
444 assertTrue(builder.commit());
445
446 assertEquals("[a.txt, mode:100644, stage:1]"
447 + "[a.txt, mode:100644, stage:2]"
448 + "[a.txt, mode:100644, stage:3]"
449 + "[b.txt, mode:100644]",
450 indexState(0));
451
452 assertSameAsHead(git.reset().addPath(file).call());
453
454 assertEquals("[a.txt, mode:100644]" + "[b.txt, mode:100644]",
455 indexState(0));
456 }
457
458 @Test
459 public void testPathsResetOnUnbornBranch() throws Exception {
460 git = new Git(db);
461 writeTrashFile("a.txt", "content");
462 git.add().addFilepattern("a.txt").call();
463
464 assertSameAsHead(git.reset().addPath("a.txt").call());
465
466 DirCache cache = db.readDirCache();
467 DirCacheEntry aEntry = cache.getEntry("a.txt");
468 assertNull(aEntry);
469 }
470
471 @Test(expected = JGitInternalException.class)
472 public void testPathsResetToNonexistingRef() throws Exception {
473 git = new Git(db);
474 writeTrashFile("a.txt", "content");
475 git.add().addFilepattern("a.txt").call();
476 assertSameAsHead(
477 git.reset().setRef("doesnotexist").addPath("a.txt").call());
478 }
479
480 @Test
481 public void testResetDefaultMode() throws Exception {
482 git = new Git(db);
483 writeTrashFile("a.txt", "content");
484 git.add().addFilepattern("a.txt").call();
485 writeTrashFile("a.txt", "modified");
486
487 assertSameAsHead(git.reset().call());
488
489 DirCache cache = db.readDirCache();
490 DirCacheEntry aEntry = cache.getEntry("a.txt");
491 assertNull(aEntry);
492 assertEquals("modified", read("a.txt"));
493 }
494
495 @Test
496 public void testHardResetOnTag() throws Exception {
497 setupRepository();
498 String tagName = "initialtag";
499 git.tag().setName(tagName).setObjectId(secondCommit)
500 .setMessage("message").call();
501
502 DirCacheEntry preReset = DirCache.read(db.getIndexFile(), db.getFS())
503 .getEntry(indexFile.getName());
504 assertNotNull(preReset);
505
506 git.add().addFilepattern(untrackedFile.getName()).call();
507
508 assertSameAsHead(git.reset().setRef(tagName).setMode(HARD).call());
509
510 ObjectId head = db.resolve(Constants.HEAD);
511 assertEquals(secondCommit, head);
512 }
513
514 @Test
515 public void testHardResetAfterSquashMerge() throws Exception {
516 git = new Git(db);
517
518 writeTrashFile("file1", "file1");
519 git.add().addFilepattern("file1").call();
520 RevCommit first = git.commit().setMessage("initial commit").call();
521
522 assertTrue(new File(db.getWorkTree(), "file1").exists());
523 createBranch(first, "refs/heads/branch1");
524 checkoutBranch("refs/heads/branch1");
525
526 writeTrashFile("file2", "file2");
527 git.add().addFilepattern("file2").call();
528 git.commit().setMessage("second commit").call();
529 assertTrue(new File(db.getWorkTree(), "file2").exists());
530
531 checkoutBranch("refs/heads/master");
532
533 MergeResult result = git.merge()
534 .include(db.exactRef("refs/heads/branch1"))
535 .setSquash(true)
536 .call();
537
538 assertEquals(MergeResult.MergeStatus.FAST_FORWARD_SQUASHED,
539 result.getMergeStatus());
540 assertNotNull(db.readSquashCommitMsg());
541
542 assertSameAsHead(git.reset().setMode(ResetType.HARD)
543 .setRef(first.getName()).call());
544
545 assertNull(db.readSquashCommitMsg());
546 }
547
548 @Test
549 public void testHardResetOnUnbornBranch() throws Exception {
550 git = new Git(db);
551 File fileA = writeTrashFile("a.txt", "content");
552 git.add().addFilepattern("a.txt").call();
553
554 assertSameAsHead(git.reset().setMode(ResetType.HARD).call());
555
556 DirCache cache = db.readDirCache();
557 DirCacheEntry aEntry = cache.getEntry("a.txt");
558 assertNull(aEntry);
559 assertFalse(fileA.exists());
560 assertNull(db.resolve(Constants.HEAD));
561 }
562
563 private void assertReflog(ObjectId prevHead, ObjectId head)
564 throws IOException {
565
566 String actualHeadMessage = db.getReflogReader(Constants.HEAD)
567 .getLastEntry().getComment();
568 String expectedHeadMessage = head.getName() + ": updating HEAD";
569 assertEquals(expectedHeadMessage, actualHeadMessage);
570 assertEquals(head.getName(), db.getReflogReader(Constants.HEAD)
571 .getLastEntry().getNewId().getName());
572 assertEquals(prevHead.getName(), db.getReflogReader(Constants.HEAD)
573 .getLastEntry().getOldId().getName());
574
575
576 String actualMasterMessage = db.getReflogReader("refs/heads/master")
577 .getLastEntry().getComment();
578 String expectedMasterMessage = head.getName() + ": updating HEAD";
579 assertEquals(expectedMasterMessage, actualMasterMessage);
580 assertEquals(head.getName(), db.getReflogReader(Constants.HEAD)
581 .getLastEntry().getNewId().getName());
582 assertEquals(prevHead.getName(), db
583 .getReflogReader("refs/heads/master").getLastEntry().getOldId()
584 .getName());
585 }
586
587 private void assertReflogDisabled(ObjectId head)
588 throws IOException {
589
590 String actualHeadMessage = db.getReflogReader(Constants.HEAD)
591 .getLastEntry().getComment();
592 String expectedHeadMessage = "commit: adding a.txt and dir/b.txt";
593 assertEquals(expectedHeadMessage, actualHeadMessage);
594 assertEquals(head.getName(), db.getReflogReader(Constants.HEAD)
595 .getLastEntry().getOldId().getName());
596
597
598 String actualMasterMessage = db.getReflogReader("refs/heads/master")
599 .getLastEntry().getComment();
600 String expectedMasterMessage = "commit: adding a.txt and dir/b.txt";
601 assertEquals(expectedMasterMessage, actualMasterMessage);
602 assertEquals(head.getName(), db.getReflogReader(Constants.HEAD)
603 .getLastEntry().getOldId().getName());
604 }
605
606
607
608
609
610
611
612 private boolean inHead(String path) throws IOException {
613 ObjectId headId = db.resolve(Constants.HEAD);
614 try (RevWalk rw = new RevWalk(db);
615 TreeWalk tw = TreeWalk.forPath(db, path,
616 rw.parseTree(headId))) {
617 return tw != null;
618 }
619 }
620
621
622
623
624
625
626
627
628 private boolean inIndex(String path) throws IOException {
629 DirCache dc = DirCache.read(db.getIndexFile(), db.getFS());
630 return dc.getEntry(path) != null;
631 }
632
633
634
635
636
637
638 private void assertSameAsHead(Ref ref) throws IOException {
639 Ref headRef = db.exactRef(Constants.HEAD);
640 assertEquals(headRef.getName(), ref.getName());
641 assertEquals(headRef.getObjectId(), ref.getObjectId());
642 }
643 }