1 /*******************************************************************************
2 * Copyright (C) 2007, Dave Watson <dwatson@mimvista.com>
3 * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
4 * Copyright (C) 2006, Shawn O. Pearce <spearce@spearce.org>
6 * All rights reserved. This program and the accompanying materials
7 * are made available under the terms of the Eclipse Public License v1.0
8 * which accompanies this distribution, and is available at
9 * http://www.eclipse.org/legal/epl-v10.html
10 *******************************************************************************/
11 package org
.eclipse
.egit
.core
.op
;
13 import java
.io
.IOException
;
15 import org
.eclipse
.core
.resources
.IWorkspaceRunnable
;
16 import org
.eclipse
.core
.resources
.ResourcesPlugin
;
17 import org
.eclipse
.core
.runtime
.CoreException
;
18 import org
.eclipse
.core
.runtime
.IProgressMonitor
;
19 import org
.eclipse
.core
.runtime
.NullProgressMonitor
;
20 import org
.eclipse
.core
.runtime
.SubProgressMonitor
;
21 import org
.eclipse
.core
.runtime
.jobs
.ISchedulingRule
;
22 import org
.eclipse
.egit
.core
.CoreText
;
23 import org
.eclipse
.egit
.core
.internal
.util
.ProjectUtil
;
24 import org
.eclipse
.jgit
.errors
.CheckoutConflictException
;
25 import org
.eclipse
.jgit
.lib
.Commit
;
26 import org
.eclipse
.jgit
.lib
.Constants
;
27 import org
.eclipse
.jgit
.lib
.GitIndex
;
28 import org
.eclipse
.jgit
.lib
.RefUpdate
;
29 import org
.eclipse
.jgit
.lib
.Repository
;
30 import org
.eclipse
.jgit
.lib
.Tag
;
31 import org
.eclipse
.jgit
.lib
.Tree
;
32 import org
.eclipse
.jgit
.lib
.WorkDirCheckout
;
33 import org
.eclipse
.jgit
.lib
.RefUpdate
.Result
;
34 import org
.eclipse
.osgi
.util
.NLS
;
35 import org
.eclipse
.team
.core
.TeamException
;
38 * This class implements checkouts of a specific revision. A check
39 * is made that this can be done without data loss.
41 public class BranchOperation
implements IEGitOperation
{
43 private final Repository repository
;
45 private final String refName
;
48 * Construct a {@link BranchOperation} object.
50 * @param refName Name of git ref to checkout
52 public BranchOperation(Repository repository
, String refName
) {
53 this.repository
= repository
;
54 this.refName
= refName
;
59 private GitIndex index
;
63 private Commit oldCommit
;
65 private Commit newCommit
;
70 * @see org.eclipse.egit.core.op.IEGitOperation#execute(org.eclipse.core.runtime.IProgressMonitor)
72 public void execute(IProgressMonitor m
) throws CoreException
{
73 IProgressMonitor monitor
;
75 monitor
= new NullProgressMonitor();
79 if (!refName
.startsWith(Constants
.R_REFS
))
80 throw new TeamException(NLS
.bind(
81 CoreText
.BranchOperation_CheckoutOnlyBranchOrTag
, refName
));
83 IWorkspaceRunnable action
= new IWorkspaceRunnable() {
85 public void run(IProgressMonitor monitor
) throws CoreException
{
86 monitor
.beginTask(NLS
.bind(
87 CoreText
.BranchOperation_performingBranch
, refName
), 6);
103 ProjectUtil
.refreshProjects(repository
, new SubProgressMonitor(
110 // lock workspace to protect working tree changes
111 ResourcesPlugin
.getWorkspace().run(action
, monitor
);
115 * @see org.eclipse.egit.core.op.IEGitOperation#getSchedulingRule()
117 public ISchedulingRule
getSchedulingRule() {
118 return ResourcesPlugin
.getWorkspace().getRoot();
121 private void updateHeadRef() throws TeamException
{
122 boolean detach
= false;
123 // in case of a non-local branch or a tag,
124 // we "detach" HEAD, i.e. point it to the
125 // underlying commit instead of to the Ref
126 if (!refName
.startsWith(Constants
.R_HEADS
))
129 RefUpdate u
= repository
.updateRef(Constants
.HEAD
, detach
);
132 u
.setNewObjectId(newCommit
.getCommitId());
133 // using forceUpdate instead of update avoids
134 // the merge tests which would otherwise make
136 u
.setRefLogMessage(NLS
.bind(
137 CoreText
.BranchOperation_checkoutMovingTo
, newCommit
138 .getCommitId().toString()), false);
139 res
= u
.forceUpdate();
141 u
.setRefLogMessage(NLS
.bind(
142 CoreText
.BranchOperation_checkoutMovingTo
, refName
),
144 res
= u
.link(refName
);
153 throw new IOException(u
.getResult().name());
155 } catch (IOException e
) {
156 throw new TeamException(NLS
.bind(
157 CoreText
.BranchOperation_updatingHeadToRef
, refName
), e
);
161 private void writeIndex() throws TeamException
{
164 } catch (IOException e
) {
165 throw new TeamException(CoreText
.BranchOperation_writingIndex
, e
);
169 private void checkoutTree() throws TeamException
{
171 new WorkDirCheckout(repository
, repository
.getWorkDir(), oldTree
,
172 index
, newTree
).checkout();
173 } catch (CheckoutConflictException e
) {
174 TeamException teamException
= new TeamException(e
.getMessage());
176 } catch (IOException e
) {
177 throw new TeamException(CoreText
.BranchOperation_checkoutProblem
, e
);
181 private void mapObjects() throws TeamException
{
183 oldTree
= oldCommit
.getTree();
184 index
= repository
.getIndex();
185 newTree
= newCommit
.getTree();
186 } catch (IOException e
) {
187 throw new TeamException(CoreText
.BranchOperation_mappingTrees
, e
);
191 private void lookupRefs() throws TeamException
{
193 // if we have a tag, we have to make an indirection
194 if (refName
.startsWith(Constants
.R_TAGS
)) {
195 Tag tag
= repository
.mapTag(refName
);
196 newCommit
= repository
.mapCommit(tag
.getObjId());
198 newCommit
= repository
.mapCommit(refName
);
199 } catch (IOException e
) {
200 throw new TeamException(NLS
.bind(
201 CoreText
.BranchOperation_mappingCommit
, refName
), e
);
205 oldCommit
= repository
.mapCommit(Constants
.HEAD
);
206 } catch (IOException e
) {
207 throw new TeamException(CoreText
.BranchOperation_mappingCommitHead
,