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 java.nio.charset.StandardCharsets.UTF_8;
46 import static org.hamcrest.CoreMatchers.equalTo;
47 import static org.hamcrest.CoreMatchers.not;
48 import static org.hamcrest.MatcherAssert.assertThat;
49 import static org.junit.Assert.assertEquals;
50 import static org.junit.Assert.assertFalse;
51 import static org.junit.Assert.assertNotNull;
52 import static org.junit.Assert.assertTrue;
53 import static org.junit.Assert.fail;
54
55 import java.io.BufferedReader;
56 import java.io.File;
57 import java.io.FileInputStream;
58 import java.io.IOException;
59 import java.io.InputStreamReader;
60 import java.util.ArrayList;
61 import java.util.Collections;
62 import java.util.HashSet;
63 import java.util.Iterator;
64 import java.util.List;
65 import java.util.Set;
66
67 import org.eclipse.jgit.api.MergeResult.MergeStatus;
68 import org.eclipse.jgit.api.RebaseCommand.InteractiveHandler;
69 import org.eclipse.jgit.api.RebaseCommand.Operation;
70 import org.eclipse.jgit.api.RebaseResult.Status;
71 import org.eclipse.jgit.api.errors.InvalidRebaseStepException;
72 import org.eclipse.jgit.api.errors.RefNotFoundException;
73 import org.eclipse.jgit.api.errors.UnmergedPathsException;
74 import org.eclipse.jgit.api.errors.WrongRepositoryStateException;
75 import org.eclipse.jgit.diff.DiffEntry;
76 import org.eclipse.jgit.dircache.DirCacheCheckout;
77 import org.eclipse.jgit.errors.AmbiguousObjectException;
78 import org.eclipse.jgit.errors.IllegalTodoFileModification;
79 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
80 import org.eclipse.jgit.errors.MissingObjectException;
81 import org.eclipse.jgit.events.ListenerHandle;
82 import org.eclipse.jgit.junit.RepositoryTestCase;
83 import org.eclipse.jgit.lib.AbbreviatedObjectId;
84 import org.eclipse.jgit.lib.ConfigConstants;
85 import org.eclipse.jgit.lib.Constants;
86 import org.eclipse.jgit.lib.ObjectId;
87 import org.eclipse.jgit.lib.ObjectLoader;
88 import org.eclipse.jgit.lib.PersonIdent;
89 import org.eclipse.jgit.lib.RebaseTodoLine;
90 import org.eclipse.jgit.lib.RebaseTodoLine.Action;
91 import org.eclipse.jgit.lib.RefUpdate;
92 import org.eclipse.jgit.lib.ReflogEntry;
93 import org.eclipse.jgit.lib.RepositoryState;
94 import org.eclipse.jgit.merge.MergeStrategy;
95 import org.eclipse.jgit.revwalk.RevCommit;
96 import org.eclipse.jgit.revwalk.RevSort;
97 import org.eclipse.jgit.revwalk.RevWalk;
98 import org.eclipse.jgit.treewalk.TreeWalk;
99 import org.eclipse.jgit.treewalk.filter.TreeFilter;
100 import org.eclipse.jgit.util.FileUtils;
101 import org.eclipse.jgit.util.IO;
102 import org.eclipse.jgit.util.RawParseUtils;
103 import org.junit.Before;
104 import org.junit.Test;
105
106 public class RebaseCommandTest extends RepositoryTestCase {
107 private static final String GIT_REBASE_TODO = "rebase-merge/git-rebase-todo";
108
109 private static final String FILE1 = "file1";
110
111 protected Git git;
112
113 @Override
114 @Before
115 public void setUp() throws Exception {
116 super.setUp();
117 this.git = new Git(db);
118 }
119
120 private void checkoutCommit(RevCommit commit) throws IllegalStateException,
121 IOException {
122 RevCommit head;
123 try (RevWalk walk = new RevWalk(db)) {
124 head = walk.parseCommit(db.resolve(Constants.HEAD));
125 DirCacheCheckout dco = new DirCacheCheckout(db, head.getTree(),
126 db.lockDirCache(), commit.getTree());
127 dco.setFailOnConflict(true);
128 dco.checkout();
129 }
130
131 RefUpdate refUpdate = db.updateRef(Constants.HEAD, true);
132 refUpdate.setNewObjectId(commit);
133 refUpdate.setRefLogMessage("checkout: moving to " + head.getName(),
134 false);
135 refUpdate.forceUpdate();
136 }
137
138 @Test
139 public void testFastForwardWithNewFile() throws Exception {
140
141 writeTrashFile(FILE1, FILE1);
142 git.add().addFilepattern(FILE1).call();
143 RevCommit first = git.commit().setMessage("Add file1").call();
144
145 assertTrue(new File(db.getWorkTree(), FILE1).exists());
146
147 createBranch(first, "refs/heads/topic");
148
149 File file2 = writeTrashFile("file2", "file2");
150 git.add().addFilepattern("file2").call();
151 RevCommit second = git.commit().setMessage("Add file2").call();
152 assertTrue(new File(db.getWorkTree(), "file2").exists());
153
154 checkoutBranch("refs/heads/topic");
155 assertFalse(new File(db.getWorkTree(), "file2").exists());
156
157 RebaseResult res = git.rebase().setUpstream("refs/heads/master").call();
158 assertTrue(new File(db.getWorkTree(), "file2").exists());
159 checkFile(file2, "file2");
160 assertEquals(Status.FAST_FORWARD, res.getStatus());
161
162 List<ReflogEntry> headLog = db.getReflogReader(Constants.HEAD)
163 .getReverseEntries();
164 List<ReflogEntry> topicLog = db.getReflogReader("refs/heads/topic")
165 .getReverseEntries();
166 List<ReflogEntry> masterLog = db.getReflogReader("refs/heads/master")
167 .getReverseEntries();
168 assertEquals("rebase finished: returning to refs/heads/topic", headLog
169 .get(0).getComment());
170 assertEquals("checkout: moving from topic to " + second.getName(),
171 headLog.get(1).getComment());
172 assertEquals(2, masterLog.size());
173 assertEquals(2, topicLog.size());
174 assertEquals(
175 "rebase finished: refs/heads/topic onto " + second.getName(),
176 topicLog.get(0).getComment());
177 }
178
179 @Test
180 public void testFastForwardWithMultipleCommits() throws Exception {
181
182 writeTrashFile(FILE1, FILE1);
183 git.add().addFilepattern(FILE1).call();
184 RevCommit first = git.commit().setMessage("Add file1").call();
185
186 assertTrue(new File(db.getWorkTree(), FILE1).exists());
187
188 createBranch(first, "refs/heads/topic");
189
190 File file2 = writeTrashFile("file2", "file2");
191 git.add().addFilepattern("file2").call();
192 git.commit().setMessage("Add file2").call();
193 assertTrue(new File(db.getWorkTree(), "file2").exists());
194
195 writeTrashFile("file2", "file2 new content");
196 git.add().addFilepattern("file2").call();
197 RevCommit second = git.commit().setMessage("Change content of file2")
198 .call();
199
200 checkoutBranch("refs/heads/topic");
201 assertFalse(new File(db.getWorkTree(), "file2").exists());
202
203 RebaseResult res = git.rebase().setUpstream("refs/heads/master").call();
204 assertTrue(new File(db.getWorkTree(), "file2").exists());
205 checkFile(file2, "file2 new content");
206 assertEquals(Status.FAST_FORWARD, res.getStatus());
207
208 List<ReflogEntry> headLog = db.getReflogReader(Constants.HEAD)
209 .getReverseEntries();
210 List<ReflogEntry> topicLog = db.getReflogReader("refs/heads/topic")
211 .getReverseEntries();
212 List<ReflogEntry> masterLog = db.getReflogReader("refs/heads/master")
213 .getReverseEntries();
214 assertEquals("rebase finished: returning to refs/heads/topic", headLog
215 .get(0).getComment());
216 assertEquals("checkout: moving from topic to " + second.getName(),
217 headLog.get(1).getComment());
218 assertEquals(3, masterLog.size());
219 assertEquals(2, topicLog.size());
220 assertEquals(
221 "rebase finished: refs/heads/topic onto " + second.getName(),
222 topicLog.get(0).getComment());
223 }
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249 @Test
250 public void testRebaseShouldIgnoreMergeCommits()
251 throws Exception {
252
253 writeTrashFile(FILE1, FILE1);
254 git.add().addFilepattern(FILE1).call();
255 RevCommit a = git.commit().setMessage("Add file1").call();
256 assertTrue(new File(db.getWorkTree(), FILE1).exists());
257
258
259 createBranch(a, "refs/heads/topic");
260
261
262 writeTrashFile(FILE1, "blah");
263 git.add().addFilepattern(FILE1).call();
264 RevCommit b = git.commit().setMessage("updated file1 on master").call();
265
266 checkoutBranch("refs/heads/topic");
267 writeTrashFile("file3", "more changess");
268 git.add().addFilepattern("file3").call();
269 RevCommit c = git.commit()
270 .setMessage("update file3 on topic").call();
271
272
273 createBranch(c, "refs/heads/side");
274
275
276 writeTrashFile("file2", "file2");
277 git.add().addFilepattern("file2").call();
278 RevCommit d = git.commit().setMessage("Add file2").call();
279 assertTrue(new File(db.getWorkTree(), "file2").exists());
280
281
282 checkoutBranch("refs/heads/side");
283 writeTrashFile("file3", "more change");
284 git.add().addFilepattern("file3").call();
285 RevCommit e = git.commit().setMessage("update file2 on side")
286 .call();
287
288
289 checkoutBranch("refs/heads/topic");
290 MergeResult result = git.merge().include(e.getId())
291 .setStrategy(MergeStrategy.RESOLVE).call();
292 assertEquals(MergeStatus.MERGED, result.getMergeStatus());
293 RebaseResult res = git.rebase().setUpstream("refs/heads/master").call();
294 assertEquals(Status.OK, res.getStatus());
295
296 try (RevWalk rw = new RevWalk(db)) {
297 rw.markStart(rw.parseCommit(db.resolve("refs/heads/topic")));
298 assertDerivedFrom(rw.next(), e);
299 assertDerivedFrom(rw.next(), d);
300 assertDerivedFrom(rw.next(), c);
301 assertEquals(b, rw.next());
302 assertEquals(a, rw.next());
303 }
304
305 List<ReflogEntry> headLog = db.getReflogReader(Constants.HEAD)
306 .getReverseEntries();
307 List<ReflogEntry> sideLog = db.getReflogReader("refs/heads/side")
308 .getReverseEntries();
309 List<ReflogEntry> topicLog = db.getReflogReader("refs/heads/topic")
310 .getReverseEntries();
311 List<ReflogEntry> masterLog = db.getReflogReader("refs/heads/master")
312 .getReverseEntries();
313 assertEquals("rebase finished: returning to refs/heads/topic", headLog
314 .get(0).getComment());
315 assertEquals("rebase: update file2 on side", headLog.get(1)
316 .getComment());
317 assertEquals("rebase: Add file2", headLog.get(2).getComment());
318 assertEquals("rebase: update file3 on topic", headLog.get(3)
319 .getComment());
320 assertEquals("checkout: moving from topic to " + b.getName(), headLog
321 .get(4).getComment());
322 assertEquals(2, masterLog.size());
323 assertEquals(2, sideLog.size());
324 assertEquals(5, topicLog.size());
325 assertEquals("rebase finished: refs/heads/topic onto " + b.getName(),
326 topicLog.get(0).getComment());
327 }
328
329 static void assertDerivedFrom(RevCommit derived, RevCommit original) {
330 assertThat(derived, not(equalTo(original)));
331 assertEquals(original.getFullMessage(), derived.getFullMessage());
332 }
333
334 @Test
335 public void testRebasePreservingMerges1() throws Exception {
336 doTestRebasePreservingMerges(true);
337 }
338
339 @Test
340 public void testRebasePreservingMerges2() throws Exception {
341 doTestRebasePreservingMerges(false);
342 }
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361 private void doTestRebasePreservingMerges(boolean testConflict)
362 throws Exception {
363
364 writeTrashFile(FILE1, FILE1);
365 git.add().addFilepattern(FILE1).call();
366 RevCommit a = git.commit().setMessage("commit a").call();
367
368
369 createBranch(a, "refs/heads/topic");
370
371
372 writeTrashFile(FILE1, "blah");
373 writeTrashFile("conflict", "b");
374 git.add().addFilepattern(".").call();
375 RevCommit b = git.commit().setMessage("commit b").call();
376
377 checkoutBranch("refs/heads/topic");
378 writeTrashFile("file3", "more changess");
379 git.add().addFilepattern("file3").call();
380 RevCommit c = git.commit().setMessage("commit c").call();
381
382
383 createBranch(c, "refs/heads/side");
384
385
386 writeTrashFile("file2", "file2");
387 if (testConflict)
388 writeTrashFile("conflict", "d");
389 git.add().addFilepattern(".").call();
390 RevCommit d = git.commit().setMessage("commit d").call();
391 assertTrue(new File(db.getWorkTree(), "file2").exists());
392
393
394 checkoutBranch("refs/heads/side");
395 writeTrashFile("file3", "more change");
396 if (testConflict)
397 writeTrashFile("conflict", "e");
398 git.add().addFilepattern(".").call();
399 RevCommit e = git.commit().setMessage("commit e").call();
400
401
402 checkoutBranch("refs/heads/topic");
403 MergeResult result = git.merge().include(e.getId())
404 .setStrategy(MergeStrategy.RESOLVE).call();
405 final RevCommit f;
406 if (testConflict) {
407 assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus());
408 assertEquals(Collections.singleton("conflict"), git.status().call()
409 .getConflicting());
410
411 writeTrashFile("conflict", "f resolved");
412 git.add().addFilepattern("conflict").call();
413 f = git.commit().setMessage("commit f").call();
414 } else {
415 assertEquals(MergeStatus.MERGED, result.getMergeStatus());
416 try (RevWalk rw = new RevWalk(db)) {
417 f = rw.parseCommit(result.getNewHead());
418 }
419 }
420
421 RebaseResult res = git.rebase().setUpstream("refs/heads/master")
422 .setPreserveMerges(true).call();
423 if (testConflict) {
424
425 assertEquals(Status.STOPPED, res.getStatus());
426 assertEquals(Collections.singleton("conflict"), git.status().call()
427 .getConflicting());
428 assertTrue(read("conflict").contains("\nb\n=======\nd\n"));
429
430 writeTrashFile("conflict", "d new");
431 git.add().addFilepattern("conflict").call();
432 res = git.rebase().setOperation(Operation.CONTINUE).call();
433
434
435 assertEquals(Status.STOPPED, res.getStatus());
436 assertEquals(Collections.singleton("conflict"), git.status().call()
437 .getConflicting());
438 assertTrue(read("conflict").contains("\nb\n=======\ne\n"));
439
440 writeTrashFile("conflict", "e new");
441 git.add().addFilepattern("conflict").call();
442 res = git.rebase().setOperation(Operation.CONTINUE).call();
443
444
445 assertEquals(Status.STOPPED, res.getStatus());
446 assertEquals(Collections.singleton("conflict"), git.status().call()
447 .getConflicting());
448 assertTrue(read("conflict").contains("\nd new\n=======\ne new\n"));
449
450 writeTrashFile("conflict", "f new resolved");
451 git.add().addFilepattern("conflict").call();
452 res = git.rebase().setOperation(Operation.CONTINUE).call();
453 }
454 assertEquals(Status.OK, res.getStatus());
455
456 if (testConflict)
457 assertEquals("f new resolved", read("conflict"));
458 assertEquals("blah", read(FILE1));
459 assertEquals("file2", read("file2"));
460 assertEquals("more change", read("file3"));
461
462 try (RevWalk rw = new RevWalk(db)) {
463 rw.markStart(rw.parseCommit(db.resolve("refs/heads/topic")));
464 RevCommit newF = rw.next();
465 assertDerivedFrom(newF, f);
466 assertEquals(2, newF.getParentCount());
467 RevCommit newD = rw.next();
468 assertDerivedFrom(newD, d);
469 if (testConflict)
470 assertEquals("d new", readFile("conflict", newD));
471 RevCommit newE = rw.next();
472 assertDerivedFrom(newE, e);
473 if (testConflict)
474 assertEquals("e new", readFile("conflict", newE));
475 assertEquals(newD, newF.getParent(0));
476 assertEquals(newE, newF.getParent(1));
477 assertDerivedFrom(rw.next(), c);
478 assertEquals(b, rw.next());
479 assertEquals(a, rw.next());
480 }
481 }
482
483 private String readFile(String path, RevCommit commit) throws IOException {
484 try (TreeWalk walk = TreeWalk.forPath(db, path, commit.getTree())) {
485 ObjectLoader loader = db.open(walk.getObjectId(0),
486 Constants.OBJ_BLOB);
487 String result = RawParseUtils.decode(loader.getCachedBytes());
488 return result;
489 }
490 }
491
492 @Test
493 public void testRebasePreservingMergesWithUnrelatedSide1() throws Exception {
494 doTestRebasePreservingMergesWithUnrelatedSide(true);
495 }
496
497 @Test
498 public void testRebasePreservingMergesWithUnrelatedSide2() throws Exception {
499 doTestRebasePreservingMergesWithUnrelatedSide(false);
500 }
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526 private void doTestRebasePreservingMergesWithUnrelatedSide(
527 boolean testConflict) throws Exception {
528 try (RevWalk rw = new RevWalk(db)) {
529 rw.sort(RevSort.TOPO);
530
531 writeTrashFile(FILE1, FILE1);
532 git.add().addFilepattern(FILE1).call();
533 RevCommit a = git.commit().setMessage("commit a").call();
534
535 writeTrashFile("file2", "blah");
536 git.add().addFilepattern("file2").call();
537 RevCommit b = git.commit().setMessage("commit b").call();
538
539
540 createBranch(b, "refs/heads/topic");
541 checkoutBranch("refs/heads/topic");
542
543 writeTrashFile("file3", "more changess");
544 writeTrashFile(FILE1, "preparing conflict");
545 git.add().addFilepattern("file3").addFilepattern(FILE1).call();
546 RevCommit c = git.commit().setMessage("commit c").call();
547
548 createBranch(a, "refs/heads/side");
549 checkoutBranch("refs/heads/side");
550 writeTrashFile("conflict", "e");
551 writeTrashFile(FILE1, FILE1 + "\n" + "line 2");
552 git.add().addFilepattern(".").call();
553 RevCommit e = git.commit().setMessage("commit e").call();
554
555
556 checkoutBranch("refs/heads/topic");
557 MergeResult result = git.merge().include(e)
558 .setStrategy(MergeStrategy.RESOLVE).call();
559
560 assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus());
561 assertEquals(result.getConflicts().keySet(),
562 Collections.singleton(FILE1));
563 writeTrashFile(FILE1, "merge resolution");
564 git.add().addFilepattern(FILE1).call();
565 RevCommit d = git.commit().setMessage("commit d").call();
566
567 RevCommit f = commitFile("file2", "new content two", "topic");
568
569 checkoutBranch("refs/heads/master");
570 writeTrashFile("fileg", "fileg");
571 if (testConflict)
572 writeTrashFile("conflict", "g");
573 git.add().addFilepattern(".").call();
574 RevCommit g = git.commit().setMessage("commit g").call();
575
576 checkoutBranch("refs/heads/topic");
577 RebaseResult res = git.rebase().setUpstream("refs/heads/master")
578 .setPreserveMerges(true).call();
579 if (testConflict) {
580 assertEquals(Status.STOPPED, res.getStatus());
581 assertEquals(Collections.singleton("conflict"), git.status().call()
582 .getConflicting());
583
584 writeTrashFile("conflict", "e");
585 git.add().addFilepattern("conflict").call();
586 res = git.rebase().setOperation(Operation.CONTINUE).call();
587 }
588 assertEquals(Status.OK, res.getStatus());
589
590 assertEquals("merge resolution", read(FILE1));
591 assertEquals("new content two", read("file2"));
592 assertEquals("more changess", read("file3"));
593 assertEquals("fileg", read("fileg"));
594
595 rw.markStart(rw.parseCommit(db.resolve("refs/heads/topic")));
596 RevCommit newF = rw.next();
597 assertDerivedFrom(newF, f);
598 RevCommit newD = rw.next();
599 assertDerivedFrom(newD, d);
600 assertEquals(2, newD.getParentCount());
601 RevCommit newC = rw.next();
602 assertDerivedFrom(newC, c);
603 RevCommit newE = rw.next();
604 assertEquals(e, newE);
605 assertEquals(newC, newD.getParent(0));
606 assertEquals(e, newD.getParent(1));
607 assertEquals(g, rw.next());
608 assertEquals(b, rw.next());
609 assertEquals(a, rw.next());
610 }
611 }
612
613 @Test
614 public void testRebaseParentOntoHeadShouldBeUptoDate() throws Exception {
615 writeTrashFile(FILE1, FILE1);
616 git.add().addFilepattern(FILE1).call();
617 RevCommit parent = git.commit().setMessage("parent comment").call();
618
619 writeTrashFile(FILE1, "another change");
620 git.add().addFilepattern(FILE1).call();
621 git.commit().setMessage("head commit").call();
622
623 RebaseResult result = git.rebase().setUpstream(parent).call();
624 assertEquals(Status.UP_TO_DATE, result.getStatus());
625
626 assertEquals(2, db.getReflogReader(Constants.HEAD).getReverseEntries()
627 .size());
628 assertEquals(2, db.getReflogReader("refs/heads/master")
629 .getReverseEntries().size());
630 }
631
632 @Test
633 public void testUpToDate() throws Exception {
634
635 writeTrashFile(FILE1, FILE1);
636 git.add().addFilepattern(FILE1).call();
637 RevCommit first = git.commit().setMessage("Add file1").call();
638
639 assertTrue(new File(db.getWorkTree(), FILE1).exists());
640
641 RebaseResult res = git.rebase().setUpstream(first).call();
642 assertEquals(Status.UP_TO_DATE, res.getStatus());
643
644 assertEquals(1, db.getReflogReader(Constants.HEAD).getReverseEntries()
645 .size());
646 assertEquals(1, db.getReflogReader("refs/heads/master")
647 .getReverseEntries().size());
648 }
649
650 @Test
651 public void testUnknownUpstream() throws Exception {
652
653 writeTrashFile(FILE1, FILE1);
654 git.add().addFilepattern(FILE1).call();
655 git.commit().setMessage("Add file1").call();
656
657 assertTrue(new File(db.getWorkTree(), FILE1).exists());
658
659 try {
660 git.rebase().setUpstream("refs/heads/xyz").call();
661 fail("expected exception was not thrown");
662 } catch (RefNotFoundException e) {
663
664 }
665 }
666
667 @Test
668 public void testConflictFreeWithSingleFile() throws Exception {
669
670 File theFile = writeTrashFile(FILE1, "1\n2\n3\n");
671 git.add().addFilepattern(FILE1).call();
672 RevCommit second = git.commit().setMessage("Add file1").call();
673 assertTrue(new File(db.getWorkTree(), FILE1).exists());
674
675 writeTrashFile(FILE1, "1master\n2\n3\n");
676 checkFile(theFile, "1master\n2\n3\n");
677 git.add().addFilepattern(FILE1).call();
678 RevCommit lastMasterChange = git.commit().setMessage(
679 "change file1 in master").call();
680
681
682 createBranch(second, "refs/heads/topic");
683 checkoutBranch("refs/heads/topic");
684
685 checkFile(theFile, "1\n2\n3\n");
686
687 assertTrue(new File(db.getWorkTree(), FILE1).exists());
688
689 writeTrashFile(FILE1, "1\n2\n3\ntopic\n");
690 git.add().addFilepattern(FILE1).call();
691 RevCommit origHead = git.commit().setMessage("change file1 in topic")
692 .call();
693
694 RebaseResult res = git.rebase().setUpstream("refs/heads/master").call();
695 assertEquals(Status.OK, res.getStatus());
696 checkFile(theFile, "1master\n2\n3\ntopic\n");
697
698 assertEquals("refs/heads/topic", db.getFullBranch());
699 try (RevWalk rw = new RevWalk(db)) {
700 assertEquals(lastMasterChange, rw.parseCommit(
701 db.resolve(Constants.HEAD)).getParent(0));
702 }
703 assertEquals(origHead, db.readOrigHead());
704 List<ReflogEntry> headLog = db.getReflogReader(Constants.HEAD)
705 .getReverseEntries();
706 List<ReflogEntry> topicLog = db.getReflogReader("refs/heads/topic")
707 .getReverseEntries();
708 List<ReflogEntry> masterLog = db.getReflogReader("refs/heads/master")
709 .getReverseEntries();
710 assertEquals(2, masterLog.size());
711 assertEquals(3, topicLog.size());
712 assertEquals("rebase finished: refs/heads/topic onto "
713 + lastMasterChange.getName(), topicLog.get(0).getComment());
714 assertEquals("rebase finished: returning to refs/heads/topic", headLog
715 .get(0).getComment());
716 }
717
718 @Test
719 public void testDetachedHead() throws Exception {
720
721 File theFile = writeTrashFile(FILE1, "1\n2\n3\n");
722 git.add().addFilepattern(FILE1).call();
723 RevCommit second = git.commit().setMessage("Add file1").call();
724 assertTrue(new File(db.getWorkTree(), FILE1).exists());
725
726 writeTrashFile(FILE1, "1master\n2\n3\n");
727 checkFile(theFile, "1master\n2\n3\n");
728 git.add().addFilepattern(FILE1).call();
729 RevCommit lastMasterChange = git.commit().setMessage(
730 "change file1 in master").call();
731
732
733 createBranch(second, "refs/heads/topic");
734 checkoutBranch("refs/heads/topic");
735
736 checkFile(theFile, "1\n2\n3\n");
737
738 assertTrue(new File(db.getWorkTree(), FILE1).exists());
739
740 writeTrashFile(FILE1, "1\n2\n3\ntopic\n");
741 git.add().addFilepattern(FILE1).call();
742 RevCommit topicCommit = git.commit()
743 .setMessage("change file1 in topic").call();
744 checkoutBranch("refs/heads/master");
745 checkoutCommit(topicCommit);
746 assertEquals(topicCommit.getId().getName(), db.getFullBranch());
747
748 RebaseResult res = git.rebase().setUpstream("refs/heads/master").call();
749 assertEquals(Status.OK, res.getStatus());
750 checkFile(theFile, "1master\n2\n3\ntopic\n");
751 try (RevWalk rw = new RevWalk(db)) {
752 assertEquals(lastMasterChange, rw.parseCommit(
753 db.resolve(Constants.HEAD)).getParent(0));
754 }
755
756 List<ReflogEntry> headLog = db.getReflogReader(Constants.HEAD)
757 .getReverseEntries();
758 assertEquals(8, headLog.size());
759 assertEquals("rebase: change file1 in topic", headLog.get(0)
760 .getComment());
761 assertEquals("checkout: moving from " + topicCommit.getName() + " to "
762 + lastMasterChange.getName(), headLog.get(1).getComment());
763 }
764
765 @Test
766 public void testFilesAddedFromTwoBranches() throws Exception {
767
768 writeTrashFile(FILE1, FILE1);
769 git.add().addFilepattern(FILE1).call();
770 RevCommit masterCommit = git.commit().setMessage("Add file1 to master")
771 .call();
772
773
774 createBranch(masterCommit, "refs/heads/file2");
775 checkoutBranch("refs/heads/file2");
776 writeTrashFile("file2", "file2");
777 git.add().addFilepattern("file2").call();
778 RevCommit addFile2 = git.commit().setMessage(
779 "Add file2 to branch file2").call();
780
781
782 createBranch(masterCommit, "refs/heads/file3");
783 checkoutBranch("refs/heads/file3");
784 writeTrashFile("file3", "file3");
785 git.add().addFilepattern("file3").call();
786 git.commit().setMessage("Add file3 to branch file3").call();
787
788 assertTrue(new File(db.getWorkTree(), FILE1).exists());
789 assertFalse(new File(db.getWorkTree(), "file2").exists());
790 assertTrue(new File(db.getWorkTree(), "file3").exists());
791
792 RebaseResult res = git.rebase().setUpstream("refs/heads/file2").call();
793 assertEquals(Status.OK, res.getStatus());
794
795 assertTrue(new File(db.getWorkTree(), FILE1).exists());
796 assertTrue(new File(db.getWorkTree(), "file2").exists());
797 assertTrue(new File(db.getWorkTree(), "file3").exists());
798
799
800 assertEquals("refs/heads/file3", db.getFullBranch());
801 try (RevWalk rw = new RevWalk(db)) {
802 assertEquals(addFile2, rw.parseCommit(
803 db.resolve(Constants.HEAD)).getParent(0));
804 }
805
806 checkoutBranch("refs/heads/file2");
807 assertTrue(new File(db.getWorkTree(), FILE1).exists());
808 assertTrue(new File(db.getWorkTree(), "file2").exists());
809 assertFalse(new File(db.getWorkTree(), "file3").exists());
810 }
811
812 @Test
813 public void testStopOnConflict() throws Exception {
814
815 RevCommit firstInMaster = writeFileAndCommit(FILE1, "Add file1", "1",
816 "2", "3");
817
818 writeFileAndCommit(FILE1, "change file1 in master", "1master", "2", "3");
819 checkFile(FILE1, "1master", "2", "3");
820
821 createBranch(firstInMaster, "refs/heads/topic");
822 checkoutBranch("refs/heads/topic");
823
824 checkFile(FILE1, "1", "2", "3");
825
826
827 writeFileAndCommit(FILE1, "add a line to file1 in topic", "1", "2",
828 "3", "topic4");
829
830
831 RevCommit conflicting = writeFileAndCommit(FILE1,
832 "change file1 in topic", "1topic", "2", "3", "topic4");
833
834 RevCommit lastTopicCommit = writeFileAndCommit(FILE1,
835 "change file1 in topic again", "1topic", "2", "3", "topic4");
836
837 RebaseResult res = git.rebase().setUpstream("refs/heads/master").call();
838 assertEquals(Status.STOPPED, res.getStatus());
839 assertEquals(conflicting, res.getCurrentCommit());
840 checkFile(FILE1,
841 "<<<<<<< Upstream, based on master\n1master\n=======\n1topic",
842 ">>>>>>> e0d1dea change file1 in topic\n2\n3\ntopic4");
843
844 assertEquals(RepositoryState.REBASING_MERGE, db
845 .getRepositoryState());
846 assertTrue(new File(db.getDirectory(), "rebase-merge").exists());
847
848
849 assertEquals(1, countPicks());
850
851
852 try {
853 git.rebase().setUpstream("refs/heads/master").call();
854 fail("Expected exception was not thrown");
855 } catch (WrongRepositoryStateException e) {
856
857 }
858
859
860 res = git.rebase().setOperation(Operation.ABORT).call();
861 assertEquals(res.getStatus(), Status.ABORTED);
862 assertEquals("refs/heads/topic", db.getFullBranch());
863 checkFile(FILE1, "1topic", "2", "3", "topic4");
864 try (RevWalk rw = new RevWalk(db)) {
865 assertEquals(lastTopicCommit,
866 rw.parseCommit(db.resolve(Constants.HEAD)));
867 }
868 assertEquals(RepositoryState.SAFE, db.getRepositoryState());
869
870
871 assertFalse(new File(db.getDirectory(), "rebase-merge").exists());
872 }
873
874 @Test
875 public void testStopOnConflictAndAbortWithDetachedHEAD() throws Exception {
876
877 RevCommit firstInMaster = writeFileAndCommit(FILE1, "Add file1", "1",
878 "2", "3");
879
880 writeFileAndCommit(FILE1, "change file1 in master", "1master", "2", "3");
881 checkFile(FILE1, "1master", "2", "3");
882
883 createBranch(firstInMaster, "refs/heads/topic");
884 checkoutBranch("refs/heads/topic");
885
886 checkFile(FILE1, "1", "2", "3");
887
888
889 writeFileAndCommit(FILE1, "add a line to file1 in topic", "1", "2",
890 "3", "topic4");
891
892
893 RevCommit conflicting = writeFileAndCommit(FILE1,
894 "change file1 in topic", "1topic", "2", "3", "topic4");
895
896 RevCommit lastTopicCommit = writeFileAndCommit(FILE1,
897 "change file1 in topic again", "1topic", "2", "3", "topic4");
898
899 git.checkout().setName(lastTopicCommit.getName()).call();
900
901 RebaseResult res = git.rebase().setUpstream("refs/heads/master").call();
902 assertEquals(Status.STOPPED, res.getStatus());
903 assertEquals(conflicting, res.getCurrentCommit());
904 checkFile(FILE1,
905 "<<<<<<< Upstream, based on master\n1master\n=======\n1topic",
906 ">>>>>>> e0d1dea change file1 in topic\n2\n3\ntopic4");
907
908 assertEquals(RepositoryState.REBASING_MERGE,
909 db.getRepositoryState());
910 assertTrue(new File(db.getDirectory(), "rebase-merge").exists());
911
912
913 assertEquals(1, countPicks());
914
915
916 try {
917 git.rebase().setUpstream("refs/heads/master").call();
918 fail("Expected exception was not thrown");
919 } catch (WrongRepositoryStateException e) {
920
921 }
922
923
924 res = git.rebase().setOperation(Operation.ABORT).call();
925 assertEquals(res.getStatus(), Status.ABORTED);
926 assertEquals(lastTopicCommit.getName(), db.getFullBranch());
927 checkFile(FILE1, "1topic", "2", "3", "topic4");
928 try (RevWalk rw = new RevWalk(db)) {
929 assertEquals(lastTopicCommit,
930 rw.parseCommit(db.resolve(Constants.HEAD)));
931 }
932 assertEquals(RepositoryState.SAFE, db.getRepositoryState());
933
934
935 assertFalse(new File(db.getDirectory(), "rebase-merge").exists());
936 }
937
938 @Test
939 public void testStopOnConflictAndContinue() throws Exception {
940
941 RevCommit firstInMaster = writeFileAndCommit(FILE1, "Add file1", "1",
942 "2", "3");
943
944 writeFileAndCommit(FILE1, "change file1 in master", "1master", "2", "3");
945
946 checkFile(FILE1, "1master", "2", "3");
947
948 createBranch(firstInMaster, "refs/heads/topic");
949 checkoutBranch("refs/heads/topic");
950
951 checkFile(FILE1, "1", "2", "3");
952
953
954 writeFileAndCommit(FILE1, "add a line to file1 in topic", "1", "2",
955 "3", "4topic");
956
957
958 writeFileAndCommit(FILE1,
959 "change file1 in topic\n\nThis is conflicting", "1topic", "2",
960 "3", "4topic");
961
962
963 writeFileAndCommit(FILE1, "change file1 in topic again", "1topic",
964 "2topic", "3", "4topic");
965
966 RebaseResult res = git.rebase().setUpstream("refs/heads/master").call();
967 assertEquals(Status.STOPPED, res.getStatus());
968
969
970 try {
971 res = git.rebase().setOperation(Operation.CONTINUE).call();
972 fail("Expected Exception not thrown");
973 } catch (UnmergedPathsException e) {
974
975 }
976
977
978 writeFileAndAdd(FILE1, "1topic", "2", "3", "4topic");
979
980 res = git.rebase().setOperation(Operation.CONTINUE).call();
981 assertNotNull(res);
982 assertEquals(Status.OK, res.getStatus());
983 assertEquals(RepositoryState.SAFE, db.getRepositoryState());
984
985 ObjectId headId = db.resolve(Constants.HEAD);
986 try (RevWalk rw = new RevWalk(db)) {
987 RevCommit rc = rw.parseCommit(headId);
988 RevCommit parent = rw.parseCommit(rc.getParent(0));
989 assertEquals("change file1 in topic\n\nThis is conflicting", parent
990 .getFullMessage());
991 }
992 }
993
994 @Test
995 public void testStopOnConflictAndContinueWithNoDeltaToMaster()
996 throws Exception {
997
998 RevCommit firstInMaster = writeFileAndCommit(FILE1, "Add file1", "1",
999 "2", "3");
1000
1001 writeFileAndCommit(FILE1, "change file1 in master", "1master", "2", "3");
1002
1003 checkFile(FILE1, "1master", "2", "3");
1004
1005 createBranch(firstInMaster, "refs/heads/topic");
1006 checkoutBranch("refs/heads/topic");
1007
1008 checkFile(FILE1, "1", "2", "3");
1009
1010
1011 writeFileAndCommit(FILE1,
1012 "change file1 in topic\n\nThis is conflicting", "1topic", "2",
1013 "3", "4topic");
1014
1015 RebaseResult res = git.rebase().setUpstream("refs/heads/master").call();
1016 assertEquals(Status.STOPPED, res.getStatus());
1017
1018
1019 try {
1020 res = git.rebase().setOperation(Operation.CONTINUE).call();
1021 fail("Expected Exception not thrown");
1022 } catch (UnmergedPathsException e) {
1023
1024 }
1025
1026
1027 writeFileAndAdd(FILE1, "1master", "2", "3");
1028
1029 res = git.rebase().setOperation(Operation.CONTINUE).call();
1030 assertNotNull(res);
1031 assertEquals(Status.NOTHING_TO_COMMIT, res.getStatus());
1032 assertEquals(RepositoryState.REBASING_MERGE,
1033 db.getRepositoryState());
1034
1035 git.rebase().setOperation(Operation.SKIP).call();
1036
1037 ObjectId headId = db.resolve(Constants.HEAD);
1038 try (RevWalk rw = new RevWalk(db)) {
1039 RevCommit rc = rw.parseCommit(headId);
1040 assertEquals("change file1 in master", rc.getFullMessage());
1041 }
1042 }
1043
1044 @Test
1045 public void testStopOnConflictAndFailContinueIfFileIsDirty()
1046 throws Exception {
1047
1048 RevCommit firstInMaster = writeFileAndCommit(FILE1, "Add file1", "1",
1049 "2", "3");
1050
1051 writeFileAndCommit(FILE1, "change file1 in master", "1master", "2", "3");
1052
1053 checkFile(FILE1, "1master", "2", "3");
1054
1055 createBranch(firstInMaster, "refs/heads/topic");
1056 checkoutBranch("refs/heads/topic");
1057
1058 checkFile(FILE1, "1", "2", "3");
1059
1060
1061 writeFileAndCommit(FILE1, "add a line to file1 in topic", "1", "2",
1062 "3", "4topic");
1063
1064
1065 writeFileAndCommit(FILE1,
1066 "change file1 in topic\n\nThis is conflicting", "1topic", "2",
1067 "3", "4topic");
1068
1069
1070 writeFileAndCommit(FILE1, "change file1 in topic again", "1topic",
1071 "2topic", "3", "4topic");
1072
1073 RebaseResult res = git.rebase().setUpstream("refs/heads/master").call();
1074 assertEquals(Status.STOPPED, res.getStatus());
1075
1076 git.add().addFilepattern(FILE1).call();
1077 File trashFile = writeTrashFile(FILE1, "Some local change");
1078
1079 res = git.rebase().setOperation(Operation.CONTINUE).call();
1080 assertNotNull(res);
1081 assertEquals(Status.STOPPED, res.getStatus());
1082 checkFile(trashFile, "Some local change");
1083 }
1084
1085 @Test
1086 public void testStopOnLastConflictAndContinue() throws Exception {
1087
1088 RevCommit firstInMaster = writeFileAndCommit(FILE1, "Add file1", "1",
1089 "2", "3");
1090
1091 writeFileAndCommit(FILE1, "change file1 in master", "1master", "2", "3");
1092
1093 checkFile(FILE1, "1master", "2", "3");
1094
1095 createBranch(firstInMaster, "refs/heads/topic");
1096 checkoutBranch("refs/heads/topic");
1097
1098 checkFile(FILE1, "1", "2", "3");
1099
1100
1101 writeFileAndCommit(FILE1, "add a line to file1 in topic", "1", "2",
1102 "3", "4topic");
1103
1104
1105 writeFileAndCommit(FILE1,
1106 "change file1 in topic\n\nThis is conflicting", "1topic", "2",
1107 "3", "4topic");
1108
1109 RebaseResult res = git.rebase().setUpstream("refs/heads/master").call();
1110 assertEquals(Status.STOPPED, res.getStatus());
1111
1112
1113 writeFileAndAdd(FILE1, "1topic", "2", "3", "4topic");
1114
1115 res = git.rebase().setOperation(Operation.CONTINUE).call();
1116 assertNotNull(res);
1117 assertEquals(Status.OK, res.getStatus());
1118 assertEquals(RepositoryState.SAFE, db.getRepositoryState());
1119 }
1120
1121 @Test
1122 public void testStopOnLastConflictAndSkip() throws Exception {
1123
1124 RevCommit firstInMaster = writeFileAndCommit(FILE1, "Add file1", "1",
1125 "2", "3");
1126
1127 writeFileAndCommit(FILE1, "change file1 in master", "1master", "2", "3");
1128
1129 checkFile(FILE1, "1master", "2", "3");
1130
1131 createBranch(firstInMaster, "refs/heads/topic");
1132 checkoutBranch("refs/heads/topic");
1133
1134 checkFile(FILE1, "1", "2", "3");
1135
1136
1137 writeFileAndCommit(FILE1, "add a line to file1 in topic", "1", "2",
1138 "3", "4topic");
1139
1140
1141 writeFileAndCommit(FILE1,
1142 "change file1 in topic\n\nThis is conflicting", "1topic", "2",
1143 "3", "4topic");
1144
1145 RebaseResult res = git.rebase().setUpstream("refs/heads/master").call();
1146 assertEquals(Status.STOPPED, res.getStatus());
1147
1148
1149 writeFileAndAdd(FILE1, "1topic", "2", "3", "4topic");
1150
1151 res = git.rebase().setOperation(Operation.SKIP).call();
1152 assertNotNull(res);
1153 assertEquals(Status.OK, res.getStatus());
1154 assertEquals(RepositoryState.SAFE, db.getRepositoryState());
1155 }
1156
1157 @Test
1158 public void testMergeFirstStopOnLastConflictAndSkip() throws Exception {
1159
1160 RevCommit firstInMaster = writeFileAndCommit(FILE1, "Add file1", "1",
1161 "2", "3");
1162
1163 writeFileAndCommit(FILE1, "change file1 in master", "1master", "2", "3");
1164
1165 checkFile(FILE1, "1master", "2", "3");
1166
1167 createBranch(firstInMaster, "refs/heads/topic");
1168 checkoutBranch("refs/heads/topic");
1169
1170 checkFile(FILE1, "1", "2", "3");
1171
1172
1173 writeFileAndCommit(FILE1, "add a line to file1 in topic", "1topic",
1174 "2", "3", "4topic");
1175
1176
1177 writeFileAndCommit(FILE1,
1178 "change file1 in topic\n\nThis is conflicting", "1topicagain",
1179 "2", "3", "4topic");
1180
1181 RebaseResult res = git.rebase().setUpstream("refs/heads/master").call();
1182 assertEquals(Status.STOPPED, res.getStatus());
1183
1184 writeFileAndAdd(FILE1, "merged");
1185
1186 res = git.rebase().setOperation(Operation.CONTINUE).call();
1187 assertEquals(Status.STOPPED, res.getStatus());
1188
1189 res = git.rebase().setOperation(Operation.SKIP).call();
1190 assertNotNull(res);
1191 assertEquals(Status.OK, res.getStatus());
1192 assertEquals(RepositoryState.SAFE, db.getRepositoryState());
1193 checkFile(FILE1, "merged");
1194 }
1195
1196 @Test
1197 public void testStopOnConflictAndSkipNoConflict() throws Exception {
1198
1199 RevCommit firstInMaster = writeFileAndCommit(FILE1, "Add file1", "1",
1200 "2", "3");
1201
1202 writeFileAndCommit(FILE1, "change file1 in master", "1master", "2", "3");
1203
1204 checkFile(FILE1, "1master", "2", "3");
1205
1206 createBranch(firstInMaster, "refs/heads/topic");
1207 checkoutBranch("refs/heads/topic");
1208
1209 checkFile(FILE1, "1", "2", "3");
1210
1211
1212 writeFileAndCommit(FILE1, "add a line to file1 in topic", "1", "2",
1213 "3", "4topic");
1214
1215
1216 writeFileAndCommit(FILE1,
1217 "change file1 in topic\n\nThis is conflicting", "1topic", "2",
1218 "3", "4topic");
1219
1220
1221 writeFileAndCommit(FILE1, "change file1 in topic again", "1topic", "2",
1222 "3topic", "4topic");
1223
1224 RebaseResult res = git.rebase().setUpstream("refs/heads/master").call();
1225 assertEquals(Status.STOPPED, res.getStatus());
1226
1227 res = git.rebase().setOperation(Operation.SKIP).call();
1228
1229 checkFile(FILE1, "1master", "2", "3topic", "4topic");
1230 assertEquals(Status.OK, res.getStatus());
1231 }
1232
1233 @Test
1234 public void testStopOnConflictAndSkipWithConflict() throws Exception {
1235
1236 RevCommit firstInMaster = writeFileAndCommit(FILE1, "Add file1", "1",
1237 "2", "3", "4");
1238
1239 writeFileAndCommit(FILE1, "change file1 in master", "1master", "2",
1240 "3master", "4");
1241
1242 checkFile(FILE1, "1master", "2", "3master", "4");
1243
1244 createBranch(firstInMaster, "refs/heads/topic");
1245 checkoutBranch("refs/heads/topic");
1246
1247 checkFile(FILE1, "1", "2", "3", "4");
1248
1249
1250 writeFileAndCommit(FILE1, "add a line to file1 in topic", "1", "2",
1251 "3", "4", "5topic");
1252
1253
1254 writeFileAndCommit(FILE1,
1255 "change file1 in topic\n\nThis is conflicting", "1topic", "2",
1256 "3", "4", "5topic");
1257
1258
1259 writeFileAndCommit(FILE1, "change file1 in topic again", "1topic", "2",
1260 "3topic", "4", "5topic");
1261
1262 RebaseResult res = git.rebase().setUpstream("refs/heads/master").call();
1263 assertEquals(Status.STOPPED, res.getStatus());
1264
1265 res = git.rebase().setOperation(Operation.SKIP).call();
1266
1267 checkFile(
1268 FILE1,
1269 "1master\n2\n<<<<<<< Upstream, based on master\n3master\n=======\n3topic",
1270 ">>>>>>> 5afc8df change file1 in topic again\n4\n5topic");
1271 assertEquals(Status.STOPPED, res.getStatus());
1272 }
1273
1274 @Test
1275 public void testStopOnConflictCommitAndContinue() throws Exception {
1276
1277 RevCommit firstInMaster = writeFileAndCommit(FILE1, "Add file1", "1",
1278 "2", "3");
1279
1280 writeFileAndCommit(FILE1, "change file1 in master", "1master", "2", "3");
1281
1282 checkFile(FILE1, "1master", "2", "3");
1283
1284 createBranch(firstInMaster, "refs/heads/topic");
1285 checkoutBranch("refs/heads/topic");
1286
1287 checkFile(FILE1, "1", "2", "3");
1288
1289
1290 writeFileAndCommit(FILE1, "add a line to file1 in topic", "1", "2",
1291 "3", "4topic");
1292
1293
1294 writeFileAndCommit(FILE1,
1295 "change file1 in topic\n\nThis is conflicting", "1topic", "2",
1296 "3", "4topic");
1297
1298
1299 writeFileAndCommit(FILE1, "change file1 in topic again", "1topic", "2",
1300 "3topic", "4topic");
1301
1302 RebaseResult res = git.rebase().setUpstream("refs/heads/master").call();
1303 assertEquals(Status.STOPPED, res.getStatus());
1304
1305
1306 try {
1307 res = git.rebase().setOperation(Operation.CONTINUE).call();
1308 fail("Expected Exception not thrown");
1309 } catch (UnmergedPathsException e) {
1310
1311 }
1312
1313
1314 writeFileAndCommit(FILE1, "A different commit message", "1topic", "2",
1315 "3", "4topic");
1316
1317 res = git.rebase().setOperation(Operation.CONTINUE).call();
1318 assertNotNull(res);
1319
1320
1321
1322
1323 assertEquals(Status.NOTHING_TO_COMMIT, res.getStatus());
1324 assertEquals(RepositoryState.REBASING_MERGE,
1325 db.getRepositoryState());
1326
1327 git.rebase().setOperation(Operation.SKIP).call();
1328
1329 ObjectId headId = db.resolve(Constants.HEAD);
1330 try (RevWalk rw = new RevWalk(db)) {
1331 RevCommit rc = rw.parseCommit(headId);
1332 RevCommit parent = rw.parseCommit(rc.getParent(0));
1333 assertEquals("A different commit message", parent.getFullMessage());
1334 }
1335 }
1336
1337 private RevCommit writeFileAndCommit(String fileName, String commitMessage,
1338 String... lines) throws Exception {
1339 StringBuilder sb = new StringBuilder();
1340 for (String line : lines) {
1341 sb.append(line);
1342 sb.append('\n');
1343 }
1344 writeTrashFile(fileName, sb.toString());
1345 git.add().addFilepattern(fileName).call();
1346 return git.commit().setMessage(commitMessage).call();
1347 }
1348
1349 private void writeFileAndAdd(String fileName, String... lines)
1350 throws Exception {
1351 StringBuilder sb = new StringBuilder();
1352 for (String line : lines) {
1353 sb.append(line);
1354 sb.append('\n');
1355 }
1356 writeTrashFile(fileName, sb.toString());
1357 git.add().addFilepattern(fileName).call();
1358 }
1359
1360 private void checkFile(String fileName, String... lines) throws Exception {
1361 File file = new File(db.getWorkTree(), fileName);
1362 StringBuilder sb = new StringBuilder();
1363 for (String line : lines) {
1364 sb.append(line);
1365 sb.append('\n');
1366 }
1367 checkFile(file, sb.toString());
1368 }
1369
1370 @Test
1371 public void testStopOnConflictFileCreationAndDeletion() throws Exception {
1372
1373 writeTrashFile(FILE1, "Hello World");
1374 git.add().addFilepattern(FILE1).call();
1375
1376 File file2 = writeTrashFile("file2", "Hello World 2");
1377 git.add().addFilepattern("file2").call();
1378
1379 File file3 = writeTrashFile("file3", "Hello World 3");
1380 git.add().addFilepattern("file3").call();
1381
1382 RevCommit firstInMaster = git.commit()
1383 .setMessage("Add file 1, 2 and 3").call();
1384
1385
1386 File file4 = writeTrashFile("file4", "Hello World 4");
1387 git.add().addFilepattern("file4").call();
1388
1389 deleteTrashFile("file2");
1390 git.add().setUpdate(true).addFilepattern("file2").call();
1391
1392
1393 writeTrashFile("folder6/file1", "Hello World folder6");
1394 git.add().addFilepattern("folder6/file1").call();
1395
1396 git.commit().setMessage(
1397 "Add file 4 and folder folder6, delete file2 on master").call();
1398
1399
1400 createBranch(firstInMaster, "refs/heads/topic");
1401 checkoutBranch("refs/heads/topic");
1402
1403 deleteTrashFile("file3");
1404 git.add().setUpdate(true).addFilepattern("file3").call();
1405
1406 File file5 = writeTrashFile("file5", "Hello World 5");
1407 git.add().addFilepattern("file5").call();
1408 git.commit().setMessage("Delete file3 and add file5 in topic").call();
1409
1410
1411 writeTrashFile("folder6", "Hello World 6");
1412 git.add().addFilepattern("folder6").call();
1413
1414 File file7 = writeTrashFile("file7", "Hello World 7");
1415 git.add().addFilepattern("file7").call();
1416
1417 deleteTrashFile("file5");
1418 git.add().setUpdate(true).addFilepattern("file5").call();
1419 RevCommit conflicting = git.commit().setMessage(
1420 "Delete file5, add file folder6 and file7 in topic").call();
1421
1422 RebaseResult res = git.rebase().setUpstream("refs/heads/master").call();
1423 assertEquals(Status.STOPPED, res.getStatus());
1424 assertEquals(conflicting, res.getCurrentCommit());
1425
1426 assertEquals(RepositoryState.REBASING_MERGE, db
1427 .getRepositoryState());
1428 assertTrue(new File(db.getDirectory(), "rebase-merge").exists());
1429
1430
1431 assertEquals(0, countPicks());
1432
1433 assertFalse(file2.exists());
1434 assertFalse(file3.exists());
1435 assertTrue(file4.exists());
1436 assertFalse(file5.exists());
1437 assertTrue(file7.exists());
1438
1439
1440 res = git.rebase().setOperation(Operation.ABORT).call();
1441 assertEquals(res.getStatus(), Status.ABORTED);
1442 assertEquals("refs/heads/topic", db.getFullBranch());
1443 try (RevWalk rw = new RevWalk(db)) {
1444 assertEquals(conflicting, rw.parseCommit(db.resolve(Constants.HEAD)));
1445 assertEquals(RepositoryState.SAFE, db.getRepositoryState());
1446 }
1447
1448
1449 assertFalse(new File(db.getDirectory(), "rebase-merge").exists());
1450
1451 assertTrue(file2.exists());
1452 assertFalse(file3.exists());
1453 assertFalse(file4.exists());
1454 assertFalse(file5.exists());
1455 assertTrue(file7.exists());
1456
1457 }
1458
1459 @Test
1460 public void testAuthorScriptConverter() throws Exception {
1461
1462 PersonIdent ident = new PersonIdent("Author name", "a.mail@some.com",
1463 123456789123L, -60);
1464 String convertedAuthor = git.rebase().toAuthorScript(ident);
1465 String[] lines = convertedAuthor.split("\n");
1466 assertEquals("GIT_AUTHOR_NAME='Author name'", lines[0]);
1467 assertEquals("GIT_AUTHOR_EMAIL='a.mail@some.com'", lines[1]);
1468 assertEquals("GIT_AUTHOR_DATE='@123456789 -0100'", lines[2]);
1469
1470 PersonIdent parsedIdent = git.rebase().parseAuthor(
1471 convertedAuthor.getBytes(UTF_8));
1472 assertEquals(ident.getName(), parsedIdent.getName());
1473 assertEquals(ident.getEmailAddress(), parsedIdent.getEmailAddress());
1474
1475 assertEquals(123456789000L, parsedIdent.getWhen().getTime());
1476 assertEquals(ident.getTimeZoneOffset(), parsedIdent.getTimeZoneOffset());
1477
1478
1479 ident = new PersonIdent("Author name", "a.mail@some.com",
1480 123456789123L, +570);
1481 convertedAuthor = git.rebase().toAuthorScript(ident);
1482 lines = convertedAuthor.split("\n");
1483 assertEquals("GIT_AUTHOR_NAME='Author name'", lines[0]);
1484 assertEquals("GIT_AUTHOR_EMAIL='a.mail@some.com'", lines[1]);
1485 assertEquals("GIT_AUTHOR_DATE='@123456789 +0930'", lines[2]);
1486
1487 parsedIdent = git.rebase().parseAuthor(
1488 convertedAuthor.getBytes(UTF_8));
1489 assertEquals(ident.getName(), parsedIdent.getName());
1490 assertEquals(ident.getEmailAddress(), parsedIdent.getEmailAddress());
1491 assertEquals(123456789000L, parsedIdent.getWhen().getTime());
1492 assertEquals(ident.getTimeZoneOffset(), parsedIdent.getTimeZoneOffset());
1493 }
1494
1495 @Test
1496 public void testRepositoryStateChecks() throws Exception {
1497 try {
1498 git.rebase().setOperation(Operation.ABORT).call();
1499 fail("Expected Exception not thrown");
1500 } catch (WrongRepositoryStateException e) {
1501
1502 }
1503 try {
1504 git.rebase().setOperation(Operation.SKIP).call();
1505 fail("Expected Exception not thrown");
1506 } catch (WrongRepositoryStateException e) {
1507
1508 }
1509 try {
1510 git.rebase().setOperation(Operation.CONTINUE).call();
1511 fail("Expected Exception not thrown");
1512 } catch (WrongRepositoryStateException e) {
1513
1514 }
1515 }
1516
1517 @Test
1518 public void testRebaseWithUntrackedFile() throws Exception {
1519
1520 writeTrashFile(FILE1, "file1");
1521 git.add().addFilepattern(FILE1).call();
1522 RevCommit commit = git.commit().setMessage("commit1").call();
1523
1524
1525 createBranch(commit, "refs/heads/topic");
1526 checkoutBranch("refs/heads/topic");
1527 writeTrashFile("file2", "file2");
1528 git.add().addFilepattern("file2").call();
1529 git.commit().setMessage("commit2").call();
1530
1531
1532 checkoutBranch("refs/heads/master");
1533 writeTrashFile(FILE1, "modified file1");
1534 git.add().addFilepattern(FILE1).call();
1535 git.commit().setMessage("commit3").call();
1536
1537
1538 checkoutBranch("refs/heads/topic");
1539 writeTrashFile("file3", "untracked file3");
1540
1541
1542 assertEquals(Status.OK, git.rebase().setUpstream("refs/heads/master")
1543 .call().getStatus());
1544 }
1545
1546 @Test
1547 public void testRebaseWithUnstagedTopicChange() throws Exception {
1548
1549 writeTrashFile(FILE1, "file1");
1550 git.add().addFilepattern(FILE1).call();
1551 RevCommit commit = git.commit().setMessage("commit1").call();
1552
1553
1554 createBranch(commit, "refs/heads/topic");
1555 checkoutBranch("refs/heads/topic");
1556 writeTrashFile("file2", "file2");
1557 git.add().addFilepattern("file2").call();
1558 git.commit().setMessage("commit2").call();
1559
1560
1561 checkoutBranch("refs/heads/master");
1562 writeTrashFile(FILE1, "modified file1");
1563 git.add().addFilepattern(FILE1).call();
1564 git.commit().setMessage("commit3").call();
1565
1566
1567 checkoutBranch("refs/heads/topic");
1568 writeTrashFile("file2", "unstaged file2");
1569
1570
1571 RebaseResult result = git.rebase().setUpstream("refs/heads/master")
1572 .call();
1573 assertEquals(Status.UNCOMMITTED_CHANGES, result.getStatus());
1574 assertEquals(1, result.getUncommittedChanges().size());
1575 assertEquals("file2", result.getUncommittedChanges().get(0));
1576 }
1577
1578 @Test
1579 public void testRebaseWithUncommittedTopicChange() throws Exception {
1580
1581 writeTrashFile(FILE1, "file1");
1582 git.add().addFilepattern(FILE1).call();
1583 RevCommit commit = git.commit().setMessage("commit1").call();
1584
1585
1586 createBranch(commit, "refs/heads/topic");
1587 checkoutBranch("refs/heads/topic");
1588 writeTrashFile("file2", "file2");
1589 git.add().addFilepattern("file2").call();
1590 git.commit().setMessage("commit2").call();
1591
1592
1593 checkoutBranch("refs/heads/master");
1594 writeTrashFile(FILE1, "modified file1");
1595 git.add().addFilepattern(FILE1).call();
1596 git.commit().setMessage("commit3").call();
1597
1598
1599 checkoutBranch("refs/heads/topic");
1600 File uncommittedFile = writeTrashFile("file2", "uncommitted file2");
1601 git.add().addFilepattern("file2").call();
1602
1603
1604 RebaseResult result = git.rebase().setUpstream("refs/heads/master")
1605 .call();
1606 assertEquals(Status.UNCOMMITTED_CHANGES, result.getStatus());
1607 assertEquals(1, result.getUncommittedChanges().size());
1608 assertEquals("file2", result.getUncommittedChanges().get(0));
1609
1610 checkFile(uncommittedFile, "uncommitted file2");
1611 assertEquals(RepositoryState.SAFE, git.getRepository().getRepositoryState());
1612 }
1613
1614 @Test
1615 public void testRebaseWithUnstagedMasterChange() throws Exception {
1616
1617 writeTrashFile(FILE1, "file1");
1618 git.add().addFilepattern(FILE1).call();
1619 RevCommit commit = git.commit().setMessage("commit1").call();
1620
1621
1622 createBranch(commit, "refs/heads/topic");
1623 checkoutBranch("refs/heads/topic");
1624 writeTrashFile("file2", "file2");
1625 git.add().addFilepattern("file2").call();
1626 git.commit().setMessage("commit2").call();
1627
1628
1629 checkoutBranch("refs/heads/master");
1630 writeTrashFile(FILE1, "modified file1");
1631 git.add().addFilepattern(FILE1).call();
1632 git.commit().setMessage("commit3").call();
1633
1634
1635 checkoutBranch("refs/heads/topic");
1636 writeTrashFile(FILE1, "unstaged modified file1");
1637
1638
1639 RebaseResult result = git.rebase().setUpstream("refs/heads/master")
1640 .call();
1641 assertEquals(Status.UNCOMMITTED_CHANGES, result.getStatus());
1642 assertEquals(1, result.getUncommittedChanges().size());
1643 assertEquals(FILE1, result.getUncommittedChanges().get(0));
1644 }
1645
1646 @Test
1647 public void testRebaseWithUncommittedMasterChange() throws Exception {
1648
1649 writeTrashFile(FILE1, "file1");
1650 git.add().addFilepattern(FILE1).call();
1651 RevCommit commit = git.commit().setMessage("commit1").call();
1652
1653
1654 createBranch(commit, "refs/heads/topic");
1655 checkoutBranch("refs/heads/topic");
1656 writeTrashFile("file2", "file2");
1657 git.add().addFilepattern("file2").call();
1658 git.commit().setMessage("commit2").call();
1659
1660
1661 checkoutBranch("refs/heads/master");
1662 writeTrashFile(FILE1, "modified file1");
1663 git.add().addFilepattern(FILE1).call();
1664 git.commit().setMessage("commit3").call();
1665
1666
1667 checkoutBranch("refs/heads/topic");
1668 writeTrashFile(FILE1, "uncommitted modified file1");
1669 git.add().addFilepattern(FILE1).call();
1670
1671
1672
1673 RebaseResult result = git.rebase().setUpstream("refs/heads/master")
1674 .call();
1675 assertEquals(Status.UNCOMMITTED_CHANGES, result.getStatus());
1676 assertEquals(1, result.getUncommittedChanges().size());
1677 assertEquals(FILE1, result.getUncommittedChanges().get(0));
1678 }
1679
1680 @Test
1681 public void testRebaseWithUnstagedMasterChangeBaseCommit() throws Exception {
1682
1683 writeTrashFile("file0", "file0");
1684 writeTrashFile(FILE1, "file1");
1685 git.add().addFilepattern("file0").addFilepattern(FILE1).call();
1686 RevCommit commit = git.commit().setMessage("commit1").call();
1687
1688
1689 createBranch(commit, "refs/heads/topic");
1690 checkoutBranch("refs/heads/topic");
1691 writeTrashFile("file2", "file2");
1692 git.add().addFilepattern("file2").call();
1693 git.commit().setMessage("commit2").call();
1694
1695
1696 checkoutBranch("refs/heads/master");
1697 writeTrashFile(FILE1, "modified file1");
1698 git.add().addFilepattern(FILE1).call();
1699 git.commit().setMessage("commit3").call();
1700
1701
1702 checkoutBranch("refs/heads/topic");
1703 writeTrashFile("file0", "unstaged modified file0");
1704
1705
1706 assertEquals(Status.UNCOMMITTED_CHANGES,
1707 git.rebase().setUpstream("refs/heads/master")
1708 .call().getStatus());
1709 }
1710
1711 @Test
1712 public void testRebaseWithUncommittedMasterChangeBaseCommit()
1713 throws Exception {
1714
1715 File file0 = writeTrashFile("file0", "file0");
1716 writeTrashFile(FILE1, "file1");
1717 git.add().addFilepattern("file0").addFilepattern(FILE1).call();
1718 RevCommit commit = git.commit().setMessage("commit1").call();
1719
1720
1721 createBranch(commit, "refs/heads/topic");
1722 checkoutBranch("refs/heads/topic");
1723 writeTrashFile("file2", "file2");
1724 git.add().addFilepattern("file2").call();
1725 git.commit().setMessage("commit2").call();
1726
1727
1728 checkoutBranch("refs/heads/master");
1729 writeTrashFile(FILE1, "modified file1");
1730 git.add().addFilepattern(FILE1).call();
1731 git.commit().setMessage("commit3").call();
1732
1733
1734 checkoutBranch("refs/heads/topic");
1735 write(file0, "unstaged modified file0");
1736 git.add().addFilepattern("file0").call();
1737
1738
1739
1740 String indexState = indexState(CONTENT);
1741
1742
1743 RebaseResult result = git.rebase().setUpstream("refs/heads/master")
1744 .call();
1745 assertEquals(Status.UNCOMMITTED_CHANGES, result.getStatus());
1746 assertEquals(1, result.getUncommittedChanges().size());
1747
1748 assertEquals(indexState, indexState(CONTENT));
1749 assertEquals(RepositoryState.SAFE, db.getRepositoryState());
1750 }
1751
1752 @Test
1753 public void testRebaseWithUnstagedMasterChangeOtherCommit()
1754 throws Exception {
1755
1756 writeTrashFile("file0", "file0");
1757 git.add().addFilepattern("file0").call();
1758 git.commit().setMessage("commit0").call();
1759
1760 writeTrashFile(FILE1, "file1");
1761 git.add().addFilepattern(FILE1).call();
1762 RevCommit commit = git.commit().setMessage("commit1").call();
1763
1764
1765 createBranch(commit, "refs/heads/topic");
1766 checkoutBranch("refs/heads/topic");
1767 writeTrashFile("file2", "file2");
1768 git.add().addFilepattern("file2").call();
1769 git.commit().setMessage("commit2").call();
1770
1771
1772 checkoutBranch("refs/heads/master");
1773 writeTrashFile(FILE1, "modified file1");
1774 git.add().addFilepattern(FILE1).call();
1775 git.commit().setMessage("commit3").call();
1776
1777
1778 checkoutBranch("refs/heads/topic");
1779 writeTrashFile("file0", "unstaged modified file0");
1780
1781
1782 assertEquals(Status.UNCOMMITTED_CHANGES,
1783 git.rebase().setUpstream("refs/heads/master")
1784 .call().getStatus());
1785 }
1786
1787 @Test
1788 public void testRebaseWithUncommittedMasterChangeOtherCommit()
1789 throws Exception {
1790
1791 File file0 = writeTrashFile("file0", "file0");
1792 git.add().addFilepattern("file0").call();
1793 git.commit().setMessage("commit0").call();
1794
1795 writeTrashFile(FILE1, "file1");
1796 git.add().addFilepattern(FILE1).call();
1797 RevCommit commit = git.commit().setMessage("commit1").call();
1798
1799
1800 createBranch(commit, "refs/heads/topic");
1801 checkoutBranch("refs/heads/topic");
1802 writeTrashFile("file2", "file2");
1803 git.add().addFilepattern("file2").call();
1804 git.commit().setMessage("commit2").call();
1805
1806
1807 checkoutBranch("refs/heads/master");
1808 writeTrashFile(FILE1, "modified file1");
1809 git.add().addFilepattern(FILE1).call();
1810 git.commit().setMessage("commit3").call();
1811
1812
1813 checkoutBranch("refs/heads/topic");
1814 write(file0, "unstaged modified file0");
1815 git.add().addFilepattern("file0").call();
1816
1817
1818
1819 String indexState = indexState(CONTENT);
1820
1821
1822 RebaseResult result = git.rebase().setUpstream("refs/heads/master")
1823 .call();
1824 assertEquals(Status.UNCOMMITTED_CHANGES, result.getStatus());
1825
1826 assertEquals(1, result.getUncommittedChanges().size());
1827 assertEquals("unstaged modified file0", read(file0));
1828
1829 assertEquals(indexState, indexState(CONTENT));
1830 assertEquals(RepositoryState.SAFE, db.getRepositoryState());
1831 }
1832
1833 @Test
1834 public void testFastForwardRebaseWithModification() throws Exception {
1835
1836 writeTrashFile("file0", "file0");
1837 writeTrashFile(FILE1, "file1");
1838 git.add().addFilepattern("file0").addFilepattern(FILE1).call();
1839 RevCommit commit = git.commit().setMessage("commit1").call();
1840
1841
1842 createBranch(commit, "refs/heads/topic");
1843
1844
1845 writeTrashFile(FILE1, "modified file1");
1846 git.add().addFilepattern(FILE1).call();
1847 git.commit().setMessage("commit2").call();
1848
1849
1850 checkoutBranch("refs/heads/topic");
1851 writeTrashFile("file0", "modified file0 in index");
1852 git.add().addFilepattern("file0").addFilepattern(FILE1).call();
1853
1854 writeTrashFile("file0", "modified file0");
1855
1856
1857 RebaseResult result = git.rebase().setUpstream("refs/heads/master")
1858 .call();
1859 assertEquals(Status.FAST_FORWARD, result.getStatus());
1860 checkFile(new File(db.getWorkTree(), "file0"), "modified file0");
1861 checkFile(new File(db.getWorkTree(), FILE1), "modified file1");
1862 assertEquals("[file0, mode:100644, content:modified file0 in index]"
1863 + "[file1, mode:100644, content:modified file1]",
1864 indexState(CONTENT));
1865 assertEquals(RepositoryState.SAFE, db.getRepositoryState());
1866 }
1867
1868 @Test
1869 public void testRebaseWithModificationShouldNotDeleteData()
1870 throws Exception {
1871
1872 writeTrashFile("file0", "file0");
1873 writeTrashFile(FILE1, "file1");
1874 git.add().addFilepattern("file0").addFilepattern(FILE1).call();
1875 RevCommit commit = git.commit().setMessage("commit1").call();
1876
1877
1878 createBranch(commit, "refs/heads/topic");
1879
1880
1881 writeTrashFile(FILE1, "modified file1");
1882 git.add().addFilepattern(FILE1).call();
1883 git.commit().setMessage("commit2").call();
1884
1885
1886 checkoutBranch("refs/heads/topic");
1887 writeTrashFile(FILE1, "modified file1 on topic");
1888 git.add().addFilepattern(FILE1).call();
1889 git.commit().setMessage("commit3").call();
1890
1891 writeTrashFile("file0", "modified file0");
1892
1893 RebaseResult result = git.rebase().setUpstream("refs/heads/master")
1894 .call();
1895
1896
1897
1898 if (result.getStatus() == Status.STOPPED)
1899 git.rebase().setOperation(Operation.ABORT).call();
1900
1901 checkFile(new File(db.getWorkTree(), "file0"), "modified file0");
1902 checkFile(new File(db.getWorkTree(), FILE1),
1903 "modified file1 on topic");
1904 assertEquals("[file0, mode:100644, content:file0]"
1905 + "[file1, mode:100644, content:modified file1 on topic]",
1906 indexState(CONTENT));
1907 }
1908
1909 @Test
1910 public void testRebaseWithUncommittedDelete() throws Exception {
1911
1912 File file0 = writeTrashFile("file0", "file0");
1913 writeTrashFile(FILE1, "file1");
1914 git.add().addFilepattern("file0").addFilepattern(FILE1).call();
1915 RevCommit commit = git.commit().setMessage("commit1").call();
1916
1917
1918 createBranch(commit, "refs/heads/topic");
1919
1920
1921 writeTrashFile(FILE1, "modified file1");
1922 git.add().addFilepattern(FILE1).call();
1923 git.commit().setMessage("commit2").call();
1924
1925
1926 checkoutBranch("refs/heads/topic");
1927 git.rm().addFilepattern("file0").call();
1928
1929
1930
1931 RebaseResult result = git.rebase().setUpstream("refs/heads/master")
1932 .call();
1933 assertEquals(Status.FAST_FORWARD, result.getStatus());
1934 assertFalse("File should still be deleted", file0.exists());
1935
1936 assertEquals("[file1, mode:100644, content:modified file1]",
1937 indexState(CONTENT));
1938 assertEquals(RepositoryState.SAFE, db.getRepositoryState());
1939 }
1940
1941 @Test
1942 public void testRebaseWithAutoStash()
1943 throws Exception {
1944
1945 db.getConfig().setBoolean(ConfigConstants.CONFIG_REBASE_SECTION, null,
1946 ConfigConstants.CONFIG_KEY_AUTOSTASH, true);
1947 writeTrashFile("file0", "file0");
1948 git.add().addFilepattern("file0").call();
1949 git.commit().setMessage("commit0").call();
1950
1951 writeTrashFile(FILE1, "file1");
1952 git.add().addFilepattern(FILE1).call();
1953 RevCommit commit = git.commit().setMessage("commit1").call();
1954
1955
1956 createBranch(commit, "refs/heads/topic");
1957 checkoutBranch("refs/heads/topic");
1958 writeTrashFile("file2", "file2");
1959 git.add().addFilepattern("file2").call();
1960 git.commit().setMessage("commit2").call();
1961
1962
1963 checkoutBranch("refs/heads/master");
1964 writeTrashFile(FILE1, "modified file1");
1965 git.add().addFilepattern(FILE1).call();
1966 git.commit().setMessage("commit3").call();
1967
1968
1969 checkoutBranch("refs/heads/topic");
1970 writeTrashFile("file0", "unstaged modified file0");
1971
1972
1973 assertEquals(Status.OK,
1974 git.rebase().setUpstream("refs/heads/master").call()
1975 .getStatus());
1976 checkFile(new File(db.getWorkTree(), "file0"),
1977 "unstaged modified file0");
1978 checkFile(new File(db.getWorkTree(), FILE1), "modified file1");
1979 checkFile(new File(db.getWorkTree(), "file2"), "file2");
1980 assertEquals("[file0, mode:100644, content:file0]"
1981 + "[file1, mode:100644, content:modified file1]"
1982 + "[file2, mode:100644, content:file2]",
1983 indexState(CONTENT));
1984 assertEquals(RepositoryState.SAFE, db.getRepositoryState());
1985 }
1986
1987 @Test
1988 public void testRebaseWithAutoStashAndSubdirs() throws Exception {
1989
1990 db.getConfig().setBoolean(ConfigConstants.CONFIG_REBASE_SECTION, null,
1991 ConfigConstants.CONFIG_KEY_AUTOSTASH, true);
1992 writeTrashFile("sub/file0", "file0");
1993 git.add().addFilepattern("sub/file0").call();
1994 git.commit().setMessage("commit0").call();
1995
1996 writeTrashFile(FILE1, "file1");
1997 git.add().addFilepattern(FILE1).call();
1998 RevCommit commit = git.commit().setMessage("commit1").call();
1999
2000
2001 createBranch(commit, "refs/heads/topic");
2002 checkoutBranch("refs/heads/topic");
2003 writeTrashFile("file2", "file2");
2004 git.add().addFilepattern("file2").call();
2005 git.commit().setMessage("commit2").call();
2006
2007
2008 checkoutBranch("refs/heads/master");
2009 writeTrashFile(FILE1, "modified file1");
2010 git.add().addFilepattern(FILE1).call();
2011 git.commit().setMessage("commit3").call();
2012
2013
2014 checkoutBranch("refs/heads/topic");
2015 writeTrashFile("sub/file0", "unstaged modified file0");
2016
2017 Set<String> modifiedFiles = new HashSet<>();
2018 ListenerHandle handle = db.getListenerList()
2019 .addWorkingTreeModifiedListener(
2020 event -> modifiedFiles.addAll(event.getModified()));
2021 try {
2022
2023 assertEquals(Status.OK, git.rebase()
2024 .setUpstream("refs/heads/master").call().getStatus());
2025 } finally {
2026 handle.remove();
2027 }
2028 checkFile(new File(new File(db.getWorkTree(), "sub"), "file0"),
2029 "unstaged modified file0");
2030 checkFile(new File(db.getWorkTree(), FILE1), "modified file1");
2031 checkFile(new File(db.getWorkTree(), "file2"), "file2");
2032 assertEquals(
2033 "[file1, mode:100644, content:modified file1]"
2034 + "[file2, mode:100644, content:file2]"
2035 + "[sub/file0, mode:100644, content:file0]",
2036 indexState(CONTENT));
2037 assertEquals(RepositoryState.SAFE, db.getRepositoryState());
2038 List<String> modified = new ArrayList<>(modifiedFiles);
2039 Collections.sort(modified);
2040 assertEquals("[file1, sub/file0]", modified.toString());
2041 }
2042
2043 @Test
2044 public void testRebaseWithAutoStashConflictOnApply() throws Exception {
2045
2046 db.getConfig().setBoolean(ConfigConstants.CONFIG_REBASE_SECTION, null,
2047 ConfigConstants.CONFIG_KEY_AUTOSTASH, true);
2048 writeTrashFile("file0", "file0");
2049 git.add().addFilepattern("file0").call();
2050 git.commit().setMessage("commit0").call();
2051
2052 writeTrashFile(FILE1, "file1");
2053 git.add().addFilepattern(FILE1).call();
2054 RevCommit commit = git.commit().setMessage("commit1").call();
2055
2056
2057 createBranch(commit, "refs/heads/topic");
2058 checkoutBranch("refs/heads/topic");
2059 writeTrashFile("file2", "file2");
2060 git.add().addFilepattern("file2").call();
2061 git.commit().setMessage("commit2").call();
2062
2063
2064 checkoutBranch("refs/heads/master");
2065 writeTrashFile(FILE1, "modified file1");
2066 git.add().addFilepattern(FILE1).call();
2067 git.commit().setMessage("commit3").call();
2068
2069
2070 checkoutBranch("refs/heads/topic");
2071 writeTrashFile("file1", "unstaged modified file1");
2072
2073
2074 assertEquals(Status.STASH_APPLY_CONFLICTS,
2075 git.rebase().setUpstream("refs/heads/master").call()
2076 .getStatus());
2077 checkFile(new File(db.getWorkTree(), "file0"), "file0");
2078 checkFile(
2079 new File(db.getWorkTree(), FILE1),
2080 "<<<<<<< HEAD\nmodified file1\n=======\nunstaged modified file1\n>>>>>>> stash\n");
2081 checkFile(new File(db.getWorkTree(), "file2"), "file2");
2082 assertEquals(
2083 "[file0, mode:100644, content:file0]"
2084 + "[file1, mode:100644, stage:1, content:file1]"
2085 + "[file1, mode:100644, stage:2, content:modified file1]"
2086 + "[file1, mode:100644, stage:3, content:unstaged modified file1]"
2087 + "[file2, mode:100644, content:file2]",
2088 indexState(CONTENT));
2089 assertEquals(RepositoryState.SAFE, db.getRepositoryState());
2090
2091 List<DiffEntry> diffs = getStashedDiff();
2092 assertEquals(1, diffs.size());
2093 assertEquals(DiffEntry.ChangeType.MODIFY, diffs.get(0).getChangeType());
2094 assertEquals("file1", diffs.get(0).getOldPath());
2095 }
2096
2097 @Test
2098 public void testFastForwardRebaseWithAutoStash() throws Exception {
2099
2100 db.getConfig().setBoolean(ConfigConstants.CONFIG_REBASE_SECTION, null,
2101 ConfigConstants.CONFIG_KEY_AUTOSTASH, true);
2102 writeTrashFile("file0", "file0");
2103 git.add().addFilepattern("file0").call();
2104 git.commit().setMessage("commit0").call();
2105
2106 writeTrashFile(FILE1, "file1");
2107 git.add().addFilepattern(FILE1).call();
2108 RevCommit commit = git.commit().setMessage("commit1").call();
2109
2110
2111 createBranch(commit, "refs/heads/topic");
2112
2113
2114 checkoutBranch("refs/heads/master");
2115 writeTrashFile(FILE1, "modified file1");
2116 git.add().addFilepattern(FILE1).call();
2117 git.commit().setMessage("commit3").call();
2118
2119
2120 checkoutBranch("refs/heads/topic");
2121 writeTrashFile("file0", "unstaged modified file0");
2122
2123
2124 assertEquals(Status.FAST_FORWARD,
2125 git.rebase().setUpstream("refs/heads/master")
2126 .call().getStatus());
2127 checkFile(new File(db.getWorkTree(), "file0"),
2128 "unstaged modified file0");
2129 checkFile(new File(db.getWorkTree(), FILE1), "modified file1");
2130 assertEquals("[file0, mode:100644, content:file0]"
2131 + "[file1, mode:100644, content:modified file1]",
2132 indexState(CONTENT));
2133 assertEquals(RepositoryState.SAFE, db.getRepositoryState());
2134 }
2135
2136 private List<DiffEntry> getStashedDiff() throws AmbiguousObjectException,
2137 IncorrectObjectTypeException, IOException, MissingObjectException {
2138 ObjectId stashId = db.resolve("stash@{0}");
2139 RevWalk revWalk = new RevWalk(db);
2140 RevCommit stashCommit = revWalk.parseCommit(stashId);
2141 List<DiffEntry> diffs = diffWorkingAgainstHead(stashCommit, revWalk);
2142 return diffs;
2143 }
2144
2145 private TreeWalk createTreeWalk() {
2146 TreeWalk walk = new TreeWalk(db);
2147 walk.setRecursive(true);
2148 walk.setFilter(TreeFilter.ANY_DIFF);
2149 return walk;
2150 }
2151
2152 private List<DiffEntry> diffWorkingAgainstHead(final RevCommit commit,
2153 RevWalk revWalk)
2154 throws IOException {
2155 RevCommit parentCommit = revWalk.parseCommit(commit.getParent(0));
2156 try (TreeWalk walk = createTreeWalk()) {
2157 walk.addTree(parentCommit.getTree());
2158 walk.addTree(commit.getTree());
2159 return DiffEntry.scan(walk);
2160 }
2161 }
2162
2163 private int countPicks() throws IOException {
2164 int count = 0;
2165 File todoFile = getTodoFile();
2166 try (BufferedReader br = new BufferedReader(new InputStreamReader(
2167 new FileInputStream(todoFile), UTF_8))) {
2168 String line = br.readLine();
2169 while (line != null) {
2170 int firstBlank = line.indexOf(' ');
2171 if (firstBlank != -1) {
2172 String actionToken = line.substring(0, firstBlank);
2173 Action action = null;
2174 try {
2175 action = Action.parse(actionToken);
2176 } catch (Exception e) {
2177
2178 }
2179 if (Action.PICK.equals(action))
2180 count++;
2181 }
2182 line = br.readLine();
2183 }
2184 return count;
2185 }
2186 }
2187
2188 @Test
2189 public void testFastForwardWithMultipleCommitsOnDifferentBranches()
2190 throws Exception {
2191
2192 writeTrashFile(FILE1, FILE1);
2193 git.add().addFilepattern(FILE1).call();
2194 RevCommit first = git.commit().setMessage("Add file1").call();
2195 assertTrue(new File(db.getWorkTree(), FILE1).exists());
2196
2197
2198 createBranch(first, "refs/heads/topic");
2199
2200
2201 writeTrashFile("file2", "file2");
2202 git.add().addFilepattern("file2").call();
2203 RevCommit second = git.commit().setMessage("Add file2").call();
2204 assertTrue(new File(db.getWorkTree(), "file2").exists());
2205
2206
2207 createBranch(second, "refs/heads/side");
2208
2209
2210 writeTrashFile(FILE1, "blah");
2211 git.add().addFilepattern(FILE1).call();
2212 git.commit().setMessage("updated file1 on master")
2213 .call();
2214
2215
2216 checkoutBranch("refs/heads/side");
2217 writeTrashFile("file2", "more change");
2218 git.add().addFilepattern("file2").call();
2219 RevCommit fourth = git.commit().setMessage("update file2 on side")
2220 .call();
2221
2222
2223 checkoutBranch("refs/heads/master");
2224 MergeResult result = git.merge().include(fourth.getId())
2225 .setStrategy(MergeStrategy.RESOLVE).call();
2226 assertEquals(MergeStatus.MERGED, result.getMergeStatus());
2227
2228
2229 checkoutBranch("refs/heads/topic");
2230 RebaseResult res = git.rebase().setUpstream("refs/heads/master").call();
2231 assertTrue(new File(db.getWorkTree(), "file2").exists());
2232 checkFile(new File(db.getWorkTree(), "file2"), "more change");
2233 assertEquals(Status.FAST_FORWARD, res.getStatus());
2234 }
2235
2236 @Test
2237 public void testRebaseShouldLeaveWorkspaceUntouchedWithUnstagedChangesConflict()
2238 throws Exception {
2239 writeTrashFile(FILE1, "initial file");
2240 git.add().addFilepattern(FILE1).call();
2241 RevCommit initial = git.commit().setMessage("initial commit").call();
2242 createBranch(initial, "refs/heads/side");
2243
2244 writeTrashFile(FILE1, "updated file");
2245 git.add().addFilepattern(FILE1).call();
2246 git.commit().setMessage("updated FILE1 on master").call();
2247
2248
2249 checkoutBranch("refs/heads/side");
2250 writeTrashFile(FILE1, "side update");
2251 git.add().addFilepattern(FILE1).call();
2252 git.commit().setMessage("updated FILE1 on side").call();
2253
2254 File theFile = writeTrashFile(FILE1, "dirty the file");
2255
2256
2257 RebaseResult rebaseResult = git.rebase()
2258 .setUpstream("refs/heads/master").call();
2259 assertEquals(Status.UNCOMMITTED_CHANGES, rebaseResult.getStatus());
2260 assertEquals(1, rebaseResult.getUncommittedChanges().size());
2261 assertEquals(FILE1, rebaseResult.getUncommittedChanges().get(0));
2262
2263 checkFile(theFile, "dirty the file");
2264
2265 assertEquals(RepositoryState.SAFE, git.getRepository()
2266 .getRepositoryState());
2267 }
2268
2269 @Test
2270 public void testAbortShouldAlsoAbortNonInteractiveRebaseWithRebaseApplyDir()
2271 throws Exception {
2272 writeTrashFile(FILE1, "initial file");
2273 git.add().addFilepattern(FILE1).call();
2274 git.commit().setMessage("initial commit").call();
2275
2276 File applyDir = new File(db.getDirectory(), "rebase-apply");
2277 File headName = new File(applyDir, "head-name");
2278 FileUtils.mkdir(applyDir);
2279 write(headName, "master");
2280 db.writeOrigHead(db.resolve(Constants.HEAD));
2281
2282 git.rebase().setOperation(Operation.ABORT).call();
2283
2284 assertFalse("Abort should clean up .git/rebase-apply",
2285 applyDir.exists());
2286 assertEquals(RepositoryState.SAFE, git.getRepository()
2287 .getRepositoryState());
2288 }
2289
2290 @Test
2291 public void testRebaseShouldBeAbleToHandleEmptyLinesInRebaseTodoFile()
2292 throws IOException {
2293 String emptyLine = "\n";
2294 String todo = "pick 1111111 Commit 1\n" + emptyLine
2295 + "pick 2222222 Commit 2\n" + emptyLine
2296 + "# Comment line at end\n";
2297 write(getTodoFile(), todo);
2298
2299 List<RebaseTodoLine> steps = db.readRebaseTodo(GIT_REBASE_TODO, false);
2300 assertEquals(2, steps.size());
2301 assertEquals("1111111", steps.get(0).getCommit().name());
2302 assertEquals("2222222", steps.get(1).getCommit().name());
2303 }
2304
2305 @Test
2306 public void testRebaseShouldBeAbleToHandleLinesWithoutCommitMessageInRebaseTodoFile()
2307 throws IOException {
2308 String todo = "pick 1111111 \n" + "pick 2222222 Commit 2\n"
2309 + "# Comment line at end\n";
2310 write(getTodoFile(), todo);
2311
2312 List<RebaseTodoLine> steps = db.readRebaseTodo(GIT_REBASE_TODO, false);
2313 assertEquals(2, steps.size());
2314 assertEquals("1111111", steps.get(0).getCommit().name());
2315 assertEquals("2222222", steps.get(1).getCommit().name());
2316 }
2317
2318 @Test
2319 public void testRebaseShouldNotFailIfUserAddCommentLinesInPrepareSteps()
2320 throws Exception {
2321 commitFile(FILE1, FILE1, "master");
2322 RevCommit c2 = commitFile("file2", "file2", "master");
2323
2324
2325 commitFile(FILE1, "blah", "master");
2326 RevCommit c4 = commitFile("file2", "more change", "master");
2327
2328 RebaseResult res = git.rebase().setUpstream("HEAD~2")
2329 .runInteractively(new InteractiveHandler() {
2330 @Override
2331 public void prepareSteps(List<RebaseTodoLine> steps) {
2332 steps.add(0, new RebaseTodoLine(
2333 "# Comment that should not be processed"));
2334 }
2335
2336 @Override
2337 public String modifyCommitMessage(String commit) {
2338 fail("modifyCommitMessage() was not expected to be called");
2339 return commit;
2340 }
2341 }).call();
2342
2343 assertEquals(RebaseResult.Status.FAST_FORWARD, res.getStatus());
2344
2345 RebaseResult res2 = git.rebase().setUpstream("HEAD~2")
2346 .runInteractively(new InteractiveHandler() {
2347 @Override
2348 public void prepareSteps(List<RebaseTodoLine> steps) {
2349 try {
2350
2351 steps.get(0).setAction(Action.COMMENT);
2352 } catch (IllegalTodoFileModification e) {
2353 fail("unexpected exception: " + e);
2354 }
2355 }
2356
2357 @Override
2358 public String modifyCommitMessage(String commit) {
2359 fail("modifyCommitMessage() was not expected to be called");
2360 return commit;
2361 }
2362 }).call();
2363
2364 assertEquals(RebaseResult.Status.OK, res2.getStatus());
2365
2366 ObjectId headId = db.resolve(Constants.HEAD);
2367 try (RevWalk rw = new RevWalk(db)) {
2368 RevCommit rc = rw.parseCommit(headId);
2369
2370 ObjectId head1Id = db.resolve(Constants.HEAD + "~1");
2371 RevCommit rc1 = rw.parseCommit(head1Id);
2372
2373 assertEquals(rc.getFullMessage(), c4.getFullMessage());
2374 assertEquals(rc1.getFullMessage(), c2.getFullMessage());
2375 }
2376 }
2377
2378 @Test
2379 public void testParseRewordCommand() throws Exception {
2380 String todo = "pick 1111111 Commit 1\n"
2381 + "reword 2222222 Commit 2\n";
2382 write(getTodoFile(), todo);
2383
2384 List<RebaseTodoLine> steps = db.readRebaseTodo(GIT_REBASE_TODO, false);
2385
2386 assertEquals(2, steps.size());
2387 assertEquals("1111111", steps.get(0).getCommit().name());
2388 assertEquals("2222222", steps.get(1).getCommit().name());
2389 assertEquals(Action.REWORD, steps.get(1).getAction());
2390 }
2391
2392 @Test
2393 public void testEmptyRebaseTodo() throws Exception {
2394 write(getTodoFile(), "");
2395 assertEquals(0, db.readRebaseTodo(GIT_REBASE_TODO, true).size());
2396 assertEquals(0, db.readRebaseTodo(GIT_REBASE_TODO, false).size());
2397 }
2398
2399 @Test
2400 public void testOnlyCommentRebaseTodo() throws Exception {
2401 write(getTodoFile(), "# a b c d e\n# e f");
2402 assertEquals(0, db.readRebaseTodo(GIT_REBASE_TODO, false).size());
2403 List<RebaseTodoLine> lines = db.readRebaseTodo(GIT_REBASE_TODO, true);
2404 assertEquals(2, lines.size());
2405 for (RebaseTodoLine line : lines)
2406 assertEquals(Action.COMMENT, line.getAction());
2407 write(getTodoFile(), "# a b c d e\n# e f\n");
2408 assertEquals(0, db.readRebaseTodo(GIT_REBASE_TODO, false).size());
2409 lines = db.readRebaseTodo(GIT_REBASE_TODO, true);
2410 assertEquals(2, lines.size());
2411 for (RebaseTodoLine line : lines)
2412 assertEquals(Action.COMMENT, line.getAction());
2413 write(getTodoFile(), " \r\n# a b c d e\r\n# e f\r\n#");
2414 assertEquals(0, db.readRebaseTodo(GIT_REBASE_TODO, false).size());
2415 lines = db.readRebaseTodo(GIT_REBASE_TODO, true);
2416 assertEquals(4, lines.size());
2417 for (RebaseTodoLine line : lines)
2418 assertEquals(Action.COMMENT, line.getAction());
2419 }
2420
2421 @Test
2422 public void testLeadingSpacesRebaseTodo() throws Exception {
2423 String todo = " \t\t pick 1111111 Commit 1\n"
2424 + "\t\n"
2425 + "\treword 2222222 Commit 2\n";
2426 write(getTodoFile(), todo);
2427
2428 List<RebaseTodoLine> steps = db.readRebaseTodo(GIT_REBASE_TODO, false);
2429
2430 assertEquals(2, steps.size());
2431 assertEquals("1111111", steps.get(0).getCommit().name());
2432 assertEquals("2222222", steps.get(1).getCommit().name());
2433 assertEquals(Action.REWORD, steps.get(1).getAction());
2434 }
2435
2436 @Test
2437 public void testRebaseShouldTryToParseValidLineMarkedAsComment()
2438 throws IOException {
2439 String todo = "# pick 1111111 Valid line commented out with space\n"
2440 + "#edit 2222222 Valid line commented out without space\n"
2441 + "# pick invalidLine Comment line at end\n";
2442 write(getTodoFile(), todo);
2443
2444 List<RebaseTodoLine> steps = db.readRebaseTodo(GIT_REBASE_TODO, true);
2445 assertEquals(3, steps.size());
2446
2447 RebaseTodoLine firstLine = steps.get(0);
2448
2449 assertEquals("1111111", firstLine.getCommit().name());
2450 assertEquals("Valid line commented out with space",
2451 firstLine.getShortMessage());
2452 assertEquals("comment", firstLine.getAction().toToken());
2453
2454 try {
2455 firstLine.setAction(Action.PICK);
2456 assertEquals("1111111", firstLine.getCommit().name());
2457 assertEquals("pick", firstLine.getAction().toToken());
2458 } catch (Exception e) {
2459 fail("Valid parsable RebaseTodoLine that has been commented out should allow to change the action, but failed");
2460 }
2461
2462 assertEquals("2222222", steps.get(1).getCommit().name());
2463 assertEquals("comment", steps.get(1).getAction().toToken());
2464
2465 assertEquals(null, steps.get(2).getCommit());
2466 assertEquals(null, steps.get(2).getShortMessage());
2467 assertEquals("comment", steps.get(2).getAction().toToken());
2468 assertEquals("# pick invalidLine Comment line at end", steps.get(2)
2469 .getComment());
2470 try {
2471 steps.get(2).setAction(Action.PICK);
2472 fail("A comment RebaseTodoLine that doesn't contain a valid parsable line should fail, but doesn't");
2473 } catch (Exception e) {
2474
2475 }
2476
2477 }
2478
2479 @SuppressWarnings("unused")
2480 @Test
2481 public void testRebaseTodoLineSetComment() throws Exception {
2482 try {
2483 new RebaseTodoLine("This is a invalid comment");
2484 fail("Constructing a comment line with invalid comment string should fail, but doesn't");
2485 } catch (IllegalArgumentException e) {
2486
2487 }
2488 RebaseTodoLine validCommentLine = new RebaseTodoLine(
2489 "# This is a comment");
2490 assertEquals(Action.COMMENT, validCommentLine.getAction());
2491 assertEquals("# This is a comment", validCommentLine.getComment());
2492
2493 RebaseTodoLine actionLineToBeChanged = new RebaseTodoLine(Action.EDIT,
2494 AbbreviatedObjectId.fromString("1111111"), "short Message");
2495 assertEquals(null, actionLineToBeChanged.getComment());
2496
2497 try {
2498 actionLineToBeChanged.setComment("invalid comment");
2499 fail("Setting a invalid comment string should fail but doesn't");
2500 } catch (IllegalArgumentException e) {
2501 assertEquals(null, actionLineToBeChanged.getComment());
2502 }
2503
2504 actionLineToBeChanged.setComment("# valid comment");
2505 assertEquals("# valid comment", actionLineToBeChanged.getComment());
2506 try {
2507 actionLineToBeChanged.setComment("invalid comment");
2508 fail("Setting a invalid comment string should fail but doesn't");
2509 } catch (IllegalArgumentException e) {
2510
2511
2512
2513 assertEquals("# valid comment", actionLineToBeChanged.getComment());
2514 }
2515 try {
2516 actionLineToBeChanged.setComment("# line1 \n line2");
2517 actionLineToBeChanged.setComment("line1 \n line2");
2518 actionLineToBeChanged.setComment("\n");
2519 actionLineToBeChanged.setComment("# line1 \r line2");
2520 actionLineToBeChanged.setComment("line1 \r line2");
2521 actionLineToBeChanged.setComment("\r");
2522 actionLineToBeChanged.setComment("# line1 \n\r line2");
2523 actionLineToBeChanged.setComment("line1 \n\r line2");
2524 actionLineToBeChanged.setComment("\n\r");
2525 fail("Setting a multiline comment string should fail but doesn't");
2526 } catch (IllegalArgumentException e) {
2527
2528 }
2529
2530 actionLineToBeChanged.setComment("# valid comment");
2531 assertEquals("# valid comment", actionLineToBeChanged.getComment());
2532
2533 actionLineToBeChanged.setComment("# \t \t valid comment");
2534 assertEquals("# \t \t valid comment",
2535 actionLineToBeChanged.getComment());
2536
2537 actionLineToBeChanged.setComment("# ");
2538 assertEquals("# ", actionLineToBeChanged.getComment());
2539
2540 actionLineToBeChanged.setComment("");
2541 assertEquals("", actionLineToBeChanged.getComment());
2542
2543 actionLineToBeChanged.setComment(" ");
2544 assertEquals(" ", actionLineToBeChanged.getComment());
2545
2546 actionLineToBeChanged.setComment("\t\t");
2547 assertEquals("\t\t", actionLineToBeChanged.getComment());
2548
2549 actionLineToBeChanged.setComment(null);
2550 assertEquals(null, actionLineToBeChanged.getComment());
2551 }
2552
2553 @Test
2554 public void testRebaseInteractiveReword() throws Exception {
2555
2556 writeTrashFile(FILE1, FILE1);
2557 git.add().addFilepattern(FILE1).call();
2558 git.commit().setMessage("Add file1").call();
2559 assertTrue(new File(db.getWorkTree(), FILE1).exists());
2560
2561
2562 writeTrashFile("file2", "file2");
2563 git.add().addFilepattern("file2").call();
2564 git.commit().setMessage("Add file2").call();
2565 assertTrue(new File(db.getWorkTree(), "file2").exists());
2566
2567
2568 writeTrashFile(FILE1, "blah");
2569 git.add().addFilepattern(FILE1).call();
2570 git.commit().setMessage("updated file1 on master").call();
2571
2572 writeTrashFile("file2", "more change");
2573 git.add().addFilepattern("file2").call();
2574 git.commit().setMessage("update file2 on side").call();
2575
2576 RebaseResult res = git.rebase().setUpstream("HEAD~2")
2577 .runInteractively(new InteractiveHandler() {
2578
2579 @Override
2580 public void prepareSteps(List<RebaseTodoLine> steps) {
2581 try {
2582 steps.get(0).setAction(Action.REWORD);
2583 } catch (IllegalTodoFileModification e) {
2584 fail("unexpected exception: " + e);
2585 }
2586 }
2587
2588 @Override
2589 public String modifyCommitMessage(String commit) {
2590 return "rewritten commit message";
2591 }
2592 }).call();
2593 assertTrue(new File(db.getWorkTree(), "file2").exists());
2594 checkFile(new File(db.getWorkTree(), "file2"), "more change");
2595 assertEquals(Status.OK, res.getStatus());
2596 Iterator<RevCommit> logIterator = git.log().all().call().iterator();
2597 logIterator.next();
2598 String actualCommitMag = logIterator.next().getShortMessage();
2599 assertEquals("rewritten commit message", actualCommitMag);
2600 }
2601
2602 @Test
2603 public void testRebaseInteractiveEdit() throws Exception {
2604
2605 writeTrashFile(FILE1, FILE1);
2606 git.add().addFilepattern(FILE1).call();
2607 git.commit().setMessage("Add file1").call();
2608 assertTrue(new File(db.getWorkTree(), FILE1).exists());
2609
2610
2611 writeTrashFile("file2", "file2");
2612 git.add().addFilepattern("file2").call();
2613 git.commit().setMessage("Add file2").call();
2614 assertTrue(new File(db.getWorkTree(), "file2").exists());
2615
2616
2617 writeTrashFile(FILE1, "blah");
2618 git.add().addFilepattern(FILE1).call();
2619 git.commit().setMessage("updated file1 on master").call();
2620
2621 writeTrashFile("file2", "more change");
2622 git.add().addFilepattern("file2").call();
2623 git.commit().setMessage("update file2 on side").call();
2624
2625 RebaseResult res = git.rebase().setUpstream("HEAD~2")
2626 .runInteractively(new InteractiveHandler() {
2627 @Override
2628 public void prepareSteps(List<RebaseTodoLine> steps) {
2629 try {
2630 steps.get(0).setAction(Action.EDIT);
2631 } catch (IllegalTodoFileModification e) {
2632 fail("unexpected exception: " + e);
2633 }
2634 }
2635
2636 @Override
2637 public String modifyCommitMessage(String commit) {
2638 return "";
2639 }
2640 }).call();
2641 assertEquals(Status.EDIT, res.getStatus());
2642 RevCommit toBeEditted = git.log().call().iterator().next();
2643 assertEquals("updated file1 on master", toBeEditted.getFullMessage());
2644
2645
2646 writeTrashFile("file1", "edited");
2647 git.commit().setAll(true).setAmend(true)
2648 .setMessage("edited commit message").call();
2649
2650 res = git.rebase().setOperation(Operation.CONTINUE).call();
2651
2652 checkFile(new File(db.getWorkTree(), "file1"), "edited");
2653 assertEquals(Status.OK, res.getStatus());
2654 Iterator<RevCommit> logIterator = git.log().all().call().iterator();
2655 logIterator.next();
2656 String actualCommitMag = logIterator.next().getShortMessage();
2657 assertEquals("edited commit message", actualCommitMag);
2658 }
2659
2660 @Test
2661 public void testParseSquashFixupSequenceCount() {
2662 int count = RebaseCommand
2663 .parseSquashFixupSequenceCount("# This is a combination of 3 commits.\n# newline");
2664 assertEquals(3, count);
2665 }
2666
2667 @Test
2668 public void testRebaseInteractiveSingleSquashAndModifyMessage() throws Exception {
2669
2670 writeTrashFile(FILE1, FILE1);
2671 git.add().addFilepattern(FILE1).call();
2672 git.commit().setMessage("Add file1\nnew line").call();
2673 assertTrue(new File(db.getWorkTree(), FILE1).exists());
2674
2675
2676 writeTrashFile("file2", "file2");
2677 git.add().addFilepattern("file2").call();
2678 git.commit().setMessage("Add file2\nnew line").call();
2679 assertTrue(new File(db.getWorkTree(), "file2").exists());
2680
2681
2682 writeTrashFile(FILE1, "blah");
2683 git.add().addFilepattern(FILE1).call();
2684 git.commit().setMessage("updated file1 on master\nnew line").call();
2685
2686 writeTrashFile("file2", "more change");
2687 git.add().addFilepattern("file2").call();
2688 git.commit().setMessage("update file2 on master\nnew line").call();
2689
2690 git.rebase().setUpstream("HEAD~3")
2691 .runInteractively(new InteractiveHandler() {
2692
2693 @Override
2694 public void prepareSteps(List<RebaseTodoLine> steps) {
2695 try {
2696 steps.get(1).setAction(Action.SQUASH);
2697 } catch (IllegalTodoFileModification e) {
2698 fail("unexpected exception: " + e);
2699 }
2700 }
2701
2702 @Override
2703 public String modifyCommitMessage(String commit) {
2704 final File messageSquashFile = new File(db
2705 .getDirectory(), "rebase-merge/message-squash");
2706 final File messageFixupFile = new File(db
2707 .getDirectory(), "rebase-merge/message-fixup");
2708
2709 assertFalse(messageFixupFile.exists());
2710 assertTrue(messageSquashFile.exists());
2711 assertEquals(
2712 "# This is a combination of 2 commits.\n# The first commit's message is:\nAdd file2\nnew line\n# This is the 2nd commit message:\nupdated file1 on master\nnew line",
2713 commit);
2714
2715 try {
2716 byte[] messageSquashBytes = IO
2717 .readFully(messageSquashFile);
2718 int end = RawParseUtils.prevLF(messageSquashBytes,
2719 messageSquashBytes.length);
2720 String messageSquashContent = RawParseUtils.decode(
2721 messageSquashBytes, 0, end + 1);
2722 assertEquals(messageSquashContent, commit);
2723 } catch (Throwable t) {
2724 fail(t.getMessage());
2725 }
2726
2727 return "changed";
2728 }
2729 }).call();
2730
2731 try (RevWalk walk = new RevWalk(db)) {
2732 ObjectId headId = db.resolve(Constants.HEAD);
2733 RevCommit headCommit = walk.parseCommit(headId);
2734 assertEquals(headCommit.getFullMessage(),
2735 "update file2 on master\nnew line");
2736
2737 ObjectId head2Id = db.resolve(Constants.HEAD + "^1");
2738 RevCommit head1Commit = walk.parseCommit(head2Id);
2739 assertEquals("changed", head1Commit.getFullMessage());
2740 }
2741 }
2742
2743 @Test
2744 public void testRebaseInteractiveMultipleSquash() throws Exception {
2745
2746 writeTrashFile("file0", "file0");
2747 git.add().addFilepattern("file0").call();
2748 git.commit().setMessage("Add file0\nnew line").call();
2749 assertTrue(new File(db.getWorkTree(), "file0").exists());
2750
2751
2752 writeTrashFile(FILE1, FILE1);
2753 git.add().addFilepattern(FILE1).call();
2754 git.commit().setMessage("Add file1\nnew line").call();
2755 assertTrue(new File(db.getWorkTree(), FILE1).exists());
2756
2757
2758 writeTrashFile("file2", "file2");
2759 git.add().addFilepattern("file2").call();
2760 git.commit().setMessage("Add file2\nnew line").call();
2761 assertTrue(new File(db.getWorkTree(), "file2").exists());
2762
2763
2764 writeTrashFile(FILE1, "blah");
2765 git.add().addFilepattern(FILE1).call();
2766 git.commit().setMessage("updated file1 on master\nnew line").call();
2767
2768 writeTrashFile("file2", "more change");
2769 git.add().addFilepattern("file2").call();
2770 git.commit().setMessage("update file2 on master\nnew line").call();
2771
2772 git.rebase().setUpstream("HEAD~4")
2773 .runInteractively(new InteractiveHandler() {
2774
2775 @Override
2776 public void prepareSteps(List<RebaseTodoLine> steps) {
2777 try {
2778 steps.get(1).setAction(Action.SQUASH);
2779 steps.get(2).setAction(Action.SQUASH);
2780 } catch (IllegalTodoFileModification e) {
2781 fail("unexpected exception: " + e);
2782 }
2783 }
2784
2785 @Override
2786 public String modifyCommitMessage(String commit) {
2787 final File messageSquashFile = new File(db.getDirectory(),
2788 "rebase-merge/message-squash");
2789 final File messageFixupFile = new File(db.getDirectory(),
2790 "rebase-merge/message-fixup");
2791 assertFalse(messageFixupFile.exists());
2792 assertTrue(messageSquashFile.exists());
2793 assertEquals(
2794 "# This is a combination of 3 commits.\n# The first commit's message is:\nAdd file1\nnew line\n# This is the 2nd commit message:\nAdd file2\nnew line\n# This is the 3rd commit message:\nupdated file1 on master\nnew line",
2795 commit);
2796
2797 try {
2798 byte[] messageSquashBytes = IO
2799 .readFully(messageSquashFile);
2800 int end = RawParseUtils.prevLF(messageSquashBytes,
2801 messageSquashBytes.length);
2802 String messageSquashContend = RawParseUtils.decode(
2803 messageSquashBytes, 0, end + 1);
2804 assertEquals(messageSquashContend, commit);
2805 } catch (Throwable t) {
2806 fail(t.getMessage());
2807 }
2808
2809 return "# This is a combination of 3 commits.\n# The first commit's message is:\nAdd file1\nnew line\n# This is the 2nd commit message:\nAdd file2\nnew line\n# This is the 3rd commit message:\nupdated file1 on master\nnew line";
2810 }
2811 }).call();
2812
2813 try (RevWalk walk = new RevWalk(db)) {
2814 ObjectId headId = db.resolve(Constants.HEAD);
2815 RevCommit headCommit = walk.parseCommit(headId);
2816 assertEquals(headCommit.getFullMessage(),
2817 "update file2 on master\nnew line");
2818
2819 ObjectId head2Id = db.resolve(Constants.HEAD + "^1");
2820 RevCommit head1Commit = walk.parseCommit(head2Id);
2821 assertEquals(
2822 "Add file1\nnew line\nAdd file2\nnew line\nupdated file1 on master\nnew line",
2823 head1Commit.getFullMessage());
2824 }
2825 }
2826
2827 @Test
2828 public void testRebaseInteractiveMixedSquashAndFixup() throws Exception {
2829
2830 writeTrashFile("file0", "file0");
2831 git.add().addFilepattern("file0").call();
2832 git.commit().setMessage("Add file0\nnew line").call();
2833 assertTrue(new File(db.getWorkTree(), "file0").exists());
2834
2835
2836 writeTrashFile(FILE1, FILE1);
2837 git.add().addFilepattern(FILE1).call();
2838 git.commit().setMessage("Add file1\nnew line").call();
2839 assertTrue(new File(db.getWorkTree(), FILE1).exists());
2840
2841
2842 writeTrashFile("file2", "file2");
2843 git.add().addFilepattern("file2").call();
2844 git.commit().setMessage("Add file2\nnew line").call();
2845 assertTrue(new File(db.getWorkTree(), "file2").exists());
2846
2847
2848 writeTrashFile(FILE1, "blah");
2849 git.add().addFilepattern(FILE1).call();
2850 git.commit().setMessage("updated file1 on master\nnew line").call();
2851
2852 writeTrashFile("file2", "more change");
2853 git.add().addFilepattern("file2").call();
2854 git.commit().setMessage("update file2 on master\nnew line").call();
2855
2856 git.rebase().setUpstream("HEAD~4")
2857 .runInteractively(new InteractiveHandler() {
2858
2859 @Override
2860 public void prepareSteps(List<RebaseTodoLine> steps) {
2861 try {
2862 steps.get(1).setAction(Action.FIXUP);
2863 steps.get(2).setAction(Action.SQUASH);
2864 } catch (IllegalTodoFileModification e) {
2865 fail("unexpected exception: " + e);
2866 }
2867 }
2868
2869 @Override
2870 public String modifyCommitMessage(String commit) {
2871 final File messageSquashFile = new File(db
2872 .getDirectory(), "rebase-merge/message-squash");
2873 final File messageFixupFile = new File(db
2874 .getDirectory(), "rebase-merge/message-fixup");
2875
2876 assertFalse(messageFixupFile.exists());
2877 assertTrue(messageSquashFile.exists());
2878 assertEquals(
2879 "# This is a combination of 3 commits.\n# The first commit's message is:\nAdd file1\nnew line\n# The 2nd commit message will be skipped:\n# Add file2\n# new line\n# This is the 3rd commit message:\nupdated file1 on master\nnew line",
2880 commit);
2881
2882 try {
2883 byte[] messageSquashBytes = IO
2884 .readFully(messageSquashFile);
2885 int end = RawParseUtils.prevLF(messageSquashBytes,
2886 messageSquashBytes.length);
2887 String messageSquashContend = RawParseUtils.decode(
2888 messageSquashBytes, 0, end + 1);
2889 assertEquals(messageSquashContend, commit);
2890 } catch (Throwable t) {
2891 fail(t.getMessage());
2892 }
2893
2894 return "changed";
2895 }
2896 }).call();
2897
2898 try (RevWalk walk = new RevWalk(db)) {
2899 ObjectId headId = db.resolve(Constants.HEAD);
2900 RevCommit headCommit = walk.parseCommit(headId);
2901 assertEquals(headCommit.getFullMessage(),
2902 "update file2 on master\nnew line");
2903
2904 ObjectId head2Id = db.resolve(Constants.HEAD + "^1");
2905 RevCommit head1Commit = walk.parseCommit(head2Id);
2906 assertEquals("changed", head1Commit.getFullMessage());
2907 }
2908 }
2909
2910 @Test
2911 public void testRebaseInteractiveSingleFixup() throws Exception {
2912
2913 writeTrashFile(FILE1, FILE1);
2914 git.add().addFilepattern(FILE1).call();
2915 git.commit().setMessage("Add file1\nnew line").call();
2916 assertTrue(new File(db.getWorkTree(), FILE1).exists());
2917
2918
2919 writeTrashFile("file2", "file2");
2920 git.add().addFilepattern("file2").call();
2921 git.commit().setMessage("Add file2\nnew line").call();
2922 assertTrue(new File(db.getWorkTree(), "file2").exists());
2923
2924
2925 writeTrashFile(FILE1, "blah");
2926 git.add().addFilepattern(FILE1).call();
2927 git.commit().setMessage("updated file1 on master\nnew line").call();
2928
2929 writeTrashFile("file2", "more change");
2930 git.add().addFilepattern("file2").call();
2931 git.commit().setMessage("update file2 on master\nnew line").call();
2932
2933 git.rebase().setUpstream("HEAD~3")
2934 .runInteractively(new InteractiveHandler() {
2935
2936 @Override
2937 public void prepareSteps(List<RebaseTodoLine> steps) {
2938 try {
2939 steps.get(1).setAction(Action.FIXUP);
2940 } catch (IllegalTodoFileModification e) {
2941 fail("unexpected exception: " + e);
2942 }
2943 }
2944
2945 @Override
2946 public String modifyCommitMessage(String commit) {
2947 fail("No callback to modify commit message expected for single fixup");
2948 return commit;
2949 }
2950 }).call();
2951
2952 try (RevWalk walk = new RevWalk(db)) {
2953 ObjectId headId = db.resolve(Constants.HEAD);
2954 RevCommit headCommit = walk.parseCommit(headId);
2955 assertEquals("update file2 on master\nnew line",
2956 headCommit.getFullMessage());
2957
2958 ObjectId head1Id = db.resolve(Constants.HEAD + "^1");
2959 RevCommit head1Commit = walk.parseCommit(head1Id);
2960 assertEquals("Add file2\nnew line",
2961 head1Commit.getFullMessage());
2962 }
2963 }
2964
2965 @Test
2966 public void testRebaseInteractiveFixupWithBlankLines() throws Exception {
2967
2968 writeTrashFile(FILE1, FILE1);
2969 git.add().addFilepattern(FILE1).call();
2970 git.commit().setMessage("Add file1\nnew line").call();
2971 assertTrue(new File(db.getWorkTree(), FILE1).exists());
2972
2973
2974 writeTrashFile("file2", "file2");
2975 git.add().addFilepattern("file2").call();
2976 git.commit().setMessage("Add file2").call();
2977 assertTrue(new File(db.getWorkTree(), "file2").exists());
2978
2979
2980 writeTrashFile(FILE1, "blah");
2981 git.add().addFilepattern(FILE1).call();
2982 git.commit().setMessage("updated file1 on master\n\nsome text").call();
2983
2984 git.rebase().setUpstream("HEAD~2")
2985 .runInteractively(new InteractiveHandler() {
2986
2987 @Override
2988 public void prepareSteps(List<RebaseTodoLine> steps) {
2989 try {
2990 steps.get(1).setAction(Action.FIXUP);
2991 } catch (IllegalTodoFileModification e) {
2992 fail("unexpected exception: " + e);
2993 }
2994 }
2995
2996 @Override
2997 public String modifyCommitMessage(String commit) {
2998 fail("No callback to modify commit message expected for single fixup");
2999 return commit;
3000 }
3001 }).call();
3002
3003 try (RevWalk walk = new RevWalk(db)) {
3004 ObjectId headId = db.resolve(Constants.HEAD);
3005 RevCommit headCommit = walk.parseCommit(headId);
3006 assertEquals("Add file2",
3007 headCommit.getFullMessage());
3008 }
3009 }
3010
3011 @Test(expected = InvalidRebaseStepException.class)
3012 public void testRebaseInteractiveFixupFirstCommitShouldFail()
3013 throws Exception {
3014
3015 writeTrashFile(FILE1, FILE1);
3016 git.add().addFilepattern(FILE1).call();
3017 git.commit().setMessage("Add file1\nnew line").call();
3018 assertTrue(new File(db.getWorkTree(), FILE1).exists());
3019
3020
3021 writeTrashFile("file2", "file2");
3022 git.add().addFilepattern("file2").call();
3023 git.commit().setMessage("Add file2\nnew line").call();
3024 assertTrue(new File(db.getWorkTree(), "file2").exists());
3025
3026 git.rebase().setUpstream("HEAD~1")
3027 .runInteractively(new InteractiveHandler() {
3028
3029 @Override
3030 public void prepareSteps(List<RebaseTodoLine> steps) {
3031 try {
3032 steps.get(0).setAction(Action.FIXUP);
3033 } catch (IllegalTodoFileModification e) {
3034 fail("unexpected exception: " + e);
3035 }
3036 }
3037
3038 @Override
3039 public String modifyCommitMessage(String commit) {
3040 return commit;
3041 }
3042 }).call();
3043 }
3044
3045 @Test(expected = InvalidRebaseStepException.class)
3046 public void testRebaseInteractiveSquashFirstCommitShouldFail()
3047 throws Exception {
3048
3049 writeTrashFile(FILE1, FILE1);
3050 git.add().addFilepattern(FILE1).call();
3051 git.commit().setMessage("Add file1\nnew line").call();
3052 assertTrue(new File(db.getWorkTree(), FILE1).exists());
3053
3054
3055 writeTrashFile("file2", "file2");
3056 git.add().addFilepattern("file2").call();
3057 git.commit().setMessage("Add file2\nnew line").call();
3058 assertTrue(new File(db.getWorkTree(), "file2").exists());
3059
3060 git.rebase().setUpstream("HEAD~1")
3061 .runInteractively(new InteractiveHandler() {
3062
3063 @Override
3064 public void prepareSteps(List<RebaseTodoLine> steps) {
3065 try {
3066 steps.get(0).setAction(Action.SQUASH);
3067 } catch (IllegalTodoFileModification e) {
3068 fail("unexpected exception: " + e);
3069 }
3070 }
3071
3072 @Override
3073 public String modifyCommitMessage(String commit) {
3074 return commit;
3075 }
3076 }).call();
3077 }
3078
3079 @Test
3080 public void testRebaseEndsIfLastStepIsEdit() throws Exception {
3081
3082 writeTrashFile(FILE1, FILE1);
3083 git.add().addFilepattern(FILE1).call();
3084 git.commit().setMessage("Add file1\nnew line").call();
3085 assertTrue(new File(db.getWorkTree(), FILE1).exists());
3086
3087
3088 writeTrashFile("file2", "file2");
3089 git.add().addFilepattern("file2").call();
3090 git.commit().setMessage("Add file2\nnew line").call();
3091 assertTrue(new File(db.getWorkTree(), "file2").exists());
3092
3093 git.rebase().setUpstream("HEAD~1")
3094 .runInteractively(new InteractiveHandler() {
3095
3096 @Override
3097 public void prepareSteps(List<RebaseTodoLine> steps) {
3098 try {
3099 steps.get(0).setAction(Action.EDIT);
3100 } catch (IllegalTodoFileModification e) {
3101 fail("unexpected exception: " + e);
3102 }
3103 }
3104
3105 @Override
3106 public String modifyCommitMessage(String commit) {
3107 return commit;
3108 }
3109 }).call();
3110 git.commit().setAmend(true)
3111 .setMessage("Add file2\nnew line\nanother line").call();
3112 RebaseResult result = git.rebase().setOperation(Operation.CONTINUE)
3113 .call();
3114 assertEquals(Status.OK, result.getStatus());
3115
3116 }
3117
3118 @Test
3119 public void testRebaseShouldStopForEditInCaseOfConflict()
3120 throws Exception {
3121
3122 writeTrashFile(FILE1, FILE1);
3123 git.add().addFilepattern(FILE1).call();
3124 git.commit().setMessage("Add file1\nnew line").call();
3125 assertTrue(new File(db.getWorkTree(), FILE1).exists());
3126
3127
3128 writeTrashFile(FILE1, FILE1 + "a");
3129 git.add().addFilepattern(FILE1).call();
3130 git.commit().setMessage("Change file1").call();
3131
3132
3133 writeTrashFile(FILE1, FILE1 + "b");
3134 git.add().addFilepattern(FILE1).call();
3135 git.commit().setMessage("Change file1").call();
3136
3137 RebaseResult result = git.rebase().setUpstream("HEAD~2")
3138 .runInteractively(new InteractiveHandler() {
3139
3140 @Override
3141 public void prepareSteps(List<RebaseTodoLine> steps) {
3142 steps.remove(0);
3143 try {
3144 steps.get(0).setAction(Action.EDIT);
3145 } catch (IllegalTodoFileModification e) {
3146 fail("unexpected exception: " + e);
3147 }
3148 }
3149
3150 @Override
3151 public String modifyCommitMessage(String commit) {
3152 return commit;
3153 }
3154 }).call();
3155 assertEquals(Status.STOPPED, result.getStatus());
3156 git.add().addFilepattern(FILE1).call();
3157 result = git.rebase().setOperation(Operation.CONTINUE).call();
3158 assertEquals(Status.EDIT, result.getStatus());
3159
3160 }
3161
3162 @Test
3163 public void testRebaseShouldStopForRewordInCaseOfConflict()
3164 throws Exception {
3165
3166 writeTrashFile(FILE1, FILE1);
3167 git.add().addFilepattern(FILE1).call();
3168 git.commit().setMessage("Add file1\nnew line").call();
3169 assertTrue(new File(db.getWorkTree(), FILE1).exists());
3170
3171
3172 writeTrashFile(FILE1, FILE1 + "a");
3173 git.add().addFilepattern(FILE1).call();
3174 git.commit().setMessage("Change file1").call();
3175
3176
3177 writeTrashFile(FILE1, FILE1 + "b");
3178 git.add().addFilepattern(FILE1).call();
3179 git.commit().setMessage("Change file1").call();
3180
3181 RebaseResult result = git.rebase().setUpstream("HEAD~2")
3182 .runInteractively(new InteractiveHandler() {
3183
3184 @Override
3185 public void prepareSteps(List<RebaseTodoLine> steps) {
3186 steps.remove(0);
3187 try {
3188 steps.get(0).setAction(Action.REWORD);
3189 } catch (IllegalTodoFileModification e) {
3190 fail("unexpected exception: " + e);
3191 }
3192 }
3193
3194 @Override
3195 public String modifyCommitMessage(String commit) {
3196 return "rewritten commit message";
3197 }
3198 }).call();
3199 assertEquals(Status.STOPPED, result.getStatus());
3200 git.add().addFilepattern(FILE1).call();
3201 result = git.rebase().runInteractively(new InteractiveHandler() {
3202
3203 @Override
3204 public void prepareSteps(List<RebaseTodoLine> steps) {
3205 steps.remove(0);
3206 try {
3207 steps.get(0).setAction(Action.REWORD);
3208 } catch (IllegalTodoFileModification e) {
3209 fail("unexpected exception: " + e);
3210 }
3211 }
3212
3213 @Override
3214 public String modifyCommitMessage(String commit) {
3215 return "rewritten commit message";
3216 }
3217 }).setOperation(Operation.CONTINUE).call();
3218 assertEquals(Status.OK, result.getStatus());
3219 Iterator<RevCommit> logIterator = git.log().all().call().iterator();
3220 String actualCommitMag = logIterator.next().getShortMessage();
3221 assertEquals("rewritten commit message", actualCommitMag);
3222
3223 }
3224
3225 @Test
3226 public void testRebaseShouldSquashInCaseOfConflict() throws Exception {
3227
3228 writeTrashFile(FILE1, FILE1);
3229 git.add().addFilepattern(FILE1).call();
3230 git.commit().setMessage("Add file1\nnew line").call();
3231 assertTrue(new File(db.getWorkTree(), FILE1).exists());
3232
3233
3234 writeTrashFile("file2", "file2");
3235 git.add().addFilepattern("file2").call();
3236 git.commit().setMessage("Change file2").call();
3237
3238
3239 writeTrashFile(FILE1, FILE1 + "a");
3240 git.add().addFilepattern(FILE1).call();
3241 git.commit().setMessage("Change file1").call();
3242
3243
3244 writeTrashFile(FILE1, FILE1 + "b");
3245 git.add().addFilepattern(FILE1).call();
3246 git.commit().setMessage("Change file1").call();
3247
3248 RebaseResult result = git.rebase().setUpstream("HEAD~3")
3249 .runInteractively(new InteractiveHandler() {
3250
3251 @Override
3252 public void prepareSteps(List<RebaseTodoLine> steps) {
3253 try {
3254 steps.get(0).setAction(Action.PICK);
3255 steps.remove(1);
3256 steps.get(1).setAction(Action.SQUASH);
3257 } catch (IllegalTodoFileModification e) {
3258 fail("unexpected exception: " + e);
3259 }
3260 }
3261
3262 @Override
3263 public String modifyCommitMessage(String commit) {
3264 return "squashed message";
3265 }
3266 }).call();
3267 assertEquals(Status.STOPPED, result.getStatus());
3268 git.add().addFilepattern(FILE1).call();
3269 result = git.rebase().runInteractively(new InteractiveHandler() {
3270
3271 @Override
3272 public void prepareSteps(List<RebaseTodoLine> steps) {
3273 try {
3274 steps.get(0).setAction(Action.PICK);
3275 steps.remove(1);
3276 steps.get(1).setAction(Action.SQUASH);
3277 } catch (IllegalTodoFileModification e) {
3278 fail("unexpected exception: " + e);
3279 }
3280 }
3281
3282 @Override
3283 public String modifyCommitMessage(String commit) {
3284 return "squashed message";
3285 }
3286 }).setOperation(Operation.CONTINUE).call();
3287 assertEquals(Status.OK, result.getStatus());
3288 Iterator<RevCommit> logIterator = git.log().all().call().iterator();
3289 String actualCommitMag = logIterator.next().getShortMessage();
3290 assertEquals("squashed message", actualCommitMag);
3291 }
3292
3293 @Test
3294 public void testRebaseShouldFixupInCaseOfConflict() throws Exception {
3295
3296 writeTrashFile(FILE1, FILE1);
3297 git.add().addFilepattern(FILE1).call();
3298 git.commit().setMessage("Add file1").call();
3299 assertTrue(new File(db.getWorkTree(), FILE1).exists());
3300
3301
3302 writeTrashFile("file2", "file2");
3303 git.add().addFilepattern("file2").call();
3304 git.commit().setMessage("Change file2").call();
3305
3306
3307 writeTrashFile(FILE1, FILE1 + "a");
3308 git.add().addFilepattern(FILE1).call();
3309 git.commit().setMessage("Change file1").call();
3310
3311
3312 writeTrashFile(FILE1, FILE1 + "b");
3313 writeTrashFile("file3", "file3");
3314 git.add().addFilepattern(FILE1).call();
3315 git.add().addFilepattern("file3").call();
3316 git.commit().setMessage("Change file1, add file3").call();
3317
3318 RebaseResult result = git.rebase().setUpstream("HEAD~3")
3319 .runInteractively(new InteractiveHandler() {
3320
3321 @Override
3322 public void prepareSteps(List<RebaseTodoLine> steps) {
3323 try {
3324 steps.get(0).setAction(Action.PICK);
3325 steps.remove(1);
3326 steps.get(1).setAction(Action.FIXUP);
3327 } catch (IllegalTodoFileModification e) {
3328 fail("unexpected exception: " + e);
3329 }
3330 }
3331
3332 @Override
3333 public String modifyCommitMessage(String commit) {
3334 return commit;
3335 }
3336 }).call();
3337 assertEquals(Status.STOPPED, result.getStatus());
3338 git.add().addFilepattern(FILE1).call();
3339 result = git.rebase().runInteractively(new InteractiveHandler() {
3340
3341 @Override
3342 public void prepareSteps(List<RebaseTodoLine> steps) {
3343 try {
3344 steps.get(0).setAction(Action.PICK);
3345 steps.remove(1);
3346 steps.get(1).setAction(Action.FIXUP);
3347 } catch (IllegalTodoFileModification e) {
3348 fail("unexpected exception: " + e);
3349 }
3350 }
3351
3352 @Override
3353 public String modifyCommitMessage(String commit) {
3354 return "commit";
3355 }
3356 }).setOperation(Operation.CONTINUE).call();
3357 assertEquals(Status.OK, result.getStatus());
3358 Iterator<RevCommit> logIterator = git.log().all().call().iterator();
3359 String actualCommitMsg = logIterator.next().getShortMessage();
3360 assertEquals("Change file2", actualCommitMsg);
3361 actualCommitMsg = logIterator.next().getShortMessage();
3362 assertEquals("Add file1", actualCommitMsg);
3363 assertTrue(new File(db.getWorkTree(), "file3").exists());
3364
3365 }
3366
3367 @Test
3368 public void testInteractiveRebaseWithModificationShouldNotDeleteDataOnAbort()
3369 throws Exception {
3370
3371 writeTrashFile("file0", "file0");
3372 writeTrashFile(FILE1, "file1");
3373 git.add().addFilepattern("file0").addFilepattern(FILE1).call();
3374 git.commit().setMessage("commit1").call();
3375
3376
3377 writeTrashFile(FILE1, "modified file1");
3378 git.add().addFilepattern(FILE1).call();
3379 git.commit().setMessage("commit2").call();
3380
3381
3382 writeTrashFile(FILE1, "modified file1 a second time");
3383 git.add().addFilepattern(FILE1).call();
3384 git.commit().setMessage("commit3").call();
3385
3386
3387 writeTrashFile("file0", "modified file0 in index");
3388 git.add().addFilepattern("file0").addFilepattern(FILE1).call();
3389
3390 writeTrashFile("file0", "modified file0");
3391
3392
3393 RebaseResult result = git.rebase().setUpstream("HEAD~2")
3394 .runInteractively(new InteractiveHandler() {
3395
3396 @Override
3397 public void prepareSteps(List<RebaseTodoLine> steps) {
3398 try {
3399 steps.get(0).setAction(Action.EDIT);
3400 steps.get(1).setAction(Action.PICK);
3401 } catch (IllegalTodoFileModification e) {
3402 fail("unexpected exception: " + e);
3403 }
3404 }
3405
3406 @Override
3407 public String modifyCommitMessage(String commit) {
3408 return commit;
3409 }
3410 }).call();
3411
3412
3413
3414 if (result.getStatus() == Status.EDIT)
3415 git.rebase().setOperation(Operation.ABORT).call();
3416
3417 checkFile(new File(db.getWorkTree(), "file0"), "modified file0");
3418 checkFile(new File(db.getWorkTree(), "file1"),
3419 "modified file1 a second time");
3420 assertEquals("[file0, mode:100644, content:modified file0 in index]"
3421 + "[file1, mode:100644, content:modified file1 a second time]",
3422 indexState(CONTENT));
3423
3424 }
3425
3426 private File getTodoFile() {
3427 File todoFile = new File(db.getDirectory(), GIT_REBASE_TODO);
3428 return todoFile;
3429 }
3430 }