1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45 package org.eclipse.jgit.api;
46
47 import java.io.IOException;
48 import java.text.MessageFormat;
49
50 import org.eclipse.jgit.annotations.Nullable;
51 import org.eclipse.jgit.api.MergeCommand.FastForwardMode;
52 import org.eclipse.jgit.api.MergeCommand.FastForwardMode.Merge;
53 import org.eclipse.jgit.api.RebaseCommand.Operation;
54 import org.eclipse.jgit.api.errors.CanceledException;
55 import org.eclipse.jgit.api.errors.GitAPIException;
56 import org.eclipse.jgit.api.errors.InvalidConfigurationException;
57 import org.eclipse.jgit.api.errors.InvalidRemoteException;
58 import org.eclipse.jgit.api.errors.JGitInternalException;
59 import org.eclipse.jgit.api.errors.NoHeadException;
60 import org.eclipse.jgit.api.errors.RefNotAdvertisedException;
61 import org.eclipse.jgit.api.errors.RefNotFoundException;
62 import org.eclipse.jgit.api.errors.WrongRepositoryStateException;
63 import org.eclipse.jgit.internal.JGitText;
64 import org.eclipse.jgit.lib.AnyObjectId;
65 import org.eclipse.jgit.lib.BranchConfig.BranchRebaseMode;
66 import org.eclipse.jgit.lib.Config;
67 import org.eclipse.jgit.lib.ConfigConstants;
68 import org.eclipse.jgit.lib.Constants;
69 import org.eclipse.jgit.lib.NullProgressMonitor;
70 import org.eclipse.jgit.lib.ProgressMonitor;
71 import org.eclipse.jgit.lib.Ref;
72 import org.eclipse.jgit.lib.Repository;
73 import org.eclipse.jgit.lib.RepositoryState;
74 import org.eclipse.jgit.lib.SubmoduleConfig.FetchRecurseSubmodulesMode;
75 import org.eclipse.jgit.merge.MergeStrategy;
76 import org.eclipse.jgit.transport.FetchResult;
77 import org.eclipse.jgit.transport.TagOpt;
78
79
80
81
82
83
84
85 public class PullCommand extends TransportCommand<PullCommand, PullResult> {
86
87 private final static String DOT = ".";
88
89 private ProgressMonitor monitor = NullProgressMonitor.INSTANCE;
90
91 private BranchRebaseMode pullRebaseMode = null;
92
93 private String remote;
94
95 private String remoteBranchName;
96
97 private MergeStrategy strategy = MergeStrategy.RECURSIVE;
98
99 private TagOpt tagOption;
100
101 private FastForwardMode fastForwardMode;
102
103 private FetchRecurseSubmodulesMode submoduleRecurseMode = null;
104
105
106
107
108
109
110
111 protected PullCommand(Repository repo) {
112 super(repo);
113 }
114
115
116
117
118
119
120
121
122 public PullCommand setProgressMonitor(ProgressMonitor monitor) {
123 if (monitor == null) {
124 monitor = NullProgressMonitor.INSTANCE;
125 }
126 this.monitor = monitor;
127 return this;
128 }
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149 public PullCommand setRebase(boolean useRebase) {
150 checkCallable();
151 pullRebaseMode = useRebase ? BranchRebaseMode.REBASE
152 : BranchRebaseMode.NONE;
153 return this;
154 }
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190 public PullCommand setRebase(BranchRebaseMode rebaseMode) {
191 checkCallable();
192 pullRebaseMode = rebaseMode;
193 return this;
194 }
195
196
197
198
199
200
201
202
203
204
205 @Override
206 public PullResult call() throws GitAPIException,
207 WrongRepositoryStateException, InvalidConfigurationException,
208 InvalidRemoteException, CanceledException,
209 RefNotFoundException, RefNotAdvertisedException, NoHeadException,
210 org.eclipse.jgit.api.errors.TransportException {
211 checkCallable();
212
213 monitor.beginTask(JGitText.get().pullTaskName, 2);
214 Config repoConfig = repo.getConfig();
215
216 String branchName = null;
217 try {
218 String fullBranch = repo.getFullBranch();
219 if (fullBranch != null
220 && fullBranch.startsWith(Constants.R_HEADS)) {
221 branchName = fullBranch.substring(Constants.R_HEADS.length());
222 }
223 } catch (IOException e) {
224 throw new JGitInternalException(
225 JGitText.get().exceptionCaughtDuringExecutionOfPullCommand,
226 e);
227 }
228 if (remoteBranchName == null && branchName != null) {
229
230
231 remoteBranchName = repoConfig.getString(
232 ConfigConstants.CONFIG_BRANCH_SECTION, branchName,
233 ConfigConstants.CONFIG_KEY_MERGE);
234 }
235 if (remoteBranchName == null) {
236 remoteBranchName = branchName;
237 }
238 if (remoteBranchName == null) {
239 throw new NoHeadException(
240 JGitText.get().cannotCheckoutFromUnbornBranch);
241 }
242
243 if (!repo.getRepositoryState().equals(RepositoryState.SAFE))
244 throw new WrongRepositoryStateException(MessageFormat.format(
245 JGitText.get().cannotPullOnARepoWithState, repo
246 .getRepositoryState().name()));
247
248 if (remote == null && branchName != null) {
249
250
251 remote = repoConfig.getString(
252 ConfigConstants.CONFIG_BRANCH_SECTION, branchName,
253 ConfigConstants.CONFIG_KEY_REMOTE);
254 }
255 if (remote == null) {
256
257 remote = Constants.DEFAULT_REMOTE_NAME;
258 }
259
260
261 if (pullRebaseMode == null && branchName != null) {
262 pullRebaseMode = getRebaseMode(branchName, repoConfig);
263 }
264
265
266 final boolean isRemote = !remote.equals(".");
267 String remoteUri;
268 FetchResult fetchRes;
269 if (isRemote) {
270 remoteUri = repoConfig.getString(
271 ConfigConstants.CONFIG_REMOTE_SECTION, remote,
272 ConfigConstants.CONFIG_KEY_URL);
273 if (remoteUri == null) {
274 String missingKey = ConfigConstants.CONFIG_REMOTE_SECTION + DOT
275 + remote + DOT + ConfigConstants.CONFIG_KEY_URL;
276 throw new InvalidConfigurationException(MessageFormat.format(
277 JGitText.get().missingConfigurationForKey, missingKey));
278 }
279
280 if (monitor.isCancelled())
281 throw new CanceledException(MessageFormat.format(
282 JGitText.get().operationCanceled,
283 JGitText.get().pullTaskName));
284
285 FetchCommand fetch = new FetchCommand(repo).setRemote(remote)
286 .setProgressMonitor(monitor).setTagOpt(tagOption)
287 .setRecurseSubmodules(submoduleRecurseMode);
288 configure(fetch);
289
290 fetchRes = fetch.call();
291 } else {
292
293 remoteUri = JGitText.get().localRepository;
294 fetchRes = null;
295 }
296
297 monitor.update(1);
298
299 if (monitor.isCancelled())
300 throw new CanceledException(MessageFormat.format(
301 JGitText.get().operationCanceled,
302 JGitText.get().pullTaskName));
303
304
305
306
307 AnyObjectId commitToMerge;
308 if (isRemote) {
309 Ref r = null;
310 if (fetchRes != null) {
311 r = fetchRes.getAdvertisedRef(remoteBranchName);
312 if (r == null)
313 r = fetchRes.getAdvertisedRef(Constants.R_HEADS
314 + remoteBranchName);
315 }
316 if (r == null) {
317 throw new RefNotAdvertisedException(MessageFormat.format(
318 JGitText.get().couldNotGetAdvertisedRef, remote,
319 remoteBranchName));
320 } else {
321 commitToMerge = r.getObjectId();
322 }
323 } else {
324 try {
325 commitToMerge = repo.resolve(remoteBranchName);
326 if (commitToMerge == null)
327 throw new RefNotFoundException(MessageFormat.format(
328 JGitText.get().refNotResolved, remoteBranchName));
329 } catch (IOException e) {
330 throw new JGitInternalException(
331 JGitText.get().exceptionCaughtDuringExecutionOfPullCommand,
332 e);
333 }
334 }
335
336 String upstreamName = MessageFormat.format(
337 JGitText.get().upstreamBranchName,
338 Repository.shortenRefName(remoteBranchName), remoteUri);
339
340 PullResult result;
341 if (pullRebaseMode != BranchRebaseMode.NONE) {
342 RebaseCommand rebase = new RebaseCommand(repo);
343 RebaseResult rebaseRes = rebase.setUpstream(commitToMerge)
344 .setUpstreamName(upstreamName).setProgressMonitor(monitor)
345 .setOperation(Operation.BEGIN).setStrategy(strategy)
346 .setPreserveMerges(
347 pullRebaseMode == BranchRebaseMode.PRESERVE)
348 .call();
349 result = new PullResult(fetchRes, remote, rebaseRes);
350 } else {
351 MergeCommand merge = new MergeCommand(repo);
352 MergeResult mergeRes = merge.include(upstreamName, commitToMerge)
353 .setStrategy(strategy).setProgressMonitor(monitor)
354 .setFastForward(getFastForwardMode()).call();
355 monitor.update(1);
356 result = new PullResult(fetchRes, remote, mergeRes);
357 }
358 monitor.endTask();
359 return result;
360 }
361
362
363
364
365
366
367
368
369
370
371
372
373
374 public PullCommand setRemote(String remote) {
375 checkCallable();
376 this.remote = remote;
377 return this;
378 }
379
380
381
382
383
384
385
386
387
388
389
390
391 public PullCommand setRemoteBranchName(String remoteBranchName) {
392 checkCallable();
393 this.remoteBranchName = remoteBranchName;
394 return this;
395 }
396
397
398
399
400
401
402
403 public String getRemote() {
404 return remote;
405 }
406
407
408
409
410
411
412
413
414 public String getRemoteBranchName() {
415 return remoteBranchName;
416 }
417
418
419
420
421
422
423
424
425
426 public PullCommand setStrategy(MergeStrategy strategy) {
427 this.strategy = strategy;
428 return this;
429 }
430
431
432
433
434
435
436
437
438
439 public PullCommand setTagOpt(TagOpt tagOpt) {
440 checkCallable();
441 this.tagOption = tagOpt;
442 return this;
443 }
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459 public PullCommand setFastForward(
460 @Nullable FastForwardMode fastForwardMode) {
461 checkCallable();
462 this.fastForwardMode = fastForwardMode;
463 return this;
464 }
465
466
467
468
469
470
471
472
473
474
475
476
477 public PullCommand setRecurseSubmodules(
478 @Nullable FetchRecurseSubmodulesMode recurse) {
479 this.submoduleRecurseMode = recurse;
480 return this;
481 }
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497 public static BranchRebaseMode getRebaseMode(String branchName,
498 Config config) {
499 BranchRebaseMode mode = config.getEnum(BranchRebaseMode.values(),
500 ConfigConstants.CONFIG_BRANCH_SECTION,
501 branchName, ConfigConstants.CONFIG_KEY_REBASE, null);
502 if (mode == null) {
503 mode = config.getEnum(BranchRebaseMode.values(),
504 ConfigConstants.CONFIG_PULL_SECTION, null,
505 ConfigConstants.CONFIG_KEY_REBASE, BranchRebaseMode.NONE);
506 }
507 return mode;
508 }
509
510 private FastForwardMode getFastForwardMode() {
511 if (fastForwardMode != null) {
512 return fastForwardMode;
513 }
514 Config config = repo.getConfig();
515 Merge ffMode = config.getEnum(Merge.values(),
516 ConfigConstants.CONFIG_PULL_SECTION, null,
517 ConfigConstants.CONFIG_KEY_FF, null);
518 return ffMode != null ? FastForwardMode.valueOf(ffMode) : null;
519 }
520 }