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