feature: add worktree support (#205)

This commit is contained in:
leo 2024-06-27 18:25:16 +08:00
parent 43af8c49a1
commit 8a8aabede3
No known key found for this signature in database
23 changed files with 959 additions and 21 deletions

View file

@ -131,6 +131,13 @@ namespace SourceGit.ViewModels
private set => SetProperty(ref _remoteBranchTrees, value);
}
[JsonIgnore]
public List<Models.Worktree> Worktrees
{
get => _worktrees;
private set => SetProperty(ref _worktrees, value);
}
[JsonIgnore]
public List<Models.Tag> Tags
{
@ -219,6 +226,13 @@ namespace SourceGit.ViewModels
set => SetProperty(ref _isSubmoduleGroupExpanded, value);
}
[JsonIgnore]
public bool IsWorktreeGroupExpanded
{
get => _isWorktreeGroupExpanded;
set => SetProperty(ref _isWorktreeGroupExpanded, value);
}
[JsonIgnore]
public InProgressContext InProgressContext
{
@ -295,6 +309,7 @@ namespace SourceGit.ViewModels
});
Task.Run(RefreshSubmodules);
Task.Run(RefreshWorktrees);
Task.Run(RefreshWorkingCopyChanges);
Task.Run(RefreshStashes);
}
@ -590,11 +605,31 @@ namespace SourceGit.ViewModels
});
}
public void RefreshWorktrees()
{
var worktrees = new Commands.Worktree(_fullpath).List();
var cleaned = new List<Models.Worktree>();
foreach (var worktree in worktrees)
{
if (worktree.IsBare || worktree.FullPath.Equals(_fullpath))
continue;
cleaned.Add(worktree);
}
Dispatcher.UIThread.Invoke(() =>
{
Worktrees = cleaned;
});
}
public void RefreshTags()
{
var tags = new Commands.QueryTags(FullPath).Result();
foreach (var tag in tags)
tag.IsFiltered = Filters.Contains(tag.Name);
Dispatcher.UIThread.Invoke(() =>
{
Tags = tags;
@ -656,10 +691,7 @@ namespace SourceGit.ViewModels
public void RefreshSubmodules()
{
var submodules = new Commands.QuerySubmodules(FullPath).Result();
Dispatcher.UIThread.Invoke(() =>
{
Submodules = submodules;
});
Dispatcher.UIThread.Invoke(() => Submodules = submodules);
}
public void RefreshWorkingCopyChanges()
@ -732,6 +764,16 @@ namespace SourceGit.ViewModels
public void CheckoutBranch(Models.Branch branch)
{
if (branch.IsLocal)
{
var worktree = _worktrees.Find(x => x.Branch == branch.FullName);
if (worktree != null)
{
OpenWorktree(worktree);
return;
}
}
if (!PopupHost.CanCreatePopup())
return;
@ -817,6 +859,36 @@ namespace SourceGit.ViewModels
}
}
public void AddWorktree()
{
if (PopupHost.CanCreatePopup())
PopupHost.ShowPopup(new AddWorktree(this));
}
public void PruneWorktrees()
{
if (PopupHost.CanCreatePopup())
PopupHost.ShowAndStartPopup(new PruneWorktrees(this));
}
public void OpenWorktree(Models.Worktree worktree)
{
var gitDir = new Commands.QueryGitDir(worktree.FullPath).Result();
var repo = Preference.AddRepository(worktree.FullPath, gitDir);
var node = new RepositoryNode()
{
Id = repo.FullPath,
Name = Path.GetFileName(repo.FullPath),
Bookmark = 0,
IsRepository = true,
};
var launcher = App.GetTopLevel().DataContext as Launcher;
if (launcher != null)
launcher.OpenRepositoryInTab(node, null);
}
public ContextMenu CreateContextMenuForGitFlow()
{
var menu = new ContextMenu();
@ -1260,9 +1332,8 @@ namespace SourceGit.ViewModels
target.Click += (o, e) =>
{
if (Commands.Branch.SetUpstream(_fullpath, branch.Name, upstream))
{
Task.Run(RefreshBranches);
}
e.Handled = true;
};
@ -1274,9 +1345,8 @@ namespace SourceGit.ViewModels
unsetUpstream.Click += (_, e) =>
{
if (Commands.Branch.SetUpstream(_fullpath, branch.Name, string.Empty))
{
Task.Run(RefreshBranches);
}
e.Handled = true;
};
tracking.Items.Add(new MenuItem() { Header = "-" });
@ -1634,6 +1704,65 @@ namespace SourceGit.ViewModels
return menu;
}
public ContextMenu CreateContextMenuForWorktree(Models.Worktree worktree)
{
var menu = new ContextMenu();
if (worktree.IsLocked)
{
var unlock = new MenuItem();
unlock.Header = App.Text("Worktree.Unlock");
unlock.Icon = App.CreateMenuIcon("Icons.Unlock");
unlock.Click += (o, ev) =>
{
SetWatcherEnabled(false);
var succ = new Commands.Worktree(_fullpath).Unlock(worktree.FullPath);
if (succ)
worktree.IsLocked = false;
SetWatcherEnabled(true);
ev.Handled = true;
};
menu.Items.Add(unlock);
}
else
{
var loc = new MenuItem();
loc.Header = App.Text("Worktree.Lock");
loc.Icon = App.CreateMenuIcon("Icons.Lock");
loc.Click += (o, ev) =>
{
if (PopupHost.CanCreatePopup())
PopupHost.ShowPopup(new LockWorktree(this, worktree));
ev.Handled = true;
};
menu.Items.Add(loc);
}
var remove = new MenuItem();
remove.Header = App.Text("Worktree.Remove");
remove.Icon = App.CreateMenuIcon("Icons.Clear");
remove.Click += (o, ev) =>
{
if (PopupHost.CanCreatePopup())
PopupHost.ShowPopup(new RemoveWorktree(this, worktree));
ev.Handled = true;
};
menu.Items.Add(remove);
var copy = new MenuItem();
copy.Header = App.Text("Worktree.CopyPath");
copy.Icon = App.CreateMenuIcon("Icons.Copy");
copy.Click += (o, e) =>
{
App.CopyText(worktree.FullPath);
e.Handled = true;
};
menu.Items.Add(new MenuItem() { Header = "-" });
menu.Items.Add(copy);
return menu;
}
private MenuItem CreateMenuItemToCompareBranches(Models.Branch branch)
{
if (Branches.Count == 1)
@ -1712,6 +1841,7 @@ namespace SourceGit.ViewModels
private bool _isTagGroupExpanded = false;
private bool _isSubmoduleGroupExpanded = false;
private bool _isWorktreeGroupExpanded = false;
private string _searchBranchFilter = string.Empty;
@ -1719,6 +1849,7 @@ namespace SourceGit.ViewModels
private List<Models.Branch> _branches = new List<Models.Branch>();
private List<BranchTreeNode> _localBranchTrees = new List<BranchTreeNode>();
private List<BranchTreeNode> _remoteBranchTrees = new List<BranchTreeNode>();
private List<Models.Worktree> _worktrees = new List<Models.Worktree>();
private List<Models.Tag> _tags = new List<Models.Tag>();
private List<string> _submodules = new List<string>();
private bool _includeUntracked = true;