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