public override Task UpdateAsync(GitUpdateOptions options)
        {
            this.log.LogDebug($"Using repository at '{this.repository.LocalRepositoryPath}'...");
            using (var repository = new Repository(this.repository.LocalRepositoryPath))
            {
                this.log.LogDebug("Fetching commits from origin...");
                repository.Fetch("origin", new FetchOptions {
                    CredentialsProvider = CredentialsHandler, Prune = true
                });
                var refName = "FETCH_HEAD";
                if (options.Branch != null)
                {
                    refName = "origin/" + options.Branch;
                }
                else if (options.Tag != null)
                {
                    refName = "origin/" + options.Tag;
                }
                this.log.LogDebug($"Resetting the index and working tree to {refName}...");
                repository.Reset(ResetMode.Hard, refName);
                repository.RemoveUntrackedFiles();

                if (options.RecurseSubmodules)
                {
                    foreach (var submodule in repository.Submodules)
                    {
                        repository.Submodules.Update(submodule.Name, new SubmoduleUpdateOptions {
                            CredentialsProvider = CredentialsHandler, Init = true
                        });
                    }
                }
            }

            return(Complete);
        }
Exemple #2
0
 public async override Task UpdateAsync(GitUpdateOptions options)
 {
     await this.ExecuteRemoteAsync(
         ClientCommand.Update,
         new RemoteLibGitSharpContext { UpdateOptions = options }
         ).ConfigureAwait(false);
 }
Exemple #3
0
        public override async Task <string> UpdateAsync(GitUpdateOptions options)
        {
            /*
             *  git remote set-url origin <url>         | Make sure we're talking to the correct remote repository
             *  git fetch origin                        | Update the local cache of the remote repository
             *  git reset --hard <ref>                  | Resets to the HEAD revision and removes commits that haven't been pushed
             *  git clean -dfq                          | Remove all non-Git versioned files and directories from the repository working directory
             *  git submodule update --init --recursive | Updates submodules to the version referenced by the HEAD revision
             */

            var remoteArgs = new GitArgumentsBuilder("remote set-url origin");

            remoteArgs.AppendSensitive(this.repository.GetRemoteUrlWithCredentials());
            await this.ExecuteCommandLineAsync(remoteArgs, this.repository.LocalRepositoryPath).ConfigureAwait(false);

            await this.ExecuteCommandLineAsync(new GitArgumentsBuilder("fetch origin"), this.repository.LocalRepositoryPath).ConfigureAwait(false);

            var resetArgs = new GitArgumentsBuilder("reset --hard");

            if (options.Ref != null)
            {
                resetArgs.AppendQuoted(options.Ref);
            }
            else if (options.Branch != null)
            {
                resetArgs.AppendQuoted("origin/" + options.Branch);
            }
            else
            {
                resetArgs.Append("FETCH_HEAD");
            }

            await this.ExecuteCommandLineAsync(
                resetArgs,
                this.repository.LocalRepositoryPath
                ).ConfigureAwait(false);

            await this.ExecuteCommandLineAsync(
                new GitArgumentsBuilder("clean -dfq"),
                this.repository.LocalRepositoryPath
                ).ConfigureAwait(false);

            if (options.RecurseSubmodules)
            {
                await this.ExecuteCommandLineAsync(
                    new GitArgumentsBuilder("submodule update --init --recursive"),
                    this.repository.LocalRepositoryPath
                    ).ConfigureAwait(false);
            }

            var results = await this.ExecuteCommandLineAsync(
                new GitArgumentsBuilder("log -n 1 --format=%H"),
                this.repository.LocalRepositoryPath
                ).ConfigureAwait(false);

            return(string.Join(" ", results.Output).Trim());
        }
        public override Task <string> UpdateAsync(GitUpdateOptions options)
        {
            try
            {
                this.log.LogDebug($"Using repository at '{this.repository.LocalRepositoryPath}'...");
                using (var repository = new Repository(this.repository.LocalRepositoryPath))
                {
                    this.log.LogDebug("Fetching commits from origin...");
                    Commands.Fetch(repository, "origin", new string[0], new FetchOptions {
                        CredentialsProvider = this.CredentialsHandler, Prune = true
                    }, null);
                    var refName = "FETCH_HEAD";
                    if (options.Branch != null)
                    {
                        refName = "origin/" + options.Branch;
                    }
                    else if (options.Ref != null)
                    {
                        refName = options.Ref;
                    }
                    this.log.LogDebug($"Resetting the index and working tree to {refName}...");
                    repository.Reset(ResetMode.Hard, refName);
                    repository.RemoveUntrackedFiles();

                    if (options.RecurseSubmodules)
                    {
                        foreach (var submodule in repository.Submodules)
                        {
                            repository.Submodules.Update(submodule.Name, new SubmoduleUpdateOptions {
                                CredentialsProvider = this.CredentialsHandler, Init = true
                            });
                        }
                    }

                    return(Task.FromResult(repository.Head?.Tip?.Sha));
                }
            }
            catch (Exception ex)
            {
                // gitsharp exceptions are not always serializable
                throw new ExecutionFailureException("Update failed: " + ex.Message);
            }
            finally
            {
                this.EndOperation();
            }
        }
		public void Merge (string branch, GitUpdateOptions options, IProgressMonitor monitor)
		{
			IEnumerable<DiffEntry> statusList = null;
			Stash stash = null;
			StashCollection stashes = GetStashes (RootRepository);
			NGit.Api.Git git = new NGit.Api.Git (RootRepository);

			try {
				monitor.BeginTask (GettextCatalog.GetString ("Merging"), 5);
				List<string> UpdateSubmodules = new List<string> ();

				// TODO: Fix stash so we don't have to do update before the main repo update.
				if ((options & GitUpdateOptions.UpdateSubmodules) == GitUpdateOptions.UpdateSubmodules) {
					monitor.Log.WriteLine (GettextCatalog.GetString ("Checking repository submodules"));
					if (!GetSubmodulesToUpdate (UpdateSubmodules))
						return;

					monitor.Log.WriteLine (GettextCatalog.GetString ("Updating repository submodules"));
					var submoduleUpdate = git.SubmoduleUpdate ();
					foreach (var submodule in UpdateSubmodules)
						submoduleUpdate.AddPath (submodule);

					submoduleUpdate.Call ();
					monitor.Step (1);
				}

				// Get a list of files that are different in the target branch
				statusList = GitUtil.GetChangedFiles (RootRepository, branch);
				monitor.Step (1);

				if ((options & GitUpdateOptions.SaveLocalChanges) != GitUpdateOptions.SaveLocalChanges) {
					const VersionStatus unclean = VersionStatus.Modified | VersionStatus.ScheduledAdd | VersionStatus.ScheduledDelete;
					bool modified = false;
					if (GetDirectoryVersionInfo (RootPath, false, true).Any (v => (v.Status & unclean) != VersionStatus.Unversioned))
						modified = true;

					if (modified) {
						if (MessageService.GenericAlert (
							MonoDevelop.Ide.Gui.Stock.Question,
							GettextCatalog.GetString ("You have uncommitted changes"),
							GettextCatalog.GetString ("What do you want to do?"),
							AlertButton.Cancel,
							new AlertButton ("Stash")) == AlertButton.Cancel)
							return;

						options |= GitUpdateOptions.SaveLocalChanges;
					}
				}

				if ((options & GitUpdateOptions.SaveLocalChanges) == GitUpdateOptions.SaveLocalChanges) {
					monitor.Log.WriteLine (GettextCatalog.GetString ("Saving local changes"));
					using (var gm = new GitMonitor (monitor))
						stash = stashes.Create (gm, GetStashName ("_tmp_"));
					monitor.Step (1);
				}
				
				// Apply changes
				
				ObjectId branchId = RootRepository.Resolve (branch);

				MergeCommandResult mergeResult = git.Merge ().SetStrategy (MergeStrategy.RESOLVE).Include (branchId).Call ();
				if (mergeResult.GetMergeStatus () == MergeStatus.CONFLICTING || mergeResult.GetMergeStatus () == MergeStatus.FAILED) {
					var conflicts = mergeResult.GetConflicts ();
					bool commit = true;
					if (conflicts != null) {
						foreach (string conflictFile in conflicts.Keys) {
							ConflictResult res = ResolveConflict (RootRepository.FromGitPath (conflictFile));
							if (res == ConflictResult.Abort) {
								GitUtil.HardReset (RootRepository, GetHeadCommit (RootRepository));
								commit = false;
								break;
							} else if (res == ConflictResult.Skip) {
								Revert (RootRepository.FromGitPath (conflictFile), false, monitor);
								break;
							}
						}
					}
					if (commit)
						git.Commit ().Call ();
				}

				if ((options & GitUpdateOptions.UpdateSubmodules) == GitUpdateOptions.UpdateSubmodules) {
					monitor.Log.WriteLine (GettextCatalog.GetString ("Updating repository submodules"));
					var submoduleUpdate = git.SubmoduleUpdate ();
					foreach (var submodule in CachedSubmodules)
						submoduleUpdate.AddPath (submodule.Item1);

					submoduleUpdate.Call ();
					monitor.Step (1);
				}
			} finally {
				if ((options & GitUpdateOptions.SaveLocalChanges) == GitUpdateOptions.SaveLocalChanges)
					monitor.Step (1);
				
				// Restore local changes
				if (stash != null) {
					monitor.Log.WriteLine (GettextCatalog.GetString ("Restoring local changes"));
					using (var gm = new GitMonitor (monitor))
						stash.Apply (gm);
					stashes.Remove (stash);
					monitor.Step (1);
				}
				monitor.EndTask ();
			}
			
			// Notify changes
			if (statusList != null)
				NotifyFileChanges (monitor, statusList);
		}
		public void Rebase (string upstreamRef, GitUpdateOptions options, IProgressMonitor monitor)
		{
			StashCollection stashes = GitUtil.GetStashes (RootRepository);
			Stash stash = null;
			NGit.Api.Git git = new NGit.Api.Git (RootRepository);
			try
			{
				monitor.BeginTask (GettextCatalog.GetString ("Rebasing"), 5);
				List<string> UpdateSubmodules = new List<string> ();

				// TODO: Fix stash so we don't have to do update before the main repo update.
				if ((options & GitUpdateOptions.UpdateSubmodules) == GitUpdateOptions.UpdateSubmodules) {
					monitor.Log.WriteLine (GettextCatalog.GetString ("Checking repository submodules"));
					if (!GetSubmodulesToUpdate (UpdateSubmodules))
						return;

					monitor.Log.WriteLine (GettextCatalog.GetString ("Updating repository submodules"));
					var submoduleUpdate = git.SubmoduleUpdate ();
					foreach (var submodule in UpdateSubmodules)
						submoduleUpdate.AddPath (submodule);

					submoduleUpdate.Call ();
					monitor.Step (1);
				}

				if ((options & GitUpdateOptions.SaveLocalChanges) != GitUpdateOptions.SaveLocalChanges) {
					const VersionStatus unclean = VersionStatus.Modified | VersionStatus.ScheduledAdd | VersionStatus.ScheduledDelete;
					bool modified = false;
					if (GetDirectoryVersionInfo (RootPath, false, true).Any (v => (v.Status & unclean) != VersionStatus.Unversioned))
						modified = true;

					if (modified) {
						if (MessageService.GenericAlert (
							MonoDevelop.Ide.Gui.Stock.Question,
							GettextCatalog.GetString ("You have uncommitted changes"),
							GettextCatalog.GetString ("What do you want to do?"),
							AlertButton.Cancel,
							new AlertButton ("Stash")) == AlertButton.Cancel)
							return;

						options |= GitUpdateOptions.SaveLocalChanges;
					}
				}

				if ((options & GitUpdateOptions.SaveLocalChanges) == GitUpdateOptions.SaveLocalChanges) {
					monitor.Log.WriteLine (GettextCatalog.GetString ("Saving local changes"));
					using (var gm = new GitMonitor (monitor))
						stash = stashes.Create (gm, GetStashName ("_tmp_"));
					monitor.Step (1);
				}

				RebaseCommand rebase = git.Rebase ();
				rebase.SetOperation (RebaseCommand.Operation.BEGIN);
				rebase.SetUpstream (upstreamRef);
				var gmonitor = new GitMonitor (monitor);
				rebase.SetProgressMonitor (gmonitor);
				
				bool aborted = false;
				
				try {
					var result = rebase.Call ();
					while (!aborted && result.GetStatus () == RebaseResult.Status.STOPPED) {
						rebase = git.Rebase ();
						rebase.SetProgressMonitor (gmonitor);
						rebase.SetOperation (RebaseCommand.Operation.CONTINUE);
						bool commitChanges = true;
						var conflicts = GitUtil.GetConflictedFiles (RootRepository);
						foreach (string conflictFile in conflicts) {
							ConflictResult res = ResolveConflict (RootRepository.FromGitPath (conflictFile));
							if (res == ConflictResult.Abort) {
								aborted = true;
								commitChanges = false;
								rebase.SetOperation (RebaseCommand.Operation.ABORT);
								break;
							} else if (res == ConflictResult.Skip) {
								rebase.SetOperation (RebaseCommand.Operation.SKIP);
								commitChanges = false;
								break;
							}
						}
						if (commitChanges) {
							NGit.Api.AddCommand cmd = git.Add ();
							foreach (string conflictFile in conflicts)
								cmd.AddFilepattern (conflictFile);
							cmd.Call ();
						}
						result = rebase.Call ();
					}

					if ((options & GitUpdateOptions.UpdateSubmodules) == GitUpdateOptions.UpdateSubmodules) {
						monitor.Log.WriteLine (GettextCatalog.GetString ("Updating repository submodules"));
						var submoduleUpdate = git.SubmoduleUpdate ();
						foreach (var submodule in UpdateSubmodules)
							submoduleUpdate.AddPath (submodule);

						submoduleUpdate.Call ();
					}
				} catch {
					if (!aborted) {
						rebase = git.Rebase ();
						rebase.SetOperation (RebaseCommand.Operation.ABORT);
						rebase.SetProgressMonitor (gmonitor);
						rebase.Call ();
					}
					throw;
				} finally {
					gmonitor.Dispose ();
				}
				
			} finally {
				if ((options & GitUpdateOptions.SaveLocalChanges) == GitUpdateOptions.SaveLocalChanges)
					monitor.Step (1);
				
				// Restore local changes
				if (stash != null) {
					monitor.Log.WriteLine (GettextCatalog.GetString ("Restoring local changes"));
					using (var gm = new GitMonitor (monitor))
						stash.Apply (gm);
					stashes.Remove (stash);
				}
				monitor.EndTask ();
			}
		}
		public void Merge (string branch, GitUpdateOptions options, ProgressMonitor monitor, FastForwardStrategy strategy = FastForwardStrategy.Default)
		{
			int stashIndex = -1;
			var oldHead = RootRepository.Head.Tip;

			Signature sig = GetSignature ();
			if (sig == null)
				return;

			try {
				monitor.BeginTask (GettextCatalog.GetString ("Merging"), 5);
				CommonPreMergeRebase (options, monitor, out stashIndex);

				// Do a merge.
				MergeResult mergeResult = RootRepository.Merge (branch, sig, new MergeOptions {
					CheckoutNotifyFlags = refreshFlags,
					OnCheckoutNotify = RefreshFile,
				});

				if (mergeResult.Status == MergeStatus.Conflicts)
					ConflictResolver (monitor, RootRepository.Head.Tip, RootRepository.Info.Message);
			} finally {
				CommonPostMergeRebase (stashIndex, GitUpdateOptions.SaveLocalChanges, monitor, oldHead);
			}
		}
		public void Rebase (string branch, GitUpdateOptions options, ProgressMonitor monitor)
		{
			int stashIndex = -1;
			var oldHead = RootRepository.Head.Tip;

			try {
				monitor.BeginTask (GettextCatalog.GetString ("Rebasing"), 5);
				if (!CommonPreMergeRebase (options, monitor, out stashIndex))
					return;

				// Do a rebase.
				var divergence = RootRepository.ObjectDatabase.CalculateHistoryDivergence (RootRepository.Head.Tip, RootRepository.Branches [branch].Tip);
				var toApply = RootRepository.Commits.QueryBy (new CommitFilter {
					IncludeReachableFrom = RootRepository.Head.Tip,
					ExcludeReachableFrom = divergence.CommonAncestor,
					SortBy = CommitSortStrategies.Topological | CommitSortStrategies.Reverse
				}).ToArray ();

				RootRepository.Reset (ResetMode.Hard, divergence.Another);

				int count = toApply.Length;
				int i = 1;
				foreach (var com in toApply) {
					monitor.Log.WriteLine ("Cherry-picking {0} - {1}/{2}", com.Id, i, count);
					CherryPickResult cherryRes = RootRepository.CherryPick (com, com.Author, new CherryPickOptions {
						CheckoutNotifyFlags = refreshFlags,
						OnCheckoutNotify = RefreshFile,
					});
					if (cherryRes.Status == CherryPickStatus.Conflicts)
						ConflictResolver(monitor, toApply.Last(), RootRepository.Info.Message ?? com.Message);
					++i;
				}
			} finally {
				CommonPostMergeRebase (stashIndex, options, monitor, oldHead);
			}
		}
		void CommonPostMergeRebase(int stashIndex, GitUpdateOptions options, ProgressMonitor monitor, Commit oldHead)
		{
			if ((options & GitUpdateOptions.SaveLocalChanges) == GitUpdateOptions.SaveLocalChanges) {
				monitor.Step (1);

				// Restore local changes
				if (stashIndex != -1) {
					monitor.Log.WriteLine (GettextCatalog.GetString ("Restoring local changes"));
					ApplyStash (monitor, stashIndex);
					// FIXME: No StashApplyStatus.Conflicts here.
					if (RootRepository.Index.Conflicts.Any () && !ConflictResolver (monitor, oldHead, string.Empty))
						PopStash (monitor, stashIndex);
					else
						RootRepository.Stashes.Remove (stashIndex);

					monitor.Step (1);
				}
			}
			monitor.EndTask ();
		}
		bool CommonPreMergeRebase (GitUpdateOptions options, ProgressMonitor monitor, out int stashIndex)
		{
			stashIndex = -1;
			monitor.Step (1);

			if ((options & GitUpdateOptions.SaveLocalChanges) != GitUpdateOptions.SaveLocalChanges) {
				const VersionStatus unclean = VersionStatus.Modified | VersionStatus.ScheduledAdd | VersionStatus.ScheduledDelete;
				bool modified = false;
				if (GetDirectoryVersionInfo (RootPath, false, true).Any (v => (v.Status & unclean) != VersionStatus.Unversioned))
					modified = true;

				if (modified) {
					if (MessageService.GenericAlert (
						    MonoDevelop.Ide.Gui.Stock.Question,
						    GettextCatalog.GetString ("You have uncommitted changes"),
						    GettextCatalog.GetString ("What do you want to do?"),
						    AlertButton.Cancel,
						    new AlertButton ("Stash")) == AlertButton.Cancel)
						return false;

					options |= GitUpdateOptions.SaveLocalChanges;
				}
			}
			if ((options & GitUpdateOptions.SaveLocalChanges) == GitUpdateOptions.SaveLocalChanges) {
				monitor.Log.WriteLine (GettextCatalog.GetString ("Saving local changes"));
				Stash stash;
				if (!TryCreateStash (monitor, GetStashName ("_tmp_"), out stash))
					return false;

				if (stash != null)
					stashIndex = 0;
				monitor.Step (1);
			}
			return true;
		}
		public void Rebase (string upstreamRef, GitUpdateOptions options, IProgressMonitor monitor)
		{
			StashCollection stashes = GitUtil.GetStashes (RootRepository);
			Stash stash = null;
			NGit.Api.Git git = new NGit.Api.Git (RootRepository);
			try
			{
				monitor.BeginTask (GettextCatalog.GetString ("Rebasing"), 5);
				List<string> UpdateSubmodules = new List<string> ();

				// TODO: Fix stash so we don't have to do update before the main repo update.
				if ((options & GitUpdateOptions.UpdateSubmodules) == GitUpdateOptions.UpdateSubmodules) {
					monitor.Log.WriteLine (GettextCatalog.GetString ("Checking repository submodules"));
					if (!GetSubmodulesToUpdate (UpdateSubmodules))
						return;

					monitor.Log.WriteLine (GettextCatalog.GetString ("Updating repository submodules"));
					var submoduleUpdate = git.SubmoduleUpdate ();
					foreach (var submodule in UpdateSubmodules)
						submoduleUpdate.AddPath (submodule);

					submoduleUpdate.Call ();
					monitor.Step (1);
				}

				if ((options & GitUpdateOptions.SaveLocalChanges) == GitUpdateOptions.SaveLocalChanges) {
					monitor.Log.WriteLine (GettextCatalog.GetString ("Saving local changes"));
					using (var gm = new GitMonitor (monitor))
						stash = stashes.Create (gm, GetStashName ("_tmp_"));
					monitor.Step (1);
				}

				RebaseCommand rebase = git.Rebase ();
				rebase.SetOperation (RebaseCommand.Operation.BEGIN);
				rebase.SetUpstream (upstreamRef);
				var gmonitor = new GitMonitor (monitor);
				rebase.SetProgressMonitor (gmonitor);
				
				bool aborted = false;
				
				try {
					var result = rebase.Call ();
					while (!aborted && result.GetStatus () == RebaseResult.Status.STOPPED) {
						rebase = git.Rebase ();
						rebase.SetProgressMonitor (gmonitor);
						rebase.SetOperation (RebaseCommand.Operation.CONTINUE);
						bool commitChanges = true;
						var conflicts = GitUtil.GetConflictedFiles (RootRepository);
						foreach (string conflictFile in conflicts) {
							ConflictResult res = ResolveConflict (RootRepository.FromGitPath (conflictFile));
							if (res == ConflictResult.Abort) {
								aborted = true;
								commitChanges = false;
								rebase.SetOperation (RebaseCommand.Operation.ABORT);
								break;
							} else if (res == ConflictResult.Skip) {
								rebase.SetOperation (RebaseCommand.Operation.SKIP);
								commitChanges = false;
								break;
							}
						}
						if (commitChanges) {
							NGit.Api.AddCommand cmd = git.Add ();
							foreach (string conflictFile in conflicts)
								cmd.AddFilepattern (conflictFile);
							cmd.Call ();
						}
						result = rebase.Call ();
					}

					if ((options & GitUpdateOptions.UpdateSubmodules) == GitUpdateOptions.UpdateSubmodules) {
						monitor.Log.WriteLine (GettextCatalog.GetString ("Updating repository submodules"));
						var submoduleUpdate = git.SubmoduleUpdate ();
						foreach (var submodule in UpdateSubmodules)
							submoduleUpdate.AddPath (submodule);

						submoduleUpdate.Call ();
						monitor.Step (1);
					}
				} catch {
					if (!aborted) {
						rebase = git.Rebase ();
						rebase.SetOperation (RebaseCommand.Operation.ABORT);
						rebase.SetProgressMonitor (gmonitor);
						rebase.Call ();
					}
					throw;
				} finally {
					gmonitor.Dispose ();
				}
				
			} finally {
				if ((options & GitUpdateOptions.SaveLocalChanges) == GitUpdateOptions.SaveLocalChanges)
					monitor.Step (1);
				
				// Restore local changes
				if (stash != null) {
					monitor.Log.WriteLine (GettextCatalog.GetString ("Restoring local changes"));
					using (var gm = new GitMonitor (monitor))
						stash.Apply (gm);
					stashes.Remove (stash);
				}
				monitor.EndTask ();
			}
		}
		void CommonPostMergeRebase(int stashIndex, GitUpdateOptions options, IProgressMonitor monitor)
		{
			if ((options & GitUpdateOptions.SaveLocalChanges) == GitUpdateOptions.SaveLocalChanges) {
				monitor.Step (1);

				// Restore local changes
				if (stashIndex != -1) {
					monitor.Log.WriteLine (GettextCatalog.GetString ("Restoring local changes"));
					PopStash (monitor, stashIndex);
					monitor.Step (1);
				}
			}
			monitor.EndTask ();
		}