Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions src/Commands/Merge.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ namespace SourceGit.Commands
{
public class Merge : Command
{
public Merge(string repo, string source, string mode, Action<string> outputHandler)
public Merge(string repo, string source, string mode, string strategy, Action<string> outputHandler)
{
_outputHandler = outputHandler;
WorkingDirectory = repo;
Context = repo;
TraitErrorAsOutput = true;
Args = $"merge --progress {source} {mode}";
if (strategy != null)
strategy = string.Concat("--strategy=", strategy);
Args = $"merge --progress {strategy} {source} {mode}";
}

protected override void OnReadline(string line)
Expand Down
24 changes: 24 additions & 0 deletions src/Models/MergeStrategy.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using System.Collections.Generic;

namespace SourceGit.Models
{
public class MergeStrategy
{
public string Name { get; internal set; }
public string Desc { get; internal set; }
public string Arg { get; internal set; }

public static List<MergeStrategy> ForMultiple { get; private set; } = [
new MergeStrategy(string.Empty, "Let Git automatically select a strategy", null),
new MergeStrategy("Octopus", "Attempt merging multiple heads", "octopus"),
new MergeStrategy("Ours", "Record the merge without modifying the tree", "ours"),
];

public MergeStrategy(string n, string d, string a)
{
Name = n;
Desc = d;
Arg = a;
}
}
}
6 changes: 6 additions & 0 deletions src/Resources/Locales/en_US.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
<x:String x:Key="Text.BranchCM.FetchInto" xml:space="preserve">Fetch ${0}$ into ${1}$...</x:String>
<x:String x:Key="Text.BranchCM.Finish" xml:space="preserve">Git Flow - Finish ${0}$</x:String>
<x:String x:Key="Text.BranchCM.Merge" xml:space="preserve">Merge ${0}$ into ${1}$...</x:String>
<x:String x:Key="Text.BranchCM.MergeMultiBranches" xml:space="preserve">Merge selected {0} branches</x:String>
<x:String x:Key="Text.BranchCM.Pull" xml:space="preserve">Pull ${0}$</x:String>
<x:String x:Key="Text.BranchCM.PullInto" xml:space="preserve">Pull ${0}$ into ${1}$...</x:String>
<x:String x:Key="Text.BranchCM.Push" xml:space="preserve">Push ${0}$</x:String>
Expand Down Expand Up @@ -110,6 +111,7 @@
<x:String x:Key="Text.CommitCM.CopySHA" xml:space="preserve">Copy SHA</x:String>
<x:String x:Key="Text.CommitCM.CustomAction" xml:space="preserve">Custom Action</x:String>
<x:String x:Key="Text.CommitCM.InteractiveRebase" xml:space="preserve">Interactive Rebase ${0}$ to Here</x:String>
<x:String x:Key="Text.CommitCM.MergeMultiple" xml:space="preserve">Merge ...</x:String>
<x:String x:Key="Text.CommitCM.Rebase" xml:space="preserve">Rebase ${0}$ to Here</x:String>
<x:String x:Key="Text.CommitCM.Reset" xml:space="preserve">Reset ${0}$ to Here</x:String>
<x:String x:Key="Text.CommitCM.Revert" xml:space="preserve">Revert Commit</x:String>
Expand Down Expand Up @@ -403,6 +405,10 @@
<x:String x:Key="Text.Merge.Into" xml:space="preserve">Into:</x:String>
<x:String x:Key="Text.Merge.Mode" xml:space="preserve">Merge Option:</x:String>
<x:String x:Key="Text.Merge.Source" xml:space="preserve">Source Branch:</x:String>
<x:String x:Key="Text.MergeMultiple" xml:space="preserve">Merge commits</x:String>
<x:String x:Key="Text.MergeMultiple.Commit" xml:space="preserve">Commit(s):</x:String>
<x:String x:Key="Text.MergeMultiple.CommitChanges" xml:space="preserve">Commit all changes</x:String>
<x:String x:Key="Text.MergeMultiple.Strategy" xml:space="preserve">Strategy:</x:String>
<x:String x:Key="Text.MoveRepositoryNode" xml:space="preserve">Move Repository Node</x:String>
<x:String x:Key="Text.MoveRepositoryNode.Target" xml:space="preserve">Select parent node for:</x:String>
<x:String x:Key="Text.Name" xml:space="preserve">Name:</x:String>
Expand Down
34 changes: 28 additions & 6 deletions src/ViewModels/Histories.cs
Original file line number Diff line number Diff line change
Expand Up @@ -228,22 +228,28 @@ public ContextMenu MakeContextMenu(ListBox list)
{
var selected = new List<Models.Commit>();
var canCherryPick = true;
var canMerge = true;

foreach (var item in list.SelectedItems)
{
if (item is Models.Commit c)
{
selected.Add(c);

if (c.IsMerged || c.Parents.Count > 1)
if (c.IsMerged)
{
canMerge = false;
canCherryPick = false;
}
else if (c.Parents.Count > 1)
{
canCherryPick = false;
}
}
}

// Sort selected commits in order.
selected.Sort((l, r) =>
{
return _commits.IndexOf(r) - _commits.IndexOf(l);
});
selected.Sort((l, r) => _commits.IndexOf(r) - _commits.IndexOf(l));

var multipleMenu = new ContextMenu();

Expand All @@ -259,9 +265,25 @@ public ContextMenu MakeContextMenu(ListBox list)
e.Handled = true;
};
multipleMenu.Items.Add(cherryPickMultiple);
multipleMenu.Items.Add(new MenuItem() { Header = "-" });
}

if (canMerge)
{
var mergeMultiple = new MenuItem();
mergeMultiple.Header = App.Text("CommitCM.MergeMultiple");
mergeMultiple.Icon = App.CreateMenuIcon("Icons.Merge");
mergeMultiple.Click += (_, e) =>
{
if (PopupHost.CanCreatePopup())
PopupHost.ShowPopup(new MergeMultiple(_repo, selected));
e.Handled = true;
};
multipleMenu.Items.Add(mergeMultiple);
}

if (canCherryPick || canMerge)
multipleMenu.Items.Add(new MenuItem() { Header = "-" });

var saveToPatchMultiple = new MenuItem();
saveToPatchMultiple.Icon = App.CreateMenuIcon("Icons.Diff");
saveToPatchMultiple.Header = App.Text("CommitCM.SaveAsPatch");
Expand Down
2 changes: 1 addition & 1 deletion src/ViewModels/Merge.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public override Task<bool> Sure()

return Task.Run(() =>
{
var succ = new Commands.Merge(_repo.FullPath, Source, SelectedMode.Arg, SetProgressDescription).Exec();
var succ = new Commands.Merge(_repo.FullPath, Source, SelectedMode.Arg, null, SetProgressDescription).Exec();
CallUIThread(() => _repo.SetWatcherEnabled(true));
return succ;
});
Expand Down
59 changes: 59 additions & 0 deletions src/ViewModels/MergeMultiple.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using SourceGit.Models;

namespace SourceGit.ViewModels
{
public class MergeMultiple : Popup
{
public List<string> Strategies = ["octopus", "ours"];

public List<Commit> Targets
{
get;
private set;
}

public bool AutoCommit
{
get;
set;
}

public MergeStrategy Strategy
{
get;
set;
}

public MergeMultiple(Repository repo, List<Commit> targets)
{
_repo = repo;
Targets = targets;
AutoCommit = true;
Strategy = MergeStrategy.ForMultiple.Find(s => s.Arg == null);
View = new Views.MergeMultiple() { DataContext = this };
}

public override Task<bool> Sure()
{
_repo.SetWatcherEnabled(false);
ProgressDescription = "Merge head(s) ...";

return Task.Run(() =>
{
var succ = new Commands.Merge(
_repo.FullPath,
string.Join(" ", Targets.ConvertAll(c => c.Decorators.Find(d => d.Type == DecoratorType.RemoteBranchHead || d.Type == DecoratorType.LocalBranchHead)?.Name ?? c.Decorators.Find(d => d.Type == DecoratorType.Tag)?.Name ?? c.SHA)),
AutoCommit ? string.Empty : "--no-commit",
Strategy?.Arg,
SetProgressDescription).Exec();

CallUIThread(() => _repo.SetWatcherEnabled(true));
return succ;
});
}

private readonly Repository _repo = null;
}
}
2 changes: 1 addition & 1 deletion src/ViewModels/Pull.cs
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ public override Task<bool> Sure()
else
{
SetProgressDescription($"Merge {_selectedBranch.FriendlyName} into {_current.Name} ...");
rs = new Commands.Merge(_repo.FullPath, _selectedBranch.FriendlyName, "", SetProgressDescription).Exec();
rs = new Commands.Merge(_repo.FullPath, _selectedBranch.FriendlyName, "", null, SetProgressDescription).Exec();
}
}
else
Expand Down
7 changes: 7 additions & 0 deletions src/ViewModels/Repository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
using Avalonia.Threading;

using CommunityToolkit.Mvvm.ComponentModel;
using SourceGit.Models;

namespace SourceGit.ViewModels
{
Expand Down Expand Up @@ -950,6 +951,12 @@ public void DeleteMultipleBranches(List<Models.Branch> branches, bool isLocal)
PopupHost.ShowPopup(new DeleteMultipleBranches(this, branches, isLocal));
}

public void MergeMultipleBranches(List<Models.Branch> branches)
{
if (PopupHost.CanCreatePopup())
PopupHost.ShowPopup(new MergeMultiple(this, branches.ConvertAll(b => _histories?.Commits?.Find(c => c.SHA == b.Head))));
}

public void CreateNewTag()
{
if (_currentBranch == null)
Expand Down
11 changes: 11 additions & 0 deletions src/Views/BranchTree.axaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,17 @@ private void OnTreeContextRequested(object _1, ContextRequestedEventArgs _2)
ev.Handled = true;
};
menu.Items.Add(deleteMulti);

var mergeMulti = new MenuItem();
mergeMulti.Header = App.Text("BranchCM.MergeMultiBranches", branches.Count);
mergeMulti.Icon = App.CreateMenuIcon("Icons.Merge");
mergeMulti.Click += (_, ev) =>
{
repo.MergeMultipleBranches(branches);
ev.Handled = true;
};
menu.Items.Add(mergeMulti);

menu?.Open(this);
}
}
Expand Down
79 changes: 79 additions & 0 deletions src/Views/MergeMultiple.axaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:m="using:SourceGit.Models"
xmlns:vm="using:SourceGit.ViewModels"
xmlns:c="using:SourceGit.Converters"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="SourceGit.Views.MergeMultiple"
x:DataType="vm:MergeMultiple">
<StackPanel Orientation="Vertical" Margin="8,0">
<TextBlock FontSize="18"
Classes="bold"
Text="{DynamicResource Text.MergeMultiple}"/>
<Grid Margin="0,16,0,0" RowDefinitions="Auto,32,32" ColumnDefinitions="100,*">
<TextBlock Grid.Row="0" Grid.Column="0"
HorizontalAlignment="Right" VerticalAlignment="Center"
Margin="0,0,8,0"
Text="{DynamicResource Text.MergeMultiple.Commit}"/>
<ListBox Grid.Row="0" Grid.Column="1"
MinHeight="32" MaxHeight="100"
ItemsSource="{Binding Targets}"
Background="{DynamicResource Brush.Contents}"
BorderThickness="1"
BorderBrush="{DynamicResource Brush.Border2}"
Padding="4"
CornerRadius="4"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollBarVisibility="Auto">
<ListBox.Styles>
<Style Selector="ListBoxItem">
<Setter Property="Padding" Value="4,0"/>
<Setter Property="Height" Value="26"/>
<Setter Property="CornerRadius" Value="4"/>
</Style>
</ListBox.Styles>

<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>

<ListBox.ItemTemplate>
<DataTemplate DataType="m:Commit">
<Grid ColumnDefinitions="14,Auto,*">
<Path Grid.Column="0" Width="14" Height="14" Margin="0,8,0,0" Data="{StaticResource Icons.Commit}"/>
<TextBlock Grid.Column="1" FontFamily="{DynamicResource Fonts.Monospace}" VerticalAlignment="Center" Text="{Binding SHA, Converter={x:Static c:StringConverters.ToShortSHA}}" Foreground="DarkOrange" Margin="6,0,4,0"/>
<TextBlock Grid.Column="2" VerticalAlignment="Center" Text="{Binding Subject}" TextTrimming="CharacterEllipsis"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

<CheckBox Grid.Row="1" Grid.Column="1"
Content="{DynamicResource Text.MergeMultiple.CommitChanges}"
IsChecked="{Binding AutoCommit, Mode=TwoWay}"/>

<TextBlock Grid.Row="2" Grid.Column="0"
HorizontalAlignment="Right" VerticalAlignment="Center"
Margin="0,0,8,0"
Text="{DynamicResource Text.MergeMultiple.Strategy}"/>
<ComboBox Grid.Row="2" Grid.Column="1"
Height="28" Padding="8,0"
VerticalAlignment="Center" HorizontalAlignment="Stretch"
ItemsSource="{Binding Source={x:Static m:MergeStrategy.ForMultiple}}"
SelectedItem="{Binding Strategy, Mode=TwoWay}">
<ComboBox.ItemTemplate>
<DataTemplate DataType="m:MergeStrategy">
<StackPanel Orientation="Horizontal" Height="20" VerticalAlignment="Center">
<TextBlock Text="{Binding Name}"/>
<TextBlock Text="{Binding Desc}" Margin="8,0,0,0" FontSize="11" Foreground="{DynamicResource Brush.FG2}"/>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</Grid>
</StackPanel>
</UserControl>
12 changes: 12 additions & 0 deletions src/Views/MergeMultiple.axaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using Avalonia.Controls;

namespace SourceGit.Views
{
public partial class MergeMultiple : UserControl
{
public MergeMultiple()
{
InitializeComponent();
}
}
}
Loading