Fail clone if initial branch doesn't exist in remote repository
jgit clone --branch foo <url> did not fail if the remote branch "foo" didn't exist in the remote repository being cloned. Bug: 546580 Change-Id: I55648ad3a39da4a5711dfa8e6d6682bb8190a6d6 Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
This commit is contained in:
parent
704ccdc096
commit
64cb7148ac
|
@ -11,7 +11,9 @@
|
|||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.File;
|
||||
|
@ -25,6 +27,7 @@
|
|||
import org.eclipse.jgit.lib.ObjectId;
|
||||
import org.eclipse.jgit.lib.Ref;
|
||||
import org.eclipse.jgit.lib.RefUpdate;
|
||||
import org.eclipse.jgit.lib.Repository;
|
||||
import org.eclipse.jgit.lib.StoredConfig;
|
||||
import org.eclipse.jgit.revwalk.RevCommit;
|
||||
import org.eclipse.jgit.transport.RefSpec;
|
||||
|
@ -64,6 +67,45 @@ public void testClone() throws Exception {
|
|||
assertEquals("expected 1 branch", 1, branches.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCloneInitialBranch() throws Exception {
|
||||
createInitialCommit();
|
||||
|
||||
File gitDir = db.getDirectory();
|
||||
String sourceURI = gitDir.toURI().toString();
|
||||
File target = createTempDirectory("target");
|
||||
String cmd = "git clone --branch master " + sourceURI + " "
|
||||
+ shellQuote(target.getPath());
|
||||
String[] result = execute(cmd);
|
||||
assertArrayEquals(new String[] {
|
||||
"Cloning into '" + target.getPath() + "'...", "", "" }, result);
|
||||
|
||||
Git git2 = Git.open(target);
|
||||
List<Ref> branches = git2.branchList().call();
|
||||
assertEquals("expected 1 branch", 1, branches.size());
|
||||
|
||||
Repository db2 = git2.getRepository();
|
||||
ObjectId head = db2.resolve("HEAD");
|
||||
assertNotNull(head);
|
||||
assertNotEquals(ObjectId.zeroId(), head);
|
||||
ObjectId master = db2.resolve("master");
|
||||
assertEquals(head, master);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCloneInitialBranchMissing() throws Exception {
|
||||
createInitialCommit();
|
||||
|
||||
File gitDir = db.getDirectory();
|
||||
String sourceURI = gitDir.toURI().toString();
|
||||
File target = createTempDirectory("target");
|
||||
String cmd = "git clone --branch foo " + sourceURI + " "
|
||||
+ shellQuote(target.getPath());
|
||||
Die e = assertThrows(Die.class, () -> execute(cmd));
|
||||
assertEquals("Remote branch 'foo' not found in upstream origin",
|
||||
e.getMessage());
|
||||
}
|
||||
|
||||
private RevCommit createInitialCommit() throws Exception {
|
||||
JGitTestUtil.writeTrashFile(db, "hello.txt", "world");
|
||||
git.add().addFilepattern("hello.txt").call();
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
import org.eclipse.jgit.api.CloneCommand;
|
||||
import org.eclipse.jgit.api.Git;
|
||||
import org.eclipse.jgit.api.errors.InvalidRemoteException;
|
||||
import org.eclipse.jgit.api.errors.TransportException;
|
||||
import org.eclipse.jgit.lib.AnyObjectId;
|
||||
import org.eclipse.jgit.lib.Constants;
|
||||
import org.eclipse.jgit.lib.TextProgressMonitor;
|
||||
|
@ -110,6 +111,8 @@ protected void run() throws Exception {
|
|||
db = command.call().getRepository();
|
||||
if (msgs && db.resolve(Constants.HEAD) == null)
|
||||
outw.println(CLIText.get().clonedEmptyRepository);
|
||||
} catch (TransportException e) {
|
||||
throw die(e.getMessage(), e);
|
||||
} catch (InvalidRemoteException e) {
|
||||
throw die(MessageFormat.format(CLIText.get().doesNotExist,
|
||||
sourceUri), e);
|
||||
|
|
|
@ -568,6 +568,7 @@ refNotResolved=Ref {0} cannot be resolved
|
|||
reftableDirExists=reftable dir exists and is nonempty
|
||||
reftableRecordsMustIncrease=records must be increasing: last {0}, this {1}
|
||||
refUpdateReturnCodeWas=RefUpdate return code was: {0}
|
||||
remoteBranchNotFound=Remote branch ''{0}'' not found in upstream origin
|
||||
remoteConfigHasNoURIAssociated=Remote config "{0}" has no URIs associated
|
||||
remoteDoesNotHaveSpec=Remote does not have {0} available for fetch.
|
||||
remoteDoesNotSupportSmartHTTPPush=remote does not support smart HTTP push
|
||||
|
|
|
@ -297,6 +297,7 @@ private FetchResult fetch(Repository clonedRepo, URIish u)
|
|||
command.setTagOpt(
|
||||
fetchAll ? TagOpt.FETCH_TAGS : TagOpt.AUTO_FOLLOW);
|
||||
}
|
||||
command.setInitialBranch(branch);
|
||||
configure(command);
|
||||
|
||||
return command.call();
|
||||
|
|
|
@ -74,6 +74,8 @@ public class FetchCommand extends TransportCommand<FetchCommand, FetchResult> {
|
|||
|
||||
private boolean isForceUpdate;
|
||||
|
||||
private String initialBranch;
|
||||
|
||||
/**
|
||||
* Callback for status of fetch operation.
|
||||
*
|
||||
|
@ -209,7 +211,7 @@ public FetchResult call() throws GitAPIException, InvalidRemoteException,
|
|||
transport.setFetchThin(thin);
|
||||
configure(transport);
|
||||
FetchResult result = transport.fetch(monitor,
|
||||
applyOptions(refSpecs));
|
||||
applyOptions(refSpecs), initialBranch);
|
||||
if (!repo.isBare()) {
|
||||
fetchSubmodules(result);
|
||||
}
|
||||
|
@ -487,6 +489,24 @@ public FetchCommand setTagOpt(TagOpt tagOpt) {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the initial branch
|
||||
*
|
||||
* @param branch
|
||||
* the initial branch to check out when cloning the repository.
|
||||
* Can be specified as ref name (<code>refs/heads/master</code>),
|
||||
* branch name (<code>master</code>) or tag name
|
||||
* (<code>v1.2.3</code>). The default is to use the branch
|
||||
* pointed to by the cloned repository's HEAD and can be
|
||||
* requested by passing {@code null} or <code>HEAD</code>.
|
||||
* @return {@code this}
|
||||
* @since 5.11
|
||||
*/
|
||||
public FetchCommand setInitialBranch(String branch) {
|
||||
this.initialBranch = branch;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a progress callback.
|
||||
*
|
||||
|
|
|
@ -596,6 +596,7 @@ public static JGitText get() {
|
|||
/***/ public String reftableDirExists;
|
||||
/***/ public String reftableRecordsMustIncrease;
|
||||
/***/ public String refUpdateReturnCodeWas;
|
||||
/***/ public String remoteBranchNotFound;
|
||||
/***/ public String remoteConfigHasNoURIAssociated;
|
||||
/***/ public String remoteDoesNotHaveSpec;
|
||||
/***/ public String remoteDoesNotSupportSmartHTTPPush;
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
import org.eclipse.jgit.lib.RefDatabase;
|
||||
import org.eclipse.jgit.revwalk.ObjectWalk;
|
||||
import org.eclipse.jgit.revwalk.RevWalk;
|
||||
import org.eclipse.jgit.util.StringUtils;
|
||||
|
||||
class FetchProcess {
|
||||
/** Transport we will fetch over. */
|
||||
|
@ -79,7 +80,8 @@ class FetchProcess {
|
|||
toFetch = f;
|
||||
}
|
||||
|
||||
void execute(ProgressMonitor monitor, FetchResult result)
|
||||
void execute(ProgressMonitor monitor, FetchResult result,
|
||||
String initialBranch)
|
||||
throws NotSupportedException, TransportException {
|
||||
askFor.clear();
|
||||
localUpdates.clear();
|
||||
|
@ -89,7 +91,7 @@ void execute(ProgressMonitor monitor, FetchResult result)
|
|||
|
||||
Throwable e1 = null;
|
||||
try {
|
||||
executeImp(monitor, result);
|
||||
executeImp(monitor, result, initialBranch);
|
||||
} catch (NotSupportedException | TransportException err) {
|
||||
e1 = err;
|
||||
throw err;
|
||||
|
@ -107,9 +109,22 @@ void execute(ProgressMonitor monitor, FetchResult result)
|
|||
}
|
||||
}
|
||||
|
||||
private boolean isInitialBranchMissing(Map<String, Ref> refsMap,
|
||||
String initialBranch) {
|
||||
if (StringUtils.isEmptyOrNull(initialBranch) || refsMap.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
if (refsMap.containsKey(initialBranch)
|
||||
|| refsMap.containsKey(Constants.R_HEADS + initialBranch)
|
||||
|| refsMap.containsKey(Constants.R_TAGS + initialBranch)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void executeImp(final ProgressMonitor monitor,
|
||||
final FetchResult result) throws NotSupportedException,
|
||||
TransportException {
|
||||
final FetchResult result, String initialBranch)
|
||||
throws NotSupportedException, TransportException {
|
||||
final TagOpt tagopt = transport.getTagOpt();
|
||||
String getTags = (tagopt == TagOpt.NO_TAGS) ? null : Constants.R_TAGS;
|
||||
String getHead = null;
|
||||
|
@ -126,7 +141,12 @@ private void executeImp(final ProgressMonitor monitor,
|
|||
}
|
||||
conn = transport.openFetch(toFetch, getTags, getHead);
|
||||
try {
|
||||
result.setAdvertisedRefs(transport.getURI(), conn.getRefsMap());
|
||||
Map<String, Ref> refsMap = conn.getRefsMap();
|
||||
if (isInitialBranchMissing(refsMap, initialBranch)) {
|
||||
throw new TransportException(MessageFormat.format(
|
||||
JGitText.get().remoteBranchNotFound, initialBranch));
|
||||
}
|
||||
result.setAdvertisedRefs(transport.getURI(), refsMap);
|
||||
result.peerUserAgent = conn.getPeerUserAgent();
|
||||
final Set<Ref> matched = new HashSet<>();
|
||||
for (RefSpec spec : toFetch) {
|
||||
|
|
|
@ -1231,9 +1231,52 @@ public void setPushOptions(List<String> pushOptions) {
|
|||
* the remote connection could not be established or object
|
||||
* copying (if necessary) failed or update specification was
|
||||
* incorrect.
|
||||
* @since 5.11
|
||||
*/
|
||||
public FetchResult fetch(final ProgressMonitor monitor,
|
||||
Collection<RefSpec> toFetch) throws NotSupportedException,
|
||||
Collection<RefSpec> toFetch)
|
||||
throws NotSupportedException, TransportException {
|
||||
return fetch(monitor, toFetch, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch objects and refs from the remote repository to the local one.
|
||||
* <p>
|
||||
* This is a utility function providing standard fetch behavior. Local
|
||||
* tracking refs associated with the remote repository are automatically
|
||||
* updated if this transport was created from a
|
||||
* {@link org.eclipse.jgit.transport.RemoteConfig} with fetch RefSpecs
|
||||
* defined.
|
||||
*
|
||||
* @param monitor
|
||||
* progress monitor to inform the user about our processing
|
||||
* activity. Must not be null. Use
|
||||
* {@link org.eclipse.jgit.lib.NullProgressMonitor} if progress
|
||||
* updates are not interesting or necessary.
|
||||
* @param toFetch
|
||||
* specification of refs to fetch locally. May be null or the
|
||||
* empty collection to use the specifications from the
|
||||
* RemoteConfig. Source for each RefSpec can't be null.
|
||||
* @param branch
|
||||
* the initial branch to check out when cloning the repository.
|
||||
* Can be specified as ref name (<code>refs/heads/master</code>),
|
||||
* branch name (<code>master</code>) or tag name
|
||||
* (<code>v1.2.3</code>). The default is to use the branch
|
||||
* pointed to by the cloned repository's HEAD and can be
|
||||
* requested by passing {@code null} or <code>HEAD</code>.
|
||||
* @return information describing the tracking refs updated.
|
||||
* @throws org.eclipse.jgit.errors.NotSupportedException
|
||||
* this transport implementation does not support fetching
|
||||
* objects.
|
||||
* @throws org.eclipse.jgit.errors.TransportException
|
||||
* the remote connection could not be established or object
|
||||
* copying (if necessary) failed or update specification was
|
||||
* incorrect.
|
||||
* @since 5.11
|
||||
*/
|
||||
public FetchResult fetch(final ProgressMonitor monitor,
|
||||
Collection<RefSpec> toFetch, String branch)
|
||||
throws NotSupportedException,
|
||||
TransportException {
|
||||
if (toFetch == null || toFetch.isEmpty()) {
|
||||
// If the caller did not ask for anything use the defaults.
|
||||
|
@ -1263,7 +1306,7 @@ public FetchResult fetch(final ProgressMonitor monitor,
|
|||
}
|
||||
|
||||
final FetchResult result = new FetchResult();
|
||||
new FetchProcess(this, toFetch).execute(monitor, result);
|
||||
new FetchProcess(this, toFetch).execute(monitor, result, branch);
|
||||
|
||||
local.autoGC(monitor);
|
||||
|
||||
|
|
Loading…
Reference in New Issue