1
2
3
4
5
6
7
8
9
10 package org.eclipse.jgit.api;
11
12 import static java.nio.charset.StandardCharsets.UTF_8;
13 import static org.junit.Assert.assertEquals;
14 import static org.junit.Assert.assertFalse;
15 import static org.junit.Assert.assertNotNull;
16 import static org.junit.Assert.assertNull;
17 import static org.junit.Assert.assertTrue;
18
19 import java.io.ByteArrayOutputStream;
20 import java.io.File;
21 import java.io.FileInputStream;
22 import java.io.FileOutputStream;
23 import java.io.IOException;
24
25 import org.eclipse.jgit.api.CreateBranchCommand.SetupUpstreamMode;
26 import org.eclipse.jgit.api.MergeResult.MergeStatus;
27 import org.eclipse.jgit.api.RebaseResult.Status;
28 import org.eclipse.jgit.junit.RepositoryTestCase;
29 import org.eclipse.jgit.lib.ConfigConstants;
30 import org.eclipse.jgit.lib.Constants;
31 import org.eclipse.jgit.lib.ObjectId;
32 import org.eclipse.jgit.lib.Ref;
33 import org.eclipse.jgit.lib.Repository;
34 import org.eclipse.jgit.lib.RepositoryState;
35 import org.eclipse.jgit.lib.StoredConfig;
36 import org.eclipse.jgit.merge.MergeStrategy;
37 import org.eclipse.jgit.revwalk.RevCommit;
38 import org.eclipse.jgit.revwalk.RevWalk;
39 import org.eclipse.jgit.transport.RefSpec;
40 import org.eclipse.jgit.transport.RemoteConfig;
41 import org.eclipse.jgit.transport.URIish;
42 import org.junit.Before;
43 import org.junit.Test;
44
45 public class PullCommandWithRebaseTest extends RepositoryTestCase {
46
47 protected Repository dbTarget;
48
49 private Git source;
50
51 private Git target;
52
53 private File sourceFile;
54
55 private File targetFile;
56
57 @Test
58 public void testPullFastForward() throws Exception {
59 PullResult res = target.pull().call();
60
61 assertTrue(res.getFetchResult().getTrackingRefUpdates().isEmpty());
62 assertEquals(Status.UP_TO_DATE, res.getRebaseResult().getStatus());
63
64 assertFileContentsEqual(targetFile, "Hello world");
65
66
67 writeToFile(sourceFile, "Another change");
68 source.add().addFilepattern("SomeFile.txt").call();
69 source.commit().setMessage("Some change in remote").call();
70
71 res = target.pull().call();
72
73 assertFalse(res.getFetchResult().getTrackingRefUpdates().isEmpty());
74 assertEquals(Status.FAST_FORWARD, res.getRebaseResult().getStatus());
75 assertFileContentsEqual(targetFile, "Another change");
76 assertEquals(RepositoryState.SAFE, target.getRepository()
77 .getRepositoryState());
78
79 res = target.pull().call();
80 assertEquals(Status.UP_TO_DATE, res.getRebaseResult().getStatus());
81 }
82
83 @Test
84 public void testPullFastForwardWithBranchInSource() throws Exception {
85 PullResult res = target.pull().call();
86
87 assertTrue(res.getFetchResult().getTrackingRefUpdates().isEmpty());
88 assertEquals(Status.UP_TO_DATE, res.getRebaseResult().getStatus());
89
90 assertFileContentsEqual(targetFile, "Hello world");
91
92
93 writeToFile(sourceFile, "Another change\n\n\n\nFoo");
94 source.add().addFilepattern("SomeFile.txt").call();
95 RevCommit initialCommit = source.commit()
96 .setMessage("Some change in remote").call();
97
98
99 createBranch(initialCommit, "refs/heads/side");
100 checkoutBranch("refs/heads/side");
101 writeToFile(sourceFile, "Another change\n\n\n\nBoo");
102 source.add().addFilepattern("SomeFile.txt").call();
103 RevCommit sideCommit = source.commit()
104 .setMessage("Some change in remote").call();
105
106
107 checkoutBranch("refs/heads/master");
108 writeToFile(sourceFile, "More change\n\n\n\nFoo");
109 source.add().addFilepattern("SomeFile.txt").call();
110 source.commit().setMessage("Some change in remote").call();
111
112
113 MergeResult result = source.merge().include(sideCommit.getId())
114 .setStrategy(MergeStrategy.RESOLVE).call();
115 assertEquals(MergeStatus.MERGED, result.getMergeStatus());
116
117 }
118
119 @Test
120 public void testPullFastForwardDetachedHead() throws Exception {
121 Repository repository = source.getRepository();
122 writeToFile(sourceFile, "2nd commit");
123 source.add().addFilepattern("SomeFile.txt").call();
124 source.commit().setMessage("2nd commit").call();
125
126 try (RevWalk revWalk = new RevWalk(repository)) {
127
128 String initialBranch = repository.getBranch();
129 Ref initialRef = repository.findRef(Constants.HEAD);
130 RevCommit initialCommit = revWalk
131 .parseCommit(initialRef.getObjectId());
132 assertEquals("this test need linear history", 1,
133 initialCommit.getParentCount());
134 source.checkout().setName(initialCommit.getParent(0).getName())
135 .call();
136 assertFalse("expected detached HEAD",
137 repository.getFullBranch().startsWith(Constants.R_HEADS));
138
139
140 File otherFile = new File(sourceFile.getParentFile(),
141 System.currentTimeMillis() + ".tst");
142 writeToFile(otherFile, "other 2nd commit");
143 source.add().addFilepattern(otherFile.getName()).call();
144 RevCommit newCommit = source.commit().setMessage("other 2nd commit")
145 .call();
146
147
148 source.pull().setRebase(true).setRemote(".")
149 .setRemoteBranchName(initialBranch)
150 .call();
151
152 assertEquals(RepositoryState.SAFE,
153 source.getRepository().getRepositoryState());
154 Ref head = source.getRepository().findRef(Constants.HEAD);
155 RevCommit headCommit = revWalk.parseCommit(head.getObjectId());
156
157
158 assertEquals(1, headCommit.getParentCount());
159 assertEquals(initialCommit, headCommit.getParent(0));
160
161
162 assertFileContentsEqual(sourceFile, "2nd commit");
163 assertFileContentsEqual(otherFile, "other 2nd commit");
164
165 assertEquals(newCommit.getShortMessage(),
166 headCommit.getShortMessage());
167 }
168 }
169
170 @Test
171 public void testPullConflict() throws Exception {
172 PullResult res = target.pull().call();
173
174 assertTrue(res.getFetchResult().getTrackingRefUpdates().isEmpty());
175 assertEquals(Status.UP_TO_DATE, res.getRebaseResult().getStatus());
176
177 assertFileContentsEqual(targetFile, "Hello world");
178
179
180 writeToFile(sourceFile, "Source change");
181 source.add().addFilepattern("SomeFile.txt").call();
182 source.commit().setMessage("Source change in remote").call();
183
184
185 writeToFile(targetFile, "Target change");
186 target.add().addFilepattern("SomeFile.txt").call();
187 target.commit().setMessage("Target change in local").call();
188
189 res = target.pull().call();
190
191 String remoteUri = target
192 .getRepository()
193 .getConfig()
194 .getString(ConfigConstants.CONFIG_REMOTE_SECTION, "origin",
195 ConfigConstants.CONFIG_KEY_URL);
196
197 assertFalse(res.getFetchResult().getTrackingRefUpdates().isEmpty());
198 assertEquals(Status.STOPPED, res.getRebaseResult().getStatus());
199 String result = "<<<<<<< Upstream, based on branch 'master' of "
200 + remoteUri
201 + "\nSource change\n=======\nTarget change\n>>>>>>> 42453fd Target change in local\n";
202 assertFileContentsEqual(targetFile, result);
203 assertEquals(RepositoryState.REBASING_MERGE, target
204 .getRepository().getRepositoryState());
205 }
206
207 @Test
208 public void testPullLocalConflict() throws Exception {
209 target.branchCreate().setName("basedOnMaster").setStartPoint(
210 "refs/heads/master").setUpstreamMode(SetupUpstreamMode.NOTRACK)
211 .call();
212 StoredConfig config = target.getRepository().getConfig();
213 config.setString("branch", "basedOnMaster", "remote", ".");
214 config.setString("branch", "basedOnMaster", "merge",
215 "refs/heads/master");
216 config.setBoolean("branch", "basedOnMaster", "rebase", true);
217 config.save();
218 target.getRepository().updateRef(Constants.HEAD).link(
219 "refs/heads/basedOnMaster");
220 PullResult res = target.pull().call();
221
222 assertNull(res.getFetchResult());
223 assertEquals(Status.UP_TO_DATE, res.getRebaseResult().getStatus());
224
225 assertFileContentsEqual(targetFile, "Hello world");
226
227
228 target.getRepository().updateRef(Constants.HEAD).link(
229 "refs/heads/master");
230 writeToFile(targetFile, "Master change");
231 target.add().addFilepattern("SomeFile.txt").call();
232 target.commit().setMessage("Source change in master").call();
233
234
235 target.getRepository().updateRef(Constants.HEAD).link(
236 "refs/heads/basedOnMaster");
237 writeToFile(targetFile, "Slave change");
238 target.add().addFilepattern("SomeFile.txt").call();
239 target.commit().setMessage("Source change in based on master").call();
240
241 res = target.pull().call();
242
243 assertNull(res.getFetchResult());
244 assertEquals(Status.STOPPED, res.getRebaseResult().getStatus());
245 String result = "<<<<<<< Upstream, based on branch 'master' of local repository\n"
246 + "Master change\n=======\nSlave change\n>>>>>>> 4049c9e Source change in based on master\n";
247 assertFileContentsEqual(targetFile, result);
248 assertEquals(RepositoryState.REBASING_MERGE, target
249 .getRepository().getRepositoryState());
250 }
251
252 @Test
253 public void testPullFastForwardWithLocalCommitAndRebaseFlagSet() throws Exception {
254 final String SOURCE_COMMIT_MESSAGE = "Source commit message for rebase flag test";
255 final String TARGET_COMMIT_MESSAGE = "Target commit message for rebase flag test";
256
257 assertFalse(SOURCE_COMMIT_MESSAGE.equals(TARGET_COMMIT_MESSAGE));
258
259 final String SOURCE_FILE_CONTENTS = "Source change";
260 final String NEW_FILE_CONTENTS = "New file from target";
261
262
263
264 StoredConfig targetConfig = dbTarget.getConfig();
265 targetConfig.setBoolean("branch", "master", "rebase", false);
266 targetConfig.save();
267
268
269 writeToFile(sourceFile, SOURCE_FILE_CONTENTS);
270 source.add().addFilepattern(sourceFile.getName()).call();
271 source.commit().setMessage(SOURCE_COMMIT_MESSAGE).call();
272
273
274 File newFile = new File(dbTarget.getWorkTree().getPath() + "/newFile.txt");
275 writeToFile(newFile, NEW_FILE_CONTENTS);
276 target.add().addFilepattern(newFile.getName()).call();
277 target.commit().setMessage(TARGET_COMMIT_MESSAGE).call();
278
279
280 assertFalse(targetConfig.getBoolean("branch", "master", "rebase", true));
281
282
283 PullResult pullResult = target.pull().setRebase(true).call();
284
285
286 assertTrue(pullResult.isSuccessful());
287
288
289 RebaseResult rebaseResult = pullResult.getRebaseResult();
290 assertNotNull(rebaseResult);
291 assertNull(rebaseResult.getFailingPaths());
292 assertEquals(Status.OK, rebaseResult.getStatus());
293
294
295 Repository targetRepo = target.getRepository();
296 try (RevWalk revWalk = new RevWalk(targetRepo)) {
297 ObjectId headId = targetRepo.resolve(Constants.HEAD);
298 RevCommit root = revWalk.parseCommit(headId);
299 revWalk.markStart(root);
300
301 RevCommit head = revWalk.next();
302
303 RevCommit beforeHead = revWalk.next();
304
305
306 assertEquals(TARGET_COMMIT_MESSAGE, head.getFullMessage());
307
308 assertEquals(SOURCE_COMMIT_MESSAGE, beforeHead.getFullMessage());
309
310
311 assertFileContentsEqual(sourceFile, SOURCE_FILE_CONTENTS);
312 assertFileContentsEqual(newFile, NEW_FILE_CONTENTS);
313
314 assertEquals(RepositoryState.SAFE, target
315 .getRepository().getRepositoryState());
316 }
317 }
318
319 @Override
320 @Before
321 public void setUp() throws Exception {
322 super.setUp();
323 dbTarget = createWorkRepository();
324 source = new Git(db);
325 target = new Git(dbTarget);
326 addRepoToClose(dbTarget);
327
328
329 sourceFile = new File(db.getWorkTree(), "SomeFile.txt");
330 writeToFile(sourceFile, "Hello world");
331
332 source.add().addFilepattern("SomeFile.txt").call();
333 source.commit().setMessage("Initial commit for source").call();
334
335
336 StoredConfig targetConfig = dbTarget.getConfig();
337 targetConfig.setString("branch", "master", "remote", "origin");
338 targetConfig
339 .setString("branch", "master", "merge", "refs/heads/master");
340 RemoteConfig config = new RemoteConfig(targetConfig, "origin");
341
342 config
343 .addURI(new URIish(source.getRepository().getWorkTree()
344 .getAbsolutePath()));
345 config.addFetchRefSpec(new RefSpec(
346 "+refs/heads/*:refs/remotes/origin/*"));
347 config.update(targetConfig);
348 targetConfig.save();
349
350 targetFile = new File(dbTarget.getWorkTree(), "SomeFile.txt");
351
352 target.pull().call();
353 target.checkout().setStartPoint("refs/remotes/origin/master").setName(
354 "master").call();
355
356 targetConfig
357 .setString("branch", "master", "merge", "refs/heads/master");
358 targetConfig.setBoolean("branch", "master", "rebase", true);
359 targetConfig.save();
360
361 assertFileContentsEqual(targetFile, "Hello world");
362 }
363
364 private static void writeToFile(File actFile, String string)
365 throws IOException {
366 try (FileOutputStream fos = new FileOutputStream(actFile)) {
367 fos.write(string.getBytes(UTF_8));
368 }
369 }
370
371 private static void assertFileContentsEqual(File actFile, String string)
372 throws IOException {
373 ByteArrayOutputStream bos = new ByteArrayOutputStream();
374 byte[] buffer = new byte[100];
375 try (FileInputStream fis = new FileInputStream(actFile)) {
376 int read = fis.read(buffer);
377 while (read > 0) {
378 bos.write(buffer, 0, read);
379 read = fis.read(buffer);
380 }
381 String content = new String(bos.toByteArray(), UTF_8);
382 assertEquals(string, content);
383 }
384 }
385 }