/*
 * Copyright (C) 2010, Chris Aniszczyk <caniszczyk@gmail.com> and others
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Distribution License v. 1.0 which is available at
 * https://www.eclipse.org/org/documents/edl-v10.php.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */
package org.eclipse.jgit.api;

import static java.util.stream.Collectors.toList;

import java.io.IOException;
import java.net.URISyntaxException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.eclipse.jgit.annotations.Nullable;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.api.errors.InvalidConfigurationException;
import org.eclipse.jgit.api.errors.InvalidRemoteException;
import org.eclipse.jgit.api.errors.JGitInternalException;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.errors.NoRemoteRepositoryException;
import org.eclipse.jgit.errors.NotSupportedException;
import org.eclipse.jgit.errors.TransportException;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.NullProgressMonitor;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ProgressMonitor;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.StoredConfig;
import org.eclipse.jgit.lib.SubmoduleConfig.FetchRecurseSubmodulesMode;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.submodule.SubmoduleWalk;
import org.eclipse.jgit.transport.FetchResult;
import org.eclipse.jgit.transport.RefSpec;
import org.eclipse.jgit.transport.TagOpt;
import org.eclipse.jgit.transport.Transport;

A class used to execute a Fetch command. It has setters for all supported options and arguments of this command and a call() method to finally execute the command.
See Also:
/** * A class used to execute a {@code Fetch} command. It has setters for all * supported options and arguments of this command and a {@link #call()} method * to finally execute the command. * * @see <a href="http://www.kernel.org/pub/software/scm/git/docs/git-fetch.html" * >Git documentation about Fetch</a> */
public class FetchCommand extends TransportCommand<FetchCommand, FetchResult> { private String remote = Constants.DEFAULT_REMOTE_NAME; private List<RefSpec> refSpecs; private ProgressMonitor monitor = NullProgressMonitor.INSTANCE; private boolean checkFetchedObjects; private Boolean removeDeletedRefs; private boolean dryRun; private boolean thin = Transport.DEFAULT_FETCH_THIN; private TagOpt tagOption; private FetchRecurseSubmodulesMode submoduleRecurseMode = null; private Callback callback; private boolean isForceUpdate;
Callback for status of fetch operation.
Since:4.8
/** * Callback for status of fetch operation. * * @since 4.8 * */
public interface Callback {
Notify fetching a submodule.
Params:
  • name – the submodule name.
/** * Notify fetching a submodule. * * @param name * the submodule name. */
void fetchingSubmodule(String name); }
Constructor for FetchCommand.
Params:
/** * Constructor for FetchCommand. * * @param repo * a {@link org.eclipse.jgit.lib.Repository} object. */
protected FetchCommand(Repository repo) { super(repo); refSpecs = new ArrayList<>(3); } private FetchRecurseSubmodulesMode getRecurseMode(String path) { // Use the caller-specified mode, if set if (submoduleRecurseMode != null) { return submoduleRecurseMode; } // Fall back to submodule.name.fetchRecurseSubmodules, if set FetchRecurseSubmodulesMode mode = repo.getConfig().getEnum( FetchRecurseSubmodulesMode.values(), ConfigConstants.CONFIG_SUBMODULE_SECTION, path, ConfigConstants.CONFIG_KEY_FETCH_RECURSE_SUBMODULES, null); if (mode != null) { return mode; } // Fall back to fetch.recurseSubmodules, if set mode = repo.getConfig().getEnum(FetchRecurseSubmodulesMode.values(), ConfigConstants.CONFIG_FETCH_SECTION, null, ConfigConstants.CONFIG_KEY_RECURSE_SUBMODULES, null); if (mode != null) { return mode; } // Default to on-demand mode return FetchRecurseSubmodulesMode.ON_DEMAND; } private void fetchSubmodules(FetchResult results) throws org.eclipse.jgit.api.errors.TransportException, GitAPIException, InvalidConfigurationException { try (SubmoduleWalk walk = new SubmoduleWalk(repo); RevWalk revWalk = new RevWalk(repo)) { // Walk over submodules in the parent repository's FETCH_HEAD. ObjectId fetchHead = repo.resolve(Constants.FETCH_HEAD); if (fetchHead == null) { return; } walk.setTree(revWalk.parseTree(fetchHead)); while (walk.next()) { try (Repository submoduleRepo = walk.getRepository()) { // Skip submodules that don't exist locally (have not been // cloned), are not registered in the .gitmodules file, or // not registered in the parent repository's config. if (submoduleRepo == null || walk.getModulesPath() == null || walk.getConfigUrl() == null) { continue; } FetchRecurseSubmodulesMode recurseMode = getRecurseMode( walk.getPath()); // When the fetch mode is "yes" we always fetch. When the // mode // is "on demand", we only fetch if the submodule's revision // was // updated to an object that is not currently present in the // submodule. if ((recurseMode == FetchRecurseSubmodulesMode.ON_DEMAND && !submoduleRepo.getObjectDatabase() .has(walk.getObjectId())) || recurseMode == FetchRecurseSubmodulesMode.YES) { FetchCommand f = new FetchCommand(submoduleRepo) .setProgressMonitor(monitor) .setTagOpt(tagOption) .setCheckFetchedObjects(checkFetchedObjects) .setRemoveDeletedRefs(isRemoveDeletedRefs()) .setThin(thin) .setRefSpecs(applyOptions(refSpecs)) .setDryRun(dryRun) .setRecurseSubmodules(recurseMode); configure(f); if (callback != null) { callback.fetchingSubmodule(walk.getPath()); } results.addSubmodule(walk.getPath(), f.call()); } } } } catch (IOException e) { throw new JGitInternalException(e.getMessage(), e); } catch (ConfigInvalidException e) { throw new InvalidConfigurationException(e.getMessage(), e); } }
{@inheritDoc}

Execute the fetch command with all the options and parameters collected by the setter methods of this class. Each instance of this class should only be used for one invocation of the command (means: one call to call())

/** * {@inheritDoc} * <p> * Execute the {@code fetch} command with all the options and parameters * collected by the setter methods of this class. Each instance of this * class should only be used for one invocation of the command (means: one * call to {@link #call()}) */
@Override public FetchResult call() throws GitAPIException, InvalidRemoteException, org.eclipse.jgit.api.errors.TransportException { checkCallable(); try (Transport transport = Transport.open(repo, remote)) { transport.setCheckFetchedObjects(checkFetchedObjects); transport.setRemoveDeletedRefs(isRemoveDeletedRefs()); transport.setDryRun(dryRun); if (tagOption != null) transport.setTagOpt(tagOption); transport.setFetchThin(thin); configure(transport); FetchResult result = transport.fetch(monitor, applyOptions(refSpecs)); if (!repo.isBare()) { fetchSubmodules(result); } return result; } catch (NoRemoteRepositoryException e) { throw new InvalidRemoteException(MessageFormat.format( JGitText.get().invalidRemote, remote), e); } catch (TransportException e) { throw new org.eclipse.jgit.api.errors.TransportException( e.getMessage(), e); } catch (URISyntaxException e) { throw new InvalidRemoteException(MessageFormat.format( JGitText.get().invalidRemote, remote), e); } catch (NotSupportedException e) { throw new JGitInternalException( JGitText.get().exceptionCaughtDuringExecutionOfFetchCommand, e); } } private List<RefSpec> applyOptions(List<RefSpec> refSpecs2) { if (!isForceUpdate()) { return refSpecs2; } List<RefSpec> updated = new ArrayList<>(3); for (RefSpec refSpec : refSpecs2) { updated.add(refSpec.setForceUpdate(true)); } return updated; }
Set the mode to be used for recursing into submodules.
Params:
  • recurse – corresponds to the --recurse-submodules/--no-recurse-submodules options. If null use the value of the submodule.name.fetchRecurseSubmodules option configured per submodule. If not specified there, use the value of the fetch.recurseSubmodules option configured in git config. If not configured in either, "on-demand" is the built-in default.
Returns:this
Since:4.7
/** * Set the mode to be used for recursing into submodules. * * @param recurse * corresponds to the * --recurse-submodules/--no-recurse-submodules options. If * {@code null} use the value of the * {@code submodule.name.fetchRecurseSubmodules} option * configured per submodule. If not specified there, use the * value of the {@code fetch.recurseSubmodules} option configured * in git config. If not configured in either, "on-demand" is the * built-in default. * @return {@code this} * @since 4.7 */
public FetchCommand setRecurseSubmodules( @Nullable FetchRecurseSubmodulesMode recurse) { checkCallable(); submoduleRecurseMode = recurse; return this; }
The remote (uri or name) used for the fetch operation. If no remote is set, the default value of Constants.DEFAULT_REMOTE_NAME will be used.
Params:
  • remote – name of a remote
See Also:
  • DEFAULT_REMOTE_NAME.DEFAULT_REMOTE_NAME
Returns:this
/** * The remote (uri or name) used for the fetch operation. If no remote is * set, the default value of <code>Constants.DEFAULT_REMOTE_NAME</code> will * be used. * * @see Constants#DEFAULT_REMOTE_NAME * @param remote * name of a remote * @return {@code this} */
public FetchCommand setRemote(String remote) { checkCallable(); this.remote = remote; return this; }
Get the remote
Returns:the remote used for the remote operation
/** * Get the remote * * @return the remote used for the remote operation */
public String getRemote() { return remote; }
Get timeout
Returns:the timeout used for the fetch operation
/** * Get timeout * * @return the timeout used for the fetch operation */
public int getTimeout() { return timeout; }
Whether to check received objects for validity
Returns:whether to check received objects for validity
/** * Whether to check received objects for validity * * @return whether to check received objects for validity */
public boolean isCheckFetchedObjects() { return checkFetchedObjects; }
If set to true, objects received will be checked for validity
Params:
  • checkFetchedObjects – whether to check objects for validity
Returns:this
/** * If set to {@code true}, objects received will be checked for validity * * @param checkFetchedObjects * whether to check objects for validity * @return {@code this} */
public FetchCommand setCheckFetchedObjects(boolean checkFetchedObjects) { checkCallable(); this.checkFetchedObjects = checkFetchedObjects; return this; }
Whether to remove refs which no longer exist in the source
Returns:whether to remove refs which no longer exist in the source
/** * Whether to remove refs which no longer exist in the source * * @return whether to remove refs which no longer exist in the source */
public boolean isRemoveDeletedRefs() { if (removeDeletedRefs != null) { return removeDeletedRefs.booleanValue(); } // fall back to configuration boolean result = false; StoredConfig config = repo.getConfig(); result = config.getBoolean(ConfigConstants.CONFIG_FETCH_SECTION, null, ConfigConstants.CONFIG_KEY_PRUNE, result); result = config.getBoolean(ConfigConstants.CONFIG_REMOTE_SECTION, remote, ConfigConstants.CONFIG_KEY_PRUNE, result); return result; }
If set to true, refs are removed which no longer exist in the source
Params:
  • removeDeletedRefs – whether to remove deleted Refs
Returns:this
/** * If set to {@code true}, refs are removed which no longer exist in the * source * * @param removeDeletedRefs * whether to remove deleted {@code Ref}s * @return {@code this} */
public FetchCommand setRemoveDeletedRefs(boolean removeDeletedRefs) { checkCallable(); this.removeDeletedRefs = Boolean.valueOf(removeDeletedRefs); return this; }
Get progress monitor
Returns:the progress monitor for the fetch operation
/** * Get progress monitor * * @return the progress monitor for the fetch operation */
public ProgressMonitor getProgressMonitor() { return monitor; }
The progress monitor associated with the fetch operation. By default, this is set to NullProgressMonitor
Params:
See Also:
  • NullProgressMonitor
Returns:this
/** * The progress monitor associated with the fetch operation. By default, * this is set to <code>NullProgressMonitor</code> * * @see NullProgressMonitor * @param monitor * a {@link org.eclipse.jgit.lib.ProgressMonitor} * @return {@code this} */
public FetchCommand setProgressMonitor(ProgressMonitor monitor) { checkCallable(); if (monitor == null) { monitor = NullProgressMonitor.INSTANCE; } this.monitor = monitor; return this; }
Get list of RefSpecs
Returns:the ref specs
/** * Get list of {@code RefSpec}s * * @return the ref specs */
public List<RefSpec> getRefSpecs() { return refSpecs; }
The ref specs to be used in the fetch operation
Params:
  • specs – String representation of RefSpecs
Returns:this
Since:4.9
/** * The ref specs to be used in the fetch operation * * @param specs * String representation of {@code RefSpec}s * @return {@code this} * @since 4.9 */
public FetchCommand setRefSpecs(String... specs) { return setRefSpecs( Arrays.stream(specs).map(RefSpec::new).collect(toList())); }
The ref specs to be used in the fetch operation
Params:
Returns:this
/** * The ref specs to be used in the fetch operation * * @param specs * one or multiple {@link org.eclipse.jgit.transport.RefSpec}s * @return {@code this} */
public FetchCommand setRefSpecs(RefSpec... specs) { return setRefSpecs(Arrays.asList(specs)); }
The ref specs to be used in the fetch operation
Params:
Returns:this
/** * The ref specs to be used in the fetch operation * * @param specs * list of {@link org.eclipse.jgit.transport.RefSpec}s * @return {@code this} */
public FetchCommand setRefSpecs(List<RefSpec> specs) { checkCallable(); this.refSpecs.clear(); this.refSpecs.addAll(specs); return this; }
Whether to do a dry run
Returns:the dry run preference for the fetch operation
/** * Whether to do a dry run * * @return the dry run preference for the fetch operation */
public boolean isDryRun() { return dryRun; }
Sets whether the fetch operation should be a dry run
Params:
  • dryRun – whether to do a dry run
Returns:this
/** * Sets whether the fetch operation should be a dry run * * @param dryRun * whether to do a dry run * @return {@code this} */
public FetchCommand setDryRun(boolean dryRun) { checkCallable(); this.dryRun = dryRun; return this; }
Get thin-pack preference
Returns:the thin-pack preference for fetch operation
/** * Get thin-pack preference * * @return the thin-pack preference for fetch operation */
public boolean isThin() { return thin; }
Sets the thin-pack preference for fetch operation. Default setting is Transport.DEFAULT_FETCH_THIN
Params:
  • thin – the thin-pack preference
Returns:this
/** * Sets the thin-pack preference for fetch operation. * * Default setting is Transport.DEFAULT_FETCH_THIN * * @param thin * the thin-pack preference * @return {@code this} */
public FetchCommand setThin(boolean thin) { checkCallable(); this.thin = thin; return this; }
Sets the specification of annotated tag behavior during fetch
Params:
Returns:this
/** * Sets the specification of annotated tag behavior during fetch * * @param tagOpt * the {@link org.eclipse.jgit.transport.TagOpt} * @return {@code this} */
public FetchCommand setTagOpt(TagOpt tagOpt) { checkCallable(); this.tagOption = tagOpt; return this; }
Register a progress callback.
Params:
  • callback – the callback
Returns:this
Since:4.8
/** * Register a progress callback. * * @param callback * the callback * @return {@code this} * @since 4.8 */
public FetchCommand setCallback(Callback callback) { this.callback = callback; return this; }
Whether fetch --force option is enabled
Returns:whether refs affected by the fetch are updated forcefully
Since:5.0
/** * Whether fetch --force option is enabled * * @return whether refs affected by the fetch are updated forcefully * @since 5.0 */
public boolean isForceUpdate() { return this.isForceUpdate; }
Set fetch --force option
Params:
  • force – whether to update refs affected by the fetch forcefully
Returns:this command
Since:5.0
/** * Set fetch --force option * * @param force * whether to update refs affected by the fetch forcefully * @return this command * @since 5.0 */
public FetchCommand setForceUpdate(boolean force) { this.isForceUpdate = force; return this; } }