Browse Source

Add "Branch" command

The need for branching becomes more pressing with pull
support: we need to make sure the upstream configuration entries
are written correctly when creating and renaming branches
(and of course are cleaned up when deleting them).
This adds support for listing, adding, deleting and renaming
branches including the more common options.

Bug: 326938
Change-Id: I00bcc19476e835d6fd78fd188acde64946c1505c
Signed-off-by: Mathias Kinzler <mathias.kinzler@sap.com>
Signed-off-by: Chris Aniszczyk <caniszczyk@gmail.com>
stable-0.10
Mathias Kinzler 14 years ago committed by Chris Aniszczyk
parent
commit
7bdef4583b
  1. 416
      org.eclipse.jgit.test/tst/org/eclipse/jgit/api/BranchCommandTest.java
  2. 11
      org.eclipse.jgit/resources/org/eclipse/jgit/JGitText.properties
  3. 11
      org.eclipse.jgit/src/org/eclipse/jgit/JGitText.java
  4. 365
      org.eclipse.jgit/src/org/eclipse/jgit/api/CreateBranchCommand.java
  5. 197
      org.eclipse.jgit/src/org/eclipse/jgit/api/DeleteBranchCommand.java
  6. 36
      org.eclipse.jgit/src/org/eclipse/jgit/api/Git.java
  7. 132
      org.eclipse.jgit/src/org/eclipse/jgit/api/ListBranchCommand.java
  8. 207
      org.eclipse.jgit/src/org/eclipse/jgit/api/RenameBranchCommand.java
  9. 53
      org.eclipse.jgit/src/org/eclipse/jgit/api/errors/CannotDeleteCurrentBranchException.java
  10. 52
      org.eclipse.jgit/src/org/eclipse/jgit/api/errors/InvalidRefNameException.java
  11. 54
      org.eclipse.jgit/src/org/eclipse/jgit/api/errors/NotMergedException.java
  12. 55
      org.eclipse.jgit/src/org/eclipse/jgit/api/errors/RefAlreadyExistsException.java
  13. 52
      org.eclipse.jgit/src/org/eclipse/jgit/api/errors/RefNotFoundException.java
  14. 2
      org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java

416
org.eclipse.jgit.test/tst/org/eclipse/jgit/api/BranchCommandTest.java

@ -0,0 +1,416 @@
/*
* Copyright (C) 2010, Mathias Kinzler <mathias.kinzler@sap.com>
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
* under the terms of the Eclipse Distribution License v1.0 which
* accompanies this distribution, is reproduced below, and is
* available at http://www.eclipse.org/org/documents/edl-v10.php
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* - Neither the name of the Eclipse Foundation, Inc. nor the
* names of its contributors may be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.eclipse.jgit.api;
import java.util.List;
import org.eclipse.jgit.api.CreateBranchCommand.SetupUpstreamMode;
import org.eclipse.jgit.api.ListBranchCommand.ListMode;
import org.eclipse.jgit.api.errors.CannotDeleteCurrentBranchException;
import org.eclipse.jgit.api.errors.DetachedHeadException;
import org.eclipse.jgit.api.errors.InvalidRefNameException;
import org.eclipse.jgit.api.errors.JGitInternalException;
import org.eclipse.jgit.api.errors.NotMergedException;
import org.eclipse.jgit.api.errors.RefAlreadyExistsException;
import org.eclipse.jgit.api.errors.RefNotFoundException;
import org.eclipse.jgit.errors.AmbiguousObjectException;
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.FetchResult;
import org.eclipse.jgit.transport.RefSpec;
import org.eclipse.jgit.transport.RemoteConfig;
import org.eclipse.jgit.transport.URIish;
public class BranchCommandTest extends RepositoryTestCase {
private Git git;
RevCommit initialCommit;
RevCommit secondCommit;
@Override
protected void setUp() throws Exception {
super.setUp();
git = new Git(db);
// checkout master
git.commit().setMessage("initial commit").call();
// commit something
writeTrashFile("Test.txt", "Hello world");
git.add().addFilepattern("Test.txt").call();
initialCommit = git.commit().setMessage("Initial commit").call();
writeTrashFile("Test.txt", "Some change");
git.add().addFilepattern("Test.txt").call();
secondCommit = git.commit().setMessage("Second commit").call();
// create a master branch
RefUpdate rup = db.updateRef("refs/heads/master");
rup.setNewObjectId(initialCommit.getId());
rup.setForceUpdate(true);
rup.update();
}
private Git setUpRepoWithRemote() throws Exception {
Repository remoteRepository = createWorkRepository();
Git remoteGit = new Git(remoteRepository);
// commit something
writeTrashFile("Test.txt", "Hello world");
remoteGit.add().addFilepattern("Test.txt").call();
initialCommit = remoteGit.commit().setMessage("Initial commit").call();
writeTrashFile("Test.txt", "Some change");
remoteGit.add().addFilepattern("Test.txt").call();
secondCommit = remoteGit.commit().setMessage("Second commit").call();
// create a master branch
RefUpdate rup = remoteRepository.updateRef("refs/heads/master");
rup.setNewObjectId(initialCommit.getId());
rup.forceUpdate();
Repository localRepository = createWorkRepository();
Git localGit = new Git(localRepository);
StoredConfig config = localRepository.getConfig();
RemoteConfig rc = new RemoteConfig(config, "origin");
rc.addURI(new URIish(remoteRepository.getDirectory().getPath()));
rc.addFetchRefSpec(new RefSpec("+refs/heads/*:refs/remotes/origin/*"));
rc.update(config);
config.save();
FetchResult res = localGit.fetch().setRemote("origin").call();
assertFalse(res.getTrackingRefUpdates().isEmpty());
rup = localRepository.updateRef("refs/heads/master");
rup.setNewObjectId(initialCommit.getId());
rup.forceUpdate();
rup = localRepository.updateRef(Constants.HEAD);
rup.link("refs/heads/master");
rup.setNewObjectId(initialCommit.getId());
rup.update();
return localGit;
}
public void testCreateAndList() throws Exception {
int localBefore;
int remoteBefore;
int allBefore;
// invalid name not allowed
try {
git.branchCreate().setName("In va lid").call();
fail("Create branch with invalid ref name should fail");
} catch (InvalidRefNameException e) {
// expected
}
// existing name not allowed w/o force
try {
git.branchCreate().setName("master").call();
fail("Create branch with existing ref name should fail");
} catch (RefAlreadyExistsException e) {
// expected
}
localBefore = git.branchList().call().size();
remoteBefore = git.branchList().setListMode(ListMode.REMOTE).call()
.size();
allBefore = git.branchList().setListMode(ListMode.ALL).call().size();
assertEquals(localBefore + remoteBefore, allBefore);
Ref newBranch = createBranch(git, "NewForTestList", false, "master",
null);
assertEquals("refs/heads/NewForTestList", newBranch.getName());
assertEquals(1, git.branchList().call().size() - localBefore);
assertEquals(0, git.branchList().setListMode(ListMode.REMOTE).call()
.size()
- remoteBefore);
assertEquals(1, git.branchList().setListMode(ListMode.ALL).call()
.size()
- allBefore);
// we can only create local branches
newBranch = createBranch(git,
"refs/remotes/origin/NewRemoteForTestList", false, "master",
null);
assertEquals("refs/heads/refs/remotes/origin/NewRemoteForTestList",
newBranch.getName());
assertEquals(2, git.branchList().call().size() - localBefore);
assertEquals(0, git.branchList().setListMode(ListMode.REMOTE).call()
.size()
- remoteBefore);
assertEquals(2, git.branchList().setListMode(ListMode.ALL).call()
.size()
- allBefore);
}
public void testCreateFromCommit() throws Exception {
Ref branch = git.branchCreate().setName("FromInitial").setStartPoint(
initialCommit).call();
assertEquals(initialCommit.getId(), branch.getObjectId());
branch = git.branchCreate().setName("FromInitial2").setStartPoint(
initialCommit.getId().name()).call();
assertEquals(initialCommit.getId(), branch.getObjectId());
try {
git.branchCreate().setName("FromInitial").setStartPoint(
secondCommit).call();
} catch (RefAlreadyExistsException e) {
// expected
}
branch = git.branchCreate().setName("FromInitial").setStartPoint(
secondCommit).setForce(true).call();
assertEquals(secondCommit.getId(), branch.getObjectId());
}
public void testCreateForce() throws Exception {
// using commits
Ref newBranch = createBranch(git, "NewForce", false, secondCommit
.getId().name(), null);
assertEquals(newBranch.getTarget().getObjectId(), secondCommit.getId());
try {
newBranch = createBranch(git, "NewForce", false, initialCommit
.getId().name(), null);
fail("Should have failed");
} catch (RefAlreadyExistsException e) {
// expected
}
newBranch = createBranch(git, "NewForce", true, initialCommit.getId()
.name(), null);
assertEquals(newBranch.getTarget().getObjectId(), initialCommit.getId());
git.branchDelete().setBranchNames("NewForce").call();
// using names
git.branchCreate().setName("NewForce").setStartPoint("master").call();
assertEquals(newBranch.getTarget().getObjectId(), initialCommit.getId());
try {
git.branchCreate().setName("NewForce").setStartPoint("master")
.call();
fail("Should have failed");
} catch (RefAlreadyExistsException e) {
// expected
}
git.branchCreate().setName("NewForce").setStartPoint("master")
.setForce(true).call();
assertEquals(newBranch.getTarget().getObjectId(), initialCommit.getId());
}
public void testDelete() throws Exception {
createBranch(git, "ForDelete", false, "master", null);
git.branchDelete().setBranchNames("ForDelete").call();
// now point the branch to a non-merged commit
createBranch(git, "ForDelete", false, secondCommit.getId().name(), null);
try {
git.branchDelete().setBranchNames("ForDelete").call();
fail("Deletion of a non-merged branch without force should have failed");
} catch (NotMergedException e) {
// expected
}
List<String> deleted = git.branchDelete().setBranchNames("ForDelete")
.setForce(true).call();
assertEquals(1, deleted.size());
assertEquals(Constants.R_HEADS + "ForDelete", deleted.get(0));
createBranch(git, "ForDelete", false, "master", null);
try {
createBranch(git, "ForDelete", false, "master", null);
fail("Repeated creation of same branch without force should fail");
} catch (RefAlreadyExistsException e) {
// expected
}
// change starting point
Ref newBranch = createBranch(git, "ForDelete", true, initialCommit
.name(), null);
assertEquals(newBranch.getTarget().getObjectId(), initialCommit.getId());
newBranch = createBranch(git, "ForDelete", true, secondCommit.name(),
null);
assertEquals(newBranch.getTarget().getObjectId(), secondCommit.getId());
git.branchDelete().setBranchNames("ForDelete").setForce(true);
try {
git.branchDelete().setBranchNames("master").call();
fail("Deletion of checked out branch without force should have failed");
} catch (CannotDeleteCurrentBranchException e) {
// expected
}
try {
git.branchDelete().setBranchNames("master").setForce(true).call();
fail("Deletion of checked out branch with force should have failed");
} catch (CannotDeleteCurrentBranchException e) {
// expected
}
}
public void testPullConfigRemoteBranch() throws Exception {
Git localGit = setUpRepoWithRemote();
Ref remote = localGit.branchList().setListMode(ListMode.REMOTE).call()
.get(0);
assertEquals("refs/remotes/origin/master", remote.getName());
// by default, we should create pull configuration
createBranch(localGit, "newFromRemote", false, remote.getName(), null);
assertEquals("origin", localGit.getRepository().getConfig().getString(
"branch", "newFromRemote", "remote"));
localGit.branchDelete().setBranchNames("newFromRemote").call();
// the pull configuration should be gone after deletion
assertNull(localGit.getRepository().getConfig().getString("branch",
"newFromRemote", "remote"));
// use --no-track
createBranch(localGit, "newFromRemote", false, remote.getName(),
SetupUpstreamMode.NOTRACK);
assertNull(localGit.getRepository().getConfig().getString("branch",
"newFromRemote", "remote"));
localGit.branchDelete().setBranchNames("newFromRemote").call();
}
public void testPullConfigLocalBranch() throws Exception {
Git localGit = setUpRepoWithRemote();
// by default, we should not create pull configuration
createBranch(localGit, "newFromMaster", false, "master", null);
assertNull(localGit.getRepository().getConfig().getString("branch",
"newFromMaster", "remote"));
localGit.branchDelete().setBranchNames("newFromMaster").call();
// use --track
createBranch(localGit, "newFromMaster", false, "master",
SetupUpstreamMode.TRACK);
assertEquals(".", localGit.getRepository().getConfig().getString(
"branch", "newFromMaster", "remote"));
localGit.branchDelete().setBranchNames("newFromMaster").call();
// the pull configuration should be gone after deletion
assertNull(localGit.getRepository().getConfig().getString("branch",
"newFromRemote", "remote"));
}
public void testPullConfigRenameLocalBranch() throws Exception {
Git localGit = setUpRepoWithRemote();
// by default, we should not create pull configuration
createBranch(localGit, "newFromMaster", false, "master", null);
assertNull(localGit.getRepository().getConfig().getString("branch",
"newFromMaster", "remote"));
localGit.branchDelete().setBranchNames("newFromMaster").call();
// use --track
createBranch(localGit, "newFromMaster", false, "master",
SetupUpstreamMode.TRACK);
assertEquals(".", localGit.getRepository().getConfig().getString(
"branch", "newFromMaster", "remote"));
localGit.branchRename().setOldName("newFromMaster").setNewName(
"renamed").call();
assertNull(".", localGit.getRepository().getConfig().getString(
"branch", "newFromMaster", "remote"));
assertEquals(".", localGit.getRepository().getConfig().getString(
"branch", "renamed", "remote"));
localGit.branchDelete().setBranchNames("renamed").call();
// the pull configuration should be gone after deletion
assertNull(localGit.getRepository().getConfig().getString("branch",
"newFromRemote", "remote"));
}
public void testRenameLocalBranch() throws Exception {
// null newName not allowed
try {
git.branchRename().call();
} catch (InvalidRefNameException e) {
// expected
}
// invalid newName not allowed
try {
git.branchRename().setNewName("In va lid").call();
} catch (InvalidRefNameException e) {
// expected
}
// not existing name not allowed
try {
git.branchRename().setOldName("notexistingbranch").setNewName(
"newname").call();
} catch (RefNotFoundException e) {
// expected
}
// create some branch
createBranch(git, "existing", false, "master", null);
// a local branch
Ref branch = createBranch(git, "fromMasterForRename", false, "master",
null);
assertEquals(Constants.R_HEADS + "fromMasterForRename", branch
.getName());
Ref renamed = git.branchRename().setOldName("fromMasterForRename")
.setNewName("newName").call();
assertEquals(Constants.R_HEADS + "newName", renamed.getName());
try {
git.branchRename().setOldName(renamed.getName()).setNewName(
"existing").call();
fail("Should have failed");
} catch (RefAlreadyExistsException e) {
// expected
}
try {
git.branchRename().setNewName("In va lid").call();
fail("Rename with invalid ref name should fail");
} catch (InvalidRefNameException e) {
// expected
}
// rename without old name and detached head not allowed
RefUpdate rup = git.getRepository().updateRef(Constants.HEAD, true);
rup.setNewObjectId(initialCommit);
rup.forceUpdate();
try {
git.branchRename().setNewName("detached").call();
} catch (DetachedHeadException e) {
// expected
}
}
public void testRenameRemoteTrackingBranch() throws Exception {
Git localGit = setUpRepoWithRemote();
Ref remoteBranch = localGit.branchList().setListMode(ListMode.REMOTE)
.call().get(0);
Ref renamed = localGit.branchRename()
.setOldName(remoteBranch.getName()).setNewName("newRemote")
.call();
assertEquals(Constants.R_REMOTES + "newRemote", renamed.getName());
}
public Ref createBranch(Git actGit, String name, boolean force,
String startPoint, SetupUpstreamMode mode)
throws JGitInternalException, RefAlreadyExistsException,
AmbiguousObjectException, RefNotFoundException,
InvalidRefNameException {
CreateBranchCommand cmd = actGit.branchCreate();
cmd.setName(name);
cmd.setForce(force);
cmd.setStartPoint(startPoint);
cmd.setUpstreamMode(mode);
return cmd.call();
}
}

11
org.eclipse.jgit/resources/org/eclipse/jgit/JGitText.properties

@ -30,6 +30,7 @@ base64InputNotProperlyPadded=Base64 input not properly padded.
baseLengthIncorrect=base length incorrect baseLengthIncorrect=base length incorrect
bareRepositoryNoWorkdirAndIndex=Bare Repository has neither a working tree, nor an index bareRepositoryNoWorkdirAndIndex=Bare Repository has neither a working tree, nor an index
blobNotFound=Blob not found: {0} blobNotFound=Blob not found: {0}
branchNameInvalid=Branch name {0} is not allowed
blobNotFoundForPath=Blob not found: {0} for path: {1} blobNotFoundForPath=Blob not found: {0} for path: {1}
cannotBeCombined=Cannot be combined. cannotBeCombined=Cannot be combined.
cannotCombineTreeFilterWithRevFilter=Cannot combine TreeFilter {0} with RefFilter {1}. cannotCombineTreeFilterWithRevFilter=Cannot combine TreeFilter {0} with RefFilter {1}.
@ -40,6 +41,7 @@ cannotConvertScriptToText=Cannot convert script to text
cannotCreateConfig=cannot create config cannotCreateConfig=cannot create config
cannotCreateDirectory=Cannot create directory {0} cannotCreateDirectory=Cannot create directory {0}
cannotCreateHEAD=cannot create HEAD cannotCreateHEAD=cannot create HEAD
cannotDeleteCheckedOutBranch=Branch {0} is checked out and can not be deleted
cannotDeleteFile=Cannot delete file: {0} cannotDeleteFile=Cannot delete file: {0}
cannotDeleteStaleTrackingRef2=Cannot delete stale tracking ref {0}: {1} cannotDeleteStaleTrackingRef2=Cannot delete stale tracking ref {0}: {1}
cannotDeleteStaleTrackingRef=Cannot delete stale tracking ref {0} cannotDeleteStaleTrackingRef=Cannot delete stale tracking ref {0}
@ -118,8 +120,11 @@ couldNotRenameTemporaryIndexFileToIndex=Could not rename temporary index file to
couldNotURLEncodeToUTF8=Could not URL encode to UTF-8 couldNotURLEncodeToUTF8=Could not URL encode to UTF-8
couldNotWriteFile=Could not write file {0} couldNotWriteFile=Could not write file {0}
countingObjects=Counting objects countingObjects=Counting objects
createBranchFailedUnknownReason=Create branch failed for unknown reason
createBranchUnexpectedResult=Create branch returned unexpected result {0}
creatingDeltasIsNotImplemented=creating deltas is not implemented creatingDeltasIsNotImplemented=creating deltas is not implemented
daemonAlreadyRunning=Daemon already running daemonAlreadyRunning=Daemon already running
deleteBranchUnexpectedResult=Delete branch returned unexpected result {0}
deletingNotSupported=Deleting {0} not supported. deletingNotSupported=Deleting {0} not supported.
destinationIsNotAWildcard=Destination is not a wildcard. destinationIsNotAWildcard=Destination is not a wildcard.
detachedHeadDetected=HEAD is detached detachedHeadDetected=HEAD is detached
@ -277,6 +282,7 @@ notFound=not found.
notValid={0} not valid notValid={0} not valid
nothingToFetch=Nothing to fetch. nothingToFetch=Nothing to fetch.
nothingToPush=Nothing to push. nothingToPush=Nothing to push.
notMergedExceptionMessage=Branch was not deleted as it has not been merged yet; use the force option to delete it anyway
objectAtHasBadZlibStream=Object at {0} in {1} has bad zlib stream objectAtHasBadZlibStream=Object at {0} in {1} has bad zlib stream
objectAtPathDoesNotHaveId=Object at path "{0}" does not have an id assigned. All object ids must be assigned prior to writing a tree. objectAtPathDoesNotHaveId=Object at path "{0}" does not have an id assigned. All object ids must be assigned prior to writing a tree.
objectIsCorrupt=Object {0} is corrupt: {1} objectIsCorrupt=Object {0} is corrupt: {1}
@ -317,6 +323,8 @@ rawLogMessageDoesNotParseAsLogEntry=Raw log message does not parse as log entry
readTimedOut=Read timed out readTimedOut=Read timed out
readingObjectsFromLocalRepositoryFailed=reading objects from local repository failed: {0} readingObjectsFromLocalRepositoryFailed=reading objects from local repository failed: {0}
receivingObjects=Receiving objects receivingObjects=Receiving objects
refAlreadExists=Ref {0} already exists
refNotResolved=Ref {0} can not be resolved
refUpdateReturnCodeWas=RefUpdate return code was: {0} refUpdateReturnCodeWas=RefUpdate return code was: {0}
reflogsNotYetSupportedByRevisionParser=reflogs not yet supported by revision parser reflogsNotYetSupportedByRevisionParser=reflogs not yet supported by revision parser
remoteConfigHasNoURIAssociated=Remote config "{0}" has no URIs associated remoteConfigHasNoURIAssociated=Remote config "{0}" has no URIs associated
@ -324,6 +332,9 @@ remoteDoesNotHaveSpec=Remote does not have {0} available for fetch.
remoteDoesNotSupportSmartHTTPPush=remote does not support smart HTTP push remoteDoesNotSupportSmartHTTPPush=remote does not support smart HTTP push
remoteHungUpUnexpectedly=remote hung up unexpectedly remoteHungUpUnexpectedly=remote hung up unexpectedly
remoteNameCantBeNull=Remote name can't be null. remoteNameCantBeNull=Remote name can't be null.
renameBranchFailedBecauseTag=Can not rename as Ref {0} is a tag
renameBranchFailedUnknownReason=Rename failed with unknown reason
renameBranchUnexpectedResult=Unexpected rename result {0}
renamesAlreadyFound=Renames have already been found. renamesAlreadyFound=Renames have already been found.
renamesBreakingModifies=Breaking apart modified file pairs renamesBreakingModifies=Breaking apart modified file pairs
renamesFindingByContent=Finding renames by content similarity renamesFindingByContent=Finding renames by content similarity

11
org.eclipse.jgit/src/org/eclipse/jgit/JGitText.java

@ -91,6 +91,7 @@ public class JGitText extends TranslationBundle {
/***/ public String bareRepositoryNoWorkdirAndIndex; /***/ public String bareRepositoryNoWorkdirAndIndex;
/***/ public String blobNotFound; /***/ public String blobNotFound;
/***/ public String blobNotFoundForPath; /***/ public String blobNotFoundForPath;
/***/ public String branchNameInvalid;
/***/ public String cannotBeCombined; /***/ public String cannotBeCombined;
/***/ public String cannotCombineTreeFilterWithRevFilter; /***/ public String cannotCombineTreeFilterWithRevFilter;
/***/ public String cannotCommitOnARepoWithState; /***/ public String cannotCommitOnARepoWithState;
@ -100,6 +101,7 @@ public class JGitText extends TranslationBundle {
/***/ public String cannotCreateConfig; /***/ public String cannotCreateConfig;
/***/ public String cannotCreateDirectory; /***/ public String cannotCreateDirectory;
/***/ public String cannotCreateHEAD; /***/ public String cannotCreateHEAD;
/***/ public String cannotDeleteCheckedOutBranch;
/***/ public String cannotDeleteFile; /***/ public String cannotDeleteFile;
/***/ public String cannotDeleteStaleTrackingRef2; /***/ public String cannotDeleteStaleTrackingRef2;
/***/ public String cannotDeleteStaleTrackingRef; /***/ public String cannotDeleteStaleTrackingRef;
@ -178,8 +180,11 @@ public class JGitText extends TranslationBundle {
/***/ public String couldNotURLEncodeToUTF8; /***/ public String couldNotURLEncodeToUTF8;
/***/ public String couldNotWriteFile; /***/ public String couldNotWriteFile;
/***/ public String countingObjects; /***/ public String countingObjects;
/***/ public String createBranchFailedUnknownReason;
/***/ public String createBranchUnexpectedResult;
/***/ public String creatingDeltasIsNotImplemented; /***/ public String creatingDeltasIsNotImplemented;
/***/ public String daemonAlreadyRunning; /***/ public String daemonAlreadyRunning;
/***/ public String deleteBranchUnexpectedResult;
/***/ public String deletingNotSupported; /***/ public String deletingNotSupported;
/***/ public String destinationIsNotAWildcard; /***/ public String destinationIsNotAWildcard;
/***/ public String detachedHeadDetected; /***/ public String detachedHeadDetected;
@ -337,6 +342,7 @@ public class JGitText extends TranslationBundle {
/***/ public String notValid; /***/ public String notValid;
/***/ public String nothingToFetch; /***/ public String nothingToFetch;
/***/ public String nothingToPush; /***/ public String nothingToPush;
/***/ public String notMergedExceptionMessage;
/***/ public String objectAtHasBadZlibStream; /***/ public String objectAtHasBadZlibStream;
/***/ public String objectAtPathDoesNotHaveId; /***/ public String objectAtPathDoesNotHaveId;
/***/ public String objectIsCorrupt; /***/ public String objectIsCorrupt;
@ -377,6 +383,8 @@ public class JGitText extends TranslationBundle {
/***/ public String readTimedOut; /***/ public String readTimedOut;
/***/ public String readingObjectsFromLocalRepositoryFailed; /***/ public String readingObjectsFromLocalRepositoryFailed;
/***/ public String receivingObjects; /***/ public String receivingObjects;
/***/ public String refAlreadExists;
/***/ public String refNotResolved;
/***/ public String refUpdateReturnCodeWas; /***/ public String refUpdateReturnCodeWas;
/***/ public String reflogsNotYetSupportedByRevisionParser; /***/ public String reflogsNotYetSupportedByRevisionParser;
/***/ public String remoteConfigHasNoURIAssociated; /***/ public String remoteConfigHasNoURIAssociated;
@ -384,6 +392,9 @@ public class JGitText extends TranslationBundle {
/***/ public String remoteDoesNotSupportSmartHTTPPush; /***/ public String remoteDoesNotSupportSmartHTTPPush;
/***/ public String remoteHungUpUnexpectedly; /***/ public String remoteHungUpUnexpectedly;
/***/ public String remoteNameCantBeNull; /***/ public String remoteNameCantBeNull;
/***/ public String renameBranchFailedBecauseTag;
/***/ public String renameBranchFailedUnknownReason;
/***/ public String renameBranchUnexpectedResult;
/***/ public String renamesAlreadyFound; /***/ public String renamesAlreadyFound;
/***/ public String renamesBreakingModifies; /***/ public String renamesBreakingModifies;
/***/ public String renamesFindingByContent; /***/ public String renamesFindingByContent;

365
org.eclipse.jgit/src/org/eclipse/jgit/api/CreateBranchCommand.java

@ -0,0 +1,365 @@
/*
* Copyright (C) 2010, Mathias Kinzler <mathias.kinzler@sap.com>
* Copyright (C) 2010, Chris Aniszczyk <caniszczyk@gmail.com>
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
* under the terms of the Eclipse Distribution License v1.0 which
* accompanies this distribution, is reproduced below, and is
* available at http://www.eclipse.org/org/documents/edl-v10.php
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* - Neither the name of the Eclipse Foundation, Inc. nor the
* names of its contributors may be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.eclipse.jgit.api;
import java.io.IOException;
import java.text.MessageFormat;
import org.eclipse.jgit.JGitText;
import org.eclipse.jgit.api.errors.InvalidRefNameException;
import org.eclipse.jgit.api.errors.JGitInternalException;
import org.eclipse.jgit.api.errors.RefAlreadyExistsException;
import org.eclipse.jgit.api.errors.RefNotFoundException;
import org.eclipse.jgit.errors.AmbiguousObjectException;
import org.eclipse.jgit.lib.ConfigConstants;
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.StoredConfig;
import org.eclipse.jgit.lib.RefUpdate.Result;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
/**
* Used to create a local branch.
*
* @see <a
* href="http://www.kernel.org/pub/software/scm/git/docs/git-branch.html"
* >Git documentation about Branch</a>
*/
public class CreateBranchCommand extends GitCommand<Ref> {
private String name;
private boolean force = false;
private SetupUpstreamMode upstreamMode;
private String startPoint;
private RevCommit startCommit;
/**
* The modes available for setting up the upstream configuration
* (corresponding to the --set-upstream, --track, --no-track options
*
*/
public enum SetupUpstreamMode {
/**
* Corresponds to the --track option
*/
TRACK,
/**
* Corresponds to the --no-track option
*/
NOTRACK,
/**
* Corresponds to the --set-upstream option
*/
SET_UPSTREAM;
}
/**
* @param repo
*/
protected CreateBranchCommand(Repository repo) {
super(repo);
}
/**
* @throws RefAlreadyExistsException
* when trying to create (without force) a branch with a name
* that already exists
* @throws RefNotFoundException
* if the start point can not be found
* @throws AmbiguousObjectException
* if the start point is ambiguous
* @throws InvalidRefNameException
* if the provided name is <code>null</code> or otherwise
* invalid
* @return the newly created branch
*/
public Ref call() throws JGitInternalException, RefAlreadyExistsException,
RefNotFoundException, AmbiguousObjectException,
InvalidRefNameException {
checkCallable();
processOptions();
try {
boolean exists = repo.getRef(name) != null;
if (!force && exists)
throw new RefAlreadyExistsException(MessageFormat.format(
JGitText.get().refAlreadExists, name));
ObjectId startAt = getStartPoint();
String startPointFullName = null;
if (startPoint != null) {
Ref baseRef = repo.getRef(startPoint);
if (baseRef != null)
startPointFullName = baseRef.getName();
}
// determine whether we are based on a commit,
// a branch, or a tag and compose the reflog message
String refLogMessage;
String baseBranch = "";
if (startPointFullName == null) {
String baseCommit;
if (startCommit != null)
baseCommit = startCommit.getShortMessage();
else {
RevCommit commit = new RevWalk(repo).parseCommit(repo
.resolve(startPoint));
baseCommit = commit.getShortMessage();
}
if (exists)
refLogMessage = "branch: Reset start-point to commit "
+ baseCommit;
else
refLogMessage = "branch: Created from commit " + baseCommit;
} else if (startPointFullName.startsWith(Constants.R_HEADS)
|| startPointFullName.startsWith(Constants.R_REMOTES)) {
baseBranch = startPointFullName;
if (exists)
refLogMessage = "branch: Reset start-point to branch "
+ startPointFullName; // TODO
else
refLogMessage = "branch: Created from branch " + baseBranch;
} else {
if (exists)
refLogMessage = "branch: Reset start-point to tag "
+ startPointFullName;
else
refLogMessage = "branch: Created from tag "
+ startPointFullName;
}
RefUpdate updateRef = repo.updateRef(Constants.R_HEADS + name);
updateRef.setNewObjectId(startAt);
updateRef.setRefLogMessage(refLogMessage, false);
Result updateResult;
if (exists && force)
updateResult = updateRef.forceUpdate();
else
updateResult = updateRef.update();
setCallable(false);
boolean ok = false;
switch (updateResult) {
case NEW:
ok = !exists;
break;
case NO_CHANGE:
case FAST_FORWARD:
case FORCED:
ok = exists;
break;
default:
break;
}
if (!ok)
throw new JGitInternalException(MessageFormat.format(JGitText
.get().createBranchUnexpectedResult, updateResult
.name()));
Ref result = repo.getRef(name);
if (result == null)
throw new JGitInternalException(
JGitText.get().createBranchFailedUnknownReason);
if (baseBranch.length() == 0) {
return result;
}
// if we are based on another branch, see
// if we need to configure upstream configuration: first check
// whether the setting was done explicitly
boolean doConfigure;
if (upstreamMode == SetupUpstreamMode.SET_UPSTREAM
|| upstreamMode == SetupUpstreamMode.TRACK)
// explicitly set to configure
doConfigure = true;
else if (upstreamMode == SetupUpstreamMode.NOTRACK)
// explicitly set to not configure
doConfigure = false;
else {
// if there was no explicit setting, check the configuration
String autosetupflag = repo.getConfig().getString(
ConfigConstants.CONFIG_BRANCH_SECTION, null,
ConfigConstants.CONFIG_KEY_AUTOSETUPMERGE);
if ("false".equals(autosetupflag)) {
doConfigure = false;
} else if ("always".equals(autosetupflag)) {
doConfigure = true;
} else {
// in this case, the default is to configure
// only in case the base branch was a remote branch
doConfigure = baseBranch.startsWith(Constants.R_REMOTES);
}
}
if (doConfigure) {
StoredConfig config = repo.getConfig();
String[] tokens = baseBranch.split("/", 4);
boolean isRemote = tokens[1].equals("remotes");
if (isRemote) {
// refs/remotes/<remote name>/<branch>
String remoteName = tokens[2];
String branchName = tokens[3];
config
.setString(ConfigConstants.CONFIG_BRANCH_SECTION,
name, ConfigConstants.CONFIG_KEY_REMOTE,
remoteName);
config.setString(ConfigConstants.CONFIG_BRANCH_SECTION,
name, ConfigConstants.CONFIG_KEY_MERGE,
Constants.R_HEADS + branchName);
} else {
// set "." as remote
config.setString(ConfigConstants.CONFIG_BRANCH_SECTION,
name, ConfigConstants.CONFIG_KEY_REMOTE, ".");
config.setString(ConfigConstants.CONFIG_BRANCH_SECTION,
name, ConfigConstants.CONFIG_KEY_MERGE, baseBranch);
}
config.save();
}
return result;
} catch (AmbiguousObjectException e) {
throw e;
} catch (IOException ioe) {
throw new JGitInternalException(ioe.getMessage(), ioe);
}
}
private ObjectId getStartPoint() throws AmbiguousObjectException,
RefNotFoundException, IOException {
if (startCommit != null)
return startCommit.getId();
ObjectId result = null;
try {
if (startPoint == null)
result = repo.resolve(Constants.HEAD);
result = repo.resolve(startPoint);
} catch (AmbiguousObjectException e) {
throw e;
}
if (result == null)
throw new RefNotFoundException(MessageFormat.format(
JGitText.get().refNotResolved,
startPoint != null ? startPoint : Constants.HEAD));
return result;
}
private void processOptions() throws InvalidRefNameException {
if (name == null
|| !Repository.isValidRefName(Constants.R_HEADS + name))
throw new InvalidRefNameException(MessageFormat.format(JGitText
.get().branchNameInvalid, name == null ? "<null>" : name));
}
/**
* @param name
* the name of the new branch
* @return this instance
*/
public CreateBranchCommand setName(String name) {
checkCallable();
this.name = name;
return this;
}
/**
* @param force
* if <code>true</code> and the branch with the given name
* already exists, the start-point of an existing branch will be
* set to a new start-point; if false, the existing branch will
* not be changed
* @return this instance
*/
public CreateBranchCommand setForce(boolean force) {
checkCallable();
this.force = force;
return this;
}
/**
* @param startPoint
* corresponds to the start-point option; if <code>null</code>,
* the current HEAD will be used
* @return this instance
*/
public CreateBranchCommand setStartPoint(String startPoint) {
checkCallable();
this.startPoint = startPoint;
this.startCommit = null;
return this;
}
/**
* @param startPoint
* corresponds to the start-point option; if <code>null</code>,
* the current HEAD will be used
* @return this instance
*/
public CreateBranchCommand setStartPoint(RevCommit startPoint) {
checkCallable();
this.startCommit = startPoint;
this.startPoint = null;
return this;
}
/**
* @param mode
* corresponds to the --track/--no-track/--set-upstream options;
* may be <code>null</code>
* @return this instance
*/
public CreateBranchCommand setUpstreamMode(SetupUpstreamMode mode) {
checkCallable();
this.upstreamMode = mode;
return this;
}
}

197
org.eclipse.jgit/src/org/eclipse/jgit/api/DeleteBranchCommand.java

@ -0,0 +1,197 @@
/*
* Copyright (C) 2010, Mathias Kinzler <mathias.kinzler@sap.com>
* Copyright (C) 2010, Chris Aniszczyk <caniszczyk@gmail.com>
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
* under the terms of the Eclipse Distribution License v1.0 which
* accompanies this distribution, is reproduced below, and is
* available at http://www.eclipse.org/org/documents/edl-v10.php
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* - Neither the name of the Eclipse Foundation, Inc. nor the
* names of its contributors may be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.eclipse.jgit.api;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.jgit.JGitText;
import org.eclipse.jgit.api.errors.CannotDeleteCurrentBranchException;
import org.eclipse.jgit.api.errors.JGitInternalException;
import org.eclipse.jgit.api.errors.NotMergedException;
import org.eclipse.jgit.lib.ConfigConstants;
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.RefUpdate.Result;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
/**
* Used to delete one or several branches.
*
* The result of {@link #call()} is a list with the (full) names of the deleted
* branches.
*
* Note that we don't have a setter corresponding to the -r option; remote
* tracking branches are simply deleted just like local branches.
*
* @see <a
* href="http://www.kernel.org/pub/software/scm/git/docs/git-branch.html"
* >Git documentation about Branch</a>
*/
public class DeleteBranchCommand extends GitCommand<List<String>> {
private final Set<String> branchNames = new HashSet<String>();
private boolean force;
/**
* @param repo
*/
protected DeleteBranchCommand(Repository repo) {
super(repo);
}
/**
* @throws NotMergedException
* when trying to delete a branch which has not been merged into
* the currently checked out branch without force
* @return the list with the (full) names of the deleted branches
*/
public List<String> call() throws JGitInternalException,
NotMergedException, CannotDeleteCurrentBranchException {
checkCallable();
List<String> result = new ArrayList<String>();
if (branchNames.isEmpty())
return result;
try {
String currentBranch = repo.getFullBranch();
if (!force) {
// check if the branches to be deleted
// are all merged into the current branch
RevWalk walk = new RevWalk(repo);
RevCommit tip = walk.parseCommit(repo.resolve(Constants.HEAD));
for (String branchName : branchNames) {
if (branchName == null)
continue;
Ref currentRef = repo.getRef(branchName);
if (currentRef == null)
continue;
RevCommit base = walk.parseCommit(repo.resolve(branchName));
if (!walk.isMergedInto(base, tip)) {
throw new NotMergedException();
}
}
}
setCallable(false);
for (String branchName : branchNames) {
if (branchName == null)
continue;
Ref currentRef = repo.getRef(branchName);
if (currentRef == null)
continue;
if (currentRef.getName().equals(currentBranch))
throw new CannotDeleteCurrentBranchException(
MessageFormat
.format(
JGitText.get().cannotDeleteCheckedOutBranch,
branchName));
RefUpdate update = repo.updateRef(currentRef.getName());
update.setRefLogMessage("branch deleted", false);
update.setForceUpdate(true);
Result deleteResult = update.delete();
boolean ok = true;
switch (deleteResult) {
case IO_FAILURE:
case LOCK_FAILURE:
case REJECTED:
ok = false;
break;
default:
break;
}
if (ok) {
result.add(currentRef.getName());
// remove upstream configuration if any
repo.getConfig().unsetSection(
ConfigConstants.CONFIG_BRANCH_SECTION, branchName);
repo.getConfig().save();
} else
throw new JGitInternalException(MessageFormat.format(
JGitText.get().deleteBranchUnexpectedResult,
deleteResult.name()));
}
return result;
} catch (IOException ioe) {
throw new JGitInternalException(ioe.getMessage(), ioe);
}
}
/**
* @param branchnames
* the names of the branches to delete; if not set, this will do
* nothing; invalid branch names will simply be ignored
* @return this instance
*/
public DeleteBranchCommand setBranchNames(String... branchnames) {
checkCallable();
this.branchNames.clear();
for (String branch : branchnames)
this.branchNames.add(branch);
return this;
}
/**
* @param force
* <code>true</code> corresponds to the -D option,
* <code>false</code> to the -d option (default) <br>
* if <code>false</code> a check will be performed whether the
* branch to be deleted is already merged into the current branch
* and deletion will be refused in this case
* @return this instance
*/
public DeleteBranchCommand setForce(boolean force) {
checkCallable();
this.force = force;
return this;
}
}

36
org.eclipse.jgit/src/org/eclipse/jgit/api/Git.java

@ -142,6 +142,42 @@ public class Git {
return new PullCommand(repo); return new PullCommand(repo);
} }
/**
* Returns a command object used to create branches
*
* @return a {@link CreateBranchCommand}
*/
public CreateBranchCommand branchCreate() {
return new CreateBranchCommand(repo);
}
/**
* Returns a command object used to delete branches
*
* @return a {@link DeleteBranchCommand}
*/
public DeleteBranchCommand branchDelete() {
return new DeleteBranchCommand(repo);
}
/**
* Returns a command object used to list branches
*
* @return a {@link ListBranchCommand}
*/
public ListBranchCommand branchList() {
return new ListBranchCommand(repo);
}
/**
* Returns a command object used to rename branches
*
* @return a {@link RenameBranchCommand}
*/
public RenameBranchCommand branchRename() {
return new RenameBranchCommand(repo);
}
/** /**
* Returns a command object to execute a {@code Add} command * Returns a command object to execute a {@code Add} command
* *

132
org.eclipse.jgit/src/org/eclipse/jgit/api/ListBranchCommand.java

@ -0,0 +1,132 @@
/*
* Copyright (C) 2010, Mathias Kinzler <mathias.kinzler@sap.com>
* Copyright (C) 2010, Chris Aniszczyk <caniszczyk@gmail.com>
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
* under the terms of the Eclipse Distribution License v1.0 which
* accompanies this distribution, is reproduced below, and is
* available at http://www.eclipse.org/org/documents/edl-v10.php
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* - Neither the name of the Eclipse Foundation, Inc. nor the
* names of its contributors may be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.eclipse.jgit.api;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import org.eclipse.jgit.api.errors.JGitInternalException;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
/**
* Used to obtain a list of branches.
*
* @see <a
* href="http://www.kernel.org/pub/software/scm/git/docs/git-branch.html"
* >Git documentation about Branch</a>
*/
public class ListBranchCommand extends GitCommand<List<Ref>> {
private ListMode listMode;
/**
* The modes available for listing branches (corresponding to the -r and -a
* options)
*/
public enum ListMode {
/**
* Corresponds to the -a option (all branches)
*/
ALL,
/**
* Corresponds to the -r option (remote branches only)
*/
REMOTE;
}
/**
* @param repo
*/
protected ListBranchCommand(Repository repo) {
super(repo);
}
/**
* @throws JGitInternalException
* upon internal failure
*/
public List<Ref> call() throws JGitInternalException {
checkCallable();
Map<String, Ref> refList;
try {
if (listMode == null) {
refList = repo.getRefDatabase().getRefs(Constants.R_HEADS);
} else if (listMode == ListMode.REMOTE) {
refList = repo.getRefDatabase().getRefs(Constants.R_REMOTES);
} else {
refList = repo.getRefDatabase().getRefs(Constants.R_HEADS);
refList.putAll(repo.getRefDatabase().getRefs(
Constants.R_REMOTES));
}
} catch (IOException e) {
throw new JGitInternalException(e.getMessage(), e);
}
List<Ref> resultRefs = new ArrayList<Ref>();
resultRefs.addAll(refList.values());
Collections.sort(resultRefs, new Comparator<Ref>() {
public int compare(Ref o1, Ref o2) {
return o1.getName().compareTo(o2.getName());
}
});
setCallable(false);
return resultRefs;
}
/**
* @param listMode
* optional: corresponds to the -r/-a options; by default, only
* local branches will be listed
* @return this instance
*/
public ListBranchCommand setListMode(ListMode listMode) {
checkCallable();
this.listMode = listMode;
return this;
}
}

207
org.eclipse.jgit/src/org/eclipse/jgit/api/RenameBranchCommand.java

@ -0,0 +1,207 @@
/*
* Copyright (C) 2010, Mathias Kinzler <mathias.kinzler@sap.com>
* Copyright (C) 2010, Chris Aniszczyk <caniszczyk@gmail.com>
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
* under the terms of the Eclipse Distribution License v1.0 which
* accompanies this distribution, is reproduced below, and is
* available at http://www.eclipse.org/org/documents/edl-v10.php
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* - Neither the name of the Eclipse Foundation, Inc. nor the
* names of its contributors may be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.eclipse.jgit.api;
import java.io.IOException;
import java.text.MessageFormat;
import org.eclipse.jgit.JGitText;
import org.eclipse.jgit.api.errors.DetachedHeadException;
import org.eclipse.jgit.api.errors.InvalidRefNameException;
import org.eclipse.jgit.api.errors.JGitInternalException;
import org.eclipse.jgit.api.errors.RefAlreadyExistsException;
import org.eclipse.jgit.api.errors.RefNotFoundException;
import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.RefRename;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.RefUpdate.Result;
/**
* Used to rename branches.
*
* @see <a
* href="http://www.kernel.org/pub/software/scm/git/docs/git-branch.html"
* >Git documentation about Branch</a>
*/
public class RenameBranchCommand extends GitCommand<Ref> {
private String oldName;
private String newName;
/**
* @param repo
*/
protected RenameBranchCommand(Repository repo) {
super(repo);
}
/**
* @throws RefNotFoundException
* if the old branch can not be found (branch with provided old
* name does not exist or old name resolves to a tag)
* @throws InvalidRefNameException
* if the provided new name is <code>null</code> or otherwise
* invalid
* @throws RefAlreadyExistsException
* if a branch with the new name already exists
* @throws DetachedHeadException
* if rename is tried without specifying the old name and HEAD
* is detached
*/
public Ref call() throws RefNotFoundException, InvalidRefNameException,
RefAlreadyExistsException, DetachedHeadException {
checkCallable();
if (newName == null)
throw new InvalidRefNameException(MessageFormat.format(JGitText
.get().branchNameInvalid, "<null>"));
try {
String fullOldName;
String fullNewName;
if (repo.getRef(newName) != null)
throw new RefAlreadyExistsException(MessageFormat.format(
JGitText.get().refAlreadExists, newName));
if (oldName != null) {
Ref ref = repo.getRef(oldName);
if (ref == null)
throw new RefNotFoundException(MessageFormat.format(
JGitText.get().refNotResolved, oldName));
if (ref.getName().startsWith(Constants.R_TAGS))
throw new RefNotFoundException(MessageFormat.format(
JGitText.get().renameBranchFailedBecauseTag,
oldName));
fullOldName = ref.getName();
} else {
fullOldName = repo.getFullBranch();
if (ObjectId.isId(fullOldName))
throw new DetachedHeadException();
}
if (fullOldName.startsWith(Constants.R_REMOTES))
fullNewName = Constants.R_REMOTES + newName;
else {
fullNewName = Constants.R_HEADS + newName;
}
if (!Repository.isValidRefName(fullNewName))
throw new InvalidRefNameException(MessageFormat.format(JGitText
.get().branchNameInvalid, fullNewName));
RefRename rename = repo.renameRef(fullOldName, fullNewName);
Result renameResult = rename.rename();
setCallable(false);
boolean ok = Result.RENAMED == renameResult;
if (ok) {
if (fullNewName.startsWith(Constants.R_HEADS)) {
// move the upstream configuration over to the new branch
String shortOldName = fullOldName
.substring(Constants.R_HEADS.length());
String oldRemote = repo.getConfig().getString(
ConfigConstants.CONFIG_BRANCH_SECTION,
shortOldName, ConfigConstants.CONFIG_KEY_REMOTE);
if (oldRemote != null) {
repo.getConfig().setString(
ConfigConstants.CONFIG_BRANCH_SECTION, newName,
ConfigConstants.CONFIG_KEY_REMOTE, oldRemote);
}
String oldMerge = repo.getConfig().getString(
ConfigConstants.CONFIG_BRANCH_SECTION,
shortOldName, ConfigConstants.CONFIG_KEY_MERGE);
if (oldMerge != null) {
repo.getConfig().setString(
ConfigConstants.CONFIG_BRANCH_SECTION, newName,
ConfigConstants.CONFIG_KEY_MERGE, oldMerge);
}
repo.getConfig()
.unsetSection(
ConfigConstants.CONFIG_BRANCH_SECTION,
shortOldName);
repo.getConfig().save();
}
} else
throw new JGitInternalException(MessageFormat.format(JGitText
.get().renameBranchUnexpectedResult, renameResult
.name()));
Ref resultRef = repo.getRef(newName);
if (resultRef == null)
throw new JGitInternalException(
JGitText.get().renameBranchFailedUnknownReason);
return resultRef;
} catch (IOException ioe) {
throw new JGitInternalException(ioe.getMessage(), ioe);
}
}
/**
* @param newName
* the new name
* @return this instance
*/
public RenameBranchCommand setNewName(String newName) {
checkCallable();
this.newName = newName;
return this;
}
/**
* @param oldName
* the name of the branch to rename; if not set, the currently
* checked out branch (if any) will be renamed
* @return this instance
*/
public RenameBranchCommand setOldName(String oldName) {
checkCallable();
this.oldName = oldName;
return this;
}
}

53
org.eclipse.jgit/src/org/eclipse/jgit/api/errors/CannotDeleteCurrentBranchException.java

@ -0,0 +1,53 @@
/*
* Copyright (C) 2010,Mathias Kinzler <mathias.kinzler@sap.com> and
* other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v1.0 which accompanies this
* distribution, is reproduced below, and is available at
* http://www.eclipse.org/org/documents/edl-v10.php
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* - Neither the name of the Eclipse Foundation, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.eclipse.jgit.api.errors;
/**
* Thrown when trying to delete a branch which is currently checked out
*/
public class CannotDeleteCurrentBranchException extends GitAPIException {
private static final long serialVersionUID = 1L;
/**
* @param message
* the message
*/
public CannotDeleteCurrentBranchException(String message) {
super(message);
}
}

52
org.eclipse.jgit/src/org/eclipse/jgit/api/errors/InvalidRefNameException.java

@ -0,0 +1,52 @@
/*
* Copyright (C) 2010, Mathias Kinzler <mathias.kinzler@sap.com> and
* other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v1.0 which accompanies this
* distribution, is reproduced below, and is available at
* http://www.eclipse.org/org/documents/edl-v10.php
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* - Neither the name of the Eclipse Foundation, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.eclipse.jgit.api.errors;
/**
* Exception thrown when an invalid Ref name was encountered
*/
public class InvalidRefNameException extends GitAPIException {
private static final long serialVersionUID = 1L;
/**
* @param msg
*/
public InvalidRefNameException(String msg) {
super(msg);
}
}

54
org.eclipse.jgit/src/org/eclipse/jgit/api/errors/NotMergedException.java

@ -0,0 +1,54 @@
/*
* Copyright (C) 2010,Mathias Kinzler <mathias.kinzler@sap.com> and
* other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v1.0 which accompanies this
* distribution, is reproduced below, and is available at
* http://www.eclipse.org/org/documents/edl-v10.php
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* - Neither the name of the Eclipse Foundation, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.eclipse.jgit.api.errors;
import org.eclipse.jgit.JGitText;
/**
* Thrown when branch deletion fails due to unmerged data
*/
public class NotMergedException extends GitAPIException {
private static final long serialVersionUID = 1L;
/**
* The default constructor with a default message
*/
public NotMergedException() {
super(JGitText.get().notMergedExceptionMessage);
}
}

55
org.eclipse.jgit/src/org/eclipse/jgit/api/errors/RefAlreadyExistsException.java

@ -0,0 +1,55 @@
/*
* Copyright (C) 2010,Mathias Kinzler <mathias.kinzler@sap.com> and
* other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v1.0 which accompanies this
* distribution, is reproduced below, and is available at
* http://www.eclipse.org/org/documents/edl-v10.php
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* - Neither the name of the Eclipse Foundation, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.eclipse.jgit.api.errors;
import org.eclipse.jgit.lib.Ref;
/**
* Thrown when trying to create a {@link Ref} with the same name as an exsiting
* one
*/
public class RefAlreadyExistsException extends GitAPIException {
private static final long serialVersionUID = 1L;
/**
* @param message
*/
public RefAlreadyExistsException(String message) {
super(message);
}
}

52
org.eclipse.jgit/src/org/eclipse/jgit/api/errors/RefNotFoundException.java

@ -0,0 +1,52 @@
/*
* Copyright (C) 2010,Mathias Kinzler <mathias.kinzler@sap.com> and
* other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v1.0 which accompanies this
* distribution, is reproduced below, and is available at
* http://www.eclipse.org/org/documents/edl-v10.php
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* - Neither the name of the Eclipse Foundation, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.eclipse.jgit.api.errors;
/**
* Thrown when a Ref can not be resolved
*/
public class RefNotFoundException extends GitAPIException {
private static final long serialVersionUID = 1L;
/**
* @param message
*/
public RefNotFoundException(String message) {
super(message);
}
}

2
org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java

@ -87,4 +87,6 @@ public class ConfigConstants {
/** The "url" key */ /** The "url" key */
public static final String CONFIG_KEY_URL = "url"; public static final String CONFIG_KEY_URL = "url";
/** The "autosetupmerge" key */
public static final String CONFIG_KEY_AUTOSETUPMERGE = "autosetupmerge";
} }

Loading…
Cancel
Save