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,6 +420,8 @@ namespace SourceGit.ViewModels
menu.Items.Add(patch);
menu.Items.Add(new MenuItem { Header = "-" });
if (!_repo.IsBare)
{
var resetToThisRevision = new MenuItem();
resetToThisRevision.Header = App.Text("ChangeCM.CheckoutThisRevision");
resetToThisRevision.Icon = App.CreateMenuIcon("Icons.File.Checkout");
@ -448,6 +450,7 @@ namespace SourceGit.ViewModels
if (File.Exists(Path.Combine(fullPath)))
TryToAddContextMenuItemsForGitLFS(menu, change.Path);
}
var copyPath = new MenuItem();
copyPath.Header = App.Text("CopyPath");

View file

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

View file

@ -213,7 +213,7 @@ namespace SourceGit.ViewModels
{
if (firstRemoteBranch != null)
_repo.ShowPopup(new CreateBranch(_repo, firstRemoteBranch));
else
else if (!_repo.IsBare)
_repo.ShowPopup(new CheckoutCommit(_repo, commit));
}
}
@ -253,6 +253,8 @@ namespace SourceGit.ViewModels
var multipleMenu = new ContextMenu();
if (!_repo.IsBare)
{
if (canCherryPick)
{
var cherryPickMultiple = new MenuItem();
@ -283,6 +285,7 @@ namespace SourceGit.ViewModels
if (canCherryPick || canMerge)
multipleMenu.Items.Add(new MenuItem() { Header = "-" });
}
var saveToPatchMultiple = new MenuItem();
saveToPatchMultiple.Icon = App.CreateMenuIcon("Icons.Diff");
@ -394,6 +397,8 @@ namespace SourceGit.ViewModels
menu.Items.Add(new MenuItem() { Header = "-" });
}
if (!_repo.IsBare)
{
if (current.Head != commit.SHA)
{
var reset = new MenuItem();
@ -584,6 +589,7 @@ namespace SourceGit.ViewModels
menu.Items.Add(interactiveRebase);
menu.Items.Add(new MenuItem() { Header = "-" });
}
}
if (current.Head != commit.SHA)
{
@ -914,6 +920,8 @@ namespace SourceGit.ViewModels
submenu.Items.Add(rename);
submenu.Items.Add(new MenuItem() { Header = "-" });
if (!_repo.IsBare)
{
var detect = Commands.GitFlow.DetectType(_repo.FullPath, _repo.Branches, current.Name);
if (detect.IsGitFlowBranch)
{
@ -929,6 +937,7 @@ namespace SourceGit.ViewModels
submenu.Items.Add(finish);
submenu.Items.Add(new MenuItem() { Header = "-" });
}
}
var copy = new MenuItem();
copy.Header = App.Text("BranchCM.CopyName");
@ -951,6 +960,8 @@ namespace SourceGit.ViewModels
FillBranchVisibilityMenu(submenu, branch);
if (!_repo.IsBare)
{
var checkout = new MenuItem();
checkout.Header = new Views.NameHighlightedTextBlock("BranchCM.Checkout", branch.Name);
checkout.Icon = App.CreateMenuIcon("Icons.Check");
@ -972,6 +983,7 @@ namespace SourceGit.ViewModels
e.Handled = true;
};
submenu.Items.Add(merge);
}
var rename = new MenuItem();
rename.Header = new Views.NameHighlightedTextBlock("BranchCM.Rename", branch.Name);
@ -996,6 +1008,8 @@ namespace SourceGit.ViewModels
submenu.Items.Add(delete);
submenu.Items.Add(new MenuItem() { Header = "-" });
if (!_repo.IsBare)
{
var detect = Commands.GitFlow.DetectType(_repo.FullPath, _repo.Branches, branch.Name);
if (detect.IsGitFlowBranch)
{
@ -1011,6 +1025,7 @@ namespace SourceGit.ViewModels
submenu.Items.Add(finish);
submenu.Items.Add(new MenuItem() { Header = "-" });
}
}
var copy = new MenuItem();
copy.Header = App.Text("BranchCM.CopyName");
@ -1104,10 +1119,11 @@ namespace SourceGit.ViewModels
};
submenu.Items.Add(push);
if (!_repo.IsBare && !merged)
{
var merge = new MenuItem();
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())
@ -1115,6 +1131,7 @@ namespace SourceGit.ViewModels
e.Handled = true;
};
submenu.Items.Add(merge);
}
var delete = new MenuItem();
delete.Header = new Views.NameHighlightedTextBlock("TagCM.Delete", tag.Name);

View file

@ -280,19 +280,20 @@ namespace SourceGit.ViewModels
return;
}
var gitDir = new Commands.QueryGitDir(node.Id).Result();
var isBare = new Commands.IsBareRepository(node.Id).Result();
var gitDir = node.Id;
if (!isBare)
{
gitDir = new Commands.QueryGitDir(node.Id).Result();
if (string.IsNullOrEmpty(gitDir))
{
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()
{
FullPath = node.Id,
GitDir = gitDir,
};
var repo = new Repository(isBare, node.Id, gitDir);
repo.Open();
if (page == null)

View file

@ -18,6 +18,11 @@ namespace SourceGit.ViewModels
{
public class Repository : ObservableObject, Models.IRepository
{
public bool IsBare
{
get;
}
public string FullPath
{
get => _fullpath;
@ -448,6 +453,13 @@ namespace SourceGit.ViewModels
private set => SetProperty(ref _isAutoFetching, value);
}
public Repository(bool isBare, string path, string gitDir)
{
IsBare = isBare;
FullPath = path;
GitDir = gitDir;
}
public void Open()
{
var settingsFile = Path.Combine(_gitDir, "sourcegit.settings");
@ -995,6 +1007,9 @@ namespace SourceGit.ViewModels
public void RefreshWorkingCopyChanges()
{
if (IsBare)
return;
var changes = new Commands.QueryLocalChanges(_fullpath, _settings.IncludeUntrackedInLocalChanges).Result();
if (_workingCopy == null)
return;
@ -1010,6 +1025,9 @@ namespace SourceGit.ViewModels
public void RefreshStashes()
{
if (IsBare)
return;
var stashes = new Commands.QueryStashes(_fullpath).Result();
Dispatcher.UIThread.Invoke(() =>
{
@ -1044,6 +1062,9 @@ namespace SourceGit.ViewModels
}
}
if (IsBare)
return;
if (!CanCreatePopup())
return;
@ -1415,6 +1436,8 @@ namespace SourceGit.ViewModels
};
if (branch.IsCurrent)
{
if (!IsBare)
{
var discard = new MenuItem();
discard.Header = App.Text("BranchCM.DiscardAll");
@ -1461,10 +1484,13 @@ namespace SourceGit.ViewModels
menu.Items.Add(fastForward);
menu.Items.Add(pull);
}
}
menu.Items.Add(push);
}
else
{
if (!IsBare)
{
var checkout = new MenuItem();
checkout.Header = new Views.NameHighlightedTextBlock("BranchCM.Checkout", branch.Name);
@ -1476,6 +1502,7 @@ namespace SourceGit.ViewModels
};
menu.Items.Add(checkout);
menu.Items.Add(new MenuItem() { Header = "-" });
}
var worktree = _worktrees.Find(x => x.Branch == branch.FullName);
var upstream = _branches.Find(x => x.FullName == branch.Upstream);
@ -1510,6 +1537,8 @@ namespace SourceGit.ViewModels
menu.Items.Add(push);
if (!IsBare)
{
var merge = new MenuItem();
merge.Header = new Views.NameHighlightedTextBlock("BranchCM.Merge", branch.Name, _currentBranch.Name);
merge.Icon = App.CreateMenuIcon("Icons.Merge");
@ -1532,6 +1561,7 @@ namespace SourceGit.ViewModels
menu.Items.Add(merge);
menu.Items.Add(rebase);
}
var compareWithHead = new MenuItem();
compareWithHead.Header = App.Text("BranchCM.CompareWithHead");
@ -1566,6 +1596,8 @@ namespace SourceGit.ViewModels
}
}
if (!IsBare)
{
var detect = Commands.GitFlow.DetectType(_fullpath, _branches, branch.Name);
if (detect.IsGitFlowBranch)
{
@ -1581,6 +1613,7 @@ namespace SourceGit.ViewModels
menu.Items.Add(new MenuItem() { Header = "-" });
menu.Items.Add(finish);
}
}
var rename = new MenuItem();
rename.Header = new Views.NameHighlightedTextBlock("BranchCM.Rename", branch.Name);
@ -1631,6 +1664,8 @@ namespace SourceGit.ViewModels
menu.Items.Add(createTag);
menu.Items.Add(new MenuItem() { Header = "-" });
if (!IsBare)
{
var remoteBranches = new List<Models.Branch>();
foreach (var b in _branches)
{
@ -1651,6 +1686,7 @@ namespace SourceGit.ViewModels
};
menu.Items.Add(tracking);
}
}
var archive = new MenuItem();
archive.Icon = App.CreateMenuIcon("Icons.Archive");

View file

@ -34,7 +34,7 @@ namespace SourceGit.ViewModels
watch.Start();
var rootDir = new DirectoryInfo(RootDir);
var founded = new List<string>();
var founded = new List<FoundRepository>();
GetUnmanagedRepositories(rootDir, founded, new EnumerationOptions()
{
AttributesToSkip = FileAttributes.Hidden | FileAttributes.System,
@ -47,16 +47,16 @@ namespace SourceGit.ViewModels
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))
{
Preferences.Instance.FindOrAddNodeByRepositoryPath(f, null, false);
Preferences.Instance.FindOrAddNodeByRepositoryPath(f.Path, null, false);
}
else if (parent.StartsWith(normalizedRoot, StringComparison.Ordinal))
{
var relative = parent.Substring(normalizedRoot.Length).TrimStart('/');
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);
foreach (var subdir in subdirs)
@ -111,12 +111,19 @@ namespace SourceGit.ViewModels
{
var normalized = test.StdOut.Trim().Replace("\\", "/");
if (!_managed.Contains(normalized))
outs.Add(normalized);
outs.Add(new FoundRepository(normalized, false));
}
continue;
}
var isBare = new Commands.IsBareRepository(subdir.FullName).Result();
if (isBare)
{
outs.Add(new FoundRepository(normalizedSelf, true));
continue;
}
if (depth < 5)
GetUnmanagedRepositories(subdir, outs, opts, depth + 1);
}
@ -161,6 +168,12 @@ namespace SourceGit.ViewModels
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>();
}
}

View file

@ -94,12 +94,9 @@ namespace SourceGit.ViewModels
}
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!");
return;
}
var test = new Commands.QueryRepositoryRootPath(path).ReadToEnd();
if (!test.IsSuccess || string.IsNullOrEmpty(test.StdOut))
{
@ -107,7 +104,10 @@ namespace SourceGit.ViewModels
return;
}
var node = Preferences.Instance.FindOrAddNodeByRepositoryPath(test.StdOut.Trim(), parent, bMoveExistedNode);
repoRoot = test.StdOut.Trim();
}
var node = Preferences.Instance.FindOrAddNodeByRepositoryPath(repoRoot, parent, bMoveExistedNode);
Refresh();
var launcher = App.GetLauncer();

View file

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

View file

@ -40,7 +40,7 @@
<!-- Page Switcher for Right Panel -->
<Border Grid.Row="0" Margin="8,0,4,0" BorderThickness="1" BorderBrush="{DynamicResource Brush.Border2}" CornerRadius="6">
<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>
<Style Selector="Path.icon">
<Setter Property="Width" Value="12"/>
@ -128,7 +128,7 @@
</Grid>
</ListBoxItem>
<ListBoxItem>
<ListBoxItem IsVisible="{Binding !IsBare}">
<Grid Classes="view_mode" ColumnDefinitions="Auto,*,Auto">
<Path Grid.Column="0" Classes="icon" Data="{StaticResource Icons.Changes}"/>
<TextBlock Grid.Column="1" Classes="header" Text="{DynamicResource Text.WorkingCopy}"/>
@ -143,7 +143,7 @@
</Grid>
</ListBoxItem>
<ListBoxItem>
<ListBoxItem IsVisible="{Binding !IsBare}">
<Grid Classes="view_mode" ColumnDefinitions="Auto,*,Auto">
<Path Grid.Column="0" Classes="icon" Data="{StaticResource Icons.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"/>
</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}"/>
</Button>
@ -42,7 +42,7 @@
<Path Width="14" Height="14" Data="{StaticResource Icons.Fetch}"/>
</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>
<StackPanel Orientation="Vertical">
<TextBlock Text="{DynamicResource Text.Pull}"/>
@ -64,7 +64,7 @@
<Path Width="14" Height="14" Data="{StaticResource Icons.Push}"/>
</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>
<StackPanel Orientation="Vertical">
<TextBlock Text="{DynamicResource Text.Stash}"/>
@ -75,7 +75,7 @@
<Path Width="14" Height="14" Data="{StaticResource Icons.Stashes.Add}"/>
</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}"/>
</Button>
@ -88,11 +88,11 @@
<Path Width="14" Height="14" Data="{StaticResource Icons.Branch.Add}"/>
</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}"/>
</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}"/>
</Button>

View file

@ -59,6 +59,12 @@ namespace SourceGit.Views
var launcher = this.FindAncestorOfType<Launcher>();
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);
launcher.ClearKeyModifier();
repo.Pull(startDirectly);