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