2
This code is derived from jgit (http://eclipse.org/jgit).
3
Copyright owners are documented in jgit's IP log.
5
This program and the accompanying materials are made available
6
under the terms of the Eclipse Distribution License v1.0 which
7
accompanies this distribution, is reproduced below, and is
8
available at http://www.eclipse.org/org/documents/edl-v10.php
12
Redistribution and use in source and binary forms, with or
13
without modification, are permitted provided that the following
16
- Redistributions of source code must retain the above copyright
17
notice, this list of conditions and the following disclaimer.
19
- Redistributions in binary form must reproduce the above
20
copyright notice, this list of conditions and the following
21
disclaimer in the documentation and/or other materials provided
22
with the distribution.
24
- Neither the name of the Eclipse Foundation, Inc. nor the
25
names of its contributors may be used to endorse or promote
26
products derived from this software without specific prior
29
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
30
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
31
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
32
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
34
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
35
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
36
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
37
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
38
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
40
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
41
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
47
using NGit.Api.Errors;
53
/// <summary>The Pull command</summary>
54
/// <seealso><a href="http://www.kernel.org/pub/software/scm/git/docs/git-pull.html"
55
/// * >Git documentation about Pull</a></seealso>
56
public class PullCommand : GitCommand<PullResult>
58
private int timeout = 0;
60
private static readonly string DOT = ".";
62
private ProgressMonitor monitor = NullProgressMonitor.INSTANCE;
64
private CredentialsProvider credentialsProvider;
66
/// <param name="repo"></param>
67
protected internal PullCommand(Repository repo) : base(repo)
71
/// <param name="timeout">in seconds</param>
72
/// <returns>this instance</returns>
73
public virtual NGit.Api.PullCommand SetTimeout(int timeout)
75
this.timeout = timeout;
79
/// <param name="monitor">a progress monitor</param>
80
/// <returns>this instance</returns>
81
public virtual NGit.Api.PullCommand SetProgressMonitor(ProgressMonitor monitor)
83
this.monitor = monitor;
87
/// <param name="credentialsProvider">
89
/// <see cref="NGit.Transport.CredentialsProvider">NGit.Transport.CredentialsProvider
93
/// <returns>this instance</returns>
94
public virtual NGit.Api.PullCommand SetCredentialsProvider(CredentialsProvider credentialsProvider
98
this.credentialsProvider = credentialsProvider;
104
/// <code>Pull</code>
105
/// command with all the options and parameters
106
/// collected by the setter methods (e.g.
107
/// <see cref="SetProgressMonitor(NGit.ProgressMonitor)">SetProgressMonitor(NGit.ProgressMonitor)
109
/// ) of this class. Each
110
/// instance of this class should only be used for one invocation of the
111
/// command. Don't call this method twice on an instance.
113
/// <returns>the result of the pull</returns>
114
/// <exception cref="NGit.Api.Errors.WrongRepositoryStateException"></exception>
115
/// <exception cref="NGit.Api.Errors.InvalidConfigurationException"></exception>
116
/// <exception cref="NGit.Api.Errors.DetachedHeadException"></exception>
117
/// <exception cref="NGit.Api.Errors.InvalidRemoteException"></exception>
118
/// <exception cref="NGit.Api.Errors.CanceledException"></exception>
119
/// <exception cref="NGit.Api.Errors.RefNotFoundException"></exception>
120
public override PullResult Call()
123
monitor.BeginTask(JGitText.Get().pullTaskName, 2);
127
string fullBranch = repo.GetFullBranch();
128
if (!fullBranch.StartsWith(Constants.R_HEADS))
130
// we can not pull if HEAD is detached and branch is not
131
// specified explicitly
132
throw new DetachedHeadException();
134
branchName = Sharpen.Runtime.Substring(fullBranch, Constants.R_HEADS.Length);
136
catch (IOException e)
138
throw new JGitInternalException(JGitText.Get().exceptionCaughtDuringExecutionOfPullCommand
141
if (!repo.GetRepositoryState().Equals(RepositoryState.SAFE))
143
throw new WrongRepositoryStateException(MessageFormat.Format(JGitText.Get().cannotPullOnARepoWithState
144
, repo.GetRepositoryState().Name()));
146
// get the configured remote for the currently checked out branch
147
// stored in configuration key branch.<branch name>.remote
148
Config repoConfig = repo.GetConfig();
149
string remote = repoConfig.GetString(ConfigConstants.CONFIG_BRANCH_SECTION, branchName
150
, ConfigConstants.CONFIG_KEY_REMOTE);
153
// fall back to default remote
154
remote = Constants.DEFAULT_REMOTE_NAME;
156
// get the name of the branch in the remote repository
157
// stored in configuration key branch.<branch name>.merge
158
string remoteBranchName = repoConfig.GetString(ConfigConstants.CONFIG_BRANCH_SECTION
159
, branchName, ConfigConstants.CONFIG_KEY_MERGE);
160
// check if the branch is configured for pull-rebase
161
bool doRebase = repoConfig.GetBoolean(ConfigConstants.CONFIG_BRANCH_SECTION, branchName
162
, ConfigConstants.CONFIG_KEY_REBASE, false);
163
if (remoteBranchName == null)
165
string missingKey = ConfigConstants.CONFIG_BRANCH_SECTION + DOT + branchName + DOT
166
+ ConfigConstants.CONFIG_KEY_MERGE;
167
throw new InvalidConfigurationException(MessageFormat.Format(JGitText.Get().missingConfigurationForKey
170
bool isRemote = !remote.Equals(".");
172
FetchResult fetchRes;
175
remoteUri = repoConfig.GetString("remote", remote, ConfigConstants.CONFIG_KEY_URL
177
if (remoteUri == null)
179
string missingKey = ConfigConstants.CONFIG_REMOTE_SECTION + DOT + remote + DOT +
180
ConfigConstants.CONFIG_KEY_URL;
181
throw new InvalidConfigurationException(MessageFormat.Format(JGitText.Get().missingConfigurationForKey
184
if (monitor.IsCancelled())
186
throw new CanceledException(MessageFormat.Format(JGitText.Get().operationCanceled
187
, JGitText.Get().pullTaskName));
189
FetchCommand fetch = new FetchCommand(repo);
190
fetch.SetRemote(remote);
191
fetch.SetProgressMonitor(monitor);
192
fetch.SetTimeout(this.timeout);
193
fetch.SetCredentialsProvider(credentialsProvider);
194
fetchRes = fetch.Call();
198
// we can skip the fetch altogether
199
remoteUri = "local repository";
203
if (monitor.IsCancelled())
205
throw new CanceledException(MessageFormat.Format(JGitText.Get().operationCanceled
206
, JGitText.Get().pullTaskName));
208
// we check the updates to see which of the updated branches
210
// to the remote branch name
211
AnyObjectId commitToMerge;
215
if (fetchRes != null)
217
r = fetchRes.GetAdvertisedRef(remoteBranchName);
220
r = fetchRes.GetAdvertisedRef(Constants.R_HEADS + remoteBranchName);
225
throw new JGitInternalException(MessageFormat.Format(JGitText.Get().couldNotGetAdvertisedRef
226
, remoteBranchName));
230
commitToMerge = r.GetObjectId();
237
commitToMerge = repo.Resolve(remoteBranchName);
238
if (commitToMerge == null)
240
throw new RefNotFoundException(MessageFormat.Format(JGitText.Get().refNotResolved
241
, remoteBranchName));
244
catch (IOException e)
246
throw new JGitInternalException(JGitText.Get().exceptionCaughtDuringExecutionOfPullCommand
253
RebaseCommand rebase = new RebaseCommand(repo);
256
RebaseResult rebaseRes = rebase.SetUpstream(commitToMerge).SetProgressMonitor(monitor
257
).SetOperation(RebaseCommand.Operation.BEGIN).Call();
258
result = new PullResult(fetchRes, remote, rebaseRes);
260
catch (NoHeadException e)
262
throw new JGitInternalException(e.Message, e);
264
catch (RefNotFoundException e)
266
throw new JGitInternalException(e.Message, e);
268
catch (JGitInternalException e)
270
throw new JGitInternalException(e.Message, e);
272
catch (GitAPIException e)
274
throw new JGitInternalException(e.Message, e);
279
MergeCommand merge = new MergeCommand(repo);
280
string name = "branch \'" + Repository.ShortenRefName(remoteBranchName) + "\' of "
282
merge.Include(name, commitToMerge);
283
MergeCommandResult mergeRes;
286
mergeRes = merge.Call();
288
result = new PullResult(fetchRes, remote, mergeRes);
290
catch (NoHeadException e)
292
throw new JGitInternalException(e.Message, e);
294
catch (ConcurrentRefUpdateException e)
296
throw new JGitInternalException(e.Message, e);
298
catch (NGit.Api.Errors.CheckoutConflictException e)
300
throw new JGitInternalException(e.Message, e);
302
catch (InvalidMergeHeadsException e)
304
throw new JGitInternalException(e.Message, e);
306
catch (WrongRepositoryStateException e)
308
throw new JGitInternalException(e.Message, e);
310
catch (NoMessageException e)
312
throw new JGitInternalException(e.Message, e);