feature: warn when creating commit on a detached HEAD (#1462)

Signed-off-by: leo <longshuang@msn.cn>
This commit is contained in:
leo 2025-06-26 10:09:57 +08:00
parent 271f02b694
commit 054d5e41f3
No known key found for this signature in database
4 changed files with 25 additions and 9 deletions

View file

@ -793,6 +793,7 @@
<x:String x:Key="Text.WorkingCopy.CommitTip" xml:space="preserve">Trigger click event</x:String>
<x:String x:Key="Text.WorkingCopy.CommitToEdit" xml:space="preserve">Commit (Edit)</x:String>
<x:String x:Key="Text.WorkingCopy.CommitWithAutoStage" xml:space="preserve">Stage all changes and commit</x:String>
<x:String x:Key="Text.WorkingCopy.ConfirmCommitWithDetachedHead">You are creating commit on a detached HEAD. Do you want to continue?</x:String>
<x:String x:Key="Text.WorkingCopy.ConfirmCommitWithFilter">You have staged {0} file(s) but only {1} file(s) displayed ({2} files are filtered out). Do you want to continue?</x:String>
<x:String x:Key="Text.WorkingCopy.Conflicts" xml:space="preserve">CONFLICTS DETECTED</x:String>
<x:String x:Key="Text.WorkingCopy.Conflicts.OpenExternalMergeTool" xml:space="preserve">OPEN EXTERNAL MERGETOOL</x:String>

View file

@ -797,6 +797,7 @@
<x:String x:Key="Text.WorkingCopy.CommitTip" xml:space="preserve">触发点击事件</x:String>
<x:String x:Key="Text.WorkingCopy.CommitToEdit" xml:space="preserve">提交(修改原始提交)</x:String>
<x:String x:Key="Text.WorkingCopy.CommitWithAutoStage" xml:space="preserve">自动暂存所有变更并提交</x:String>
<x:String x:Key="Text.WorkingCopy.ConfirmCommitWithDetachedHead">您正在向一个游离的 HEAD 提交变更,是否继续提交?</x:String>
<x:String x:Key="Text.WorkingCopy.ConfirmCommitWithFilter" xml:space="preserve">当前有 {0} 个文件在暂存区中,但仅显示了 {1} 个文件({2} 个文件被过滤掉了),是否继续提交?</x:String>
<x:String x:Key="Text.WorkingCopy.Conflicts" xml:space="preserve">检测到冲突</x:String>
<x:String x:Key="Text.WorkingCopy.Conflicts.OpenExternalMergeTool" xml:space="preserve">打开合并工具</x:String>

View file

@ -797,6 +797,7 @@
<x:String x:Key="Text.WorkingCopy.CommitTip" xml:space="preserve">觸發點擊事件</x:String>
<x:String x:Key="Text.WorkingCopy.CommitToEdit" xml:space="preserve">提交 (修改原始提交)</x:String>
<x:String x:Key="Text.WorkingCopy.CommitWithAutoStage" xml:space="preserve">自動暫存全部變更並提交</x:String>
<x:String x:Key="Text.WorkingCopy.ConfirmCommitWithDetachedHead">您正在向一个分離狀態的 HEAD 提交變更,您確定要繼續提交嗎?</x:String>
<x:String x:Key="Text.WorkingCopy.ConfirmCommitWithFilter" xml:space="preserve">您已暫存 {0} 個檔案,但只顯示 {1} 個檔案 ({2} 個檔案被篩選器隱藏)。您確定要繼續提交嗎?</x:String>
<x:String x:Key="Text.WorkingCopy.Conflicts" xml:space="preserve">偵測到衝突</x:String>
<x:String x:Key="Text.WorkingCopy.Conflicts.OpenExternalMergeTool" xml:space="preserve">使用外部合併工具開啟</x:String>

View file

@ -261,7 +261,6 @@ namespace SourceGit.ViewModels
}
_cached = changes;
_count = _cached.Count;
var lastSelectedUnstaged = new HashSet<string>();
var lastSelectedStaged = new HashSet<string>();
@ -1782,7 +1781,7 @@ namespace SourceGit.ViewModels
DetailContext = new DiffContext(_repo.FullPath, new Models.DiffOption(change, isUnstaged), _detailContext as DiffContext);
}
private void DoCommit(bool autoStage, bool autoPush, bool allowEmpty = false, bool confirmWithFilter = false)
private void DoCommit(bool autoStage, bool autoPush, CommitCheckPassed checkPassed = CommitCheckPassed.None)
{
if (string.IsNullOrWhiteSpace(_commitMessage))
return;
@ -1793,18 +1792,25 @@ namespace SourceGit.ViewModels
return;
}
if (!string.IsNullOrEmpty(_filter) && _staged.Count > _visibleStaged.Count && !confirmWithFilter)
if (_repo.CurrentBranch is { IsDetachedHead: true } && checkPassed < CommitCheckPassed.DetachedHead)
{
var confirmMessage = App.Text("WorkingCopy.ConfirmCommitWithFilter", _staged.Count, _visibleStaged.Count, _staged.Count - _visibleStaged.Count);
App.ShowWindow(new ConfirmCommit(confirmMessage, () => DoCommit(autoStage, autoPush, allowEmpty, true)), true);
var msg = App.Text("WorkingCopy.ConfirmCommitWithDetachedHead");
App.ShowWindow(new ConfirmCommit(msg, () => DoCommit(autoStage, autoPush, CommitCheckPassed.DetachedHead)), true);
return;
}
if (!_useAmend && !allowEmpty)
if (!string.IsNullOrEmpty(_filter) && _staged.Count > _visibleStaged.Count && checkPassed < CommitCheckPassed.Filter)
{
if ((autoStage && _count == 0) || (!autoStage && _staged.Count == 0))
var msg = App.Text("WorkingCopy.ConfirmCommitWithFilter", _staged.Count, _visibleStaged.Count, _staged.Count - _visibleStaged.Count);
App.ShowWindow(new ConfirmCommit(msg, () => DoCommit(autoStage, autoPush, CommitCheckPassed.Filter)), true);
return;
}
if (checkPassed < CommitCheckPassed.FileCount && !_useAmend)
{
if ((!autoStage && _staged.Count == 0) || (autoStage && _cached.Count == 0))
{
App.ShowWindow(new ConfirmEmptyCommit(_count > 0, stageAll => DoCommit(stageAll, autoPush, true, confirmWithFilter)), true);
App.ShowWindow(new ConfirmEmptyCommit(_cached.Count > 0, stageAll => DoCommit(stageAll, autoPush, CommitCheckPassed.FileCount)), true);
return;
}
}
@ -1871,6 +1877,14 @@ namespace SourceGit.ViewModels
return false;
}
private enum CommitCheckPassed
{
None = 0,
DetachedHead,
Filter,
FileCount,
}
private Repository _repo = null;
private bool _isLoadingData = false;
private bool _isStaging = false;
@ -1886,7 +1900,6 @@ namespace SourceGit.ViewModels
private List<Models.Change> _visibleStaged = [];
private List<Models.Change> _selectedUnstaged = [];
private List<Models.Change> _selectedStaged = [];
private int _count = 0;
private object _detailContext = null;
private string _filter = string.Empty;
private string _commitMessage = string.Empty;