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