public void AssertCleanWorkspace(string repodir) { var repo = new LibGit2Sharp.Repository(Path.Combine(Workdir, repodir)); var status = repo.Index.RetrieveStatus(); var statusString = String.Join("\n", status.Select(statusEntry => "" + statusEntry.State + ": " + statusEntry.FilePath).ToArray()); Assert.AreEqual("", statusString, "repo status"); }
public IActionResult Branches(string repositoryId) { var operation = TableOperation.Retrieve<TableStorage.Entities.Repository>("1", repositoryId); var result = _storage.Repositories.Execute(operation); var repositoryEntity = result.Result as TableStorage.Entities.Repository; if (repositoryEntity == null) { return new ObjectResult(_errorFactory.RepositoryNotFound()); } var branches = new List<Branch>(); using (var repo = new LibGit2Sharp.Repository(repositoryEntity.Path)) { foreach (var branch in repo.Branches) { branches.Add(new Branch { Name = branch.Name, CanonicalName = branch.CanonicalName }); } return new ObjectResult(branches); } }
/// <summary> /// Loads branches and commits. /// </summary> /// <param name="repo"></param> private void LoadBranchesAndCommits(LibGit2Sharp.Repository repo = null) { var dispose = false; if (repo == null) { repo = new LibGit2Sharp.Repository(RepositoryFullPath); dispose = true; } // Small performance boosts. Commits.DisableNotifications(); Branches.DisableNotifications(); // Create commits. Commits.Clear(); var commitList = new List<Commit>(); foreach (var commit in repo.Commits.QueryBy(new LibGit2Sharp.Filter { Since = repo.Branches }).Take(CommitsPerPage)) { commitList.Add(Commit.Create(repo, commit, Tags)); } Commits.AddRange(commitList); // Create branches. Branches.Clear(); foreach (var branch in repo.Branches) { var b = Branch.Create(this, repo, branch); Branches.Add(b); } // Post-process branches (tips and tracking branches). foreach (var branch in Branches) { // Set the HEAD property if it matches. if (repo.Head.Name == branch.Name) { Head = branch; branch.Tip.IsHead = true; } branch.PostProcess(Branches, Commits); } // Post-process commits (commit parents). foreach (var commit in Commits) { // Set the HEAD property to a DetachedHead branch if the HEAD matched and it was null. if (Head == null && repo.Head.Tip.Sha == commit.Hash) { Head = new DetachedHead { Tip = commit }; commit.IsHead = true; } commit.PostProcess(Commits, Branches); } // Calculate commit visual positions for each branch tree. foreach (var branch in Branches) { RepoUtil.IncrementCommitTreeVisualPositionsRecursively(branch.Tip); } // Fire notifications for the collections on the UI thread. Application.Current.Dispatcher.Invoke( DispatcherPriority.Normal, (Action) (() => { Commits.EnableNotifications(true); Branches.EnableNotifications(true); var tabControl = UIHelper.FindChild<TabControl>(Application.Current.MainWindow, "RepositoryTabs"); var changesetHistory = UIHelper.FindChild<ChangesetHistory>(tabControl); if (changesetHistory != null) changesetHistory.RedrawGraph(); }) ); if (dispose) repo.Dispose(); }
/// <summary> /// Resets (reset --soft) the repository to the given changeset. /// </summary> /// <param name="action"></param> public void ResetSoft(object action) { var commit = action as Commit; if (commit == null) return; Task.Run(() => { using (var repo = new LibGit2Sharp.Repository(RepositoryFullPath)) { repo.Reset(LibGit2Sharp.ResetOptions.Mixed, commit.Hash); LoadEntireRepository(); } }); }
/// <summary> /// Loads the repository status (modified, added, removed). /// </summary> private void LoadRepositoryStatus(LibGit2Sharp.Repository repo = null) { var dispose = false; if (repo == null) { repo = new LibGit2Sharp.Repository(RepositoryFullPath); dispose = true; } // A small performance boost. StatusItemsStaged.DisableNotifications(); StatusItemsUnstaged.DisableNotifications(); StatusItemsStaged.Clear(); StatusItemsUnstaged.Clear(); // Load status items. var itemList = new List <StatusItem>(); var status = repo.Index.RetrieveStatus(); foreach (var fileStatus in status) { foreach (LibGit2Sharp.FileStatus value in Enum.GetValues(typeof(LibGit2Sharp.FileStatus))) { var isSet = fileStatus.State.HasFlag(value); if (isSet == false || value.ToString() == "Unaltered" || value.ToString() == "Ignored") { continue; } // TODO: would it be better without full repo path? var fileFullPath = RepositoryFullPath + "/" + fileStatus.FilePath; // Only those enum statuses that were set will generate a row in the status grid (and those that are not ignored/unaltered). var item = new StatusItem { Filename = fileStatus.FilePath, Status = value, Size = FileUtil.GetFormattedFileSize(fileFullPath), // TODO: Should these two file IO be done lazily? IsBinary = FileUtil.IsBinaryFile(fileFullPath) ? "Yes" : "-" }; itemList.Add(item); } } StatusItemsStaged.AddRange(itemList.Where(s => s.IsStaged)); StatusItemsUnstaged.AddRange(itemList.Where(s => !s.IsStaged)); if (dispose) { repo.Dispose(); } // Fire notifications for the collection on the UI thread. Application.Current.Dispatcher.Invoke( DispatcherPriority.Normal, (Action)( () => { StatusItemsStaged.EnableNotifications(true); StatusItemsUnstaged.EnableNotifications(true); } ) ); }
/// <summary> /// Stages or unstages the selected item. /// </summary> /// <param name="action"></param> private void StageUnstage(object action) { var collection = (IList) action; var items = collection.Cast<StatusItem>(); var repo = new LibGit2Sharp.Repository(RepositoryFullPath); foreach (StatusItem item in items) { if (item.GenericStatus == "Staged") repo.Index.Unstage(RepositoryFullPath + "/" + item.Filename); else repo.Index.Stage(RepositoryFullPath + "/" + item.Filename); } repo.Dispose(); }
/// <summary> /// Deletes a file or many. /// </summary> /// <param name="action"></param> private void DeleteFile(object action) { var dialog = new ConfirmDialog { Title = "Delete file(s)", Message = "Are you sure you want to delete the selected file(s)?\r\n\r\nYou may lose your changes!", ButtonSet = ConfirmDialog.ButtonsSet.OK_CANCEL }; dialog.ShowDialog(); var pressedButton = (Button) dialog.PressedButton; if (pressedButton != null && ((string) pressedButton.Content) == "OK") { var collection = (IList) action; var items = collection.Cast<StatusItem>(); LibGit2Sharp.Repository repo = null; // Loop through all selected status items and remove the files physically (and in some cases also from the repository). foreach (StatusItem item in items) { // TODO: --cached ? File.Delete(RepositoryFullPath + "/" + item.Filename); if (!item.Status.HasFlag(LibGit2Sharp.FileStatus.Untracked)) { if (!(repo is LibGit2Sharp.Repository)) repo = new LibGit2Sharp.Repository(RepositoryFullPath); repo.Index.Unstage(RepositoryFullPath + "/" + item.Filename); } } if (repo is LibGit2Sharp.Repository) repo.Dispose(); } }
/// <summary> /// Loads and constructs the entire repository. /// /// This will limit the amount of changesets to CommitsPerPage. /// </summary> public void LoadEntireRepository() { using (var repo = new LibGit2Sharp.Repository(RepositoryFullPath)) { LoadTags(repo); LoadBranchesAndCommits(repo); LoadRepositoryStatus(); LoadRecentCommitMessages(); ListenToDirectoryChanges(); } }
/// <summary> /// Copies the given changeset as a patch to clipboard. /// </summary> /// <param name="action"></param> public void CopyPatch(object action) { Commit commit = action as Commit; using (var repo = new LibGit2Sharp.Repository(RepositoryFullPath)) { Clipboard.SetText(RepoUtil.GetTreeChangesForCommit(repo, commit).Patch); } }
public static bool GetHeadSha( Build build, string repositoryDirectory, Action <string> log) { if (build == null) { throw new ArgumentNullException("build"); } if (String.IsNullOrEmpty(repositoryDirectory)) { throw new ArgumentNullException("repositoryDirectory"); } if (log == null) { throw new ArgumentNullException("log"); } log("STEP: Getting HEAD's SHA."); return(RunStep(() => { if (!string.IsNullOrEmpty(build.Revision)) { log(String.Format("Build #{0} already has a SHA. Skipping.", build.Id)); return true; } var repo = (LibGit2Sharp.Repository)null; try { repo = new LibGit2Sharp.Repository(repositoryDirectory); } catch (Exception ex) { log(String.Format("ERROR: Could not get repository at {0} via LibGit2Sharp. Exception: ", repositoryDirectory)); log(ex.ToString()); return false; } var head = (LibGit2Sharp.Reference)null; try { string @ref; if (build.Ref.StartsWith("refs/heads/", StringComparison.OrdinalIgnoreCase)) { var branch = build.Ref.Substring(11); @ref = String.Format("refs/remotes/origin/{0}", branch); } else if (build.Ref.StartsWith("refs/pull", StringComparison.OrdinalIgnoreCase)) { var slashafterPrNumberIndex = build.Ref.IndexOf("/", 10, StringComparison.InvariantCultureIgnoreCase); var prNumber = build.Ref.Substring(10, slashafterPrNumberIndex - 10); @ref = String.Concat("refs/remotes/origin/pr/", prNumber); } else { throw new InvalidOperationException(String.Format("Unexpected type of ref: {0}.", build.Ref)); } head = repo.Refs[@ref]; if (head == null) { throw new InvalidOperationException(String.Format("The specified ref, '{0}', does not exist.", @ref)); } } catch (Exception ex) { log(String.Format("ERROR: Could not get HEAD for ref {0}. Exception: ", build.Ref)); log(ex.ToString()); return false; } log(String.Format("Setting SHA to {0}.", head.TargetIdentifier)); SetBuildRevision(build, head.TargetIdentifier); return true; }, log)); }
protected override async Task OnExecute(CommandLineApplication app) { var gitDirectory = LibGit2Sharp.Repository.Discover("."); using (var repository = new LibGit2Sharp.Repository(gitDirectory)) { var head = repository.Head; var trackedBranch = head.TrackedBranch; if (trackedBranch is null) { Console.WriteLine($"Current branch '{head.FriendlyName}' isn't tracking a remote."); return; } var upstreamBranchCanonicalName = trackedBranch.UpstreamBranchCanonicalName; var branchName = ToBranchName(upstreamBranchCanonicalName); var remoteUrl = new UriString(repository.Network.Remotes[trackedBranch.RemoteName].Url); var pullRequestStates = new[] { PullRequestState.Open, PullRequestState.Closed, PullRequestState.Merged }; var query = new Query() .Repository(owner: remoteUrl.Owner, name: remoteUrl.RepositoryName) .Ref(upstreamBranchCanonicalName) .Select(r => new { Repository = r.Repository.NameWithOwner, ForkedFrom = r.Repository.Parent != null ? r.Repository.Parent.NameWithOwner : null, r.Target.Oid, PullRequests = r.AssociatedPullRequests(100, null, null, null, null, branchName, null, null, pullRequestStates).Nodes.Select(pr => new { Repository = pr.Repository.NameWithOwner, pr.Number, pr.Title, pr.Url, Author = pr.Author != null ? pr.Author.Login : null, pr.CreatedAt, pr.AuthorAssociation, pr.State, pr.HeadRefName, HeadRepository = pr.HeadRepository.NameWithOwner, pr.BaseRefName, BaseRepository = pr.BaseRef != null ? pr.BaseRef.Repository.NameWithOwner : null, pr.HeadRefOid }).ToList() }).Compile(); var connection = CreateConnection(remoteUrl); var result = await connection.Run(query); Console.WriteLine(result.ForkedFrom is null ? result.Repository : $"{result.Repository} forked from {result.ForkedFrom}"); Console.WriteLine(result.Oid == trackedBranch.Tip.Sha ? "No new commits" : "There are new commits!"); var prs = result.PullRequests .Where(pr => pr.HeadRepository == pr.Repository); // Only show incoming pull requests if (prs.Count() == 0) { Console.WriteLine("No associated pull requests"); } else { Console.WriteLine(@" Associated pull requests:"); foreach (var pr in prs) { Console.WriteLine( @$ "{pr.Repository} - {pr.Title} [{pr.State}] #{pr.Number} opened on {pr.CreatedAt:D} by {pr.Author} ({pr.AuthorAssociation})"); } Console.WriteLine(); } } }
/// <summary> /// We used to group commits in a tree object so there would be only one commit per /// change but this doesn't work for trees that end up being too big (around 20K files). /// By using LibGit2Sharp we still group changes in one and we don't need to create a new /// tree. Everything happens locally in the host executing the push. /// </summary> /// <param name="filesToCommit">Collection of files to update.</param> /// <param name="repoUri">The repository to push the files to.</param> /// <param name="branch">The branch to push the files to.</param> /// <param name="commitMessage">The commmit message.</param> /// <returns></returns> protected async Task CommitFilesAsync( List <GitFile> filesToCommit, string repoUri, string branch, string commitMessage, ILogger _logger, string pat) { string dotnetMaestro = "dotnet-maestro"; using (_logger.BeginScope("Pushing files to {branch}", branch)) { string tempRepoFolder = Path.Combine(TemporaryRepositoryPath, Path.GetRandomFileName()); try { string repoPath = LibGit2Sharp.Repository.Clone( repoUri, tempRepoFolder, new LibGit2Sharp.CloneOptions { BranchName = branch, Checkout = true, CredentialsProvider = (url, user, cred) => new LibGit2Sharp.UsernamePasswordCredentials { // The PAT is actually the only thing that matters here, the username // will be ignored. Username = dotnetMaestro, Password = pat } }); using (LibGit2Sharp.Repository localRepo = new LibGit2Sharp.Repository(repoPath)) { foreach (GitFile file in filesToCommit) { string filePath = Path.Combine(tempRepoFolder, file.FilePath); if (file.Operation == GitFileOperation.Add) { if (!File.Exists(filePath)) { string parentFolder = Directory.GetParent(filePath).FullName; Directory.CreateDirectory(parentFolder); } using (FileStream stream = File.Create(filePath)) { byte[] contentBytes = GetUtf8ContentBytes(file.Content, file.ContentEncoding); await stream.WriteAsync(contentBytes, 0, contentBytes.Length); } } else { File.Delete(Path.Combine(tempRepoFolder, file.FilePath)); } } LibGit2Sharp.Commands.Stage(localRepo, "*"); LibGit2Sharp.Signature author = new LibGit2Sharp.Signature(dotnetMaestro, $"@{dotnetMaestro}", DateTime.Now); LibGit2Sharp.Signature commiter = author; localRepo.Commit(commitMessage, author, commiter, new LibGit2Sharp.CommitOptions { AllowEmptyCommit = false, PrettifyMessage = true }); localRepo.Network.Push(localRepo.Branches[branch], new LibGit2Sharp.PushOptions { CredentialsProvider = (url, user, cred) => new LibGit2Sharp.UsernamePasswordCredentials { // The PAT is actually the only thing that matters here, the username // will be ignored. Username = dotnetMaestro, Password = pat } }); } } catch (LibGit2Sharp.EmptyCommitException) { _logger.LogInformation("There was nothing to commit..."); } catch (Exception exc) { // This was originally a DarcException. Making it an actual Exception so we get to see in AppInsights if something failed while // commiting the changes throw new Exception($"Something went wrong when pushing the files to repo {repoUri} in branch {branch}", exc); } finally { try { // Libgit2Sharp behaves similarly to git and marks files under the .git/objects hierarchy as read-only, // thus if the read-only attribute is not unset an UnauthorizedAccessException is thrown. GitFileManager.NormalizeAttributes(tempRepoFolder); Directory.Delete(tempRepoFolder, true); } catch (DirectoryNotFoundException) { // If the directory wasn't found, that means that the clone operation above failed // but this error isn't interesting at all. } } } }
public static bool IsGitHubRepository(this LibGit2Sharp.Repository repository) => repository?.Network.Remotes .Where(x => x.Name == "origin") .Select(x => x.Url.Contains("github.com")) .FirstOrDefault() ?? false;
/// <summary> /// Clone a remote git repo. /// </summary> /// <param name="repoUri">Repository uri to clone</param> /// <param name="commit">Branch, commit, or tag to checkout</param> /// <param name="targetDirectory">Target directory to clone to</param> /// <param name="gitDirectory">Location for the .git directory, or null for default</param> /// <returns></returns> protected void Clone(string repoUri, string commit, string targetDirectory, ILogger _logger, string pat, string gitDirectory) { string dotnetMaestro = "dotnet-maestro"; LibGit2Sharp.CloneOptions cloneOptions = new LibGit2Sharp.CloneOptions { Checkout = false, CredentialsProvider = (url, user, cred) => new LibGit2Sharp.UsernamePasswordCredentials { // The PAT is actually the only thing that matters here, the username // will be ignored. Username = dotnetMaestro, Password = pat }, }; using (_logger.BeginScope("Cloning {repoUri} to {targetDirectory}", repoUri, targetDirectory)) { try { _logger.LogDebug($"Cloning {repoUri} to {targetDirectory}"); string repoPath = LibGit2Sharp.Repository.Clone( repoUri, targetDirectory, cloneOptions); LibGit2Sharp.CheckoutOptions checkoutOptions = new LibGit2Sharp.CheckoutOptions { CheckoutModifiers = LibGit2Sharp.CheckoutModifiers.Force, }; _logger.LogDebug($"Reading local repo from {repoPath}"); using (LibGit2Sharp.Repository localRepo = new LibGit2Sharp.Repository(repoPath)) { if (commit == null) { commit = localRepo.Head.Reference.TargetIdentifier; _logger.LogInformation($"Repo {localRepo.Info.WorkingDirectory} has no commit to clone at, assuming it's {commit}"); } try { _logger.LogDebug($"Attempting to checkout {commit} as commit in {localRepo.Info.WorkingDirectory}"); LibGit2Sharp.Commands.Checkout(localRepo, commit, checkoutOptions); } catch { _logger.LogDebug($"Failed to checkout {commit} as commit, trying to resolve"); string resolvedReference = ParseReference(localRepo, commit, _logger); _logger.LogDebug($"Resolved {commit} to {resolvedReference ?? "<invalid>"} in {localRepo.Info.WorkingDirectory}, attempting checkout"); LibGit2Sharp.Commands.Checkout(localRepo, resolvedReference, checkoutOptions); } } // LibGit2Sharp doesn't support a --git-dir equivalent yet (https://github.com/libgit2/libgit2sharp/issues/1467), so we do this manually if (gitDirectory != null) { Directory.Move(repoPath, gitDirectory); File.WriteAllText(repoPath.TrimEnd('\\', '/'), $"gitdir: {gitDirectory}"); } using (LibGit2Sharp.Repository localRepo = new LibGit2Sharp.Repository(targetDirectory)) { CheckoutSubmodules(localRepo, cloneOptions, gitDirectory, _logger); } } catch (Exception exc) { throw new Exception($"Something went wrong when cloning repo {repoUri} at {commit ?? "<default branch>"} into {targetDirectory}", exc); } } }
/// <summary> /// Loads the tags. /// </summary> private void LoadTags(LibGit2Sharp.Repository repo = null) { var dispose = false; if (repo == null) { repo = new LibGit2Sharp.Repository(RepositoryFullPath); dispose = true; } // Small performance boost. Tags.DisableNotifications(); Tags.Clear(); // Add new tags. foreach (var tag in repo.Tags) { var t = Tag.Create(repo, tag); if (t.HasCommitAsTarget) Tags.Add(t); } // Fire notifications for the Tags collection on the UI thread. Application.Current.Dispatcher.Invoke( DispatcherPriority.Normal, (Action) (() => Tags.EnableNotifications(true)) ); if (dispose) repo.Dispose(); }
internal async Task <IEnumerable <ReleaseInfo> > GetReleaseInfoAsync() { var repository = new LibGit2Sharp.Repository(_configuration.RepositoryPath); string origin = repository.Network.Remotes.First(r => r.Name == "origin").Url; string url = !origin.EndsWith(".git") ? $"{origin}.git" : origin; Console.WriteLine($"Analyzing Git Repository at '{new FileInfo(_configuration.RepositoryPath).FullName}'"); var orderedReleaseInfos = GetOrderedReleaseInfos(repository); Console.WriteLine($"Getting Issues and Pull Requests from '{url}'"); var result = await GetAllIssuesAndPullRequestsAsync(url).ConfigureAwait(false); bool IssueTimeIsLessThenReleaseTime(DateTimeOffset releaseTime, DateTimeOffset?issueClosedTime) => issueClosedTime < releaseTime.AddSeconds(DeltaSeconds); bool IssueTimeIsGreaterThenPreviousReleaseTime(int idx, DateTimeOffset?issueClosedTime) => idx <= 0 || issueClosedTime > orderedReleaseInfos[idx - 1].When.AddSeconds(DeltaSeconds); bool IssueLinkedToRelease(int idx, ReleaseInfo releaseInfo, DateTimeOffset?issueClosedAtTime) => IssueTimeIsLessThenReleaseTime(releaseInfo.When, issueClosedAtTime) && IssueTimeIsGreaterThenPreviousReleaseTime(idx, issueClosedAtTime); // Loop all orderedReleaseInfos and add the correct Pull Requests and Issues foreach (var x in orderedReleaseInfos.Select((releaseInfo, index) => new { index, releaseInfo })) { // Process only Issues var issuesForThisTag = result.Issues.Where(issue => issue.PullRequest == null && IssueLinkedToRelease(x.index, x.releaseInfo, issue.ClosedAt)); var issueInfos = issuesForThisTag.Select(issue => new IssueInfo { Number = issue.Number, IsPulRequest = false, IssueUrl = issue.HtmlUrl, Title = issue.Title, User = issue.User.Login, UserUrl = issue.User.HtmlUrl, Labels = issue.Labels.Select(label => label.Name).ToArray() }); // Process PullRequests var pullsForThisTag = result.PullRequests.Where(pullRequest => IssueLinkedToRelease(x.index, x.releaseInfo, pullRequest.ClosedAt)); var pullInfos = pullsForThisTag.Select(pull => new IssueInfo { Number = pull.Number, IsPulRequest = true, IssueUrl = pull.HtmlUrl, Title = pull.Title, User = pull.User.Login, UserUrl = pull.User.HtmlUrl, Labels = result.Issues .First(issue => issue.Number == pull.Number).Labels // Get the labels from the Issues (because this is not present in the 'PullRequest') .Select(label => label.Name) .ToArray() }); bool ExcludeIssue(string[] labels) => _configuration.ExcludeLabels != null && _configuration.ExcludeLabels.Any(s => labels.Contains(s, StringComparer.OrdinalIgnoreCase)); var allIssues = issueInfos.Union(pullInfos) .Distinct() .Where(issueInfo => !ExcludeIssue(issueInfo.Labels)); x.releaseInfo.IssueInfos = allIssues.OrderByDescending(issue => issue.IsPulRequest).ThenBy(issue => issue.Number).ToList(); } if (_configuration.SkipEmptyReleases) { orderedReleaseInfos = orderedReleaseInfos.Where(r => r.IssueInfos.Count > 0).ToList(); } return(orderedReleaseInfos.OrderByDescending(r => r.Version)); }
/// <summary> /// This methods draws the graph for the changeset history grid. /// </summary> public void Draw(ItemCollection commitList) { if (graph == null) return; Console.WriteLine("Drawing graph."); var repo = new LibGit2Sharp.Repository(repositoryViewModel.RepositoryFullPath); commitDotPositions.Clear(); SetBranchColors(repo.Branches); // Loop through all commits and draw the graph, in reverse order. commitList.MoveCurrentToLast(); // Clear the existing graph. graph.Children.Clear(); TotalHeight = 0; while (true) { Commit commit = commitList.CurrentItem as Commit; int rowNumber = commitList.CurrentPosition; if (commit == null) break; // Get a list of branches around this commit. List<Branch> branchesAroundCommit = commit.BranchesAround; // Sort the lists alphabetically. branchesAroundCommit.OrderBy(o => o.Name.ToString()); // Retrieve the index of this commit's branch on the list. This index determines the horizontal positions of dots (commit dots). int indexOfCurrentBranch; if (commit.Branches.Count > 0) indexOfCurrentBranch = branchesAroundCommit.IndexOf(commit.Branches.ElementAt(0)); else indexOfCurrentBranch = 0; int horizontalIndex = indexOfCurrentBranch + commit.VisualPosition; for (var i = indexOfCurrentBranch - 1; i >= 0; i--) horizontalIndex += ((Branch) branchesAroundCommit.ElementAt(i)).RightMostVisualPosition; // Draw the dot/ellipse based on the index of the current branch. byte dotSize = 10; byte horizontalDotSpacing = 12; int dotX = horizontalDotSpacing + dotSize * horizontalIndex + horizontalDotSpacing * horizontalIndex; int dotY = cellHeight * rowNumber + cellHeight / 2 - dotSize / 2; if (TotalHeight == 0) TotalHeight = cellHeight * (rowNumber + 1); // Store the dot position on the dictionary. commitDotPositions.Add(commit.Hash, new int[2] { dotX, dotY }); Ellipse dot = new Ellipse { Fill = Brushes.Black, StrokeThickness = 0, Width = dotSize + 2, Height = dotSize + 2 }; Canvas.SetLeft(dot, dotX - 1); Canvas.SetTop(dot, dotY - 1); Canvas.SetZIndex(dot, 1); graph.Children.Add(dot); // ToolTip for commits. var commitTooltip = new TextBlock { MaxWidth = 320, TextWrapping = TextWrapping.Wrap }; // ToolTip for paths. var pathTooltip = new TextBlock { MaxWidth = 320, TextWrapping = TextWrapping.Wrap }; if (commit.Branches.Count == 1) { pathTooltip.Text = commit.Branches.ElementAt(0).Name; } else { int i = 0, count = commit.Branches.Count; commit.Branches.ForEach(b => { i++; pathTooltip.Inlines.AddRange(new Inline[] { new Run(b.Name + (i < count ? ", " : "")), }); }); } // Regular commits have a white circle inside. if (commit.IsMergeCommit() == false && commit.ParentCount < 2) { Ellipse dotInner = new Ellipse { Fill = Brushes.White, StrokeThickness = 0, Width = dotSize, Height = dotSize }; Canvas.SetLeft(dotInner, dotX); Canvas.SetTop(dotInner, dotY); Canvas.SetZIndex(dotInner, 2); graph.Children.Add(dotInner); // ToolTip. commitTooltip.Inlines.AddRange(new Inline[] { new Run("Commit: ") {FontWeight = FontWeights.Bold}, new Run(commit.HashShort) {Foreground = highlightColor, FontWeight = FontWeights.Bold}, new LineBreak(), new Run("Author: ") {FontWeight = FontWeights.Bold}, new Run(commit.AuthorName) , new LineBreak(), new Run("Date: ") {FontWeight = FontWeights.Bold}, new Run(commit.FormattedDate), new LineBreak(), new LineBreak(), new Run(commit.Description.TrimEnd()) }); dotInner.ToolTip = commitTooltip; ToolTipService.SetShowDuration(dotInner, 60000); ToolTipService.SetInitialShowDelay(dotInner, 1); } else { // Tooltip. commitTooltip.Inlines.AddRange(new Inline[] { new Run("Merge commit: ") {FontWeight = FontWeights.Bold}, new Run(commit.HashShort) {Foreground = highlightColor, FontWeight = FontWeights.Bold}, new LineBreak(), new Run("Author: ") {FontWeight = FontWeights.Bold}, new Run(commit.AuthorName) , new LineBreak(), new Run("Date: ") {FontWeight = FontWeights.Bold}, new Run(commit.FormattedDate), new LineBreak(), new LineBreak(), new Run(commit.Description.TrimEnd()) }); dot.ToolTip = commitTooltip; ToolTipService.SetShowDuration(dot, 60000); ToolTipService.SetInitialShowDelay(dot, 1); } if (commit.Branches.Count > 0) { // Draw the line to the parent dot(s)/commit(s). foreach (string hash in commit.ParentHashes) { // Retrieve the parent commit dot position. var positions = commitDotPositions.Where(o => o.Key == hash); if (positions.Count() > 0) { int[] parentPosition = commitDotPositions.Where(o => o.Key == hash).First().Value; Brush lineColor = BranchColors[commit.Branches.ElementAt(0).Name]; // Calculate line positions. float startLineX1 = dotX + dotSize / 2; float startLineY1 = dotY + dotSize / 2; float endLineX2 = parentPosition[0] + dotSize / 2; float endLineY2 = parentPosition[1] + dotSize / 2; float startLineX2; float startLineY2; float endLineX1; float endLineY1; if (commit.IsMergeCommit()) { startLineX2 = endLineX2; startLineY2 = startLineY1; endLineX1 = endLineX2; endLineY1 = startLineY1; } else { startLineX2 = startLineX1; startLineY2 = parentPosition[1] - cellHeight / 2 + dotSize / 2 + 6; endLineX1 = startLineX1; endLineY1 = parentPosition[1] - cellHeight / 2 + dotSize / 2 + 12; } // Construct and draw the line path. Path path = new Path { Stroke = lineColor, StrokeThickness = 4, Data = new PathGeometry { Figures = new PathFigureCollection { new PathFigure { StartPoint = new Point(startLineX1, startLineY1), Segments = new PathSegmentCollection { new PolyBezierSegment { Points = new PointCollection { new Point(startLineX2, startLineY2), new Point(endLineX1, endLineY1), new Point(endLineX2, endLineY2) } } } } } } }; graph.Children.Add(path); path.ToolTip = pathTooltip; ToolTipService.SetShowDuration(path, 60000); ToolTipService.SetInitialShowDelay(path, 1); } } } commitList.MoveCurrentToPrevious(); if (commitList.IsCurrentBeforeFirst) { break; } } repo.Dispose(); }
/// <summary> /// Updates local copies of the files. /// </summary> /// <param name="filesToCommit">Files to update locally</param> /// <param name="repoUri">Base path of the repo</param> /// <param name="branch">Unused</param> /// <param name="commitMessage">Unused</param> /// <returns></returns> public async Task CommitFilesAsync(List <GitFile> filesToCommit, string repoUri, string branch, string commitMessage) { string repoDir = LocalHelpers.GetRootDir(_gitExecutable, _logger); try { using (LibGit2Sharp.Repository localRepo = new LibGit2Sharp.Repository(repoDir)) { foreach (GitFile file in filesToCommit) { Debug.Assert(file != null, "Passed in a null GitFile in filesToCommit"); switch (file.Operation) { case GitFileOperation.Add: string parentDirectory = Directory.GetParent(file.FilePath).FullName; if (!Directory.Exists(parentDirectory)) { Directory.CreateDirectory(parentDirectory); } string fullPath = Path.Combine(repoUri, file.FilePath); using (var streamWriter = new StreamWriter(fullPath)) { string finalContent; switch (file.ContentEncoding) { case ContentEncoding.Utf8: finalContent = file.Content; break; case ContentEncoding.Base64: byte[] bytes = Convert.FromBase64String(file.Content); finalContent = Encoding.UTF8.GetString(bytes); break; default: throw new DarcException($"Unknown file content encoding {file.ContentEncoding}"); } finalContent = NormalizeLineEndings(fullPath, finalContent); await streamWriter.WriteAsync(finalContent); LibGit2SharpHelpers.AddFileToIndex(localRepo, file, fullPath, _logger); } break; case GitFileOperation.Delete: if (File.Exists(file.FilePath)) { File.Delete(file.FilePath); } break; } } } } catch (Exception exc) { throw new DarcException($"Something went wrong when checking out {repoUri} in {repoDir}", exc); } }
/// <summary> /// Creates a tag. /// </summary> /// <param name="action"></param> public void CreateTag(object action) { var dialog = new PromptDialog(); dialog.Title = "Create a new tag"; dialog.Message = "Enter the name for the tag:"; dialog.ShowDialog(); if (dialog.DialogResult == true) { Commit commit = action as Commit; using (var repo = new LibGit2Sharp.Repository(RepositoryFullPath)) { repo.Tags.Create(dialog.ResponseText, commit.Hash); LoadEntireRepository(); } } }
public static void PullFromRemote(string url, string path, Credentials credentials) { logger.InfoFormat("Start repository sync: {0}", path); if (!Directory.Exists(path)) { logger.Info("Repository does not exist"); logger.InfoFormat("Clone from {0}", url); var cloneOptions = new LibGit2Sharp.CloneOptions(); if (credentials != null) { cloneOptions.CredentialsProvider = (_url, _user, _cred) => new LibGit2Sharp.UsernamePasswordCredentials { Username = credentials.Username, Password = credentials.Password }; } LibGit2Sharp.Repository.Clone(url, path, cloneOptions); } else { logger.Info("Repository exists"); var fetchOptions = new LibGit2Sharp.FetchOptions(); if (credentials != null) { fetchOptions.CredentialsProvider = (_url, _user, _cred) => new LibGit2Sharp.UsernamePasswordCredentials { Username = credentials.Username, Password = credentials.Password }; } using (var repository = new LibGit2Sharp.Repository(path)) { foreach (var remote in repository.Network.Remotes) { IEnumerable <string> refSpecs = remote.FetchRefSpecs.Select(x => x.Specification); logger.InfoFormat("Fetch repository from {0}: {1}", remote.Name, remote.Url); LibGit2Sharp.Commands.Fetch(repository, remote.Name, refSpecs, fetchOptions, ""); } var branchesUpdated = 0; var branchesCreated = 0; foreach (var branch in repository.Branches.Where(b => b.IsRemote)) { var localBranchName = branch.FriendlyName.Replace(branch.RemoteName + "/", ""); if (repository.Branches[localBranchName] == null) { logger.InfoFormat("Branch does not exist: {0}", localBranchName); logger.InfoFormat("Create branch from {0}: {1}", branch.FriendlyName, branch.Tip.Sha.Substring(0, 7)); repository.Branches.Update( repository.Branches.Add(localBranchName, branch.Tip), b => b.TrackedBranch = branch.CanonicalName); branchesCreated++; } var localBranch = repository.Branches[localBranchName]; if (localBranch.Tip.Sha != branch.Tip.Sha) { //check out branch and reset logger.InfoFormat("Branch {0} is behind: {1}", localBranchName, localBranch.Tip.Sha.Substring(0, 7)); logger.InfoFormat("Fast-forward to {0}", branch.Tip.Sha.Substring(0, 7)); LibGit2Sharp.Commands.Checkout(repository, localBranchName); repository.Reset(LibGit2Sharp.ResetMode.Hard, branch.Tip); branchesUpdated++; } else { logger.InfoFormat("Branch {0} is in sync: {1}", localBranch.FriendlyName, localBranch.Tip.Sha.Substring(0, 7)); } } logger.InfoFormat("Created branches: {0}", branchesCreated); logger.InfoFormat("Updated branches: {0}", branchesUpdated); logger.InfoFormat("Repository sync ready: {0}", path); } } }
/// <summary> /// Updates the diff panel text. /// </summary> /// <param name="items"></param> public void UpdateStatusItemDiff(IList collection) { if (NotOpened == true) return; var diff = ""; var items = collection.Cast<StatusItem>(); using (var repo = new LibGit2Sharp.Repository(RepositoryFullPath)) { foreach (StatusItem item in items) { } diff += repo.Diff.Compare(repo.Head.Tip.Tree, LibGit2Sharp.DiffTarget.Index).Patch; } StatusItemDiff = diff; }
public static void InitializeRepository(string repoUri, string repoDirectory) { LibGit2Sharp.Repository.Init(repoDirectory); using (var repo = new LibGit2Sharp.Repository(repoDirectory)) repo.Network.Remotes.Add(origin, repoUri); }
/// <summary> /// Loads the repository status (modified, added, removed). /// </summary> private void LoadRepositoryStatus() { var repo = new LibGit2Sharp.Repository(RepositoryFullPath); StatusItems.Clear(); // Load status items. List<StatusItem> itemList = new List<StatusItem>(); LibGit2Sharp.RepositoryStatus status = repo.Index.RetrieveStatus(); foreach (LibGit2Sharp.StatusEntry fileStatus in status) { foreach (LibGit2Sharp.FileStatus value in Enum.GetValues(typeof(LibGit2Sharp.FileStatus))) { bool isSet = fileStatus.State.HasFlag(value); if (isSet == false || value.ToString() == "Unaltered" || value.ToString() == "Ignored") continue; string fileFullPath = RepositoryFullPath + "/" + fileStatus.FilePath; // Only those enum statuses that were set will generate a row in the status grid (and those that are not ignored/unaltered). StatusItem item = new StatusItem { Filename = fileStatus.FilePath, Status = value, Size = FileUtil.GetFormattedFileSize(fileFullPath), IsBinary = FileUtil.IsBinaryFile(fileFullPath) ? "Yes" : "-" }; itemList.Add(item); } } StatusItems.AddRange(itemList); repo.Dispose(); }
/// <summary> /// Initializes a new instance of the <see cref="VersionOracle"/> class. /// </summary> public VersionOracle(string projectDirectory, LibGit2Sharp.Repository repo, ICloudBuild cloudBuild, int?overrideBuildNumberOffset = null, string projectPathRelativeToGitRepoRoot = null) : this(projectDirectory, repo, null, cloudBuild, overrideBuildNumberOffset, projectPathRelativeToGitRepoRoot) { }
private void OnContentRendered(object sender, EventArgs e) { _repo = OpenPasswordRepository(); FillTreeView(); }
/// <summary> /// Initializes a new instance of the <see cref="VersionOracle"/> class. /// </summary> public VersionOracle(string projectDirectory, LibGit2Sharp.Repository repo, LibGit2Sharp.Commit head, ICloudBuild cloudBuild, int?overrideVersionHeightOffset = null, string projectPathRelativeToGitRepoRoot = null) { var repoRoot = repo?.Info?.WorkingDirectory?.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); var relativeRepoProjectDirectory = !string.IsNullOrWhiteSpace(repoRoot) ? (!string.IsNullOrEmpty(projectPathRelativeToGitRepoRoot) ? projectPathRelativeToGitRepoRoot : projectDirectory.Substring(repoRoot.Length).TrimStart(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)) : null; var commit = head ?? repo?.Head.Commits.FirstOrDefault(); var committedVersion = VersionFile.GetVersion(commit, relativeRepoProjectDirectory); var workingVersion = head != null?VersionFile.GetVersion(head, relativeRepoProjectDirectory) : VersionFile.GetVersion(projectDirectory); if (overrideVersionHeightOffset.HasValue) { if (committedVersion != null) { committedVersion.VersionHeightOffset = overrideVersionHeightOffset.Value; } if (workingVersion != null) { workingVersion.VersionHeightOffset = overrideVersionHeightOffset.Value; } } this.VersionOptions = committedVersion ?? workingVersion; this.GitCommitId = commit?.Id.Sha ?? cloudBuild?.GitCommitId ?? null; this.GitCommitDate = commit?.Author.When; this.VersionHeight = CalculateVersionHeight(relativeRepoProjectDirectory, commit, committedVersion, workingVersion); this.BuildingRef = cloudBuild?.BuildingTag ?? cloudBuild?.BuildingBranch ?? repo?.Head.CanonicalName; // Override the typedVersion with the special build number and revision components, when available. if (repo != null) { this.Version = GetIdAsVersion(commit, committedVersion, workingVersion, this.VersionHeight); } else { this.Version = this.VersionOptions?.Version.Version ?? Version0; } // get the commit id abbreviation only if the commit id is set if (!string.IsNullOrEmpty(this.GitCommitId)) { var gitCommitIdShortFixedLength = this.VersionOptions?.GitCommitIdShortFixedLength ?? VersionOptions.DefaultGitCommitIdShortFixedLength; var gitCommitIdShortAutoMinimum = this.VersionOptions?.GitCommitIdShortAutoMinimum ?? 0; // get it from the git repository if there is a repository present and it is enabled if (repo != null && gitCommitIdShortAutoMinimum > 0) { this.GitCommitIdShort = repo.ObjectDatabase.ShortenObjectId(commit, gitCommitIdShortAutoMinimum); } else { this.GitCommitIdShort = this.GitCommitId.Substring(0, gitCommitIdShortFixedLength); } } this.VersionHeightOffset = this.VersionOptions?.VersionHeightOffsetOrDefault ?? 0; this.PrereleaseVersion = this.ReplaceMacros(this.VersionOptions?.Version?.Prerelease ?? string.Empty); this.CloudBuildNumberOptions = this.VersionOptions?.CloudBuild?.BuildNumberOrDefault ?? VersionOptions.CloudBuildNumberOptions.DefaultInstance; if (!string.IsNullOrEmpty(this.BuildingRef) && this.VersionOptions?.PublicReleaseRefSpec?.Length > 0) { this.PublicRelease = this.VersionOptions.PublicReleaseRefSpec.Any( expr => Regex.IsMatch(this.BuildingRef, expr)); } }
/// <summary> /// Exports the given changeset as a patch to a file. /// </summary> /// <param name="action"></param> public void ExportPatch(object action) { var commit = action as Commit; if (commit == null) return; var dialog = new SaveFileDialog { FileName = commit.Description.Right(72), DefaultExt = ".patch", Filter = "Patch files|*.patch" }; if (dialog.ShowDialog() == false) return; var filename = dialog.FileName; Task.Run(() => { using (var repo = new LibGit2Sharp.Repository(RepositoryFullPath)) { File.WriteAllText(filename, RepoUtil.GetTreeChangesForCommit(repo, commit).Patch); } }); }
/// <summary> /// Checkout the repo to the specified state. /// </summary> /// <param name="commit">Tag, branch, or commit to checkout.</param> public void Checkout(string repoDir, string commit, bool force = false) { _logger.LogDebug($"Checking out {commit}", commit ?? "default commit"); LibGit2Sharp.CheckoutOptions checkoutOptions = new LibGit2Sharp.CheckoutOptions { CheckoutModifiers = force ? LibGit2Sharp.CheckoutModifiers.Force : LibGit2Sharp.CheckoutModifiers.None, }; try { _logger.LogDebug($"Reading local repo from {repoDir}"); using (LibGit2Sharp.Repository localRepo = new LibGit2Sharp.Repository(repoDir)) { if (commit == null) { commit = localRepo.Head.Reference.TargetIdentifier; _logger.LogInformation($"Repo {localRepo.Info.WorkingDirectory} default commit to checkout is {commit}"); } try { _logger.LogDebug($"Attempting to check out {commit} in {repoDir}"); LibGit2SharpHelpers.SafeCheckout(localRepo, commit, checkoutOptions, _logger); if (force) { CleanRepoAndSubmodules(localRepo, _logger); } } catch (LibGit2Sharp.NotFoundException) { _logger.LogWarning($"Couldn't find commit {commit} in {repoDir} locally. Attempting fetch."); try { foreach (LibGit2Sharp.Remote r in localRepo.Network.Remotes) { IEnumerable <string> refSpecs = r.FetchRefSpecs.Select(x => x.Specification); _logger.LogDebug($"Fetching {string.Join(";", refSpecs)} from {r.Url} in {repoDir}"); try { LibGit2Sharp.Commands.Fetch(localRepo, r.Name, refSpecs, new LibGit2Sharp.FetchOptions(), $"Fetching from {r.Url}"); } catch { _logger.LogWarning($"Fetching failed, are you offline or missing a remote?"); } } _logger.LogDebug($"After fetch, attempting to checkout {commit} in {repoDir}"); LibGit2SharpHelpers.SafeCheckout(localRepo, commit, checkoutOptions, _logger); if (force) { CleanRepoAndSubmodules(localRepo, _logger); } } catch // Most likely network exception, could also be no remotes. We can't do anything about any error here. { _logger.LogError($"After fetch, still couldn't find commit or treeish {commit} in {repoDir}. Are you offline or missing a remote?"); throw; } } } } catch (Exception exc) { throw new Exception($"Something went wrong when checking out {commit} in {repoDir}", exc); } }
/// <summary> /// Commits the currently staged files. /// </summary> /// <param name="action"></param> private void CommitChanges(object action) { var commitMessage = ((TextBox) action).Text; Task.Run(() => { using (var repo = new LibGit2Sharp.Repository(RepositoryFullPath)) { LibGit2Sharp.RepositoryExtensions.Commit(repo, commitMessage, false); // Reconstruct the repository. LoadEntireRepository(); // Clear the commit message box. Application.Current.Dispatcher.BeginInvoke( (Action)(() => UIHelper.FindChild<TextBox>(Application.Current.MainWindow, "CommitMessageTextBox").Clear()) ); } }); }
private static void CleanRepoAndSubmodules(LibGit2Sharp.Repository repo, ILogger log) { using (log.BeginScope($"Beginning clean of {repo.Info.WorkingDirectory} and {repo.Submodules.Count()} submodules")) { log.LogDebug($"Beginning clean of {repo.Info.WorkingDirectory} and {repo.Submodules.Count()} submodules"); LibGit2Sharp.StatusOptions options = new LibGit2Sharp.StatusOptions { IncludeUntracked = true, RecurseUntrackedDirs = true, }; int count = 0; foreach (LibGit2Sharp.StatusEntry item in repo.RetrieveStatus(options)) { if (item.State == LibGit2Sharp.FileStatus.NewInWorkdir) { File.Delete(Path.Combine(repo.Info.WorkingDirectory, item.FilePath)); ++count; } } log.LogDebug($"Deleted {count} untracked files"); foreach (LibGit2Sharp.Submodule sub in repo.Submodules) { string normalizedSubPath = sub.Path.Replace('\\', Path.DirectorySeparatorChar).Replace('/', Path.DirectorySeparatorChar); string subRepoPath = Path.Combine(repo.Info.WorkingDirectory, normalizedSubPath); string subRepoGitFilePath = Path.Combine(subRepoPath, ".git"); if (!File.Exists(subRepoGitFilePath)) { log.LogDebug($"Submodule {sub.Name} in {subRepoPath} does not appear to be initialized (no file at {subRepoGitFilePath}), attempting to initialize now."); // hasn't been initialized yet, can happen when different hashes have new or moved submodules try { repo.Submodules.Update(sub.Name, new LibGit2Sharp.SubmoduleUpdateOptions { Init = true }); } catch { log.LogDebug($"Submodule {sub.Name} in {subRepoPath} is already initialized, trying to adopt from super-repo {repo.Info.Path}"); // superrepo thinks it is initialized, but it's orphaned. Go back to the master repo to find out where this is supposed to point. using (LibGit2Sharp.Repository masterRepo = new LibGit2Sharp.Repository(repo.Info.WorkingDirectory)) { LibGit2Sharp.Submodule masterSubModule = masterRepo.Submodules.Single(s => s.Name == sub.Name); string masterSubPath = Path.Combine(repo.Info.Path, "modules", masterSubModule.Path); log.LogDebug($"Writing .gitdir redirect {masterSubPath} to {subRepoGitFilePath}"); Directory.CreateDirectory(Path.GetDirectoryName(subRepoGitFilePath)); File.WriteAllText(subRepoGitFilePath, $"gitdir: {masterSubPath}"); } } } using (log.BeginScope($"Beginning clean of submodule {sub.Name}")) { log.LogDebug($"Beginning clean of submodule {sub.Name} in {subRepoPath}"); // The worktree is stored in the .gitdir/config file, so we have to change it // to get it to check out to the correct place. LibGit2Sharp.ConfigurationEntry <string> oldWorkTree = null; using (LibGit2Sharp.Repository subRepo = new LibGit2Sharp.Repository(subRepoPath)) { oldWorkTree = subRepo.Config.Get <string>("core.worktree"); if (oldWorkTree != null) { log.LogDebug($"{subRepoPath} old worktree is {oldWorkTree.Value}, setting to {subRepoPath}"); subRepo.Config.Set("core.worktree", subRepoPath); } // This branch really shouldn't happen but just in case. else { log.LogDebug($"{subRepoPath} has default worktree, leaving unchanged"); } } using (LibGit2Sharp.Repository subRepo = new LibGit2Sharp.Repository(subRepoPath)) { log.LogDebug($"Resetting {sub.Name} to {sub.HeadCommitId.Sha}"); subRepo.Reset(LibGit2Sharp.ResetMode.Hard, subRepo.Commits.QueryBy(new LibGit2Sharp.CommitFilter { IncludeReachableFrom = subRepo.Refs }).Single(c => c.Sha == sub.HeadCommitId.Sha)); // Now we reset the worktree back so that when we can initialize a Repository // from it, instead of having to figure out which hash of the repo was most recently checked out. if (oldWorkTree != null) { log.LogDebug($"resetting {subRepoPath} worktree to {oldWorkTree.Value}"); subRepo.Config.Set("core.worktree", oldWorkTree.Value); } else { log.LogDebug($"leaving {subRepoPath} worktree as default"); } log.LogDebug($"Done resetting {subRepoPath}, checking submodules"); CleanRepoAndSubmodules(subRepo, log); } } if (File.Exists(subRepoGitFilePath)) { log.LogDebug($"Deleting {subRepoGitFilePath} to orphan submodule {sub.Name}"); File.Delete(subRepoGitFilePath); } else { log.LogDebug($"{sub.Name} doesn't have a .gitdir redirect at {subRepoGitFilePath}, skipping delete"); } } } }
/// <summary> /// Loads the repository status (modified, added, removed). /// </summary> private void LoadRepositoryStatus(LibGit2Sharp.Repository repo = null) { var dispose = false; if (repo == null) { repo = new LibGit2Sharp.Repository(RepositoryFullPath); dispose = true; } // A small performance boost. StatusItemsStaged.DisableNotifications(); StatusItemsUnstaged.DisableNotifications(); StatusItemsStaged.Clear(); StatusItemsUnstaged.Clear(); // Load status items. var itemList = new List<StatusItem>(); var status = repo.Index.RetrieveStatus(); foreach (var fileStatus in status) { foreach (LibGit2Sharp.FileStatus value in Enum.GetValues(typeof(LibGit2Sharp.FileStatus))) { var isSet = fileStatus.State.HasFlag(value); if (isSet == false || value.ToString() == "Unaltered" || value.ToString() == "Ignored") continue; // TODO: would it be better without full repo path? var fileFullPath = RepositoryFullPath + "/" + fileStatus.FilePath; // Only those enum statuses that were set will generate a row in the status grid (and those that are not ignored/unaltered). var item = new StatusItem { Filename = fileStatus.FilePath, Status = value, Size = FileUtil.GetFormattedFileSize(fileFullPath), // TODO: Should these two file IO be done lazily? IsBinary = FileUtil.IsBinaryFile(fileFullPath) ? "Yes" : "-" }; itemList.Add(item); } } StatusItemsStaged.AddRange(itemList.Where(s => s.IsStaged)); StatusItemsUnstaged.AddRange(itemList.Where(s => !s.IsStaged)); if (dispose) repo.Dispose(); // Fire notifications for the collection on the UI thread. Application.Current.Dispatcher.Invoke( DispatcherPriority.Normal, (Action)( () => { StatusItemsStaged.EnableNotifications(true); StatusItemsUnstaged.EnableNotifications(true); } ) ); }
/// <summary> /// Loads branches and commits. /// </summary> /// <param name="repo"></param> private void LoadBranchesAndCommits(LibGit2Sharp.Repository repo) { var dispose = false; if (repo == null) { repo = new LibGit2Sharp.Repository(RepositoryFullPath); dispose = true; } // Small performance boosts. Commits.DisableNotifications(); Branches.DisableNotifications(); // Create commits. Commits.Clear(); List <Commit> commitList = new List <Commit>(); foreach (LibGit2Sharp.Commit commit in repo.Commits.QueryBy(new LibGit2Sharp.Filter { Since = repo.Branches }).Take(CommitsPerPage)) { commitList.Add(Commit.Create(repo, commit, Tags)); } Commits.AddRange(commitList); // Create branches. Branches.Clear(); foreach (LibGit2Sharp.Branch branch in repo.Branches) { Branch b = Branch.Create(this, repo, branch); Branches.Add(b); } // Post-process branches (tips and tracking branches). foreach (Branch branch in Branches) { // Set the HEAD property if it matches. if (repo.Head.Name == branch.Name) { Head = branch; branch.Tip.IsHead = true; } branch.PostProcess(Branches, Commits); } // Post-process commits (commit parents). foreach (Commit commit in Commits) { // Set the HEAD property to a DetachedHead branch if the HEAD matched and it was null. if (Head == null && repo.Head.Tip.Sha == commit.Hash) { Head = new DetachedHead { Tip = commit }; commit.IsHead = true; } commit.PostProcess(Commits, Branches); } // Calculate commit visual positions for each branch tree. foreach (Branch branch in Branches) { RepoUtil.IncrementCommitTreeVisualPositionsRecursively(branch.Tip); } Commits.EnableNotifications(); Branches.EnableNotifications(); if (dispose) { repo.Dispose(); } }
static int Main(string[] args) { var modelBindingDefinition = Args.Configuration.Configure<GitReleaseNotesArguments>(); if (args.Any(a => a == "/?")) { var help = new HelpProvider().GenerateModelHelp(modelBindingDefinition); var f = new ConsoleHelpFormatter(); f.WriteHelp(help, Console.Out); return 0; } var arguments = modelBindingDefinition.CreateAndBind(args); if (arguments.IssueTracker == null) { Console.WriteLine("The IssueTracker argument must be provided, see help (/?) for possible options"); return 1; } if (string.IsNullOrEmpty(arguments.OutputFile) || !arguments.OutputFile.EndsWith(".md")) { Console.WriteLine("Specify an output file (*.md)"); return 1; } CreateIssueTrackers(arguments); var issueTracker = IssueTrackers[arguments.IssueTracker.Value]; if (!issueTracker.VerifyArgumentsAndWriteErrorsToConsole(arguments)) return 1; var workingDirectory = arguments.WorkingDirectory ?? Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); var gitDirectory = GitDirFinder.TreeWalkForGitDir(workingDirectory); if (string.IsNullOrEmpty(gitDirectory)) { throw new Exception("Failed to find .git directory."); } Console.WriteLine("Git directory found at {0}", gitDirectory); var repositoryRoot = Directory.GetParent(gitDirectory).FullName; var gitHelper = new GitHelper(); var gitRepo = new Repository(gitDirectory); var taggedCommitFinder = new TaggedCommitFinder(gitRepo, gitHelper); var tagToStartFrom = string.IsNullOrEmpty(arguments.FromTag) ? taggedCommitFinder.GetLastTaggedCommit() : taggedCommitFinder.GetTag(arguments.FromTag); var commitsToScan = gitRepo.Commits.TakeWhile(c => c != tagToStartFrom.Commit).ToArray(); if (arguments.Verbose) { Console.WriteLine("Scanning the following commits for issue numbers"); foreach (var commit in commitsToScan) { Console.WriteLine(commit.Message); } } var releaseNotes = issueTracker.ScanCommitMessagesForReleaseNotes(arguments, commitsToScan); new ReleaseNotesWriter(new FileSystem(), repositoryRoot).WriteReleaseNotes(arguments, releaseNotes); return 0; }
/// <summary> /// A helper method for listing branches that contain the given commit. /// </summary> /// <param name="repo"></param> /// <param name="commitSha"></param> /// <returns></returns> public static IEnumerable <LibGit2Sharp.Branch> GetBranchesContaininingCommit(LibGit2Sharp.Repository repo, string commitSha) { bool directBranchHasBeenFound = false; foreach (var branch in repo.Branches) { if (branch.Tip.Sha != commitSha) { continue; } directBranchHasBeenFound = true; yield return(branch); } if (directBranchHasBeenFound) { yield break; } foreach (var branch in repo.Branches) { var commits = repo.Commits.QueryBy(new LibGit2Sharp.Filter { Since = branch }).Where(c => c.Sha == commitSha); if (commits.Count() == 0) { continue; } yield return(branch); } }
/// <summary> /// Adds a new note for the given commit. /// </summary> /// <param name="action"></param> public void AddNote(object action) { var dialog = new PromptDialog(); dialog.Title = "Add a note"; dialog.Message = "Enter the note to add for the commit:"; dialog.ShowDialog(); if (dialog.DialogResult == true) { Commit commit = action as Commit; using (var repo = new LibGit2Sharp.Repository(RepositoryFullPath)) { //repo.Notes.Create(commit.Hash, dialog.ResponseText); LoadEntireRepository(); } } }
/// <summary> /// Inits the repo, gpg etc /// </summary> public FrmMain(FileSystemInterface fileSystemInterface, KeySelect keySelect, ConfigHandling config) { log.Debug(() => "Init variables"); fsi = fileSystemInterface; _keySelect = keySelect; _config = config; InitializeComponent(); toolStripStatusLabel1.Text = ""; this.enableTray = false; // Getting actual version log.Debug(() => "Getting program version"); var assembly = Assembly.GetExecutingAssembly(); var fvi = FileVersionInfo.GetVersionInfo(assembly.Location); var version = fvi.FileVersion; _config["version"] = version.Remove(5); Text = @"Pass4Win " + Strings.Version + @" " + _config["version"]; // check config input log.Debug(() => "Checking config validity"); try { bool ChkBool = Directory.Exists(_config["PassDirectory"]); if (!ChkBool) { throw new Exception("Pass directory fail"); } ChkBool = File.Exists(_config["GPGEXE"]); if (!ChkBool) { throw new Exception("GPG location fail"); } if (_config["UseGitRemote"] || _config["ExternalGit"]) { // nobody cares, we want the exception and it's auto generated due to a null value or not a boolean } } catch { // no matter if it's a first run or a corrupt entry, let them fix it. log.Debug(() => "Config corrupt or first run"); _config["FirstRun"] = true; Program.Scope.Resolve <FrmConfig>().ShowDialog(); } // checking for update in the background log.Debug(() => "Checking online for latest release"); // making new git object if (_config["ExternalGit"] && !Program.NoGit) { log.Debug(() => "Using an external git executable"); GitRepo = new GitHandling(_config["PassDirectory"], _config["GitRemote"], _config["ExternalGitLocation"]); } else if (!Program.NoGit) { log.Debug(() => "Using the internal git executable"); GitRepo = new GitHandling(_config["PassDirectory"], _config["GitRemote"]); } //checking git status if (_config["UseGitRemote"] == true || _config["ExternalGit"]) { if (!Program.NoGit) { if (GitRepo.ConnectToRepo() || (_config["ExternalGit"])) { log.Debug(() => "Remote Git is valid and active"); this.gitRepoOffline = false; toolStripOffline.Visible = false; if (!GitRepo.Fetch(_config["GitUser"], DecryptConfig(_config["GitPass"], "pass4win"))) { // Something failed which shouldn't fail, rechecking online status CheckOnline(false); } } // checking if we can clone, otherwise make a new one else if (!GitRepo.GitClone(_config["GitUser"], DecryptConfig(_config["GitPass"], "pass4win"))) { log.Debug(() => "Making a new git repo"); Repository.Init(_config["PassDirectory"], false); GitRepo.ConnectToRepo(); toolStripOffline.Visible = true; } // no connection, no repo. So make a new one else if (!GitHandling.IsValid(_config["PassDirectory"])) { log.Debug(() => "Making a new git repo"); Repository.Init(_config["PassDirectory"], false); GitRepo.ConnectToRepo(); toolStripOffline.Visible = true; } } } // Init GPG if needed string gpgfile = _config["PassDirectory"]; gpgfile += "\\.gpg-id"; // Check if we need to init the directory if (!File.Exists(gpgfile) || (new FileInfo(gpgfile).Length == 0)) { log.Debug(() => "Creating .gpg-id"); // ReSharper disable once AssignNullToNotNullAttribute Directory.CreateDirectory(Path.GetDirectoryName(gpgfile)); if (_keySelect.ShowDialog() == DialogResult.OK) { using (var w = new StreamWriter(gpgfile)) { w.Write(_keySelect.Gpgkey); } if (!Program.NoGit) { if (!GitRepo.Commit(gpgfile)) { MessageBox.Show( Strings.FrmMain_EncryptCallback_Commit_failed_, Strings.Error, MessageBoxButtons.OK, MessageBoxIcon.Error); return; } } } else { _keySelect.Close(); MessageBox.Show(Strings.Error_nokey, Strings.Error, MessageBoxButtons.OK, MessageBoxIcon.Error); Environment.Exit(1); } } // Setting the exe location for the GPG Dll GpgInterface.ExePath = _config["GPGEXE"]; // Fill tree CreateNodes(); this.enableTray = true; }
/// <summary> /// Creates a branch. /// </summary> /// <param name="action"></param> public void CreateBranch(object action) { var dialog = new PromptDialog { Title = "Creating a new branch", Message = "Please give a name for your new branch:" }; dialog.ShowDialog(); if (dialog.DialogResult == true) { using (var repo = new LibGit2Sharp.Repository(RepositoryFullPath)) { var sha = repo.Head.Tip.Sha.ToString(); repo.Branches.Create(dialog.ResponseText, repo.Head.Tip.Sha.ToString()); } LoadEntireRepository(); } }
// install pyRevit by cloning from git repo // @handled @logs public static void DeployFromRepo(string cloneName, string deploymentName = null, string branchName = null, string repoUrl = null, string destPath = null, string username = null, string password = null) { string repoSourcePath = repoUrl ?? PyRevitLabsConsts.OriginalRepoGitPath; string repoBranch = branchName != null ? branchName : PyRevitLabsConsts.TragetBranch; logger.Debug("Repo source determined as \"{0}:{1}\"", repoSourcePath, repoBranch); // determine destination path if not provided if (destPath is null) { destPath = Path.Combine(PyRevitLabsConsts.PyRevitPath, PyRevitConsts.DefaultCloneInstallName); } logger.Debug("Destination path determined as \"{0}\"", destPath); // make sure destPath exists CommonUtils.EnsurePath(destPath); // check existing destination path if (CommonUtils.VerifyPath(destPath)) { logger.Debug("Destination path already exists {0}", destPath); destPath = Path.Combine(destPath, cloneName); logger.Debug("Using subpath {0}", destPath); if (CommonUtils.VerifyPath(destPath)) { throw new PyRevitException(string.Format("Destination path already exists \"{0}\"", destPath)); } } // start the clone process LibGit2Sharp.Repository repo = null; if (deploymentName != null) { // TODO: Add core checkout option. Figure out how to checkout certain folders in libgit2sharp throw new NotImplementedException("Deployment with git clones not implemented yet."); } else { repo = GitInstaller.Clone(repoSourcePath, repoBranch, destPath, username, password); } // Check installation if (repo != null) { // make sure to delete the repo if error occured after cloning var clonedPath = repo.Info.WorkingDirectory; try { PyRevitClone.VerifyCloneValidity(clonedPath); logger.Debug("Clone successful \"{0}\"", clonedPath); RegisterClone(cloneName, clonedPath); } catch (Exception ex) { logger.Debug(string.Format("Exception occured after clone complete. Deleting clone \"{0}\" | {1}", clonedPath, ex.Message)); try { CommonUtils.DeleteDirectory(clonedPath); } catch (Exception delEx) { logger.Error(string.Format("Error post-install cleanup on \"{0}\" | {1}", clonedPath, delEx.Message)); } // cleanup completed, now baloon up the exception throw ex; } } else { throw new PyRevitException(string.Format("Error installing pyRevit. Null repo error on \"{0}\"", repoUrl)); } }
/// <summary> /// Exports the given changeset as a patch to a file. /// </summary> /// <param name="action"></param> public void ExportPatch(object action) { Commit commit = action as Commit; using (var repo = new LibGit2Sharp.Repository(RepositoryFullPath)) { SaveFileDialog dialog = new SaveFileDialog(); dialog.FileName = commit.Description.Right(72); dialog.DefaultExt = ".patch"; dialog.Filter = "Patch files|*.patch"; if (dialog.ShowDialog() == true) { // Save the patch to a file. File.WriteAllText(dialog.FileName, RepoUtil.GetTreeChangesForCommit(repo, commit).Patch); } } }
public ActionResult Clone(Guid id, RepositoryDetailModel model) { if (!RepositoryPermissionService.HasCreatePermission(User.Id())) { return(RedirectToAction("Unauthorized", "Home")); } if (model != null && !String.IsNullOrEmpty(model.Name)) { model.Name = Regex.Replace(model.Name, @"\s", ""); } if (model != null && String.IsNullOrEmpty(model.Name)) { ModelState.AddModelError("Name", Resources.Repository_Create_NameFailure); } else if (ModelState.IsValid) { var repo_model = ConvertRepositoryDetailModel(model); if (RepositoryRepository.Create(repo_model)) { string targetRepositoryPath = Path.Combine(UserConfiguration.Current.Repositories, model.Name); if (!Directory.Exists(targetRepositoryPath)) { var source_repo = RepositoryRepository.GetRepository(id); string sourceRepositoryPath = Path.Combine(UserConfiguration.Current.Repositories, source_repo.Name); LibGit2Sharp.CloneOptions options = new LibGit2Sharp.CloneOptions() { IsBare = true, Checkout = false }; LibGit2Sharp.Repository.Clone(sourceRepositoryPath, targetRepositoryPath, options); using (var repo = new LibGit2Sharp.Repository(targetRepositoryPath)) { if (repo.Network.Remotes.Any(r => r.Name == "origin")) { repo.Network.Remotes.Remove("origin"); } } TempData["CloneSuccess"] = true; return(RedirectToAction("Index")); } else { RepositoryRepository.Delete(model.Id); ModelState.AddModelError("", Resources.Repository_Create_DirectoryExists); } } else { ModelState.AddModelError("", Resources.Repository_Create_Failure); } } ViewBag.ID = id; PopulateCheckboxListData(ref model); return(View(model)); }
/// <summary> /// Resets (reset --soft) the repository to the given changeset. /// </summary> /// <param name="action"></param> public void ResetSoft(object action) { Commit commit = action as Commit; using (var repo = new LibGit2Sharp.Repository(RepositoryFullPath)) { repo.Reset(LibGit2Sharp.ResetOptions.Mixed, commit.Hash); LoadEntireRepository(); } }
private static void CheckoutSubmodules(LibGit2Sharp.Repository repo, LibGit2Sharp.CloneOptions submoduleCloneOptions, string gitDirParentPath, ILogger log) { foreach (LibGit2Sharp.Submodule sub in repo.Submodules) { log.LogDebug($"Updating submodule {sub.Name} at {sub.Path} for {repo.Info.WorkingDirectory}. GitDirParent: {gitDirParentPath}"); repo.Submodules.Update(sub.Name, new LibGit2Sharp.SubmoduleUpdateOptions { CredentialsProvider = submoduleCloneOptions.CredentialsProvider, Init = true }); string normalizedSubPath = sub.Path.Replace('\\', Path.DirectorySeparatorChar).Replace('/', Path.DirectorySeparatorChar); string subRepoPath = Path.Combine(repo.Info.WorkingDirectory, normalizedSubPath); string relativeGitDirPath = File.ReadAllText(Path.Combine(subRepoPath, ".git")).Substring(8); log.LogDebug($"Submodule {sub.Name} has .gitdir {relativeGitDirPath}"); string absoluteGitDirPath = Path.GetFullPath(Path.Combine(subRepoPath, relativeGitDirPath)); string relocatedGitDirPath = absoluteGitDirPath.Replace(repo.Info.Path.TrimEnd(new[] { '/', '\\' }), gitDirParentPath.TrimEnd(new[] { '/', '\\' })); string subRepoGitFilePath = Path.Combine(subRepoPath, ".git"); log.LogDebug($"Writing new .gitdir path {relocatedGitDirPath} to submodule at {subRepoPath}"); // File.WriteAllText gets access denied for some reason using (FileStream s = File.OpenWrite(subRepoGitFilePath)) using (StreamWriter w = new StreamWriter(s)) { w.Write($"gitdir: {relocatedGitDirPath}"); w.Flush(); s.SetLength(s.Position); } // The worktree is stored in the .gitdir/config file, so we have to change it // to get it to check out to the correct place. LibGit2Sharp.ConfigurationEntry <string> oldWorkTree = null; using (LibGit2Sharp.Repository subRepo = new LibGit2Sharp.Repository(subRepoPath)) { oldWorkTree = subRepo.Config.Get <string>("core.worktree"); if (oldWorkTree != null) { log.LogDebug($"{subRepoPath} old worktree is {oldWorkTree.Value}, setting to {subRepoPath}"); subRepo.Config.Set("core.worktree", subRepoPath); } else { log.LogDebug($"{subRepoPath} has default worktree, leaving unchanged"); } } using (LibGit2Sharp.Repository subRepo = new LibGit2Sharp.Repository(subRepoPath)) { log.LogDebug($"Resetting {sub.Name} to {sub.HeadCommitId.Sha}"); subRepo.Reset(LibGit2Sharp.ResetMode.Hard, subRepo.Commits.QueryBy(new LibGit2Sharp.CommitFilter { IncludeReachableFrom = subRepo.Refs }).Single(c => c.Sha == sub.HeadCommitId.Sha)); // Now we reset the worktree back so that when we can initialize a Repository // from it, instead of having to figure out which hash of the repo was most recently checked out. if (oldWorkTree != null) { log.LogDebug($"resetting {subRepoPath} worktree to {oldWorkTree.Value}"); subRepo.Config.Set("core.worktree", oldWorkTree.Value); } else { log.LogDebug($"leaving {subRepoPath} worktree as default"); } log.LogDebug($"Done checking out {subRepoPath}, checking submodules"); CheckoutSubmodules(subRepo, submoduleCloneOptions, absoluteGitDirPath, log); } if (File.Exists(subRepoGitFilePath)) { log.LogDebug($"Deleting {subRepoGitFilePath} to orphan submodule {sub.Name}"); File.Delete(subRepoGitFilePath); } else { log.LogDebug($"{sub.Name} doesn't have a .gitdir redirect at {subRepoGitFilePath}, skipping delete"); } } }
/// <summary> /// Commits the currently staged files. /// </summary> /// <param name="action"></param> private void CommitChanges(object action) { var commitMessage = (string) action; using (LibGit2Sharp.Repository repo = new LibGit2Sharp.Repository(RepositoryFullPath)) { LibGit2Sharp.RepositoryExtensions.Commit(repo, commitMessage, false); // Reconstruct the repository. LoadEntireRepository(); LoadRepositoryStatus(); // Clear the commit message box. UIHelper.FindChild<TextBox>(Application.Current.MainWindow, "CommitMessageTextBox").Clear(); } }
private static string GetRepoRelativePath(string searchPath, LibGit2Sharp.Repository repository) { return(searchPath.Substring(repository.Info.WorkingDirectory.Length)); }
/// <summary> /// Loads branches and commits. /// </summary> /// <param name="repo"></param> private void LoadBranchesAndCommits(LibGit2Sharp.Repository repo) { var dispose = false; if (repo == null) { repo = new LibGit2Sharp.Repository(RepositoryFullPath); dispose = true; } // Small performance boosts. Commits.DisableNotifications(); Branches.DisableNotifications(); // Create commits. Commits.Clear(); List<Commit> commitList = new List<Commit>(); foreach (LibGit2Sharp.Commit commit in repo.Commits.QueryBy(new LibGit2Sharp.Filter { Since = repo.Branches }).Take(CommitsPerPage)) { commitList.Add(Commit.Create(repo, commit, Tags)); } Commits.AddRange(commitList); // Create branches. Branches.Clear(); foreach (LibGit2Sharp.Branch branch in repo.Branches) { Branch b = Branch.Create(this, repo, branch); Branches.Add(b); } // Post-process branches (tips and tracking branches). foreach (Branch branch in Branches) { // Set the HEAD property if it matches. if (repo.Head.Name == branch.Name) { Head = branch; branch.Tip.IsHead = true; } branch.PostProcess(Branches, Commits); } // Post-process commits (commit parents). foreach (Commit commit in Commits) { // Set the HEAD property to a DetachedHead branch if the HEAD matched and it was null. if (Head == null && repo.Head.Tip.Sha == commit.Hash) { Head = new DetachedHead { Tip = commit }; commit.IsHead = true; } commit.PostProcess(Commits, Branches); } // Calculate commit visual positions for each branch tree. foreach (Branch branch in Branches) { RepoUtil.IncrementCommitTreeVisualPositionsRecursively(branch.Tip); } Commits.EnableNotifications(); Branches.EnableNotifications(); if (dispose) repo.Dispose(); }
/// <summary> /// Creates a branch. /// </summary> /// <param name="action"></param> public void CreateBranch(object action) { var dialog = new PromptDialog { Title = "Creating a new branch", Message = "Please give a name for your new branch:" }; dialog.ShowDialog(); if (dialog.DialogResult != true) return; var response = dialog.ResponseText; Task.Run(() => { using (var repo = new LibGit2Sharp.Repository(RepositoryFullPath)) { repo.Branches.Create(response, repo.Head.Tip.Sha.ToString(CultureInfo.InvariantCulture)); } LoadEntireRepository(); }); }
/// <summary> /// Loads the tags. /// </summary> private void LoadTags(LibGit2Sharp.Repository repo) { var dispose = false; if (repo == null) { repo = new LibGit2Sharp.Repository(RepositoryFullPath); dispose = true; } // Small performance boost. Tags.DisableNotifications(); Tags.Clear(); // Add new tags. foreach (LibGit2Sharp.Tag tag in repo.Tags) { Tag t = Tag.Create(repo, tag); if (t.HasCommitAsTarget) Tags.Add(t); } Tags.EnableNotifications(); if (dispose) repo.Dispose(); }
/// <summary> /// Creates a tag. /// </summary> /// <param name="action"></param> public void CreateTag(object action) { var commit = action as Commit; var dialog = new PromptDialog { Title = "Create a new tag", Message = "Enter the name for the tag:" }; dialog.ShowDialog(); if (dialog.DialogResult != true || commit == null) return; var response = dialog.ResponseText; Task.Run(() => { using (var repo = new LibGit2Sharp.Repository(RepositoryFullPath)) { repo.Tags.Create(response, commit.Hash); LoadEntireRepository(); } }); }
protected LibGit2Sharp.Repository OpenPasswordRepository() { var enforceSelectionOfNewPath = false; while (true) { try { var passwordStorePath = GetPasswordStorePath(enforceSelectionOfNewPath); var repo = new LibGit2Sharp.Repository(passwordStorePath); Properties.Settings.Default.PasswordStorePath = passwordStorePath; Properties.Settings.Default.Save(); return repo; } catch { enforceSelectionOfNewPath = true; } } }
/// <summary> /// Deletes a tag. /// </summary> /// <param name="action"></param> public void DeleteTag(object action) { var tag = (Tag) action; var dialog = new ConfirmDialog { Title = "Deleting a tag", Message = String.Format("Are you sure you want to delete this tag ({0})?", tag.Name) }; dialog.ShowDialog(); var pressedButton = dialog.PressedButton; if (pressedButton == null || ((string) pressedButton.Content) != "OK") return; Task.Run(() => { using (var repo = new LibGit2Sharp.Repository(RepositoryFullPath)) { // Remove the tag from the Git repository. repo.Tags.Delete(tag.CanonicalName); // Reload all tags. LoadTags(); Application.Current.Dispatcher.BeginInvoke( DispatcherPriority.Normal, (Action) (() => tag.Target.Tags.Remove(tag)) ); } }); }
public ActionResult Clone(string id, RepositoryDetailModel model) { if (!User.IsInRole(Definitions.Roles.Administrator) && !UserConfiguration.Current.AllowUserRepositoryCreation) { return RedirectToAction("Unauthorized", "Home"); } if (model != null && !String.IsNullOrEmpty(model.Name)) { model.Name = Regex.Replace(model.Name, @"\s", ""); } if (String.IsNullOrEmpty(model.Name)) { ModelState.AddModelError("Name", Resources.Repository_Create_NameFailure); } else if (ModelState.IsValid) { if (RepositoryRepository.Create(ConvertRepositoryDetailModel(model))) { string targetRepositoryPath = Path.Combine(UserConfiguration.Current.Repositories, model.Name); if (!Directory.Exists(targetRepositoryPath)) { string sourceRepositoryPath = Path.Combine(UserConfiguration.Current.Repositories, id); LibGit2Sharp.CloneOptions options = new LibGit2Sharp.CloneOptions() { IsBare = true, Checkout = false }; LibGit2Sharp.Repository.Clone(sourceRepositoryPath, targetRepositoryPath, options); using (var repo = new LibGit2Sharp.Repository(targetRepositoryPath)) { if (repo.Network.Remotes.Any(r => r.Name == "origin")) { repo.Network.Remotes.Remove("origin"); } } TempData["CloneSuccess"] = true; return RedirectToAction("Index"); } else { RepositoryRepository.Delete(model.Name); ModelState.AddModelError("", Resources.Repository_Create_DirectoryExists); } } else { ModelState.AddModelError("", Resources.Repository_Create_Failure); } } ViewBag.ID = id; PopulateEditData(); return View(model); }
/// <summary> /// Loads branches and commits. /// </summary> /// <param name="repo"></param> private void LoadBranchesAndCommits(LibGit2Sharp.Repository repo = null) { var dispose = false; if (repo == null) { repo = new LibGit2Sharp.Repository(RepositoryFullPath); dispose = true; } // Small performance boosts. Commits.DisableNotifications(); Branches.DisableNotifications(); // Create commits. Commits.Clear(); var commitList = new List <Commit>(); foreach (var commit in repo.Commits.QueryBy(new LibGit2Sharp.Filter { Since = repo.Branches }).Take(CommitsPerPage)) { commitList.Add(Commit.Create(repo, commit, Tags)); } Commits.AddRange(commitList); // Create branches. Branches.Clear(); foreach (var branch in repo.Branches) { var b = Branch.Create(this, repo, branch); Branches.Add(b); } // Post-process branches (tips and tracking branches). foreach (var branch in Branches) { // Set the HEAD property if it matches. if (repo.Head.Name == branch.Name) { Head = branch; branch.Tip.IsHead = true; } branch.PostProcess(Branches, Commits); } // Post-process commits (commit parents). foreach (var commit in Commits) { // Set the HEAD property to a DetachedHead branch if the HEAD matched and it was null. if (Head == null && repo.Head.Tip.Sha == commit.Hash) { Head = new DetachedHead { Tip = commit }; commit.IsHead = true; } commit.PostProcess(Commits, Branches); } // Calculate commit visual positions for each branch tree. foreach (var branch in Branches) { RepoUtil.IncrementCommitTreeVisualPositionsRecursively(branch.Tip); } // Fire notifications for the collections on the UI thread. Application.Current.Dispatcher.Invoke( DispatcherPriority.Normal, (Action)(() => { Commits.EnableNotifications(true); Branches.EnableNotifications(true); var tabControl = UIHelper.FindChild <TabControl>(Application.Current.MainWindow, "RepositoryTabs"); var changesetHistory = UIHelper.FindChild <ChangesetHistory>(tabControl); if (changesetHistory != null) { changesetHistory.RedrawGraph(); } }) ); if (dispose) { repo.Dispose(); } }