Browse Source

Fix NPE on checkout of remote tracking branch

Checkout of remote tracking branch failed when no local branch
existed. Also enhance RepositoryTestCase to enable checking index
state of another test repository.

Bug: 337695
Change-Id: Idf4c05bdf23b5161688818342b2bf9a45b49f479
Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
tags/v0.12.1
Matthias Sohn 13 years ago
parent
commit
2fba1e65e1

+ 34
- 0
org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CheckoutCommandTest.java View File

@@ -1,5 +1,6 @@
/*
* Copyright (C) 2010, Chris Aniszczyk <caniszczyk@gmail.com>
* Copyright (C) 2011, Matthias Sohn <matthias.sohn@sap.com>
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
@@ -61,8 +62,13 @@ import org.eclipse.jgit.api.errors.RefNotFoundException;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.RefUpdate;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.RepositoryTestCase;
import org.eclipse.jgit.lib.StoredConfig;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.transport.RefSpec;
import org.eclipse.jgit.transport.RemoteConfig;
import org.eclipse.jgit.transport.URIish;
import org.eclipse.jgit.util.FileUtils;
import org.junit.Before;
import org.junit.Test;
@@ -205,4 +211,32 @@ public class CheckoutCommandTest extends RepositoryTestCase {
fail(e.getMessage());
}
}

@Test
public void testCheckoutRemoteTrackingWithoutLocalBranch() {
try {
// create second repository
Repository db2 = createWorkRepository();
Git git2 = new Git(db2);

// setup the second repository to fetch from the first repository
final StoredConfig config = db2.getConfig();
RemoteConfig remoteConfig = new RemoteConfig(config, "origin");
URIish uri = new URIish(db.getDirectory().toURI().toURL());
remoteConfig.addURI(uri);
remoteConfig.update(config);
config.save();

// fetch from first repository
RefSpec spec = new RefSpec("+refs/heads/*:refs/remotes/origin/*");
git2.fetch().setRemote("origin").setRefSpecs(spec).call();
// checkout remote tracking branch in second repository
// (no local branches exist yet in second repository)
git2.checkout().setName("remotes/origin/test").call();
assertEquals("[Test.txt, mode:100644, content:Some change]",
indexState(db2, CONTENT));
} catch (Exception e) {
fail(e.getMessage());
}
}
}

+ 50
- 6
org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RepositoryTestCase.java View File

@@ -167,20 +167,24 @@ public abstract class RepositoryTestCase extends LocalDiskRepositoryTestCase {
* 'stage' is only presented when the stage is different from 0. All
* reported time stamps are mapped to strings like "t0", "t1", ... "tn". The
* smallest reported time-stamp will be called "t0". This allows to write
* assertions against the string although the concrete value of the
* time stamps is unknown.
* assertions against the string although the concrete value of the time
* stamps is unknown.
*
* @param repo
* the repository the index state should be determined for
*
* @param includedOptions
* a bitmask constructed out of the constants {@link #MOD_TIME},
* {@link #SMUDGE}, {@link #LENGTH}, {@link #CONTENT_ID} and {@link #CONTENT}
* controlling which info is present in the resulting string.
* {@link #SMUDGE}, {@link #LENGTH}, {@link #CONTENT_ID} and
* {@link #CONTENT} controlling which info is present in the
* resulting string.
* @return a string encoding the index state
* @throws IllegalStateException
* @throws IOException
*/
public String indexState(int includedOptions)
public String indexState(Repository repo, int includedOptions)
throws IllegalStateException, IOException {
DirCache dc = db.readDirCache();
DirCache dc = repo.readDirCache();
StringBuilder sb = new StringBuilder();
TreeSet<Long> timeStamps = null;

@@ -223,6 +227,46 @@ public abstract class RepositoryTestCase extends LocalDiskRepositoryTestCase {
return sb.toString();
}

/**
* Represent the state of the index in one String. This representation is
* useful when writing tests which do assertions on the state of the index.
* By default information about path, mode, stage (if different from 0) is
* included. A bitmask controls which additional info about
* modificationTimes, smudge state and length is included.
* <p>
* The format of the returned string is described with this BNF:
*
* <pre>
* result = ( "[" path mode stage? time? smudge? length? sha1? content? "]" )* .
* mode = ", mode:" number .
* stage = ", stage:" number .
* time = ", time:t" timestamp-index .
* smudge = "" | ", smudged" .
* length = ", length:" number .
* sha1 = ", sha1:" hex-sha1 .
* content = ", content:" blob-data .
* </pre>
*
* 'stage' is only presented when the stage is different from 0. All
* reported time stamps are mapped to strings like "t0", "t1", ... "tn". The
* smallest reported time-stamp will be called "t0". This allows to write
* assertions against the string although the concrete value of the time
* stamps is unknown.
*
* @param includedOptions
* a bitmask constructed out of the constants {@link #MOD_TIME},
* {@link #SMUDGE}, {@link #LENGTH}, {@link #CONTENT_ID} and
* {@link #CONTENT} controlling which info is present in the
* resulting string.
* @return a string encoding the index state
* @throws IllegalStateException
* @throws IOException
*/
public String indexState(int includedOptions)
throws IllegalStateException, IOException {
return indexState(db, includedOptions);
}

/**
* Resets the index to represent exactly some filesystem content. E.g. the
* following call will replace the index with the working tree content:

+ 11
- 7
org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java View File

@@ -1,5 +1,6 @@
/*
* Copyright (C) 2010, Chris Aniszczyk <caniszczyk@gmail.com>
* Copyright (C) 2011, Matthias Sohn <matthias.sohn@sap.com>
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
@@ -54,13 +55,15 @@ import org.eclipse.jgit.api.errors.RefNotFoundException;
import org.eclipse.jgit.dircache.DirCacheCheckout;
import org.eclipse.jgit.errors.AmbiguousObjectException;
import org.eclipse.jgit.errors.CheckoutConflictException;
import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.Constants;
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.RefUpdate.Result;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevTree;
import org.eclipse.jgit.revwalk.RevWalk;

/**
@@ -119,21 +122,22 @@ public class CheckoutCommand extends GitCommand<Ref> {
command.call();
}

RevWalk revWalk = new RevWalk(repo);
Ref headRef = repo.getRef(Constants.HEAD);
RevCommit headCommit = revWalk.parseCommit(headRef.getObjectId());
String refLogMessage = "checkout: moving from "
+ headRef.getTarget().getName();
ObjectId branch = repo.resolve(name);

if (branch == null)
throw new RefNotFoundException(MessageFormat.format(JGitText
.get().refNotResolved, name));

RevWalk revWalk = new RevWalk(repo);
AnyObjectId headId = headRef.getObjectId();
RevCommit headCommit = headId == null ? null : revWalk
.parseCommit(headId);
RevCommit newCommit = revWalk.parseCommit(branch);

DirCacheCheckout dco = new DirCacheCheckout(repo, headCommit
.getTree(), repo.lockDirCache(), newCommit.getTree());
RevTree headTree = headCommit == null ? null : headCommit.getTree();
DirCacheCheckout dco = new DirCacheCheckout(repo, headTree,
repo.lockDirCache(), newCommit.getTree());
dco.setFailOnConflict(true);
try {
dco.checkout();

Loading…
Cancel
Save