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