public virtual void TestMultipleHeads() { Git git = new Git(db); WriteTrashFile("file1", "file1"); git.Add().AddFilepattern("file1").Call(); RevCommit first = git.Commit().SetMessage("initial commit").Call(); CreateBranch(first, "refs/heads/branch1"); WriteTrashFile("file2", "file2"); git.Add().AddFilepattern("file2").Call(); RevCommit second = git.Commit().SetMessage("second commit").Call(); WriteTrashFile("file3", "file3"); git.Add().AddFilepattern("file3").Call(); git.Commit().SetMessage("third commit").Call(); CheckoutBranch("refs/heads/branch1"); NUnit.Framework.Assert.IsFalse(new FilePath(db.WorkTree, "file2").Exists()); NUnit.Framework.Assert.IsFalse(new FilePath(db.WorkTree, "file3").Exists()); MergeCommand merge = git.Merge(); merge.Include(second.Id); merge.Include(db.GetRef(Constants.MASTER)); try { merge.Call(); NUnit.Framework.Assert.Fail("Expected exception not thrown when merging multiple heads" ); } catch (InvalidMergeHeadsException) { } }
/// <summary>Execute the SubmoduleUpdateCommand command.</summary> /// <remarks>Execute the SubmoduleUpdateCommand command.</remarks> /// <returns>a collection of updated submodule paths</returns> /// <exception cref="NGit.Api.Errors.ConcurrentRefUpdateException">NGit.Api.Errors.ConcurrentRefUpdateException /// </exception> /// <exception cref="NGit.Api.Errors.CheckoutConflictException">NGit.Api.Errors.CheckoutConflictException /// </exception> /// <exception cref="NGit.Api.Errors.InvalidMergeHeadsException">NGit.Api.Errors.InvalidMergeHeadsException /// </exception> /// <exception cref="NGit.Api.Errors.InvalidConfigurationException">NGit.Api.Errors.InvalidConfigurationException /// </exception> /// <exception cref="NGit.Api.Errors.NoHeadException">NGit.Api.Errors.NoHeadException /// </exception> /// <exception cref="NGit.Api.Errors.NoMessageException">NGit.Api.Errors.NoMessageException /// </exception> /// <exception cref="NGit.Api.Errors.RefNotFoundException">NGit.Api.Errors.RefNotFoundException /// </exception> /// <exception cref="NGit.Api.Errors.WrongRepositoryStateException">NGit.Api.Errors.WrongRepositoryStateException /// </exception> /// <exception cref="NGit.Api.Errors.GitAPIException">NGit.Api.Errors.GitAPIException /// </exception> public override ICollection <string> Call() { CheckCallable(); try { SubmoduleWalk generator = SubmoduleWalk.ForIndex(repo); if (!paths.IsEmpty()) { generator.SetFilter(PathFilterGroup.CreateFromStrings(paths)); } IList <string> updated = new AList <string>(); while (generator.Next()) { // Skip submodules not registered in .gitmodules file if (generator.GetModulesPath() == null) { continue; } // Skip submodules not registered in parent repository's config string url = generator.GetConfigUrl(); if (url == null) { continue; } Repository submoduleRepo = generator.GetRepository(); // Clone repository is not present if (submoduleRepo == null) { CloneCommand clone = Git.CloneRepository(); Configure(clone); clone.SetURI(url); clone.SetDirectory(generator.GetDirectory()); if (monitor != null) { clone.SetProgressMonitor(monitor); } submoduleRepo = clone.Call().GetRepository(); } try { RevWalk walk = new RevWalk(submoduleRepo); RevCommit commit = walk.ParseCommit(generator.GetObjectId()); string update = generator.GetConfigUpdate(); if (ConfigConstants.CONFIG_KEY_MERGE.Equals(update)) { MergeCommand merge = new MergeCommand(submoduleRepo); merge.Include(commit); merge.Call(); } else { if (ConfigConstants.CONFIG_KEY_REBASE.Equals(update)) { RebaseCommand rebase = new RebaseCommand(submoduleRepo); rebase.SetUpstream(commit); rebase.Call(); } else { // Checkout commit referenced in parent repository's // index as a detached HEAD DirCacheCheckout co = new DirCacheCheckout(submoduleRepo, submoduleRepo.LockDirCache (), commit.Tree); co.SetFailOnConflict(true); co.Checkout(); RefUpdate refUpdate = submoduleRepo.UpdateRef(Constants.HEAD, true); refUpdate.SetNewObjectId(commit); refUpdate.ForceUpdate(); } } } finally { submoduleRepo.Close(); } updated.AddItem(generator.GetPath()); } return(updated); } catch (IOException e) { throw new JGitInternalException(e.Message, e); } catch (ConfigInvalidException e) { throw new InvalidConfigurationException(e.Message, e); } }
/// <summary> /// Executes the /// <code>Pull</code> /// command with all the options and parameters /// collected by the setter methods (e.g. /// <see cref="SetProgressMonitor(NGit.ProgressMonitor)">SetProgressMonitor(NGit.ProgressMonitor) /// </see> /// ) of this class. Each /// instance of this class should only be used for one invocation of the /// command. Don't call this method twice on an instance. /// </summary> /// <returns>the result of the pull</returns> /// <exception cref="NGit.Api.Errors.WrongRepositoryStateException">NGit.Api.Errors.WrongRepositoryStateException /// </exception> /// <exception cref="NGit.Api.Errors.InvalidConfigurationException">NGit.Api.Errors.InvalidConfigurationException /// </exception> /// <exception cref="NGit.Api.Errors.DetachedHeadException">NGit.Api.Errors.DetachedHeadException /// </exception> /// <exception cref="NGit.Api.Errors.InvalidRemoteException">NGit.Api.Errors.InvalidRemoteException /// </exception> /// <exception cref="NGit.Api.Errors.CanceledException">NGit.Api.Errors.CanceledException /// </exception> /// <exception cref="NGit.Api.Errors.RefNotFoundException">NGit.Api.Errors.RefNotFoundException /// </exception> /// <exception cref="NGit.Api.Errors.NoHeadException">NGit.Api.Errors.NoHeadException /// </exception> /// <exception cref="NGit.Api.Errors.TransportException">NGit.Api.Errors.TransportException /// </exception> /// <exception cref="NGit.Api.Errors.GitAPIException">NGit.Api.Errors.GitAPIException /// </exception> public override PullResult Call() { CheckCallable(); monitor.BeginTask(JGitText.Get().pullTaskName, 2); string branchName; try { string fullBranch = repo.GetFullBranch(); if (fullBranch == null) { throw new NoHeadException(JGitText.Get().pullOnRepoWithoutHEADCurrentlyNotSupported ); } if (!fullBranch.StartsWith(Constants.R_HEADS)) { // we can not pull if HEAD is detached and branch is not // specified explicitly throw new DetachedHeadException(); } branchName = Sharpen.Runtime.Substring(fullBranch, Constants.R_HEADS.Length); } catch (IOException e) { throw new JGitInternalException(JGitText.Get().exceptionCaughtDuringExecutionOfPullCommand , e); } if (!repo.GetRepositoryState().Equals(RepositoryState.SAFE)) { throw new WrongRepositoryStateException(MessageFormat.Format(JGitText.Get().cannotPullOnARepoWithState , repo.GetRepositoryState().Name())); } // get the configured remote for the currently checked out branch // stored in configuration key branch.<branch name>.remote Config repoConfig = repo.GetConfig(); string remote = repoConfig.GetString(ConfigConstants.CONFIG_BRANCH_SECTION, branchName , ConfigConstants.CONFIG_KEY_REMOTE); if (remote == null) { // fall back to default remote remote = Constants.DEFAULT_REMOTE_NAME; } // get the name of the branch in the remote repository // stored in configuration key branch.<branch name>.merge string remoteBranchName = repoConfig.GetString(ConfigConstants.CONFIG_BRANCH_SECTION , branchName, ConfigConstants.CONFIG_KEY_MERGE); // check if the branch is configured for pull-rebase bool doRebase = repoConfig.GetBoolean(ConfigConstants.CONFIG_BRANCH_SECTION, branchName , ConfigConstants.CONFIG_KEY_REBASE, false); if (remoteBranchName == null) { string missingKey = ConfigConstants.CONFIG_BRANCH_SECTION + DOT + branchName + DOT + ConfigConstants.CONFIG_KEY_MERGE; throw new InvalidConfigurationException(MessageFormat.Format(JGitText.Get().missingConfigurationForKey , missingKey)); } bool isRemote = !remote.Equals("."); string remoteUri; FetchResult fetchRes; if (isRemote) { remoteUri = repoConfig.GetString(ConfigConstants.CONFIG_REMOTE_SECTION, remote, ConfigConstants .CONFIG_KEY_URL); if (remoteUri == null) { string missingKey = ConfigConstants.CONFIG_REMOTE_SECTION + DOT + remote + DOT + ConfigConstants.CONFIG_KEY_URL; throw new InvalidConfigurationException(MessageFormat.Format(JGitText.Get().missingConfigurationForKey , missingKey)); } if (monitor.IsCancelled()) { throw new CanceledException(MessageFormat.Format(JGitText.Get().operationCanceled , JGitText.Get().pullTaskName)); } FetchCommand fetch = new FetchCommand(repo); fetch.SetRemote(remote); fetch.SetProgressMonitor(monitor); Configure(fetch); fetchRes = fetch.Call(); } else { // we can skip the fetch altogether remoteUri = "local repository"; fetchRes = null; } monitor.Update(1); if (monitor.IsCancelled()) { throw new CanceledException(MessageFormat.Format(JGitText.Get().operationCanceled , JGitText.Get().pullTaskName)); } // we check the updates to see which of the updated branches // corresponds // to the remote branch name AnyObjectId commitToMerge; if (isRemote) { Ref r = null; if (fetchRes != null) { r = fetchRes.GetAdvertisedRef(remoteBranchName); if (r == null) { r = fetchRes.GetAdvertisedRef(Constants.R_HEADS + remoteBranchName); } } if (r == null) { throw new JGitInternalException(MessageFormat.Format(JGitText.Get().couldNotGetAdvertisedRef , remoteBranchName)); } else { commitToMerge = r.GetObjectId(); } } else { try { commitToMerge = repo.Resolve(remoteBranchName); if (commitToMerge == null) { throw new RefNotFoundException(MessageFormat.Format(JGitText.Get().refNotResolved , remoteBranchName)); } } catch (IOException e) { throw new JGitInternalException(JGitText.Get().exceptionCaughtDuringExecutionOfPullCommand , e); } } string upstreamName = "branch \'" + Repository.ShortenRefName(remoteBranchName) + "\' of " + remoteUri; PullResult result; if (doRebase) { RebaseCommand rebase = new RebaseCommand(repo); RebaseResult rebaseRes = rebase.SetUpstream(commitToMerge).SetUpstreamName(upstreamName ).SetProgressMonitor(monitor).SetOperation(RebaseCommand.Operation.BEGIN).Call(); result = new PullResult(fetchRes, remote, rebaseRes); } else { MergeCommand merge = new MergeCommand(repo); merge.Include(upstreamName, commitToMerge); MergeCommandResult mergeRes = merge.Call(); monitor.Update(1); result = new PullResult(fetchRes, remote, mergeRes); } monitor.EndTask(); return result; }