Merge branch 'feat-bare-repository' into develop

This commit is contained in:
leo 2025-01-14 18:08:46 +08:00
commit 8ea17e57da
No known key found for this signature in database
11 changed files with 504 additions and 419 deletions

View file

@ -420,34 +420,37 @@ namespace SourceGit.ViewModels
menu.Items.Add(patch); menu.Items.Add(patch);
menu.Items.Add(new MenuItem { Header = "-" }); menu.Items.Add(new MenuItem { Header = "-" });
var resetToThisRevision = new MenuItem(); if (!_repo.IsBare)
resetToThisRevision.Header = App.Text("ChangeCM.CheckoutThisRevision");
resetToThisRevision.Icon = App.CreateMenuIcon("Icons.File.Checkout");
resetToThisRevision.Click += (_, ev) =>
{ {
new Commands.Checkout(_repo.FullPath).FileWithRevision(change.Path, $"{_commit.SHA}"); var resetToThisRevision = new MenuItem();
ev.Handled = true; resetToThisRevision.Header = App.Text("ChangeCM.CheckoutThisRevision");
}; resetToThisRevision.Icon = App.CreateMenuIcon("Icons.File.Checkout");
resetToThisRevision.Click += (_, ev) =>
{
new Commands.Checkout(_repo.FullPath).FileWithRevision(change.Path, $"{_commit.SHA}");
ev.Handled = true;
};
var resetToFirstParent = new MenuItem(); var resetToFirstParent = new MenuItem();
resetToFirstParent.Header = App.Text("ChangeCM.CheckoutFirstParentRevision"); resetToFirstParent.Header = App.Text("ChangeCM.CheckoutFirstParentRevision");
resetToFirstParent.Icon = App.CreateMenuIcon("Icons.File.Checkout"); resetToFirstParent.Icon = App.CreateMenuIcon("Icons.File.Checkout");
resetToFirstParent.IsEnabled = _commit.Parents.Count > 0; resetToFirstParent.IsEnabled = _commit.Parents.Count > 0;
resetToFirstParent.Click += (_, ev) => resetToFirstParent.Click += (_, ev) =>
{ {
if (change.Index == Models.ChangeState.Renamed) if (change.Index == Models.ChangeState.Renamed)
new Commands.Checkout(_repo.FullPath).FileWithRevision(change.OriginalPath, $"{_commit.SHA}~1"); new Commands.Checkout(_repo.FullPath).FileWithRevision(change.OriginalPath, $"{_commit.SHA}~1");
new Commands.Checkout(_repo.FullPath).FileWithRevision(change.Path, $"{_commit.SHA}~1"); new Commands.Checkout(_repo.FullPath).FileWithRevision(change.Path, $"{_commit.SHA}~1");
ev.Handled = true; ev.Handled = true;
}; };
menu.Items.Add(resetToThisRevision); menu.Items.Add(resetToThisRevision);
menu.Items.Add(resetToFirstParent); menu.Items.Add(resetToFirstParent);
menu.Items.Add(new MenuItem { Header = "-" }); menu.Items.Add(new MenuItem { Header = "-" });
if (File.Exists(Path.Combine(fullPath))) if (File.Exists(Path.Combine(fullPath)))
TryToAddContextMenuItemsForGitLFS(menu, change.Path); TryToAddContextMenuItemsForGitLFS(menu, change.Path);
}
var copyPath = new MenuItem(); var copyPath = new MenuItem();
copyPath.Header = App.Text("CopyPath"); copyPath.Header = App.Text("CopyPath");

View file

@ -31,6 +31,11 @@ namespace SourceGit.ViewModels
set => _repo.Settings.CheckoutBranchOnCreateBranch = value; set => _repo.Settings.CheckoutBranchOnCreateBranch = value;
} }
public bool IsBareRepository
{
get => _repo.IsBare;
}
public CreateBranch(Repository repo, Models.Branch branch) public CreateBranch(Repository repo, Models.Branch branch)
{ {
_repo = repo; _repo = repo;
@ -84,7 +89,7 @@ namespace SourceGit.ViewModels
return Task.Run(() => return Task.Run(() =>
{ {
var succ = false; var succ = false;
if (CheckoutAfterCreated) if (CheckoutAfterCreated && !_repo.IsBare)
{ {
var changes = new Commands.CountLocalChangesWithoutUntracked(_repo.FullPath).Result(); var changes = new Commands.CountLocalChangesWithoutUntracked(_repo.FullPath).Result();
var needPopStash = false; var needPopStash = false;

View file

@ -213,7 +213,7 @@ namespace SourceGit.ViewModels
{ {
if (firstRemoteBranch != null) if (firstRemoteBranch != null)
_repo.ShowPopup(new CreateBranch(_repo, firstRemoteBranch)); _repo.ShowPopup(new CreateBranch(_repo, firstRemoteBranch));
else else if (!_repo.IsBare)
_repo.ShowPopup(new CheckoutCommit(_repo, commit)); _repo.ShowPopup(new CheckoutCommit(_repo, commit));
} }
} }
@ -253,36 +253,39 @@ namespace SourceGit.ViewModels
var multipleMenu = new ContextMenu(); var multipleMenu = new ContextMenu();
if (canCherryPick) if (!_repo.IsBare)
{ {
var cherryPickMultiple = new MenuItem(); if (canCherryPick)
cherryPickMultiple.Header = App.Text("CommitCM.CherryPickMultiple");
cherryPickMultiple.Icon = App.CreateMenuIcon("Icons.CherryPick");
cherryPickMultiple.Click += (_, e) =>
{ {
if (_repo.CanCreatePopup()) var cherryPickMultiple = new MenuItem();
_repo.ShowPopup(new CherryPick(_repo, selected)); cherryPickMultiple.Header = App.Text("CommitCM.CherryPickMultiple");
e.Handled = true; cherryPickMultiple.Icon = App.CreateMenuIcon("Icons.CherryPick");
}; cherryPickMultiple.Click += (_, e) =>
multipleMenu.Items.Add(cherryPickMultiple); {
} if (_repo.CanCreatePopup())
_repo.ShowPopup(new CherryPick(_repo, selected));
e.Handled = true;
};
multipleMenu.Items.Add(cherryPickMultiple);
}
if (canMerge) if (canMerge)
{
var mergeMultiple = new MenuItem();
mergeMultiple.Header = App.Text("CommitCM.MergeMultiple");
mergeMultiple.Icon = App.CreateMenuIcon("Icons.Merge");
mergeMultiple.Click += (_, e) =>
{ {
if (_repo.CanCreatePopup()) var mergeMultiple = new MenuItem();
_repo.ShowPopup(new MergeMultiple(_repo, selected)); mergeMultiple.Header = App.Text("CommitCM.MergeMultiple");
e.Handled = true; mergeMultiple.Icon = App.CreateMenuIcon("Icons.Merge");
}; mergeMultiple.Click += (_, e) =>
multipleMenu.Items.Add(mergeMultiple); {
} if (_repo.CanCreatePopup())
_repo.ShowPopup(new MergeMultiple(_repo, selected));
e.Handled = true;
};
multipleMenu.Items.Add(mergeMultiple);
}
if (canCherryPick || canMerge) if (canCherryPick || canMerge)
multipleMenu.Items.Add(new MenuItem() { Header = "-" }); multipleMenu.Items.Add(new MenuItem() { Header = "-" });
}
var saveToPatchMultiple = new MenuItem(); var saveToPatchMultiple = new MenuItem();
saveToPatchMultiple.Icon = App.CreateMenuIcon("Icons.Diff"); saveToPatchMultiple.Icon = App.CreateMenuIcon("Icons.Diff");
@ -394,25 +397,48 @@ namespace SourceGit.ViewModels
menu.Items.Add(new MenuItem() { Header = "-" }); menu.Items.Add(new MenuItem() { Header = "-" });
} }
if (current.Head != commit.SHA) if (!_repo.IsBare)
{ {
var reset = new MenuItem(); if (current.Head != commit.SHA)
reset.Header = new Views.NameHighlightedTextBlock("CommitCM.Reset", current.Name);
reset.Icon = App.CreateMenuIcon("Icons.Reset");
reset.Click += (_, e) =>
{ {
if (_repo.CanCreatePopup()) var reset = new MenuItem();
_repo.ShowPopup(new Reset(_repo, current, commit)); reset.Header = new Views.NameHighlightedTextBlock("CommitCM.Reset", current.Name);
e.Handled = true; reset.Icon = App.CreateMenuIcon("Icons.Reset");
}; reset.Click += (_, e) =>
menu.Items.Add(reset); {
if (_repo.CanCreatePopup())
_repo.ShowPopup(new Reset(_repo, current, commit));
e.Handled = true;
};
menu.Items.Add(reset);
if (commit.IsMerged) if (commit.IsMerged)
{
var squash = new MenuItem();
squash.Header = App.Text("CommitCM.SquashCommitsSinceThis");
squash.Icon = App.CreateMenuIcon("Icons.SquashIntoParent");
squash.Click += (_, e) =>
{
if (_repo.LocalChangesCount > 0)
{
App.RaiseException(_repo.FullPath, "You have local changes. Please run stash or discard first.");
return;
}
if (_repo.CanCreatePopup())
_repo.ShowPopup(new Squash(_repo, commit, commit.SHA));
e.Handled = true;
};
menu.Items.Add(squash);
}
}
else
{ {
var squash = new MenuItem(); var reword = new MenuItem();
squash.Header = App.Text("CommitCM.SquashCommitsSinceThis"); reword.Header = App.Text("CommitCM.Reword");
squash.Icon = App.CreateMenuIcon("Icons.SquashIntoParent"); reword.Icon = App.CreateMenuIcon("Icons.Edit");
squash.Click += (_, e) => reword.Click += (_, e) =>
{ {
if (_repo.LocalChangesCount > 0) if (_repo.LocalChangesCount > 0)
{ {
@ -421,169 +447,149 @@ namespace SourceGit.ViewModels
} }
if (_repo.CanCreatePopup()) if (_repo.CanCreatePopup())
_repo.ShowPopup(new Squash(_repo, commit, commit.SHA)); _repo.ShowPopup(new Reword(_repo, commit));
e.Handled = true;
};
menu.Items.Add(reword);
var squash = new MenuItem();
squash.Header = App.Text("CommitCM.Squash");
squash.Icon = App.CreateMenuIcon("Icons.SquashIntoParent");
squash.IsEnabled = commit.Parents.Count == 1;
squash.Click += (_, e) =>
{
if (_repo.LocalChangesCount > 0)
{
App.RaiseException(_repo.FullPath, "You have local changes. Please run stash or discard first.");
return;
}
if (commit.Parents.Count == 1)
{
var parent = _commits.Find(x => x.SHA == commit.Parents[0]);
if (parent != null && _repo.CanCreatePopup())
_repo.ShowPopup(new Squash(_repo, parent, commit.SHA));
}
e.Handled = true; e.Handled = true;
}; };
menu.Items.Add(squash); menu.Items.Add(squash);
} }
}
else if (!commit.IsMerged)
{
var reword = new MenuItem();
reword.Header = App.Text("CommitCM.Reword");
reword.Icon = App.CreateMenuIcon("Icons.Edit");
reword.Click += (_, e) =>
{ {
if (_repo.LocalChangesCount > 0) var rebase = new MenuItem();
{ rebase.Header = new Views.NameHighlightedTextBlock("CommitCM.Rebase", current.Name);
App.RaiseException(_repo.FullPath, "You have local changes. Please run stash or discard first."); rebase.Icon = App.CreateMenuIcon("Icons.Rebase");
return; rebase.Click += (_, e) =>
}
if (_repo.CanCreatePopup())
_repo.ShowPopup(new Reword(_repo, commit));
e.Handled = true;
};
menu.Items.Add(reword);
var squash = new MenuItem();
squash.Header = App.Text("CommitCM.Squash");
squash.Icon = App.CreateMenuIcon("Icons.SquashIntoParent");
squash.IsEnabled = commit.Parents.Count == 1;
squash.Click += (_, e) =>
{
if (_repo.LocalChangesCount > 0)
{
App.RaiseException(_repo.FullPath, "You have local changes. Please run stash or discard first.");
return;
}
if (commit.Parents.Count == 1)
{
var parent = _commits.Find(x => x.SHA == commit.Parents[0]);
if (parent != null && _repo.CanCreatePopup())
_repo.ShowPopup(new Squash(_repo, parent, commit.SHA));
}
e.Handled = true;
};
menu.Items.Add(squash);
}
if (!commit.IsMerged)
{
var rebase = new MenuItem();
rebase.Header = new Views.NameHighlightedTextBlock("CommitCM.Rebase", current.Name);
rebase.Icon = App.CreateMenuIcon("Icons.Rebase");
rebase.Click += (_, e) =>
{
if (_repo.CanCreatePopup())
_repo.ShowPopup(new Rebase(_repo, current, commit));
e.Handled = true;
};
menu.Items.Add(rebase);
if (!commit.HasDecorators)
{
var merge = new MenuItem();
merge.Header = new Views.NameHighlightedTextBlock("CommitCM.Merge", current.Name);
merge.Icon = App.CreateMenuIcon("Icons.Merge");
merge.Click += (_, e) =>
{ {
if (_repo.CanCreatePopup()) if (_repo.CanCreatePopup())
_repo.ShowPopup(new Merge(_repo, commit, current.Name)); _repo.ShowPopup(new Rebase(_repo, current, commit));
e.Handled = true;
};
menu.Items.Add(rebase);
if (!commit.HasDecorators)
{
var merge = new MenuItem();
merge.Header = new Views.NameHighlightedTextBlock("CommitCM.Merge", current.Name);
merge.Icon = App.CreateMenuIcon("Icons.Merge");
merge.Click += (_, e) =>
{
if (_repo.CanCreatePopup())
_repo.ShowPopup(new Merge(_repo, commit, current.Name));
e.Handled = true;
};
menu.Items.Add(merge);
}
var cherryPick = new MenuItem();
cherryPick.Header = App.Text("CommitCM.CherryPick");
cherryPick.Icon = App.CreateMenuIcon("Icons.CherryPick");
cherryPick.Click += (_, e) =>
{
if (_repo.CanCreatePopup())
{
if (commit.Parents.Count <= 1)
{
_repo.ShowPopup(new CherryPick(_repo, [commit]));
}
else
{
var parents = new List<Models.Commit>();
foreach (var sha in commit.Parents)
{
var parent = _commits.Find(x => x.SHA == sha);
if (parent == null)
parent = new Commands.QuerySingleCommit(_repo.FullPath, sha).Result();
if (parent != null)
parents.Add(parent);
}
_repo.ShowPopup(new CherryPick(_repo, commit, parents));
}
}
e.Handled = true; e.Handled = true;
}; };
menu.Items.Add(merge); menu.Items.Add(cherryPick);
}
else
{
var revert = new MenuItem();
revert.Header = App.Text("CommitCM.Revert");
revert.Icon = App.CreateMenuIcon("Icons.Undo");
revert.Click += (_, e) =>
{
if (_repo.CanCreatePopup())
_repo.ShowPopup(new Revert(_repo, commit));
e.Handled = true;
};
menu.Items.Add(revert);
} }
var cherryPick = new MenuItem(); if (current.Head != commit.SHA)
cherryPick.Header = App.Text("CommitCM.CherryPick");
cherryPick.Icon = App.CreateMenuIcon("Icons.CherryPick");
cherryPick.Click += (_, e) =>
{ {
if (_repo.CanCreatePopup()) var checkoutCommit = new MenuItem();
checkoutCommit.Header = App.Text("CommitCM.Checkout");
checkoutCommit.Icon = App.CreateMenuIcon("Icons.Detached");
checkoutCommit.Click += (_, e) =>
{ {
if (commit.Parents.Count <= 1) if (_repo.CanCreatePopup())
{ _repo.ShowPopup(new CheckoutCommit(_repo, commit));
_repo.ShowPopup(new CherryPick(_repo, [commit])); e.Handled = true;
} };
else menu.Items.Add(checkoutCommit);
{ }
var parents = new List<Models.Commit>();
foreach (var sha in commit.Parents)
{
var parent = _commits.Find(x => x.SHA == sha);
if (parent == null)
parent = new Commands.QuerySingleCommit(_repo.FullPath, sha).Result();
if (parent != null)
parents.Add(parent);
}
_repo.ShowPopup(new CherryPick(_repo, commit, parents));
}
}
e.Handled = true;
};
menu.Items.Add(cherryPick);
}
else
{
var revert = new MenuItem();
revert.Header = App.Text("CommitCM.Revert");
revert.Icon = App.CreateMenuIcon("Icons.Undo");
revert.Click += (_, e) =>
{
if (_repo.CanCreatePopup())
_repo.ShowPopup(new Revert(_repo, commit));
e.Handled = true;
};
menu.Items.Add(revert);
}
if (current.Head != commit.SHA)
{
var checkoutCommit = new MenuItem();
checkoutCommit.Header = App.Text("CommitCM.Checkout");
checkoutCommit.Icon = App.CreateMenuIcon("Icons.Detached");
checkoutCommit.Click += (_, e) =>
{
if (_repo.CanCreatePopup())
_repo.ShowPopup(new CheckoutCommit(_repo, commit));
e.Handled = true;
};
menu.Items.Add(checkoutCommit);
}
menu.Items.Add(new MenuItem() { Header = "-" });
if (commit.IsMerged && current.Head != commit.SHA)
{
var interactiveRebase = new MenuItem();
interactiveRebase.Header = new Views.NameHighlightedTextBlock("CommitCM.InteractiveRebase", current.Name);
interactiveRebase.Icon = App.CreateMenuIcon("Icons.InteractiveRebase");
interactiveRebase.Click += (_, e) =>
{
if (_repo.LocalChangesCount > 0)
{
App.RaiseException(_repo.FullPath, "You have local changes. Please run stash or discard first.");
return;
}
App.OpenDialog(new Views.InteractiveRebase()
{
DataContext = new InteractiveRebase(_repo, current, commit)
});
e.Handled = true;
};
menu.Items.Add(interactiveRebase);
menu.Items.Add(new MenuItem() { Header = "-" }); menu.Items.Add(new MenuItem() { Header = "-" });
}
if (commit.IsMerged && current.Head != commit.SHA)
{
var interactiveRebase = new MenuItem();
interactiveRebase.Header = new Views.NameHighlightedTextBlock("CommitCM.InteractiveRebase", current.Name);
interactiveRebase.Icon = App.CreateMenuIcon("Icons.InteractiveRebase");
interactiveRebase.Click += (_, e) =>
{
if (_repo.LocalChangesCount > 0)
{
App.RaiseException(_repo.FullPath, "You have local changes. Please run stash or discard first.");
return;
}
App.OpenDialog(new Views.InteractiveRebase()
{
DataContext = new InteractiveRebase(_repo, current, commit)
});
e.Handled = true;
};
menu.Items.Add(interactiveRebase);
menu.Items.Add(new MenuItem() { Header = "-" });
}
}
if (current.Head != commit.SHA) if (current.Head != commit.SHA)
{ {
@ -914,21 +920,24 @@ namespace SourceGit.ViewModels
submenu.Items.Add(rename); submenu.Items.Add(rename);
submenu.Items.Add(new MenuItem() { Header = "-" }); submenu.Items.Add(new MenuItem() { Header = "-" });
var detect = Commands.GitFlow.DetectType(_repo.FullPath, _repo.Branches, current.Name); if (!_repo.IsBare)
if (detect.IsGitFlowBranch)
{ {
var finish = new MenuItem(); var detect = Commands.GitFlow.DetectType(_repo.FullPath, _repo.Branches, current.Name);
finish.Header = new Views.NameHighlightedTextBlock("BranchCM.Finish", current.Name); if (detect.IsGitFlowBranch)
finish.Icon = App.CreateMenuIcon("Icons.GitFlow");
finish.Click += (_, e) =>
{ {
if (_repo.CanCreatePopup()) var finish = new MenuItem();
_repo.ShowPopup(new GitFlowFinish(_repo, current, detect.Type, detect.Prefix)); finish.Header = new Views.NameHighlightedTextBlock("BranchCM.Finish", current.Name);
e.Handled = true; finish.Icon = App.CreateMenuIcon("Icons.GitFlow");
}; finish.Click += (_, e) =>
submenu.Items.Add(finish); {
submenu.Items.Add(new MenuItem() { Header = "-" }); if (_repo.CanCreatePopup())
} _repo.ShowPopup(new GitFlowFinish(_repo, current, detect.Type, detect.Prefix));
e.Handled = true;
};
submenu.Items.Add(finish);
submenu.Items.Add(new MenuItem() { Header = "-" });
}
}
var copy = new MenuItem(); var copy = new MenuItem();
copy.Header = App.Text("BranchCM.CopyName"); copy.Header = App.Text("BranchCM.CopyName");
@ -951,27 +960,30 @@ namespace SourceGit.ViewModels
FillBranchVisibilityMenu(submenu, branch); FillBranchVisibilityMenu(submenu, branch);
var checkout = new MenuItem(); if (!_repo.IsBare)
checkout.Header = new Views.NameHighlightedTextBlock("BranchCM.Checkout", branch.Name);
checkout.Icon = App.CreateMenuIcon("Icons.Check");
checkout.Click += (_, e) =>
{ {
_repo.CheckoutBranch(branch); var checkout = new MenuItem();
e.Handled = true; checkout.Header = new Views.NameHighlightedTextBlock("BranchCM.Checkout", branch.Name);
}; checkout.Icon = App.CreateMenuIcon("Icons.Check");
submenu.Items.Add(checkout); checkout.Click += (_, e) =>
{
_repo.CheckoutBranch(branch);
e.Handled = true;
};
submenu.Items.Add(checkout);
var merge = new MenuItem(); var merge = new MenuItem();
merge.Header = new Views.NameHighlightedTextBlock("BranchCM.Merge", branch.Name, current.Name); merge.Header = new Views.NameHighlightedTextBlock("BranchCM.Merge", branch.Name, current.Name);
merge.Icon = App.CreateMenuIcon("Icons.Merge"); merge.Icon = App.CreateMenuIcon("Icons.Merge");
merge.IsEnabled = !merged; merge.IsEnabled = !merged;
merge.Click += (_, e) => merge.Click += (_, e) =>
{ {
if (_repo.CanCreatePopup()) if (_repo.CanCreatePopup())
_repo.ShowPopup(new Merge(_repo, branch, current.Name)); _repo.ShowPopup(new Merge(_repo, branch, current.Name));
e.Handled = true; e.Handled = true;
}; };
submenu.Items.Add(merge); submenu.Items.Add(merge);
}
var rename = new MenuItem(); var rename = new MenuItem();
rename.Header = new Views.NameHighlightedTextBlock("BranchCM.Rename", branch.Name); rename.Header = new Views.NameHighlightedTextBlock("BranchCM.Rename", branch.Name);
@ -996,21 +1008,24 @@ namespace SourceGit.ViewModels
submenu.Items.Add(delete); submenu.Items.Add(delete);
submenu.Items.Add(new MenuItem() { Header = "-" }); submenu.Items.Add(new MenuItem() { Header = "-" });
var detect = Commands.GitFlow.DetectType(_repo.FullPath, _repo.Branches, branch.Name); if (!_repo.IsBare)
if (detect.IsGitFlowBranch)
{ {
var finish = new MenuItem(); var detect = Commands.GitFlow.DetectType(_repo.FullPath, _repo.Branches, branch.Name);
finish.Header = new Views.NameHighlightedTextBlock("BranchCM.Finish", branch.Name); if (detect.IsGitFlowBranch)
finish.Icon = App.CreateMenuIcon("Icons.GitFlow");
finish.Click += (_, e) =>
{ {
if (_repo.CanCreatePopup()) var finish = new MenuItem();
_repo.ShowPopup(new GitFlowFinish(_repo, branch, detect.Type, detect.Prefix)); finish.Header = new Views.NameHighlightedTextBlock("BranchCM.Finish", branch.Name);
e.Handled = true; finish.Icon = App.CreateMenuIcon("Icons.GitFlow");
}; finish.Click += (_, e) =>
submenu.Items.Add(finish); {
submenu.Items.Add(new MenuItem() { Header = "-" }); if (_repo.CanCreatePopup())
} _repo.ShowPopup(new GitFlowFinish(_repo, branch, detect.Type, detect.Prefix));
e.Handled = true;
};
submenu.Items.Add(finish);
submenu.Items.Add(new MenuItem() { Header = "-" });
}
}
var copy = new MenuItem(); var copy = new MenuItem();
copy.Header = App.Text("BranchCM.CopyName"); copy.Header = App.Text("BranchCM.CopyName");
@ -1104,17 +1119,19 @@ namespace SourceGit.ViewModels
}; };
submenu.Items.Add(push); submenu.Items.Add(push);
var merge = new MenuItem(); if (!_repo.IsBare && !merged)
merge.Header = new Views.NameHighlightedTextBlock("TagCM.Merge", tag.Name, current.Name);
merge.Icon = App.CreateMenuIcon("Icons.Merge");
merge.IsEnabled = !merged;
merge.Click += (_, e) =>
{ {
if (_repo.CanCreatePopup()) var merge = new MenuItem();
_repo.ShowPopup(new Merge(_repo, tag, current.Name)); merge.Header = new Views.NameHighlightedTextBlock("TagCM.Merge", tag.Name, current.Name);
e.Handled = true; merge.Icon = App.CreateMenuIcon("Icons.Merge");
}; merge.Click += (_, e) =>
submenu.Items.Add(merge); {
if (_repo.CanCreatePopup())
_repo.ShowPopup(new Merge(_repo, tag, current.Name));
e.Handled = true;
};
submenu.Items.Add(merge);
}
var delete = new MenuItem(); var delete = new MenuItem();
delete.Header = new Views.NameHighlightedTextBlock("TagCM.Delete", tag.Name); delete.Header = new Views.NameHighlightedTextBlock("TagCM.Delete", tag.Name);

View file

@ -280,19 +280,20 @@ namespace SourceGit.ViewModels
return; return;
} }
var gitDir = new Commands.QueryGitDir(node.Id).Result(); var isBare = new Commands.IsBareRepository(node.Id).Result();
if (string.IsNullOrEmpty(gitDir)) var gitDir = node.Id;
if (!isBare)
{ {
var ctx = page == null ? ActivePage.Node.Id : page.Node.Id; gitDir = new Commands.QueryGitDir(node.Id).Result();
App.RaiseException(ctx, "Given path is not a valid git repository!"); if (string.IsNullOrEmpty(gitDir))
return; {
var ctx = page == null ? ActivePage.Node.Id : page.Node.Id;
App.RaiseException(ctx, "Given path is not a valid git repository!");
return;
}
} }
var repo = new Repository() var repo = new Repository(isBare, node.Id, gitDir);
{
FullPath = node.Id,
GitDir = gitDir,
};
repo.Open(); repo.Open();
if (page == null) if (page == null)

View file

@ -18,6 +18,11 @@ namespace SourceGit.ViewModels
{ {
public class Repository : ObservableObject, Models.IRepository public class Repository : ObservableObject, Models.IRepository
{ {
public bool IsBare
{
get;
}
public string FullPath public string FullPath
{ {
get => _fullpath; get => _fullpath;
@ -448,6 +453,13 @@ namespace SourceGit.ViewModels
private set => SetProperty(ref _isAutoFetching, value); private set => SetProperty(ref _isAutoFetching, value);
} }
public Repository(bool isBare, string path, string gitDir)
{
IsBare = isBare;
FullPath = path;
GitDir = gitDir;
}
public void Open() public void Open()
{ {
var settingsFile = Path.Combine(_gitDir, "sourcegit.settings"); var settingsFile = Path.Combine(_gitDir, "sourcegit.settings");
@ -995,6 +1007,9 @@ namespace SourceGit.ViewModels
public void RefreshWorkingCopyChanges() public void RefreshWorkingCopyChanges()
{ {
if (IsBare)
return;
var changes = new Commands.QueryLocalChanges(_fullpath, _settings.IncludeUntrackedInLocalChanges).Result(); var changes = new Commands.QueryLocalChanges(_fullpath, _settings.IncludeUntrackedInLocalChanges).Result();
if (_workingCopy == null) if (_workingCopy == null)
return; return;
@ -1010,6 +1025,9 @@ namespace SourceGit.ViewModels
public void RefreshStashes() public void RefreshStashes()
{ {
if (IsBare)
return;
var stashes = new Commands.QueryStashes(_fullpath).Result(); var stashes = new Commands.QueryStashes(_fullpath).Result();
Dispatcher.UIThread.Invoke(() => Dispatcher.UIThread.Invoke(() =>
{ {
@ -1044,6 +1062,9 @@ namespace SourceGit.ViewModels
} }
} }
if (IsBare)
return;
if (!CanCreatePopup()) if (!CanCreatePopup())
return; return;
@ -1416,66 +1437,72 @@ namespace SourceGit.ViewModels
if (branch.IsCurrent) if (branch.IsCurrent)
{ {
var discard = new MenuItem(); if (!IsBare)
discard.Header = App.Text("BranchCM.DiscardAll");
discard.Icon = App.CreateMenuIcon("Icons.Undo");
discard.Click += (_, e) =>
{ {
if (CanCreatePopup()) var discard = new MenuItem();
ShowPopup(new Discard(this)); discard.Header = App.Text("BranchCM.DiscardAll");
e.Handled = true; discard.Icon = App.CreateMenuIcon("Icons.Undo");
}; discard.Click += (_, e) =>
menu.Items.Add(discard);
menu.Items.Add(new MenuItem() { Header = "-" });
if (!string.IsNullOrEmpty(branch.Upstream))
{
var upstream = branch.Upstream.Substring(13);
var fastForward = new MenuItem();
fastForward.Header = new Views.NameHighlightedTextBlock("BranchCM.FastForward", upstream);
fastForward.Icon = App.CreateMenuIcon("Icons.FastForward");
fastForward.IsEnabled = branch.TrackStatus.Ahead.Count == 0;
fastForward.Click += (_, e) =>
{ {
var b = _branches.Find(x => x.FriendlyName == upstream);
if (b == null)
return;
if (CanCreatePopup()) if (CanCreatePopup())
ShowAndStartPopup(new Merge(this, b, branch.Name)); ShowPopup(new Discard(this));
e.Handled = true; e.Handled = true;
}; };
var pull = new MenuItem(); menu.Items.Add(discard);
pull.Header = new Views.NameHighlightedTextBlock("BranchCM.Pull", upstream); menu.Items.Add(new MenuItem() { Header = "-" });
pull.Icon = App.CreateMenuIcon("Icons.Pull");
pull.Click += (_, e) =>
{
if (CanCreatePopup())
ShowPopup(new Pull(this, null));
e.Handled = true;
};
menu.Items.Add(fastForward); if (!string.IsNullOrEmpty(branch.Upstream))
menu.Items.Add(pull); {
} var upstream = branch.Upstream.Substring(13);
var fastForward = new MenuItem();
fastForward.Header = new Views.NameHighlightedTextBlock("BranchCM.FastForward", upstream);
fastForward.Icon = App.CreateMenuIcon("Icons.FastForward");
fastForward.IsEnabled = branch.TrackStatus.Ahead.Count == 0;
fastForward.Click += (_, e) =>
{
var b = _branches.Find(x => x.FriendlyName == upstream);
if (b == null)
return;
if (CanCreatePopup())
ShowAndStartPopup(new Merge(this, b, branch.Name));
e.Handled = true;
};
var pull = new MenuItem();
pull.Header = new Views.NameHighlightedTextBlock("BranchCM.Pull", upstream);
pull.Icon = App.CreateMenuIcon("Icons.Pull");
pull.Click += (_, e) =>
{
if (CanCreatePopup())
ShowPopup(new Pull(this, null));
e.Handled = true;
};
menu.Items.Add(fastForward);
menu.Items.Add(pull);
}
}
menu.Items.Add(push); menu.Items.Add(push);
} }
else else
{ {
var checkout = new MenuItem(); if (!IsBare)
checkout.Header = new Views.NameHighlightedTextBlock("BranchCM.Checkout", branch.Name);
checkout.Icon = App.CreateMenuIcon("Icons.Check");
checkout.Click += (_, e) =>
{ {
CheckoutBranch(branch); var checkout = new MenuItem();
e.Handled = true; checkout.Header = new Views.NameHighlightedTextBlock("BranchCM.Checkout", branch.Name);
}; checkout.Icon = App.CreateMenuIcon("Icons.Check");
menu.Items.Add(checkout); checkout.Click += (_, e) =>
menu.Items.Add(new MenuItem() { Header = "-" }); {
CheckoutBranch(branch);
e.Handled = true;
};
menu.Items.Add(checkout);
menu.Items.Add(new MenuItem() { Header = "-" });
}
var worktree = _worktrees.Find(x => x.Branch == branch.FullName); var worktree = _worktrees.Find(x => x.Branch == branch.FullName);
var upstream = _branches.Find(x => x.FullName == branch.Upstream); var upstream = _branches.Find(x => x.FullName == branch.Upstream);
@ -1510,28 +1537,31 @@ namespace SourceGit.ViewModels
menu.Items.Add(push); menu.Items.Add(push);
var merge = new MenuItem(); if (!IsBare)
merge.Header = new Views.NameHighlightedTextBlock("BranchCM.Merge", branch.Name, _currentBranch.Name);
merge.Icon = App.CreateMenuIcon("Icons.Merge");
merge.Click += (_, e) =>
{ {
if (CanCreatePopup()) var merge = new MenuItem();
ShowPopup(new Merge(this, branch, _currentBranch.Name)); merge.Header = new Views.NameHighlightedTextBlock("BranchCM.Merge", branch.Name, _currentBranch.Name);
e.Handled = true; merge.Icon = App.CreateMenuIcon("Icons.Merge");
}; merge.Click += (_, e) =>
{
if (CanCreatePopup())
ShowPopup(new Merge(this, branch, _currentBranch.Name));
e.Handled = true;
};
var rebase = new MenuItem(); var rebase = new MenuItem();
rebase.Header = new Views.NameHighlightedTextBlock("BranchCM.Rebase", _currentBranch.Name, branch.Name); rebase.Header = new Views.NameHighlightedTextBlock("BranchCM.Rebase", _currentBranch.Name, branch.Name);
rebase.Icon = App.CreateMenuIcon("Icons.Rebase"); rebase.Icon = App.CreateMenuIcon("Icons.Rebase");
rebase.Click += (_, e) => rebase.Click += (_, e) =>
{ {
if (CanCreatePopup()) if (CanCreatePopup())
ShowPopup(new Rebase(this, _currentBranch, branch)); ShowPopup(new Rebase(this, _currentBranch, branch));
e.Handled = true; e.Handled = true;
}; };
menu.Items.Add(merge); menu.Items.Add(merge);
menu.Items.Add(rebase); menu.Items.Add(rebase);
}
var compareWithHead = new MenuItem(); var compareWithHead = new MenuItem();
compareWithHead.Header = App.Text("BranchCM.CompareWithHead"); compareWithHead.Header = App.Text("BranchCM.CompareWithHead");
@ -1566,21 +1596,24 @@ namespace SourceGit.ViewModels
} }
} }
var detect = Commands.GitFlow.DetectType(_fullpath, _branches, branch.Name); if (!IsBare)
if (detect.IsGitFlowBranch)
{ {
var finish = new MenuItem(); var detect = Commands.GitFlow.DetectType(_fullpath, _branches, branch.Name);
finish.Header = new Views.NameHighlightedTextBlock("BranchCM.Finish", branch.Name); if (detect.IsGitFlowBranch)
finish.Icon = App.CreateMenuIcon("Icons.GitFlow");
finish.Click += (_, e) =>
{ {
if (CanCreatePopup()) var finish = new MenuItem();
ShowPopup(new GitFlowFinish(this, branch, detect.Type, detect.Prefix)); finish.Header = new Views.NameHighlightedTextBlock("BranchCM.Finish", branch.Name);
e.Handled = true; finish.Icon = App.CreateMenuIcon("Icons.GitFlow");
}; finish.Click += (_, e) =>
menu.Items.Add(new MenuItem() { Header = "-" }); {
menu.Items.Add(finish); if (CanCreatePopup())
} ShowPopup(new GitFlowFinish(this, branch, detect.Type, detect.Prefix));
e.Handled = true;
};
menu.Items.Add(new MenuItem() { Header = "-" });
menu.Items.Add(finish);
}
}
var rename = new MenuItem(); var rename = new MenuItem();
rename.Header = new Views.NameHighlightedTextBlock("BranchCM.Rename", branch.Name); rename.Header = new Views.NameHighlightedTextBlock("BranchCM.Rename", branch.Name);
@ -1631,26 +1664,29 @@ namespace SourceGit.ViewModels
menu.Items.Add(createTag); menu.Items.Add(createTag);
menu.Items.Add(new MenuItem() { Header = "-" }); menu.Items.Add(new MenuItem() { Header = "-" });
var remoteBranches = new List<Models.Branch>(); if (!IsBare)
foreach (var b in _branches)
{ {
if (!b.IsLocal) var remoteBranches = new List<Models.Branch>();
remoteBranches.Add(b); foreach (var b in _branches)
}
if (remoteBranches.Count > 0)
{
var tracking = new MenuItem();
tracking.Header = App.Text("BranchCM.Tracking");
tracking.Icon = App.CreateMenuIcon("Icons.Track");
tracking.Click += (_, e) =>
{ {
if (CanCreatePopup()) if (!b.IsLocal)
ShowPopup(new SetUpstream(this, branch, remoteBranches)); remoteBranches.Add(b);
e.Handled = true; }
};
menu.Items.Add(tracking); if (remoteBranches.Count > 0)
} {
var tracking = new MenuItem();
tracking.Header = App.Text("BranchCM.Tracking");
tracking.Icon = App.CreateMenuIcon("Icons.Track");
tracking.Click += (_, e) =>
{
if (CanCreatePopup())
ShowPopup(new SetUpstream(this, branch, remoteBranches));
e.Handled = true;
};
menu.Items.Add(tracking);
}
}
var archive = new MenuItem(); var archive = new MenuItem();
archive.Icon = App.CreateMenuIcon("Icons.Archive"); archive.Icon = App.CreateMenuIcon("Icons.Archive");

View file

@ -34,7 +34,7 @@ namespace SourceGit.ViewModels
watch.Start(); watch.Start();
var rootDir = new DirectoryInfo(RootDir); var rootDir = new DirectoryInfo(RootDir);
var founded = new List<string>(); var founded = new List<FoundRepository>();
GetUnmanagedRepositories(rootDir, founded, new EnumerationOptions() GetUnmanagedRepositories(rootDir, founded, new EnumerationOptions()
{ {
AttributesToSkip = FileAttributes.Hidden | FileAttributes.System, AttributesToSkip = FileAttributes.Hidden | FileAttributes.System,
@ -47,16 +47,16 @@ namespace SourceGit.ViewModels
foreach (var f in founded) foreach (var f in founded)
{ {
var parent = new DirectoryInfo(f).Parent!.FullName.Replace("\\", "/"); var parent = new DirectoryInfo(f.Path).Parent!.FullName.Replace("\\", "/");
if (parent.Equals(normalizedRoot, StringComparison.Ordinal)) if (parent.Equals(normalizedRoot, StringComparison.Ordinal))
{ {
Preferences.Instance.FindOrAddNodeByRepositoryPath(f, null, false); Preferences.Instance.FindOrAddNodeByRepositoryPath(f.Path, null, false);
} }
else if (parent.StartsWith(normalizedRoot, StringComparison.Ordinal)) else if (parent.StartsWith(normalizedRoot, StringComparison.Ordinal))
{ {
var relative = parent.Substring(normalizedRoot.Length).TrimStart('/'); var relative = parent.Substring(normalizedRoot.Length).TrimStart('/');
var group = FindOrCreateGroupRecursive(Preferences.Instance.RepositoryNodes, relative); var group = FindOrCreateGroupRecursive(Preferences.Instance.RepositoryNodes, relative);
Preferences.Instance.FindOrAddNodeByRepositoryPath(f, group, false); Preferences.Instance.FindOrAddNodeByRepositoryPath(f.Path, group, false);
} }
} }
@ -85,7 +85,7 @@ namespace SourceGit.ViewModels
} }
} }
private void GetUnmanagedRepositories(DirectoryInfo dir, List<string> outs, EnumerationOptions opts, int depth = 0) private void GetUnmanagedRepositories(DirectoryInfo dir, List<FoundRepository> outs, EnumerationOptions opts, int depth = 0)
{ {
var subdirs = dir.GetDirectories("*", opts); var subdirs = dir.GetDirectories("*", opts);
foreach (var subdir in subdirs) foreach (var subdir in subdirs)
@ -111,12 +111,19 @@ namespace SourceGit.ViewModels
{ {
var normalized = test.StdOut.Trim().Replace("\\", "/"); var normalized = test.StdOut.Trim().Replace("\\", "/");
if (!_managed.Contains(normalized)) if (!_managed.Contains(normalized))
outs.Add(normalized); outs.Add(new FoundRepository(normalized, false));
} }
continue; continue;
} }
var isBare = new Commands.IsBareRepository(subdir.FullName).Result();
if (isBare)
{
outs.Add(new FoundRepository(normalizedSelf, true));
continue;
}
if (depth < 5) if (depth < 5)
GetUnmanagedRepositories(subdir, outs, opts, depth + 1); GetUnmanagedRepositories(subdir, outs, opts, depth + 1);
} }
@ -161,6 +168,12 @@ namespace SourceGit.ViewModels
return added; return added;
} }
private record FoundRepository(string path, bool isBare)
{
public string Path { get; set; } = path;
public bool IsBare { get; set; } = isBare;
}
private HashSet<string> _managed = new HashSet<string>(); private HashSet<string> _managed = new HashSet<string>();
} }
} }

View file

@ -94,20 +94,20 @@ namespace SourceGit.ViewModels
} }
var isBare = new Commands.IsBareRepository(path).Result(); var isBare = new Commands.IsBareRepository(path).Result();
if (isBare) var repoRoot = path;
if (!isBare)
{ {
App.RaiseException(string.Empty, $"'{path}' is a bare repository, which is not supported by SourceGit!"); var test = new Commands.QueryRepositoryRootPath(path).ReadToEnd();
return; if (!test.IsSuccess || string.IsNullOrEmpty(test.StdOut))
{
InitRepository(path, parent, test.StdErr);
return;
}
repoRoot = test.StdOut.Trim();
} }
var test = new Commands.QueryRepositoryRootPath(path).ReadToEnd(); var node = Preferences.Instance.FindOrAddNodeByRepositoryPath(repoRoot, parent, bMoveExistedNode);
if (!test.IsSuccess || string.IsNullOrEmpty(test.StdOut))
{
InitRepository(path, parent, test.StdErr);
return;
}
var node = Preferences.Instance.FindOrAddNodeByRepositoryPath(test.StdOut.Trim(), parent, bMoveExistedNode);
Refresh(); Refresh();
var launcher = App.GetLauncer(); var launcher = App.GetLauncer();

View file

@ -18,8 +18,8 @@
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="32"/> <RowDefinition Height="32"/>
<RowDefinition Height="32"/> <RowDefinition Height="32"/>
<RowDefinition Height="Auto" MinHeight="32"/> <RowDefinition Height="Auto"/>
<RowDefinition Height="32"/> <RowDefinition Height="Auto"/>
</Grid.RowDefinitions> </Grid.RowDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" <TextBlock Grid.Row="0" Grid.Column="0"
@ -67,27 +67,31 @@
<TextBlock Grid.Row="2" Grid.Column="0" <TextBlock Grid.Row="2" Grid.Column="0"
HorizontalAlignment="Right" VerticalAlignment="Center" HorizontalAlignment="Right" VerticalAlignment="Center"
Margin="0,0,8,0" Margin="0,0,8,0"
Text="{DynamicResource Text.CreateBranch.LocalChanges}"/> Text="{DynamicResource Text.CreateBranch.LocalChanges}"
<WrapPanel Grid.Row="2" Grid.Column="1" Orientation="Horizontal" VerticalAlignment="Center"> IsVisible="{Binding !IsBareRepository}"/>
<RadioButton Content="{DynamicResource Text.CreateBranch.LocalChanges.DoNothing}" <Border Grid.Row="2" Grid.Column="1" MinHeight="32" IsVisible="{Binding !IsBareRepository}">
x:Name="RadioDoNothing" <WrapPanel Orientation="Horizontal" VerticalAlignment="Center">
GroupName="LocalChanges" <RadioButton Content="{DynamicResource Text.CreateBranch.LocalChanges.DoNothing}"
Margin="0,0,8,0" x:Name="RadioDoNothing"
IsCheckedChanged="OnLocalChangeActionIsCheckedChanged"/> GroupName="LocalChanges"
<RadioButton Content="{DynamicResource Text.CreateBranch.LocalChanges.StashAndReply}" Margin="0,0,8,0"
x:Name="RadioStashAndReply" IsCheckedChanged="OnLocalChangeActionIsCheckedChanged"/>
GroupName="LocalChanges" <RadioButton Content="{DynamicResource Text.CreateBranch.LocalChanges.StashAndReply}"
Margin="0,0,8,0" x:Name="RadioStashAndReply"
IsCheckedChanged="OnLocalChangeActionIsCheckedChanged"/> GroupName="LocalChanges"
<RadioButton Content="{DynamicResource Text.CreateBranch.LocalChanges.Discard}" Margin="0,0,8,0"
x:Name="RadioDiscard" IsCheckedChanged="OnLocalChangeActionIsCheckedChanged"/>
GroupName="LocalChanges" <RadioButton Content="{DynamicResource Text.CreateBranch.LocalChanges.Discard}"
IsCheckedChanged="OnLocalChangeActionIsCheckedChanged"/> x:Name="RadioDiscard"
</WrapPanel> GroupName="LocalChanges"
IsCheckedChanged="OnLocalChangeActionIsCheckedChanged"/>
</WrapPanel>
</Border>
<CheckBox Grid.Row="3" Grid.Column="1" <CheckBox Grid.Row="3" Grid.Column="1"
Content="{DynamicResource Text.CreateBranch.Checkout}" Content="{DynamicResource Text.CreateBranch.Checkout}"
IsChecked="{Binding CheckoutAfterCreated, Mode=TwoWay}"/> IsChecked="{Binding CheckoutAfterCreated, Mode=TwoWay}"
IsVisible="{Binding !IsBareRepository}"/>
</Grid> </Grid>
</StackPanel> </StackPanel>
</UserControl> </UserControl>

View file

@ -40,7 +40,7 @@
<!-- Page Switcher for Right Panel --> <!-- Page Switcher for Right Panel -->
<Border Grid.Row="0" Margin="8,0,4,0" BorderThickness="1" BorderBrush="{DynamicResource Brush.Border2}" CornerRadius="6"> <Border Grid.Row="0" Margin="8,0,4,0" BorderThickness="1" BorderBrush="{DynamicResource Brush.Border2}" CornerRadius="6">
<Border CornerRadius="6" ClipToBounds="True"> <Border CornerRadius="6" ClipToBounds="True">
<ListBox Background="Transparent" SelectedIndex="{Binding SelectedViewIndex, Mode=TwoWay}"> <ListBox Background="Transparent" SelectedIndex="{Binding SelectedViewIndex, Mode=TwoWay}" SelectionMode="AlwaysSelected">
<ListBox.Styles> <ListBox.Styles>
<Style Selector="Path.icon"> <Style Selector="Path.icon">
<Setter Property="Width" Value="12"/> <Setter Property="Width" Value="12"/>
@ -128,7 +128,7 @@
</Grid> </Grid>
</ListBoxItem> </ListBoxItem>
<ListBoxItem> <ListBoxItem IsVisible="{Binding !IsBare}">
<Grid Classes="view_mode" ColumnDefinitions="Auto,*,Auto"> <Grid Classes="view_mode" ColumnDefinitions="Auto,*,Auto">
<Path Grid.Column="0" Classes="icon" Data="{StaticResource Icons.Changes}"/> <Path Grid.Column="0" Classes="icon" Data="{StaticResource Icons.Changes}"/>
<TextBlock Grid.Column="1" Classes="header" Text="{DynamicResource Text.WorkingCopy}"/> <TextBlock Grid.Column="1" Classes="header" Text="{DynamicResource Text.WorkingCopy}"/>
@ -143,7 +143,7 @@
</Grid> </Grid>
</ListBoxItem> </ListBoxItem>
<ListBoxItem> <ListBoxItem IsVisible="{Binding !IsBare}">
<Grid Classes="view_mode" ColumnDefinitions="Auto,*,Auto"> <Grid Classes="view_mode" ColumnDefinitions="Auto,*,Auto">
<Path Grid.Column="0" Classes="icon" Data="{StaticResource Icons.Stashes}"/> <Path Grid.Column="0" Classes="icon" Data="{StaticResource Icons.Stashes}"/>
<TextBlock Grid.Column="1" Classes="header" Text="{DynamicResource Text.Stashes}"/> <TextBlock Grid.Column="1" Classes="header" Text="{DynamicResource Text.Stashes}"/>

View file

@ -13,7 +13,7 @@
<Path Width="14" Height="14" Data="{StaticResource Icons.Explore}" Margin="0,2,0,0"/> <Path Width="14" Height="14" Data="{StaticResource Icons.Explore}" Margin="0,2,0,0"/>
</Button> </Button>
<Button Classes="icon_button" Width="32" Click="OpenWithExternalTools" ToolTip.Tip="{DynamicResource Text.Repository.OpenWithExternalTools}"> <Button Classes="icon_button" Width="32" Click="OpenWithExternalTools" IsVisible="{Binding !IsBare}" ToolTip.Tip="{DynamicResource Text.Repository.OpenWithExternalTools}">
<Path Width="13" Height="13" Data="{StaticResource Icons.OpenWith}"/> <Path Width="13" Height="13" Data="{StaticResource Icons.OpenWith}"/>
</Button> </Button>
@ -42,7 +42,7 @@
<Path Width="14" Height="14" Data="{StaticResource Icons.Fetch}"/> <Path Width="14" Height="14" Data="{StaticResource Icons.Fetch}"/>
</Button> </Button>
<Button Classes="icon_button" Width="32" Margin="16,0,0,0" Click="Pull" HotKey="{OnPlatform Ctrl+Shift+Down, macOS=⌘+Shift+Down}"> <Button Classes="icon_button" Width="32" Margin="16,0,0,0" Click="Pull" IsVisible="{Binding !IsBare}" IsEnabled="{Binding !IsBare}" HotKey="{OnPlatform Ctrl+Shift+Down, macOS=⌘+Shift+Down}">
<ToolTip.Tip> <ToolTip.Tip>
<StackPanel Orientation="Vertical"> <StackPanel Orientation="Vertical">
<TextBlock Text="{DynamicResource Text.Pull}"/> <TextBlock Text="{DynamicResource Text.Pull}"/>
@ -64,7 +64,7 @@
<Path Width="14" Height="14" Data="{StaticResource Icons.Push}"/> <Path Width="14" Height="14" Data="{StaticResource Icons.Push}"/>
</Button> </Button>
<Button Classes="icon_button" Width="32" Margin="16,0,0,0" Click="StashAll"> <Button Classes="icon_button" Width="32" Margin="16,0,0,0" Click="StashAll" IsVisible="{Binding !IsBare}">
<ToolTip.Tip> <ToolTip.Tip>
<StackPanel Orientation="Vertical"> <StackPanel Orientation="Vertical">
<TextBlock Text="{DynamicResource Text.Stash}"/> <TextBlock Text="{DynamicResource Text.Stash}"/>
@ -75,7 +75,7 @@
<Path Width="14" Height="14" Data="{StaticResource Icons.Stashes.Add}"/> <Path Width="14" Height="14" Data="{StaticResource Icons.Stashes.Add}"/>
</Button> </Button>
<Button Classes="icon_button" Width="32" Margin="16,0,0,0" Command="{Binding ApplyPatch}" ToolTip.Tip="{DynamicResource Text.Apply}"> <Button Classes="icon_button" Width="32" Margin="16,0,0,0" Command="{Binding ApplyPatch}" IsVisible="{Binding !IsBare}" ToolTip.Tip="{DynamicResource Text.Apply}">
<Path Width="14" Height="14" Data="{StaticResource Icons.Diff}"/> <Path Width="14" Height="14" Data="{StaticResource Icons.Diff}"/>
</Button> </Button>
@ -88,11 +88,11 @@
<Path Width="14" Height="14" Data="{StaticResource Icons.Branch.Add}"/> <Path Width="14" Height="14" Data="{StaticResource Icons.Branch.Add}"/>
</Button> </Button>
<Button Classes="icon_button" Width="32" Margin="8,0,0,0" Click="OpenGitFlowMenu" ToolTip.Tip="{DynamicResource Text.GitFlow}"> <Button Classes="icon_button" Width="32" Margin="8,0,0,0" Click="OpenGitFlowMenu" IsVisible="{Binding !IsBare}" ToolTip.Tip="{DynamicResource Text.GitFlow}">
<Path Width="14" Height="14" Data="{StaticResource Icons.GitFlow}"/> <Path Width="14" Height="14" Data="{StaticResource Icons.GitFlow}"/>
</Button> </Button>
<Button Classes="icon_button" Width="32" Margin="8,0,0,0" Click="OpenGitLFSMenu" ToolTip.Tip="{DynamicResource Text.GitLFS}"> <Button Classes="icon_button" Width="32" Margin="8,0,0,0" Click="OpenGitLFSMenu" IsVisible="{Binding !IsBare}" ToolTip.Tip="{DynamicResource Text.GitLFS}">
<Path Width="14" Height="14" Data="{StaticResource Icons.LFS}"/> <Path Width="14" Height="14" Data="{StaticResource Icons.LFS}"/>
</Button> </Button>

View file

@ -59,6 +59,12 @@ namespace SourceGit.Views
var launcher = this.FindAncestorOfType<Launcher>(); var launcher = this.FindAncestorOfType<Launcher>();
if (launcher is not null && DataContext is ViewModels.Repository repo) if (launcher is not null && DataContext is ViewModels.Repository repo)
{ {
if (repo.IsBare)
{
App.RaiseException(repo.FullPath, "Can't run `git pull` in bare repository!");
return;
}
var startDirectly = launcher.HasKeyModifier(KeyModifiers.Control); var startDirectly = launcher.HasKeyModifier(KeyModifiers.Control);
launcher.ClearKeyModifier(); launcher.ClearKeyModifier();
repo.Pull(startDirectly); repo.Pull(startDirectly);