Fix missing support for monitor == null
[egit.git] / org.eclipse.egit.core / src / org / eclipse / egit / core / op / BranchOperation.java
blobb7e30a2d0ceecffc68640ebe77b233bdb019ea2b
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;
37 /**
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;
47 /**
48 * Construct a {@link BranchOperation} object.
49 * @param repository
50 * @param refName Name of git ref to checkout
52 public BranchOperation(Repository repository, String refName) {
53 this.repository = repository;
54 this.refName = refName;
57 private Tree oldTree;
59 private GitIndex index;
61 private Tree newTree;
63 private Commit oldCommit;
65 private Commit newCommit;
69 /* (non-Javadoc)
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;
74 if (m == null)
75 monitor = new NullProgressMonitor();
76 else
77 monitor = m;
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);
88 lookupRefs();
89 monitor.worked(1);
91 mapObjects();
92 monitor.worked(1);
94 checkoutTree();
95 monitor.worked(1);
97 writeIndex();
98 monitor.worked(1);
100 updateHeadRef();
101 monitor.worked(1);
103 ProjectUtil.refreshProjects(repository, new SubProgressMonitor(
104 monitor, 1));
105 monitor.worked(1);
107 monitor.done();
110 // lock workspace to protect working tree changes
111 ResourcesPlugin.getWorkspace().run(action, monitor);
114 /* (non-Javadoc)
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))
127 detach = true;
128 try {
129 RefUpdate u = repository.updateRef(Constants.HEAD, detach);
130 Result res;
131 if (detach) {
132 u.setNewObjectId(newCommit.getCommitId());
133 // using forceUpdate instead of update avoids
134 // the merge tests which would otherwise make
135 // this fail
136 u.setRefLogMessage(NLS.bind(
137 CoreText.BranchOperation_checkoutMovingTo, newCommit
138 .getCommitId().toString()), false);
139 res = u.forceUpdate();
140 } else {
141 u.setRefLogMessage(NLS.bind(
142 CoreText.BranchOperation_checkoutMovingTo, refName),
143 false);
144 res = u.link(refName);
146 switch (res) {
147 case NEW:
148 case FORCED:
149 case NO_CHANGE:
150 case FAST_FORWARD:
151 break;
152 default:
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 {
162 try {
163 index.write();
164 } catch (IOException e) {
165 throw new TeamException(CoreText.BranchOperation_writingIndex, e);
169 private void checkoutTree() throws TeamException {
170 try {
171 new WorkDirCheckout(repository, repository.getWorkDir(), oldTree,
172 index, newTree).checkout();
173 } catch (CheckoutConflictException e) {
174 TeamException teamException = new TeamException(e.getMessage());
175 throw teamException;
176 } catch (IOException e) {
177 throw new TeamException(CoreText.BranchOperation_checkoutProblem, e);
181 private void mapObjects() throws TeamException {
182 try {
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 {
192 try {
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());
197 } else
198 newCommit = repository.mapCommit(refName);
199 } catch (IOException e) {
200 throw new TeamException(NLS.bind(
201 CoreText.BranchOperation_mappingCommit, refName), e);
204 try {
205 oldCommit = repository.mapCommit(Constants.HEAD);
206 } catch (IOException e) {
207 throw new TeamException(CoreText.BranchOperation_mappingCommitHead,