You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

PullCommand.java 18KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555
  1. /*
  2. * Copyright (C) 2010, Christian Halstrick <christian.halstrick@sap.com>
  3. * Copyright (C) 2010, Mathias Kinzler <mathias.kinzler@sap.com>
  4. * Copyright (C) 2016, 2021 Laurent Delaigue <laurent.delaigue@obeo.fr> and others
  5. *
  6. * This program and the accompanying materials are made available under the
  7. * terms of the Eclipse Distribution License v. 1.0 which is available at
  8. * https://www.eclipse.org/org/documents/edl-v10.php.
  9. *
  10. * SPDX-License-Identifier: BSD-3-Clause
  11. */
  12. package org.eclipse.jgit.api;
  13. import java.io.IOException;
  14. import java.text.MessageFormat;
  15. import org.eclipse.jgit.annotations.Nullable;
  16. import org.eclipse.jgit.api.MergeCommand.FastForwardMode;
  17. import org.eclipse.jgit.api.MergeCommand.FastForwardMode.Merge;
  18. import org.eclipse.jgit.api.RebaseCommand.Operation;
  19. import org.eclipse.jgit.api.errors.CanceledException;
  20. import org.eclipse.jgit.api.errors.GitAPIException;
  21. import org.eclipse.jgit.api.errors.InvalidConfigurationException;
  22. import org.eclipse.jgit.api.errors.InvalidRemoteException;
  23. import org.eclipse.jgit.api.errors.JGitInternalException;
  24. import org.eclipse.jgit.api.errors.NoHeadException;
  25. import org.eclipse.jgit.api.errors.RefNotAdvertisedException;
  26. import org.eclipse.jgit.api.errors.RefNotFoundException;
  27. import org.eclipse.jgit.api.errors.WrongRepositoryStateException;
  28. import org.eclipse.jgit.dircache.DirCacheCheckout;
  29. import org.eclipse.jgit.internal.JGitText;
  30. import org.eclipse.jgit.lib.AnyObjectId;
  31. import org.eclipse.jgit.lib.BranchConfig.BranchRebaseMode;
  32. import org.eclipse.jgit.lib.Config;
  33. import org.eclipse.jgit.lib.ConfigConstants;
  34. import org.eclipse.jgit.lib.Constants;
  35. import org.eclipse.jgit.lib.NullProgressMonitor;
  36. import org.eclipse.jgit.lib.ObjectId;
  37. import org.eclipse.jgit.lib.ProgressMonitor;
  38. import org.eclipse.jgit.lib.Ref;
  39. import org.eclipse.jgit.lib.RefUpdate;
  40. import org.eclipse.jgit.lib.RefUpdate.Result;
  41. import org.eclipse.jgit.lib.Repository;
  42. import org.eclipse.jgit.lib.RepositoryState;
  43. import org.eclipse.jgit.lib.SubmoduleConfig.FetchRecurseSubmodulesMode;
  44. import org.eclipse.jgit.merge.ContentMergeStrategy;
  45. import org.eclipse.jgit.merge.MergeStrategy;
  46. import org.eclipse.jgit.revwalk.RevCommit;
  47. import org.eclipse.jgit.revwalk.RevWalk;
  48. import org.eclipse.jgit.transport.FetchResult;
  49. import org.eclipse.jgit.transport.TagOpt;
  50. /**
  51. * The Pull command
  52. *
  53. * @see <a href="http://www.kernel.org/pub/software/scm/git/docs/git-pull.html"
  54. * >Git documentation about Pull</a>
  55. */
  56. public class PullCommand extends TransportCommand<PullCommand, PullResult> {
  57. private static final String DOT = "."; //$NON-NLS-1$
  58. private ProgressMonitor monitor = NullProgressMonitor.INSTANCE;
  59. private BranchRebaseMode pullRebaseMode = null;
  60. private String remote;
  61. private String remoteBranchName;
  62. private MergeStrategy strategy = MergeStrategy.RECURSIVE;
  63. private ContentMergeStrategy contentStrategy;
  64. private TagOpt tagOption;
  65. private FastForwardMode fastForwardMode;
  66. private FetchRecurseSubmodulesMode submoduleRecurseMode = null;
  67. /**
  68. * Constructor for PullCommand.
  69. *
  70. * @param repo
  71. * the {@link org.eclipse.jgit.lib.Repository}
  72. */
  73. protected PullCommand(Repository repo) {
  74. super(repo);
  75. }
  76. /**
  77. * Set progress monitor
  78. *
  79. * @param monitor
  80. * a progress monitor
  81. * @return this instance
  82. */
  83. public PullCommand setProgressMonitor(ProgressMonitor monitor) {
  84. if (monitor == null) {
  85. monitor = NullProgressMonitor.INSTANCE;
  86. }
  87. this.monitor = monitor;
  88. return this;
  89. }
  90. /**
  91. * Set if rebase should be used after fetching. If set to true, rebase is
  92. * used instead of merge. This is equivalent to --rebase on the command
  93. * line.
  94. * <p>
  95. * If set to false, merge is used after fetching, overriding the
  96. * configuration file. This is equivalent to --no-rebase on the command
  97. * line.
  98. * <p>
  99. * This setting overrides the settings in the configuration file. By
  100. * default, the setting in the repository configuration file is used.
  101. * <p>
  102. * A branch can be configured to use rebase by default. See
  103. * branch.[name].rebase and branch.autosetuprebase.
  104. *
  105. * @param useRebase
  106. * whether to use rebase after fetching
  107. * @return {@code this}
  108. */
  109. public PullCommand setRebase(boolean useRebase) {
  110. checkCallable();
  111. pullRebaseMode = useRebase ? BranchRebaseMode.REBASE
  112. : BranchRebaseMode.NONE;
  113. return this;
  114. }
  115. /**
  116. * Sets the {@link org.eclipse.jgit.lib.BranchConfig.BranchRebaseMode} to
  117. * use after fetching.
  118. *
  119. * <dl>
  120. * <dt>BranchRebaseMode.REBASE</dt>
  121. * <dd>Equivalent to {@code --rebase} on the command line: use rebase
  122. * instead of merge after fetching.</dd>
  123. * <dt>BranchRebaseMode.PRESERVE</dt>
  124. * <dd>Equivalent to {@code --preserve-merges} on the command line: rebase
  125. * preserving local merge commits.</dd>
  126. * <dt>BranchRebaseMode.INTERACTIVE</dt>
  127. * <dd>Equivalent to {@code --interactive} on the command line: use
  128. * interactive rebase.</dd>
  129. * <dt>BranchRebaseMode.NONE</dt>
  130. * <dd>Equivalent to {@code --no-rebase}: merge instead of rebasing.
  131. * <dt>{@code null}</dt>
  132. * <dd>Use the setting defined in the git configuration, either {@code
  133. * branch.[name].rebase} or, if not set, {@code pull.rebase}</dd>
  134. * </dl>
  135. *
  136. * This setting overrides the settings in the configuration file. By
  137. * default, the setting in the repository configuration file is used.
  138. * <p>
  139. * A branch can be configured to use rebase by default. See
  140. * {@code branch.[name].rebase}, {@code branch.autosetuprebase}, and
  141. * {@code pull.rebase}.
  142. *
  143. * @param rebaseMode
  144. * the {@link org.eclipse.jgit.lib.BranchConfig.BranchRebaseMode}
  145. * to use
  146. * @return {@code this}
  147. * @since 4.5
  148. */
  149. public PullCommand setRebase(BranchRebaseMode rebaseMode) {
  150. checkCallable();
  151. pullRebaseMode = rebaseMode;
  152. return this;
  153. }
  154. /**
  155. * {@inheritDoc}
  156. * <p>
  157. * Execute the {@code Pull} command with all the options and parameters
  158. * collected by the setter methods (e.g.
  159. * {@link #setProgressMonitor(ProgressMonitor)}) of this class. Each
  160. * instance of this class should only be used for one invocation of the
  161. * command. Don't call this method twice on an instance.
  162. */
  163. @Override
  164. public PullResult call() throws GitAPIException,
  165. WrongRepositoryStateException, InvalidConfigurationException,
  166. InvalidRemoteException, CanceledException,
  167. RefNotFoundException, RefNotAdvertisedException, NoHeadException,
  168. org.eclipse.jgit.api.errors.TransportException {
  169. checkCallable();
  170. monitor.beginTask(JGitText.get().pullTaskName, 2);
  171. Config repoConfig = repo.getConfig();
  172. String branchName = null;
  173. try {
  174. String fullBranch = repo.getFullBranch();
  175. if (fullBranch != null
  176. && fullBranch.startsWith(Constants.R_HEADS)) {
  177. branchName = fullBranch.substring(Constants.R_HEADS.length());
  178. }
  179. } catch (IOException e) {
  180. throw new JGitInternalException(
  181. JGitText.get().exceptionCaughtDuringExecutionOfPullCommand,
  182. e);
  183. }
  184. if (remoteBranchName == null && branchName != null) {
  185. // get the name of the branch in the remote repository
  186. // stored in configuration key branch.<branch name>.merge
  187. remoteBranchName = repoConfig.getString(
  188. ConfigConstants.CONFIG_BRANCH_SECTION, branchName,
  189. ConfigConstants.CONFIG_KEY_MERGE);
  190. }
  191. if (remoteBranchName == null) {
  192. remoteBranchName = branchName;
  193. }
  194. if (remoteBranchName == null) {
  195. throw new NoHeadException(
  196. JGitText.get().cannotCheckoutFromUnbornBranch);
  197. }
  198. if (!repo.getRepositoryState().equals(RepositoryState.SAFE))
  199. throw new WrongRepositoryStateException(MessageFormat.format(
  200. JGitText.get().cannotPullOnARepoWithState, repo
  201. .getRepositoryState().name()));
  202. if (remote == null && branchName != null) {
  203. // get the configured remote for the currently checked out branch
  204. // stored in configuration key branch.<branch name>.remote
  205. remote = repoConfig.getString(
  206. ConfigConstants.CONFIG_BRANCH_SECTION, branchName,
  207. ConfigConstants.CONFIG_KEY_REMOTE);
  208. }
  209. if (remote == null) {
  210. // fall back to default remote
  211. remote = Constants.DEFAULT_REMOTE_NAME;
  212. }
  213. // determines whether rebase should be used after fetching
  214. if (pullRebaseMode == null && branchName != null) {
  215. pullRebaseMode = getRebaseMode(branchName, repoConfig);
  216. }
  217. final boolean isRemote = !remote.equals("."); //$NON-NLS-1$
  218. String remoteUri;
  219. FetchResult fetchRes;
  220. if (isRemote) {
  221. remoteUri = repoConfig.getString(
  222. ConfigConstants.CONFIG_REMOTE_SECTION, remote,
  223. ConfigConstants.CONFIG_KEY_URL);
  224. if (remoteUri == null) {
  225. String missingKey = ConfigConstants.CONFIG_REMOTE_SECTION + DOT
  226. + remote + DOT + ConfigConstants.CONFIG_KEY_URL;
  227. throw new InvalidConfigurationException(MessageFormat.format(
  228. JGitText.get().missingConfigurationForKey, missingKey));
  229. }
  230. if (monitor.isCancelled())
  231. throw new CanceledException(MessageFormat.format(
  232. JGitText.get().operationCanceled,
  233. JGitText.get().pullTaskName));
  234. FetchCommand fetch = new FetchCommand(repo).setRemote(remote)
  235. .setProgressMonitor(monitor).setTagOpt(tagOption)
  236. .setRecurseSubmodules(submoduleRecurseMode);
  237. configure(fetch);
  238. fetchRes = fetch.call();
  239. } else {
  240. // we can skip the fetch altogether
  241. remoteUri = JGitText.get().localRepository;
  242. fetchRes = null;
  243. }
  244. monitor.update(1);
  245. if (monitor.isCancelled())
  246. throw new CanceledException(MessageFormat.format(
  247. JGitText.get().operationCanceled,
  248. JGitText.get().pullTaskName));
  249. // we check the updates to see which of the updated branches
  250. // corresponds to the remote branch name
  251. AnyObjectId commitToMerge;
  252. if (isRemote) {
  253. Ref r = null;
  254. if (fetchRes != null) {
  255. r = fetchRes.getAdvertisedRef(remoteBranchName);
  256. if (r == null) {
  257. r = fetchRes.getAdvertisedRef(Constants.R_HEADS
  258. + remoteBranchName);
  259. }
  260. }
  261. if (r == null) {
  262. throw new RefNotAdvertisedException(MessageFormat.format(
  263. JGitText.get().couldNotGetAdvertisedRef, remote,
  264. remoteBranchName));
  265. }
  266. commitToMerge = r.getObjectId();
  267. } else {
  268. try {
  269. commitToMerge = repo.resolve(remoteBranchName);
  270. if (commitToMerge == null) {
  271. throw new RefNotFoundException(MessageFormat.format(
  272. JGitText.get().refNotResolved, remoteBranchName));
  273. }
  274. } catch (IOException e) {
  275. throw new JGitInternalException(
  276. JGitText.get().exceptionCaughtDuringExecutionOfPullCommand,
  277. e);
  278. }
  279. }
  280. String upstreamName = MessageFormat.format(
  281. JGitText.get().upstreamBranchName,
  282. Repository.shortenRefName(remoteBranchName), remoteUri);
  283. PullResult result;
  284. if (pullRebaseMode != BranchRebaseMode.NONE) {
  285. try {
  286. Ref head = repo.exactRef(Constants.HEAD);
  287. if (head == null) {
  288. throw new NoHeadException(JGitText
  289. .get().commitOnRepoWithoutHEADCurrentlyNotSupported);
  290. }
  291. ObjectId headId = head.getObjectId();
  292. if (headId == null) {
  293. // Pull on an unborn branch: checkout
  294. try (RevWalk revWalk = new RevWalk(repo)) {
  295. RevCommit srcCommit = revWalk
  296. .parseCommit(commitToMerge);
  297. DirCacheCheckout dco = new DirCacheCheckout(repo,
  298. repo.lockDirCache(), srcCommit.getTree());
  299. dco.setFailOnConflict(true);
  300. dco.setProgressMonitor(monitor);
  301. dco.checkout();
  302. RefUpdate refUpdate = repo
  303. .updateRef(head.getTarget().getName());
  304. refUpdate.setNewObjectId(commitToMerge);
  305. refUpdate.setExpectedOldObjectId(null);
  306. refUpdate.setRefLogMessage("initial pull", false); //$NON-NLS-1$
  307. if (refUpdate.update() != Result.NEW) {
  308. throw new NoHeadException(JGitText
  309. .get().commitOnRepoWithoutHEADCurrentlyNotSupported);
  310. }
  311. monitor.endTask();
  312. return new PullResult(fetchRes, remote,
  313. RebaseResult.result(
  314. RebaseResult.Status.FAST_FORWARD,
  315. srcCommit));
  316. }
  317. }
  318. } catch (NoHeadException e) {
  319. throw e;
  320. } catch (IOException e) {
  321. throw new JGitInternalException(JGitText
  322. .get().exceptionCaughtDuringExecutionOfPullCommand, e);
  323. }
  324. RebaseCommand rebase = new RebaseCommand(repo);
  325. RebaseResult rebaseRes = rebase.setUpstream(commitToMerge)
  326. .setProgressMonitor(monitor)
  327. .setUpstreamName(upstreamName)
  328. .setOperation(Operation.BEGIN)
  329. .setStrategy(strategy)
  330. .setContentMergeStrategy(contentStrategy)
  331. .setPreserveMerges(
  332. pullRebaseMode == BranchRebaseMode.PRESERVE)
  333. .call();
  334. result = new PullResult(fetchRes, remote, rebaseRes);
  335. } else {
  336. MergeCommand merge = new MergeCommand(repo);
  337. MergeResult mergeRes = merge.include(upstreamName, commitToMerge)
  338. .setProgressMonitor(monitor)
  339. .setStrategy(strategy)
  340. .setContentMergeStrategy(contentStrategy)
  341. .setFastForward(getFastForwardMode()).call();
  342. monitor.update(1);
  343. result = new PullResult(fetchRes, remote, mergeRes);
  344. }
  345. monitor.endTask();
  346. return result;
  347. }
  348. /**
  349. * The remote (uri or name) to be used for the pull operation. If no remote
  350. * is set, the branch's configuration will be used. If the branch
  351. * configuration is missing the default value of
  352. * <code>Constants.DEFAULT_REMOTE_NAME</code> will be used.
  353. *
  354. * @see Constants#DEFAULT_REMOTE_NAME
  355. * @param remote
  356. * name of the remote to pull from
  357. * @return {@code this}
  358. * @since 3.3
  359. */
  360. public PullCommand setRemote(String remote) {
  361. checkCallable();
  362. this.remote = remote;
  363. return this;
  364. }
  365. /**
  366. * The remote branch name to be used for the pull operation. If no
  367. * remoteBranchName is set, the branch's configuration will be used. If the
  368. * branch configuration is missing the remote branch with the same name as
  369. * the current branch is used.
  370. *
  371. * @param remoteBranchName
  372. * remote branch name to be used for pull operation
  373. * @return {@code this}
  374. * @since 3.3
  375. */
  376. public PullCommand setRemoteBranchName(String remoteBranchName) {
  377. checkCallable();
  378. this.remoteBranchName = remoteBranchName;
  379. return this;
  380. }
  381. /**
  382. * Get the remote name used for pull operation
  383. *
  384. * @return the remote used for the pull operation if it was set explicitly
  385. * @since 3.3
  386. */
  387. public String getRemote() {
  388. return remote;
  389. }
  390. /**
  391. * Get the remote branch name for the pull operation
  392. *
  393. * @return the remote branch name used for the pull operation if it was set
  394. * explicitly
  395. * @since 3.3
  396. */
  397. public String getRemoteBranchName() {
  398. return remoteBranchName;
  399. }
  400. /**
  401. * Set the @{code MergeStrategy}
  402. *
  403. * @param strategy
  404. * The merge strategy to use during this pull operation.
  405. * @return {@code this}
  406. * @since 3.4
  407. */
  408. public PullCommand setStrategy(MergeStrategy strategy) {
  409. this.strategy = strategy;
  410. return this;
  411. }
  412. /**
  413. * Sets the content merge strategy to use if the
  414. * {@link #setStrategy(MergeStrategy) merge strategy} is "resolve" or
  415. * "recursive".
  416. *
  417. * @param strategy
  418. * the {@link ContentMergeStrategy} to be used
  419. * @return {@code this}
  420. * @since 5.12
  421. */
  422. public PullCommand setContentMergeStrategy(ContentMergeStrategy strategy) {
  423. this.contentStrategy = strategy;
  424. return this;
  425. }
  426. /**
  427. * Set the specification of annotated tag behavior during fetch
  428. *
  429. * @param tagOpt
  430. * the {@link org.eclipse.jgit.transport.TagOpt}
  431. * @return {@code this}
  432. * @since 4.7
  433. */
  434. public PullCommand setTagOpt(TagOpt tagOpt) {
  435. checkCallable();
  436. this.tagOption = tagOpt;
  437. return this;
  438. }
  439. /**
  440. * Set the fast forward mode. It is used if pull is configured to do a merge
  441. * as opposed to rebase. If non-{@code null} takes precedence over the
  442. * fast-forward mode configured in git config.
  443. *
  444. * @param fastForwardMode
  445. * corresponds to the --ff/--no-ff/--ff-only options. If
  446. * {@code null} use the value of {@code pull.ff} configured in
  447. * git config. If {@code pull.ff} is not configured fall back to
  448. * the value of {@code merge.ff}. If {@code merge.ff} is not
  449. * configured --ff is the built-in default.
  450. * @return {@code this}
  451. * @since 4.9
  452. */
  453. public PullCommand setFastForward(
  454. @Nullable FastForwardMode fastForwardMode) {
  455. checkCallable();
  456. this.fastForwardMode = fastForwardMode;
  457. return this;
  458. }
  459. /**
  460. * Set the mode to be used for recursing into submodules.
  461. *
  462. * @param recurse
  463. * the
  464. * {@link org.eclipse.jgit.lib.SubmoduleConfig.FetchRecurseSubmodulesMode}
  465. * to be used for recursing into submodules
  466. * @return {@code this}
  467. * @since 4.7
  468. * @see FetchCommand#setRecurseSubmodules(FetchRecurseSubmodulesMode)
  469. */
  470. public PullCommand setRecurseSubmodules(
  471. @Nullable FetchRecurseSubmodulesMode recurse) {
  472. this.submoduleRecurseMode = recurse;
  473. return this;
  474. }
  475. /**
  476. * Reads the rebase mode to use for a pull command from the repository
  477. * configuration. This is the value defined for the configurations
  478. * {@code branch.[branchName].rebase}, or,if not set, {@code pull.rebase}.
  479. * If neither is set, yields
  480. * {@link org.eclipse.jgit.lib.BranchConfig.BranchRebaseMode#NONE}.
  481. *
  482. * @param branchName
  483. * name of the local branch
  484. * @param config
  485. * the {@link org.eclipse.jgit.lib.Config} to read the value from
  486. * @return the {@link org.eclipse.jgit.lib.BranchConfig.BranchRebaseMode}
  487. * @since 4.5
  488. */
  489. public static BranchRebaseMode getRebaseMode(String branchName,
  490. Config config) {
  491. BranchRebaseMode mode = config.getEnum(BranchRebaseMode.values(),
  492. ConfigConstants.CONFIG_BRANCH_SECTION,
  493. branchName, ConfigConstants.CONFIG_KEY_REBASE, null);
  494. if (mode == null) {
  495. mode = config.getEnum(BranchRebaseMode.values(),
  496. ConfigConstants.CONFIG_PULL_SECTION, null,
  497. ConfigConstants.CONFIG_KEY_REBASE, BranchRebaseMode.NONE);
  498. }
  499. return mode;
  500. }
  501. private FastForwardMode getFastForwardMode() {
  502. if (fastForwardMode != null) {
  503. return fastForwardMode;
  504. }
  505. Config config = repo.getConfig();
  506. Merge ffMode = config.getEnum(Merge.values(),
  507. ConfigConstants.CONFIG_PULL_SECTION, null,
  508. ConfigConstants.CONFIG_KEY_FF, null);
  509. return ffMode != null ? FastForwardMode.valueOf(ffMode) : null;
  510. }
  511. }