diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index d4117364..bcb32580 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -19,14 +19,25 @@ jobs:
os: macos-latest
runtime: osx-arm64
- name : Linux
- os: ubuntu-20.04
+ os: ubuntu-latest
runtime: linux-x64
+ container: ubuntu:20.04
- name : Linux (arm64)
- os: ubuntu-20.04
+ os: ubuntu-latest
runtime: linux-arm64
+ container: ubuntu:20.04
name: Build ${{ matrix.name }}
runs-on: ${{ matrix.os }}
+ container: ${{ matrix.container || '' }}
steps:
+ - name: Install common CLI tools
+ if: ${{ startsWith(matrix.runtime, 'linux-') }}
+ run: |
+ export DEBIAN_FRONTEND=noninteractive
+ ln -fs /usr/share/zoneinfo/Etc/UTC /etc/localtime
+ apt-get update
+ apt-get install -y sudo
+ sudo apt-get install -y curl wget git unzip zip libicu66 tzdata clang
- name: Checkout sources
uses: actions/checkout@v4
- name: Setup .NET
@@ -47,7 +58,7 @@ jobs:
if: ${{ matrix.runtime == 'linux-arm64' }}
run: |
sudo apt-get update
- sudo apt-get install clang llvm gcc-aarch64-linux-gnu zlib1g-dev:arm64
+ sudo apt-get install -y llvm gcc-aarch64-linux-gnu zlib1g-dev:arm64
- name: Build
run: dotnet build -c Release
- name: Publish
diff --git a/.github/workflows/package.yml b/.github/workflows/package.yml
index 074c9544..2dfc97fd 100644
--- a/.github/workflows/package.yml
+++ b/.github/workflows/package.yml
@@ -9,10 +9,10 @@ on:
jobs:
windows:
name: Package Windows
- runs-on: ubuntu-latest
+ runs-on: windows-2019
strategy:
matrix:
- runtime: [win-x64, win-arm64]
+ runtime: [ win-x64, win-arm64 ]
steps:
- name: Checkout sources
uses: actions/checkout@v4
@@ -22,6 +22,7 @@ jobs:
name: sourcegit.${{ matrix.runtime }}
path: build/SourceGit
- name: Package
+ shell: bash
env:
VERSION: ${{ inputs.version }}
RUNTIME: ${{ matrix.runtime }}
@@ -69,6 +70,7 @@ jobs:
linux:
name: Package Linux
runs-on: ubuntu-latest
+ container: ubuntu:20.04
strategy:
matrix:
runtime: [linux-x64, linux-arm64]
@@ -77,9 +79,10 @@ jobs:
uses: actions/checkout@v4
- name: Download package dependencies
run: |
- sudo add-apt-repository universe
- sudo apt-get update
- sudo apt-get install desktop-file-utils rpm libfuse2
+ export DEBIAN_FRONTEND=noninteractive
+ ln -fs /usr/share/zoneinfo/Etc/UTC /etc/localtime
+ apt-get update
+ apt-get install -y curl wget git dpkg-dev fakeroot tzdata zip unzip desktop-file-utils rpm libfuse2 file build-essential binutils
- name: Download build
uses: actions/download-artifact@v4
with:
@@ -89,6 +92,7 @@ jobs:
env:
VERSION: ${{ inputs.version }}
RUNTIME: ${{ matrix.runtime }}
+ APPIMAGE_EXTRACT_AND_RUN: 1
run: |
mkdir build/SourceGit
tar -xf "build/sourcegit.${{ matrix.runtime }}.tar" -C build/SourceGit
diff --git a/LICENSE b/LICENSE
index dceab2d8..442ce085 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
The MIT License (MIT)
-Copyright (c) 2024 sourcegit
+Copyright (c) 2025 sourcegit
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
@@ -17,4 +17,4 @@ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/README.md b/README.md
index 527f5c31..846407f6 100644
--- a/README.md
+++ b/README.md
@@ -11,16 +11,16 @@
* Supports Windows/macOS/Linux
* Opensource/Free
* Fast
-* Deutsch/English/Español/Français/Italiano/Português/Русский/简体中文/繁體中文
+* Deutsch/English/Español/Français/Italiano/Português/Русский/简体中文/繁體中文/日本語/தமிழ் (Tamil)
* Built-in light/dark themes
* Customize theme
* Visual commit graph
* Supports SSH access with each remote
* GIT commands with GUI
* Clone/Fetch/Pull/Push...
- * Merge/Rebase/Reset/Revert/Amend/Cherry-pick...
- * Amend/Reword
- * Interactive rebase (Basic)
+ * Merge/Rebase/Reset/Revert/Cherry-pick...
+ * Amend/Reword/Squash
+ * Interactive rebase
* Branches
* Remotes
* Tags
@@ -40,6 +40,7 @@
* Git LFS
* Issue Link
* Workspace
+* Custom Action
* Using AI to generate commit message (C# port of [anjerodev/commitollama](https://github.com/anjerodev/commitollama))
> [!WARNING]
@@ -47,10 +48,7 @@
## Translation Status
-[](TRANSLATION.md) [](TRANSLATION.md) [](TRANSLATION.md) [](TRANSLATION.md) [](TRANSLATION.md) [](TRANSLATION.md) [](TRANSLATION.md) [](TRANSLATION.md) [](TRANSLATION.md)
-
-> [!NOTE]
-> You can find the missing keys in [TRANSLATION.md](TRANSLATION.md)
+You can find the current translation status in [TRANSLATION.md](https://github.com/sourcegit-scm/sourcegit/blob/develop/TRANSLATION.md)
## How to Use
@@ -62,7 +60,7 @@ This software creates a folder `$"{System.Environment.SpecialFolder.ApplicationD
| OS | PATH |
|---------|-----------------------------------------------------|
-| Windows | `C:\Users\USER_NAME\AppData\Roaming\SourceGit` |
+| Windows | `%APPDATA%\SourceGit` |
| Linux | `${HOME}/.config/SourceGit` or `${HOME}/.sourcegit` |
| macOS | `${HOME}/Library/Application Support/SourceGit` |
@@ -79,7 +77,7 @@ For **Windows** users:
```
> [!NOTE]
> `winget` will install this software as a commandline tool. You need run `SourceGit` from console or `Win+R` at the first time. Then you can add it to the taskbar.
-* You can install the latest stable by `scoope` with follow commands:
+* You can install the latest stable by `scoop` with follow commands:
```shell
scoop bucket add extras
scoop install sourcegit
@@ -107,7 +105,7 @@ For **Linux** users:
`deb` how to:
```shell
curl https://codeberg.org/api/packages/yataro/debian/repository.key | sudo tee /etc/apt/keyrings/sourcegit.asc
- echo "deb [signed-by=/etc/apt/keyrings/sourcegit.asc] https://codeberg.org/api/packages/yataro/debian generic main" | sudo tee /etc/apt/sources.list.d/sourcegit.list
+ echo "deb [signed-by=/etc/apt/keyrings/sourcegit.asc, arch=amd64,arm64] https://codeberg.org/api/packages/yataro/debian generic main" | sudo tee /etc/apt/sources.list.d/sourcegit.list
sudo apt update
sudo apt install sourcegit
```
@@ -132,15 +130,15 @@ For **Linux** users:
## OpenAI
-This software supports using OpenAI or other AI service that has an OpenAI comaptible HTTP API to generate commit message. You need configurate the service in `Preference` window.
+This software supports using OpenAI or other AI service that has an OpenAI compatible HTTP API to generate commit message. You need configurate the service in `Preference` window.
For `OpenAI`:
-* `Server` must be `https://api.openai.com/v1/chat/completions`
+* `Server` must be `https://api.openai.com/v1`
For other AI service:
-* The `Server` should fill in a URL equivalent to OpenAI's `https://api.openai.com/v1/chat/completions`. For example, when using `Ollama`, it should be `http://localhost:11434/v1/chat/completions` instead of `http://localhost:11434/api/generate`
+* The `Server` should fill in a URL equivalent to OpenAI's `https://api.openai.com/v1`. For example, when using `Ollama`, it should be `http://localhost:11434/v1` instead of `http://localhost:11434/api/generate`
* The `API Key` is optional that depends on the service
## External Tools
@@ -201,3 +199,7 @@ dotnet run --project src/SourceGit.csproj
Thanks to all the people who contribute.
[](https://github.com/sourcegit-scm/sourcegit/graphs/contributors)
+
+## Third-Party Components
+
+For detailed license information, see [THIRD-PARTY-LICENSES.md](THIRD-PARTY-LICENSES.md).
diff --git a/SourceGit.sln b/SourceGit.sln
index cf761abd..624322f8 100644
--- a/SourceGit.sln
+++ b/SourceGit.sln
@@ -60,6 +60,8 @@ EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "DEBIAN", "DEBIAN", "{F101849D-BDB7-40D4-A516-751150C3CCFC}"
ProjectSection(SolutionItems) = preProject
build\resources\deb\DEBIAN\control = build\resources\deb\DEBIAN\control
+ build\resources\deb\DEBIAN\preinst = build\resources\deb\DEBIAN\preinst
+ build\resources\deb\DEBIAN\prerm = build\resources\deb\DEBIAN\prerm
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "rpm", "rpm", "{9BA0B044-0CC9-46F8-B551-204F149BF45D}"
diff --git a/THIRD-PARTY-LICENSES.md b/THIRD-PARTY-LICENSES.md
new file mode 100644
index 00000000..2338263c
--- /dev/null
+++ b/THIRD-PARTY-LICENSES.md
@@ -0,0 +1,86 @@
+# Third-Party Licenses
+
+This project incorporates components from the following third parties:
+
+## Packages
+
+### AvaloniaUI
+
+- **Source**: https://github.com/AvaloniaUI/Avalonia
+- **Version**: 11.2.5
+- **License**: MIT License
+- **License Link**: https://github.com/AvaloniaUI/Avalonia/blob/master/licence.md
+
+### AvaloniaEdit
+
+- **Source**: https://github.com/AvaloniaUI/AvaloniaEdit
+- **Version**: 11.2.0
+- **License**: MIT License
+- **License Link**: https://github.com/AvaloniaUI/AvaloniaEdit/blob/master/LICENSE
+
+### LiveChartsCore.SkiaSharpView.Avalonia
+
+- **Source**: https://github.com/beto-rodriguez/LiveCharts2
+- **Version**: 2.0.0-rc5.4
+- **License**: MIT License
+- **License Link**: https://github.com/beto-rodriguez/LiveCharts2/blob/master/LICENSE
+
+### TextMateSharp
+
+- **Source**: https://github.com/danipen/TextMateSharp
+- **Version**: 1.0.66
+- **License**: MIT License
+- **License Link**: https://github.com/danipen/TextMateSharp/blob/master/LICENSE.md
+
+### OpenAI .NET SDK
+
+- **Source**: https://github.com/openai/openai-dotnet
+- **Version**: 2.2.0-beta2
+- **License**: MIT License
+- **License Link**: https://github.com/openai/openai-dotnet/blob/main/LICENSE
+
+### Azure.AI.OpenAI
+
+- **Source**: https://github.com/Azure/azure-sdk-for-net
+- **Version**: 2.2.0-beta2
+- **License**: MIT License
+- **License Link**: https://github.com/Azure/azure-sdk-for-net/blob/main/LICENSE.txt
+
+## Fonts
+
+### JetBrainsMono
+
+- **Source**: https://github.com/JetBrains/JetBrainsMono
+- **Commit**: v2.304
+- **License**: SIL Open Font License, Version 1.1
+- **License Link**: https://github.com/JetBrains/JetBrainsMono/blob/v2.304/OFL.txt
+
+## Grammar Files
+
+### haxe-TmLanguage
+
+- **Source**: https://github.com/vshaxe/haxe-TmLanguage
+- **Commit**: ddad8b4c6d0781ac20be0481174ec1be772c5da5
+- **License**: MIT License
+- **License Link**: https://github.com/vshaxe/haxe-TmLanguage/blob/ddad8b4c6d0781ac20be0481174ec1be772c5da5/LICENSE.md
+
+### coc-toml
+
+- **Source**: https://github.com/kkiyama117/coc-toml
+- **Commit**: aac3e0c65955c03314b2733041b19f903b7cc447
+- **License**: MIT License
+- **License Link**: https://github.com/kkiyama117/coc-toml/blob/aac3e0c65955c03314b2733041b19f903b7cc447/LICENSE
+
+### eclipse-buildship
+
+- **Source**: https://github.com/eclipse/buildship
+- **Commit**: 6bb773e7692f913dec27105129ebe388de34e68b
+- **License**: Eclipse Public License 1.0
+- **License Link**: https://github.com/eclipse-buildship/buildship/blob/6bb773e7692f913dec27105129ebe388de34e68b/README.md
+
+### vscode-jsp-lang
+
+- **Source**: https://github.com/samuel-weinhardt/vscode-jsp-lang
+- **Commit**: 0e89ecdb13650dbbe5a1e85b47b2e1530bf2f355
+- **License**: MIT License
+- **License Link**: https://github.com/samuel-weinhardt/vscode-jsp-lang/blob/0e89ecdb13650dbbe5a1e85b47b2e1530bf2f355/LICENSE
diff --git a/TRANSLATION.md b/TRANSLATION.md
index c8bc7efe..ccf003c7 100644
--- a/TRANSLATION.md
+++ b/TRANSLATION.md
@@ -1,55 +1,150 @@
-### de_DE.axaml: 97.55%
+# Translation Status
+This document shows the translation status of each locale file in the repository.
+
+## Details
+
+### 
+
+### 
-Missing Keys
+Missing keys in de_DE.axaml
-- Text.Configure.IssueTracker.AddSampleGiteeIssue
-- Text.Configure.IssueTracker.AddSampleGiteePullRequest
-- Text.Preference.General.DateFormat
-- Text.Preference.Git.SSLVerify
-- Text.Repository.HistoriesLayout
-- Text.Repository.HistoriesLayout.Horizontal
-- Text.Repository.HistoriesLayout.Vertical
-- Text.Repository.HistoriesOrder
-- Text.Repository.OnlyHighlightCurrentBranchInHistories
-- Text.Repository.Tags.OrderByCreatorDate
-- Text.Repository.Tags.OrderByNameAsc
+- Text.BranchUpstreamInvalid
+- Text.Configure.CustomAction.WaitForExit
+- Text.Configure.Git.PreferredMergeMode
+- Text.Configure.IssueTracker.AddSampleAzure
+- Text.ConfirmEmptyCommit.Continue
+- Text.ConfirmEmptyCommit.NoLocalChanges
+- Text.ConfirmEmptyCommit.StageAllThenCommit
+- Text.ConfirmEmptyCommit.WithLocalChanges
+- Text.CopyFullPath
+- Text.Diff.First
+- Text.Diff.Last
+- Text.Preferences.AI.Streaming
+- Text.Preferences.Appearance.EditorTabWidth
+- Text.Preferences.General.ShowTagsInGraph
+- Text.StashCM.SaveAsPatch
+- Text.WorkingCopy.ConfirmCommitWithFilter
+- Text.WorkingCopy.Conflicts.OpenExternalMergeTool
+- Text.WorkingCopy.Conflicts.OpenExternalMergeToolAllConflicts
+- Text.WorkingCopy.Conflicts.UseMine
+- Text.WorkingCopy.Conflicts.UseTheirs
+
+
+
+### 
+
+
+Missing keys in es_ES.axaml
+
+- Text.Configure.Git.PreferredMergeMode
+- Text.ConfirmEmptyCommit.Continue
+- Text.ConfirmEmptyCommit.NoLocalChanges
+- Text.ConfirmEmptyCommit.StageAllThenCommit
+- Text.ConfirmEmptyCommit.WithLocalChanges
+- Text.WorkingCopy.ConfirmCommitWithFilter
+- Text.WorkingCopy.Conflicts.OpenExternalMergeTool
+- Text.WorkingCopy.Conflicts.OpenExternalMergeToolAllConflicts
+- Text.WorkingCopy.Conflicts.UseMine
+- Text.WorkingCopy.Conflicts.UseTheirs
+
+
+
+### 
+
+
+Missing keys in fr_FR.axaml
+
+- Text.Configure.Git.PreferredMergeMode
+- Text.ConfirmEmptyCommit.Continue
+- Text.ConfirmEmptyCommit.NoLocalChanges
+- Text.ConfirmEmptyCommit.StageAllThenCommit
+- Text.ConfirmEmptyCommit.WithLocalChanges
+- Text.WorkingCopy.ConfirmCommitWithFilter
+- Text.WorkingCopy.Conflicts.OpenExternalMergeTool
+- Text.WorkingCopy.Conflicts.OpenExternalMergeToolAllConflicts
+- Text.WorkingCopy.Conflicts.UseMine
+- Text.WorkingCopy.Conflicts.UseTheirs
+
+
+
+### 
+
+
+Missing keys in it_IT.axaml
+
+- Text.Configure.Git.PreferredMergeMode
+- Text.ConfirmEmptyCommit.Continue
+- Text.ConfirmEmptyCommit.NoLocalChanges
+- Text.ConfirmEmptyCommit.StageAllThenCommit
+- Text.ConfirmEmptyCommit.WithLocalChanges
+- Text.CopyFullPath
+- Text.Preferences.General.ShowTagsInGraph
+- Text.WorkingCopy.ConfirmCommitWithFilter
+- Text.WorkingCopy.Conflicts.OpenExternalMergeTool
+- Text.WorkingCopy.Conflicts.OpenExternalMergeToolAllConflicts
+- Text.WorkingCopy.Conflicts.UseMine
+- Text.WorkingCopy.Conflicts.UseTheirs
+
+
+
+### 
+
+
+Missing keys in ja_JP.axaml
+
+- Text.Configure.Git.PreferredMergeMode
+- Text.ConfirmEmptyCommit.Continue
+- Text.ConfirmEmptyCommit.NoLocalChanges
+- Text.ConfirmEmptyCommit.StageAllThenCommit
+- Text.ConfirmEmptyCommit.WithLocalChanges
+- Text.Repository.FilterCommits
- Text.Repository.Tags.OrderByNameDes
-- Text.Repository.Tags.Sort
-- Text.Repository.UseRelativeTimeInHistories
-- Text.SetUpstream
-- Text.SetUpstream.Local
-- Text.SetUpstream.Unset
-- Text.SetUpstream.Upstream
+- Text.WorkingCopy.ConfirmCommitWithFilter
+- Text.WorkingCopy.Conflicts.OpenExternalMergeTool
+- Text.WorkingCopy.Conflicts.OpenExternalMergeToolAllConflicts
+- Text.WorkingCopy.Conflicts.UseMine
+- Text.WorkingCopy.Conflicts.UseTheirs
-### es_ES.axaml: 100.00%
-
+### 
-Missing Keys
-
-
-
-
-
-### fr_FR.axaml: 92.79%
-
-
-
-Missing Keys
+Missing keys in pt_BR.axaml
+- Text.AIAssistant.Regen
+- Text.AIAssistant.Use
+- Text.ApplyStash
+- Text.ApplyStash.DropAfterApply
+- Text.ApplyStash.RestoreIndex
+- Text.ApplyStash.Stash
+- Text.BranchCM.CustomAction
- Text.BranchCM.MergeMultiBranches
-- Text.CherryPick.AppendSourceToMessage
-- Text.CherryPick.Mainline.Tips
-- Text.CommitCM.CherryPickMultiple
+- Text.BranchUpstreamInvalid
+- Text.Clone.RecurseSubmodules
- Text.CommitCM.Merge
- Text.CommitCM.MergeMultiple
- Text.CommitDetail.Files.Search
+- Text.CommitDetail.Info.Children
+- Text.Configure.CustomAction.Scope.Branch
+- Text.Configure.CustomAction.WaitForExit
+- Text.Configure.Git.PreferredMergeMode
- Text.Configure.IssueTracker.AddSampleGiteeIssue
- Text.Configure.IssueTracker.AddSampleGiteePullRequest
+- Text.ConfirmEmptyCommit.Continue
+- Text.ConfirmEmptyCommit.NoLocalChanges
+- Text.ConfirmEmptyCommit.StageAllThenCommit
+- Text.ConfirmEmptyCommit.WithLocalChanges
+- Text.CopyFullPath
+- Text.CreateBranch.Name.WarnSpace
+- Text.DeleteRepositoryNode.Path
+- Text.DeleteRepositoryNode.TipForGroup
+- Text.DeleteRepositoryNode.TipForRepository
+- Text.Diff.First
+- Text.Diff.Last
- Text.Diff.UseBlockNavigation
- Text.Fetch.Force
- Text.FileCM.ResolveUsing
@@ -63,132 +158,18 @@
- Text.MergeMultiple.CommitChanges
- Text.MergeMultiple.Strategy
- Text.MergeMultiple.Targets
-- Text.Preference.Appearance.FontSize
-- Text.Preference.Appearance.FontSize.Default
-- Text.Preference.Appearance.FontSize.Editor
-- Text.Preference.General.DateFormat
-- Text.Preference.General.ShowChildren
-- Text.Preference.Git.SSLVerify
-- Text.Repository.CustomActions
-- Text.Repository.FilterCommits
-- Text.Repository.FilterCommits.Default
-- Text.Repository.FilterCommits.Exclude
-- Text.Repository.FilterCommits.Include
-- Text.Repository.HistoriesLayout
-- Text.Repository.HistoriesLayout.Horizontal
-- Text.Repository.HistoriesLayout.Vertical
-- Text.Repository.HistoriesOrder
-- Text.Repository.HistoriesOrder.ByDate
-- Text.Repository.HistoriesOrder.Topo
-- Text.Repository.OnlyHighlightCurrentBranchInHistories
-- Text.Repository.Skip
-- Text.Repository.Tags.OrderByCreatorDate
-- Text.Repository.Tags.OrderByNameAsc
-- Text.Repository.Tags.OrderByNameDes
-- Text.Repository.Tags.Sort
-- Text.Repository.UseRelativeTimeInHistories
-- Text.ScanRepositories
-- Text.SetUpstream
-- Text.SetUpstream.Local
-- Text.SetUpstream.Unset
-- Text.SetUpstream.Upstream
-- Text.SHALinkCM.NavigateTo
-- Text.WorkingCopy.CommitToEdit
-
-
-
-### it_IT.axaml: 93.33%
-
-
-
-Missing Keys
-
-- Text.BranchCM.MergeMultiBranches
-- Text.CommitCM.Merge
-- Text.CommitCM.MergeMultiple
-- Text.CommitDetail.Files.Search
-- Text.CommitDetail.Info.Children
-- Text.Configure.IssueTracker.AddSampleGiteeIssue
-- Text.Configure.IssueTracker.AddSampleGiteePullRequest
-- Text.Configure.IssueTracker.AddSampleGitLabMergeRequest
-- Text.Configure.OpenAI.Preferred
-- Text.Configure.OpenAI.Preferred.Tip
-- Text.Diff.UseBlockNavigation
-- Text.Fetch.Force
-- Text.FileCM.ResolveUsing
-- Text.InProgress.CherryPick.Head
-- Text.InProgress.Merge.Operating
-- Text.InProgress.Rebase.StoppedAt
-- Text.InProgress.Revert.Head
-- Text.Merge.Source
-- Text.MergeMultiple
-- Text.MergeMultiple.CommitChanges
-- Text.MergeMultiple.Strategy
-- Text.MergeMultiple.Targets
-- Text.Preference.General.DateFormat
-- Text.Preference.General.ShowChildren
-- Text.Preference.Git.SSLVerify
-- Text.Repository.FilterCommits
-- Text.Repository.FilterCommits.Default
-- Text.Repository.FilterCommits.Exclude
-- Text.Repository.FilterCommits.Include
-- Text.Repository.HistoriesLayout
-- Text.Repository.HistoriesLayout.Horizontal
-- Text.Repository.HistoriesLayout.Vertical
-- Text.Repository.HistoriesOrder
-- Text.Repository.HistoriesOrder.ByDate
-- Text.Repository.HistoriesOrder.Topo
-- Text.Repository.OnlyHighlightCurrentBranchInHistories
-- Text.Repository.Skip
-- Text.Repository.Tags.OrderByCreatorDate
-- Text.Repository.Tags.OrderByNameAsc
-- Text.Repository.Tags.OrderByNameDes
-- Text.Repository.Tags.Sort
-- Text.Repository.UseRelativeTimeInHistories
-- Text.SetUpstream
-- Text.SetUpstream.Local
-- Text.SetUpstream.Unset
-- Text.SetUpstream.Upstream
-- Text.SHALinkCM.CopySHA
-- Text.SHALinkCM.NavigateTo
-- Text.WorkingCopy.CommitToEdit
-
-
-
-### pt_BR.axaml: 94.42%
-
-
-
-Missing Keys
-
-- Text.BranchCM.MergeMultiBranches
-- Text.CommitCM.Merge
-- Text.CommitCM.MergeMultiple
-- Text.CommitDetail.Files.Search
-- Text.CommitDetail.Info.Children
-- Text.Configure.IssueTracker.AddSampleGiteeIssue
-- Text.Configure.IssueTracker.AddSampleGiteePullRequest
-- Text.Diff.UseBlockNavigation
-- Text.Fetch.Force
-- Text.FileCM.ResolveUsing
-- Text.Hotkeys.Global.Clone
-- Text.InProgress.CherryPick.Head
-- Text.InProgress.Merge.Operating
-- Text.InProgress.Rebase.StoppedAt
-- Text.InProgress.Revert.Head
-- Text.Merge.Source
-- Text.MergeMultiple
-- Text.MergeMultiple.CommitChanges
-- Text.MergeMultiple.Strategy
-- Text.MergeMultiple.Targets
-- Text.Preference.General.DateFormat
-- Text.Preference.General.ShowChildren
-- Text.Preference.Git.SSLVerify
+- Text.Preferences.AI.Streaming
+- Text.Preferences.Appearance.EditorTabWidth
+- Text.Preferences.General.DateFormat
+- Text.Preferences.General.ShowChildren
+- Text.Preferences.General.ShowTagsInGraph
+- Text.Preferences.Git.SSLVerify
- Text.Repository.FilterCommits
- Text.Repository.HistoriesLayout
- Text.Repository.HistoriesLayout.Horizontal
- Text.Repository.HistoriesLayout.Vertical
- Text.Repository.HistoriesOrder
+- Text.Repository.Notifications.Clear
- Text.Repository.OnlyHighlightCurrentBranchInHistories
- Text.Repository.Skip
- Text.Repository.Tags.OrderByCreatorDate
@@ -201,36 +182,55 @@
- Text.SetUpstream.Unset
- Text.SetUpstream.Upstream
- Text.SHALinkCM.NavigateTo
+- Text.Stash.AutoRestore
+- Text.Stash.AutoRestore.Tip
+- Text.StashCM.SaveAsPatch
- Text.WorkingCopy.CommitToEdit
+- Text.WorkingCopy.ConfirmCommitWithFilter
+- Text.WorkingCopy.Conflicts.OpenExternalMergeTool
+- Text.WorkingCopy.Conflicts.OpenExternalMergeToolAllConflicts
+- Text.WorkingCopy.Conflicts.UseMine
+- Text.WorkingCopy.Conflicts.UseTheirs
+- Text.WorkingCopy.SignOff
-### ru_RU.axaml: 100.00%
-
+### 
-Missing Keys
-
+Missing keys in ru_RU.axaml
+- Text.Configure.Git.PreferredMergeMode
+- Text.ConfirmEmptyCommit.Continue
+- Text.ConfirmEmptyCommit.NoLocalChanges
+- Text.ConfirmEmptyCommit.StageAllThenCommit
+- Text.ConfirmEmptyCommit.WithLocalChanges
+- Text.WorkingCopy.ConfirmCommitWithFilter
+- Text.WorkingCopy.Conflicts.OpenExternalMergeTool
+- Text.WorkingCopy.Conflicts.OpenExternalMergeToolAllConflicts
+- Text.WorkingCopy.Conflicts.UseMine
+- Text.WorkingCopy.Conflicts.UseTheirs
-### zh_CN.axaml: 100.00%
-
+### 
-Missing Keys
-
+Missing keys in ta_IN.axaml
+- Text.Configure.Git.PreferredMergeMode
+- Text.ConfirmEmptyCommit.Continue
+- Text.ConfirmEmptyCommit.NoLocalChanges
+- Text.ConfirmEmptyCommit.StageAllThenCommit
+- Text.ConfirmEmptyCommit.WithLocalChanges
+- Text.UpdateSubmodules.Target
+- Text.WorkingCopy.Conflicts.OpenExternalMergeTool
+- Text.WorkingCopy.Conflicts.OpenExternalMergeToolAllConflicts
+- Text.WorkingCopy.Conflicts.UseMine
+- Text.WorkingCopy.Conflicts.UseTheirs
-### zh_TW.axaml: 100.00%
+### 
-
-
-Missing Keys
-
-
-
-
+### 
\ No newline at end of file
diff --git a/VERSION b/VERSION
index d612525a..8283ecf3 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-2025.01
\ No newline at end of file
+2025.12
\ No newline at end of file
diff --git a/build/resources/deb/DEBIAN/control b/build/resources/deb/DEBIAN/control
index f553db8b..71786b43 100755
--- a/build/resources/deb/DEBIAN/control
+++ b/build/resources/deb/DEBIAN/control
@@ -1,7 +1,8 @@
Package: sourcegit
-Version: 8.23
+Version: 2025.10
Priority: optional
Depends: libx11-6, libice6, libsm6, libicu | libicu76 | libicu74 | libicu72 | libicu71 | libicu70 | libicu69 | libicu68 | libicu67 | libicu66 | libicu65 | libicu63 | libicu60 | libicu57 | libicu55 | libicu52, xdg-utils
Architecture: amd64
+Installed-Size: 60440
Maintainer: longshuang@msn.cn
Description: Open-source & Free Git GUI Client
diff --git a/build/resources/deb/DEBIAN/preinst b/build/resources/deb/DEBIAN/preinst
new file mode 100755
index 00000000..a93f8090
--- /dev/null
+++ b/build/resources/deb/DEBIAN/preinst
@@ -0,0 +1,32 @@
+#!/bin/sh
+
+set -e
+
+# summary of how this script can be called:
+# * `install'
+# * `install'
+# * `upgrade'
+# * `abort-upgrade'
+# for details, see http://www.debian.org/doc/debian-policy/
+
+case "$1" in
+ install|upgrade)
+ # Check if SourceGit is running and stop it
+ if pgrep -f '/opt/sourcegit/sourcegit' > /dev/null; then
+ echo "Stopping running SourceGit instance..."
+ pkill -f '/opt/sourcegit/sourcegit' || true
+ # Give the process a moment to terminate
+ sleep 1
+ fi
+ ;;
+
+ abort-upgrade)
+ ;;
+
+ *)
+ echo "preinst called with unknown argument \`$1'" >&2
+ exit 1
+ ;;
+esac
+
+exit 0
diff --git a/build/resources/deb/DEBIAN/prerm b/build/resources/deb/DEBIAN/prerm
new file mode 100755
index 00000000..c2c9e4f0
--- /dev/null
+++ b/build/resources/deb/DEBIAN/prerm
@@ -0,0 +1,35 @@
+#!/bin/sh
+
+set -e
+
+# summary of how this script can be called:
+# * `remove'
+# * `upgrade'
+# * `failed-upgrade'
+# * `remove' `in-favour'
+# * `deconfigure' `in-favour'
+# `removing'
+#
+# for details, see http://www.debian.org/doc/debian-policy/ or
+# the debian-policy package
+
+case "$1" in
+ remove|upgrade|deconfigure)
+ if pgrep -f '/opt/sourcegit/sourcegit' > /dev/null; then
+ echo "Stopping running SourceGit instance..."
+ pkill -f '/opt/sourcegit/sourcegit' || true
+ # Give the process a moment to terminate
+ sleep 1
+ fi
+ ;;
+
+ failed-upgrade)
+ ;;
+
+ *)
+ echo "prerm called with unknown argument \`$1'" >&2
+ exit 1
+ ;;
+esac
+
+exit 0
diff --git a/build/scripts/localization-check.js b/build/scripts/localization-check.js
index 45db82be..1e8f1f0d 100644
--- a/build/scripts/localization-check.js
+++ b/build/scripts/localization-check.js
@@ -6,7 +6,6 @@ const repoRoot = path.join(__dirname, '../../');
const localesDir = path.join(repoRoot, 'src/Resources/Locales');
const enUSFile = path.join(localesDir, 'en_US.axaml');
const outputFile = path.join(repoRoot, 'TRANSLATION.md');
-const readmeFile = path.join(repoRoot, 'README.md');
const parser = new xml2js.Parser();
@@ -18,42 +17,36 @@ async function parseXml(filePath) {
async function calculateTranslationRate() {
const enUSData = await parseXml(enUSFile);
const enUSKeys = new Set(enUSData.ResourceDictionary['x:String'].map(item => item.$['x:Key']));
-
- const translationRates = [];
- const badges = [];
-
const files = (await fs.readdir(localesDir)).filter(file => file !== 'en_US.axaml' && file.endsWith('.axaml'));
- // Add en_US badge first
- badges.push(`[](TRANSLATION.md)`);
+ const lines = [];
+
+ lines.push('# Translation Status');
+ lines.push('This document shows the translation status of each locale file in the repository.');
+ lines.push(`## Details`);
+ lines.push(`### `);
for (const file of files) {
+ const locale = file.replace('.axaml', '').replace('_', '__');
const filePath = path.join(localesDir, file);
const localeData = await parseXml(filePath);
const localeKeys = new Set(localeData.ResourceDictionary['x:String'].map(item => item.$['x:Key']));
-
const missingKeys = [...enUSKeys].filter(key => !localeKeys.has(key));
- const translationRate = ((enUSKeys.size - missingKeys.length) / enUSKeys.size) * 100;
- translationRates.push(`### ${file}: ${translationRate.toFixed(2)}%\n`);
- translationRates.push(`\nMissing Keys
\n\n${missingKeys.map(key => `- ${key}`).join('\n')}\n\n `);
+ if (missingKeys.length > 0) {
+ const progress = ((enUSKeys.size - missingKeys.length) / enUSKeys.size) * 100;
+ const badgeColor = progress >= 75 ? 'yellow' : 'red';
- // Add badges
- const locale = file.replace('.axaml', '').replace('_', '__');
- const badgeColor = translationRate === 100 ? 'brightgreen' : translationRate >= 75 ? 'yellow' : 'red';
- badges.push(`[}%25-${badgeColor})](TRANSLATION.md)`);
+ lines.push(`### }%25-${badgeColor})`);
+ lines.push(`\nMissing keys in ${file}
\n\n${missingKeys.map(key => `- ${key}`).join('\n')}\n\n `)
+ } else {
+ lines.push(`### `);
+ }
}
- console.log(translationRates.join('\n\n'));
-
- await fs.writeFile(outputFile, translationRates.join('\n\n') + '\n', 'utf8');
-
- // Update README.md
- let readmeContent = await fs.readFile(readmeFile, 'utf8');
- const badgeSection = `## Translation Status\n\n${badges.join(' ')}`;
- console.log(badgeSection);
- readmeContent = readmeContent.replace(/## Translation Status\n\n.*\n\n/, badgeSection + '\n\n');
- await fs.writeFile(readmeFile, readmeContent, 'utf8');
+ const content = lines.join('\n\n');
+ console.log(content);
+ await fs.writeFile(outputFile, content, 'utf8');
}
calculateTranslationRate().catch(err => console.error(err));
diff --git a/build/scripts/package.linux.sh b/build/scripts/package.linux.sh
index 5abb058b..1b4adbdc 100755
--- a/build/scripts/package.linux.sh
+++ b/build/scripts/package.linux.sh
@@ -56,8 +56,15 @@ cp -f SourceGit/* resources/deb/opt/sourcegit
ln -rsf resources/deb/opt/sourcegit/sourcegit resources/deb/usr/bin
cp -r resources/_common/applications resources/deb/usr/share
cp -r resources/_common/icons resources/deb/usr/share
-sed -i -e "s/^Version:.*/Version: $VERSION/" -e "s/^Architecture:.*/Architecture: $arch/" resources/deb/DEBIAN/control
-dpkg-deb --root-owner-group --build resources/deb "sourcegit_$VERSION-1_$arch.deb"
+# Calculate installed size in KB
+installed_size=$(du -sk resources/deb | cut -f1)
+# Update the control file
+sed -i -e "s/^Version:.*/Version: $VERSION/" \
+ -e "s/^Architecture:.*/Architecture: $arch/" \
+ -e "s/^Installed-Size:.*/Installed-Size: $installed_size/" \
+ resources/deb/DEBIAN/control
+# Build deb package with gzip compression
+dpkg-deb -Zgzip --root-owner-group --build resources/deb "sourcegit_$VERSION-1_$arch.deb"
rpmbuild -bb --target="$target" resources/rpm/SPECS/build.spec --define "_topdir $(pwd)/resources/rpm" --define "_version $VERSION"
mv "resources/rpm/RPMS/$target/sourcegit-$VERSION-1.$target.rpm" ./
diff --git a/build/scripts/package.windows.sh b/build/scripts/package.windows.sh
index 6bd3879b..c22a9d35 100755
--- a/build/scripts/package.windows.sh
+++ b/build/scripts/package.windows.sh
@@ -9,4 +9,8 @@ cd build
rm -rf SourceGit/*.pdb
-zip "sourcegit_$VERSION.$RUNTIME.zip" -r SourceGit
+if [[ "$OSTYPE" == "msys" || "$OSTYPE" == "cygwin" || "$OSTYPE" == "win32" ]]; then
+ powershell -Command "Compress-Archive -Path SourceGit -DestinationPath \"sourcegit_$VERSION.$RUNTIME.zip\" -Force"
+else
+ zip "sourcegit_$VERSION.$RUNTIME.zip" -r SourceGit
+fi
diff --git a/src/App.Commands.cs b/src/App.Commands.cs
index fd140f24..85a75829 100644
--- a/src/App.Commands.cs
+++ b/src/App.Commands.cs
@@ -37,7 +37,7 @@ namespace SourceGit
}
}
- public static readonly Command OpenPreferenceCommand = new Command(_ => OpenDialog(new Views.Preference()));
+ public static readonly Command OpenPreferencesCommand = new Command(_ => OpenDialog(new Views.Preferences()));
public static readonly Command OpenHotkeysCommand = new Command(_ => OpenDialog(new Views.Hotkeys()));
public static readonly Command OpenAppDataDirCommand = new Command(_ => Native.OS.OpenInFileManager(Native.OS.DataDir));
public static readonly Command OpenAboutCommand = new Command(_ => OpenDialog(new Views.About()));
diff --git a/src/App.JsonCodeGen.cs b/src/App.JsonCodeGen.cs
index 70567af5..9cad0792 100644
--- a/src/App.JsonCodeGen.cs
+++ b/src/App.JsonCodeGen.cs
@@ -46,11 +46,9 @@ namespace SourceGit
[JsonSerializable(typeof(Models.ExternalToolPaths))]
[JsonSerializable(typeof(Models.InteractiveRebaseJobCollection))]
[JsonSerializable(typeof(Models.JetBrainsState))]
- [JsonSerializable(typeof(Models.OpenAIChatRequest))]
- [JsonSerializable(typeof(Models.OpenAIChatResponse))]
[JsonSerializable(typeof(Models.ThemeOverrides))]
[JsonSerializable(typeof(Models.Version))]
[JsonSerializable(typeof(Models.RepositorySettings))]
- [JsonSerializable(typeof(ViewModels.Preference))]
+ [JsonSerializable(typeof(ViewModels.Preferences))]
internal partial class JsonCodeGen : JsonSerializerContext { }
}
diff --git a/src/App.axaml b/src/App.axaml
index 55aacb89..9d8adb89 100644
--- a/src/App.axaml
+++ b/src/App.axaml
@@ -20,6 +20,8 @@
+
+
@@ -35,7 +37,7 @@
-
+
diff --git a/src/App.axaml.cs b/src/App.axaml.cs
index 9fac35a6..0448a247 100644
--- a/src/App.axaml.cs
+++ b/src/App.axaml.cs
@@ -1,10 +1,12 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics;
using System.IO;
using System.Net.Http;
using System.Reflection;
using System.Text;
using System.Text.Json;
+using System.Threading;
using System.Threading.Tasks;
using Avalonia;
@@ -35,15 +37,14 @@ namespace SourceGit
TaskScheduler.UnobservedTaskException += (_, e) =>
{
- LogException(e.Exception);
e.SetObserved();
};
try
{
- if (TryLaunchedAsRebaseTodoEditor(args, out int exitTodo))
+ if (TryLaunchAsRebaseTodoEditor(args, out int exitTodo))
Environment.Exit(exitTodo);
- else if (TryLaunchedAsRebaseMessageEditor(args, out int exitMessage))
+ else if (TryLaunchAsRebaseMessageEditor(args, out int exitMessage))
Environment.Exit(exitMessage);
else
BuildAvaloniaApp().StartWithClassicDesktopLifetime(args);
@@ -75,6 +76,31 @@ namespace SourceGit
Native.OS.SetupApp(builder);
return builder;
}
+
+ private static void LogException(Exception ex)
+ {
+ if (ex == null)
+ return;
+
+ var builder = new StringBuilder();
+ builder.Append($"Crash::: {ex.GetType().FullName}: {ex.Message}\n\n");
+ builder.Append("----------------------------\n");
+ builder.Append($"Version: {Assembly.GetExecutingAssembly().GetName().Version}\n");
+ builder.Append($"OS: {Environment.OSVersion}\n");
+ builder.Append($"Framework: {AppDomain.CurrentDomain.SetupInformation.TargetFrameworkName}\n");
+ builder.Append($"Source: {ex.Source}\n");
+ builder.Append($"Thread Name: {Thread.CurrentThread.Name ?? "Unnamed"}\n");
+ builder.Append($"User: {Environment.UserName}\n");
+ builder.Append($"App Start Time: {Process.GetCurrentProcess().StartTime}\n");
+ builder.Append($"Exception Time: {DateTime.Now}\n");
+ builder.Append($"Memory Usage: {Process.GetCurrentProcess().PrivateMemorySize64 / 1024 / 1024} MB\n");
+ builder.Append($"---------------------------\n\n");
+ builder.Append(ex);
+
+ var time = DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss");
+ var file = Path.Combine(Native.OS.DataDir, $"crash_{time}.log");
+ File.WriteAllText(file, builder.ToString());
+ }
#endregion
#region Utility Functions
@@ -179,6 +205,9 @@ namespace SourceGit
app._fontsOverrides = null;
}
+ defaultFont = app.FixFontFamilyName(defaultFont);
+ monospaceFont = app.FixFontFamilyName(monospaceFont);
+
var resDic = new ResourceDictionary();
if (!string.IsNullOrEmpty(defaultFont))
resDic.Add("Fonts.Default", new FontFamily(defaultFont));
@@ -298,7 +327,7 @@ namespace SourceGit
{
AvaloniaXamlLoader.Load(this);
- var pref = ViewModels.Preference.Instance;
+ var pref = ViewModels.Preferences.Instance;
pref.PropertyChanged += (_, _) => pref.Save();
SetLocale(pref.Locale);
@@ -312,44 +341,18 @@ namespace SourceGit
{
BindingPlugins.DataValidators.RemoveAt(0);
- if (TryLaunchedAsCoreEditor(desktop))
+ if (TryLaunchAsCoreEditor(desktop))
return;
- if (TryLaunchedAsAskpass(desktop))
+ if (TryLaunchAsAskpass(desktop))
return;
- TryLaunchedAsNormal(desktop);
+ TryLaunchAsNormal(desktop);
}
}
#endregion
- private static void LogException(Exception ex)
- {
- if (ex == null)
- return;
-
- var builder = new StringBuilder();
- builder.Append($"Crash::: {ex.GetType().FullName}: {ex.Message}\n\n");
- builder.Append("----------------------------\n");
- builder.Append($"Version: {Assembly.GetExecutingAssembly().GetName().Version}\n");
- builder.Append($"OS: {Environment.OSVersion.ToString()}\n");
- builder.Append($"Framework: {AppDomain.CurrentDomain.SetupInformation.TargetFrameworkName}\n");
- builder.Append($"Source: {ex.Source}\n");
- builder.Append($"---------------------------\n\n");
- builder.Append(ex.StackTrace);
- while (ex.InnerException != null)
- {
- ex = ex.InnerException;
- builder.Append($"\n\nInnerException::: {ex.GetType().FullName}: {ex.Message}\n");
- builder.Append(ex.StackTrace);
- }
-
- var time = DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss");
- var file = Path.Combine(Native.OS.DataDir, $"crash_{time}.log");
- File.WriteAllText(file, builder.ToString());
- }
-
- private static bool TryLaunchedAsRebaseTodoEditor(string[] args, out int exitCode)
+ private static bool TryLaunchAsRebaseTodoEditor(string[] args, out int exitCode)
{
exitCode = -1;
@@ -402,7 +405,7 @@ namespace SourceGit
return true;
}
- private static bool TryLaunchedAsRebaseMessageEditor(string[] args, out int exitCode)
+ private static bool TryLaunchAsRebaseMessageEditor(string[] args, out int exitCode)
{
exitCode = -1;
@@ -436,7 +439,7 @@ namespace SourceGit
return true;
}
- private bool TryLaunchedAsCoreEditor(IClassicDesktopStyleApplicationLifetime desktop)
+ private bool TryLaunchAsCoreEditor(IClassicDesktopStyleApplicationLifetime desktop)
{
var args = desktop.Args;
if (args == null || args.Length <= 1 || !args[0].Equals("--core-editor", StringComparison.Ordinal))
@@ -444,14 +447,18 @@ namespace SourceGit
var file = args[1];
if (!File.Exists(file))
+ {
desktop.Shutdown(-1);
- else
- desktop.MainWindow = new Views.StandaloneCommitMessageEditor(file);
+ return true;
+ }
+ var editor = new Views.StandaloneCommitMessageEditor();
+ editor.SetFile(file);
+ desktop.MainWindow = editor;
return true;
}
- private bool TryLaunchedAsAskpass(IClassicDesktopStyleApplicationLifetime desktop)
+ private bool TryLaunchAsAskpass(IClassicDesktopStyleApplicationLifetime desktop)
{
var launchAsAskpass = Environment.GetEnvironmentVariable("SOURCEGIT_LAUNCH_AS_ASKPASS");
if (launchAsAskpass is not "TRUE")
@@ -460,14 +467,16 @@ namespace SourceGit
var args = desktop.Args;
if (args?.Length > 0)
{
- desktop.MainWindow = new Views.Askpass(args[0]);
+ var askpass = new Views.Askpass();
+ askpass.TxtDescription.Text = args[0];
+ desktop.MainWindow = askpass;
return true;
}
return false;
}
- private void TryLaunchedAsNormal(IClassicDesktopStyleApplicationLifetime desktop)
+ private void TryLaunchAsNormal(IClassicDesktopStyleApplicationLifetime desktop)
{
Native.OS.SetupEnternalTools();
Models.AvatarManager.Instance.Start();
@@ -480,7 +489,7 @@ namespace SourceGit
desktop.MainWindow = new Views.Launcher() { DataContext = _launcher };
#if !DISABLE_UPDATE_DETECTION
- var pref = ViewModels.Preference.Instance;
+ var pref = ViewModels.Preferences.Instance;
if (pref.ShouldCheck4UpdateOnStartup())
Check4Update();
#endif
@@ -512,7 +521,7 @@ namespace SourceGit
// Should not check ignored tag if this is called manually.
if (!manually)
{
- var pref = ViewModels.Preference.Instance;
+ var pref = ViewModels.Preferences.Instance;
if (ver.TagName == pref.IgnoreUpdateTag)
return;
}
@@ -522,7 +531,7 @@ namespace SourceGit
catch (Exception e)
{
if (manually)
- ShowSelfUpdateResult(e);
+ ShowSelfUpdateResult(new Models.SelfUpdateFailed(e));
}
});
}
@@ -539,6 +548,38 @@ namespace SourceGit
});
}
+ private string FixFontFamilyName(string input)
+ {
+ if (string.IsNullOrEmpty(input))
+ return string.Empty;
+
+ var parts = input.Split(',');
+ var trimmed = new List();
+
+ foreach (var part in parts)
+ {
+ var t = part.Trim();
+ if (string.IsNullOrEmpty(t))
+ continue;
+
+ // Collapse multiple spaces into single space
+ var prevChar = '\0';
+ var sb = new StringBuilder();
+
+ foreach (var c in t)
+ {
+ if (c == ' ' && prevChar == ' ')
+ continue;
+ sb.Append(c);
+ prevChar = c;
+ }
+
+ trimmed.Add(sb.ToString());
+ }
+
+ return trimmed.Count > 0 ? string.Join(',', trimmed) : string.Empty;
+ }
+
private ViewModels.Launcher _launcher = null;
private ResourceDictionary _activeLocale = null;
private ResourceDictionary _themeOverrides = null;
diff --git a/src/Commands/Add.cs b/src/Commands/Add.cs
index e1b55b68..b2aa803d 100644
--- a/src/Commands/Add.cs
+++ b/src/Commands/Add.cs
@@ -12,7 +12,7 @@ namespace SourceGit.Commands
Args = includeUntracked ? "add ." : "add -u .";
}
- public Add(string repo, List changes)
+ public Add(string repo, List changes)
{
WorkingDirectory = repo;
Context = repo;
@@ -22,7 +22,7 @@ namespace SourceGit.Commands
foreach (var c in changes)
{
builder.Append(" \"");
- builder.Append(c.Path);
+ builder.Append(c);
builder.Append("\"");
}
Args = builder.ToString();
diff --git a/src/Commands/Branch.cs b/src/Commands/Branch.cs
index 391aeeb2..2dc8a98d 100644
--- a/src/Commands/Branch.cs
+++ b/src/Commands/Branch.cs
@@ -54,21 +54,14 @@
public static bool DeleteRemote(string repo, string remote, string name)
{
+ bool exists = new Remote(repo).HasBranch(remote, name);
+ if (exists)
+ return new Push(repo, remote, $"refs/heads/{name}", true).Exec();
+
var cmd = new Command();
cmd.WorkingDirectory = repo;
cmd.Context = repo;
-
- bool exists = new Remote(repo).HasBranch(remote, name);
- if (exists)
- {
- cmd.SSHKey = new Config(repo).Get($"remote.{remote}.sshkey");
- cmd.Args = $"push {remote} --delete {name}";
- }
- else
- {
- cmd.Args = $"branch -D -r {remote}/{name}";
- }
-
+ cmd.Args = $"branch -D -r {remote}/{name}";
return cmd.Exec();
}
}
diff --git a/src/Commands/Clone.cs b/src/Commands/Clone.cs
index 683b8846..f2faed14 100644
--- a/src/Commands/Clone.cs
+++ b/src/Commands/Clone.cs
@@ -12,7 +12,7 @@ namespace SourceGit.Commands
WorkingDirectory = path;
TraitErrorAsOutput = true;
SSHKey = sshKey;
- Args = "clone --progress --verbose --recurse-submodules ";
+ Args = "clone --progress --verbose ";
if (!string.IsNullOrEmpty(extraArgs))
Args += $"{extraArgs} ";
diff --git a/src/Commands/Command.cs b/src/Commands/Command.cs
index 3f61de17..0fef1235 100644
--- a/src/Commands/Command.cs
+++ b/src/Commands/Command.cs
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.Text.RegularExpressions;
+using System.Threading;
using Avalonia.Threading;
@@ -10,11 +11,6 @@ namespace SourceGit.Commands
{
public partial class Command
{
- public class CancelToken
- {
- public bool Requested { get; set; } = false;
- }
-
public class ReadToEndResult
{
public bool IsSuccess { get; set; } = false;
@@ -30,7 +26,7 @@ namespace SourceGit.Commands
}
public string Context { get; set; } = string.Empty;
- public CancelToken Cancel { get; set; } = null;
+ public CancellationToken CancellationToken { get; set; } = CancellationToken.None;
public string WorkingDirectory { get; set; } = null;
public EditorType Editor { get; set; } = EditorType.CoreEditor; // Only used in Exec() mode
public string SSHKey { get; set; } = string.Empty;
@@ -43,36 +39,15 @@ namespace SourceGit.Commands
var start = CreateGitStartInfo();
var errs = new List();
var proc = new Process() { StartInfo = start };
- var isCancelled = false;
proc.OutputDataReceived += (_, e) =>
{
- if (Cancel != null && Cancel.Requested)
- {
- isCancelled = true;
- proc.CancelErrorRead();
- proc.CancelOutputRead();
- if (!proc.HasExited)
- proc.Kill(true);
- return;
- }
-
if (e.Data != null)
OnReadline(e.Data);
};
proc.ErrorDataReceived += (_, e) =>
{
- if (Cancel != null && Cancel.Requested)
- {
- isCancelled = true;
- proc.CancelErrorRead();
- proc.CancelOutputRead();
- if (!proc.HasExited)
- proc.Kill(true);
- return;
- }
-
if (string.IsNullOrEmpty(e.Data))
{
errs.Add(string.Empty);
@@ -97,9 +72,25 @@ namespace SourceGit.Commands
errs.Add(e.Data);
};
+ var dummy = null as Process;
+ var dummyProcLock = new object();
try
{
proc.Start();
+
+ // It not safe, please only use `CancellationToken` in readonly commands.
+ if (CancellationToken.CanBeCanceled)
+ {
+ dummy = proc;
+ CancellationToken.Register(() =>
+ {
+ lock (dummyProcLock)
+ {
+ if (dummy is { HasExited: false })
+ dummy.Kill();
+ }
+ });
+ }
}
catch (Exception e)
{
@@ -113,10 +104,18 @@ namespace SourceGit.Commands
proc.BeginErrorReadLine();
proc.WaitForExit();
+ if (dummy != null)
+ {
+ lock (dummyProcLock)
+ {
+ dummy = null;
+ }
+ }
+
int exitCode = proc.ExitCode;
proc.Close();
- if (!isCancelled && exitCode != 0)
+ if (!CancellationToken.IsCancellationRequested && exitCode != 0)
{
if (RaiseError)
{
@@ -192,13 +191,12 @@ namespace SourceGit.Commands
if (!start.Environment.ContainsKey("GIT_SSH_COMMAND") && !string.IsNullOrEmpty(SSHKey))
start.Environment.Add("GIT_SSH_COMMAND", $"ssh -i '{SSHKey}'");
- // Force using en_US.UTF-8 locale to avoid GCM crash
+ // Force using en_US.UTF-8 locale
if (OperatingSystem.IsLinux())
- start.Environment.Add("LANG", "en_US.UTF-8");
-
- // Fix macOS `PATH` env
- if (OperatingSystem.IsMacOS() && !string.IsNullOrEmpty(Native.OS.CustomPathEnv))
- start.Environment.Add("PATH", Native.OS.CustomPathEnv);
+ {
+ start.Environment.Add("LANG", "C");
+ start.Environment.Add("LC_ALL", "C");
+ }
// Force using this app as git editor.
switch (Editor)
diff --git a/src/Commands/CompareRevisions.cs b/src/Commands/CompareRevisions.cs
index c4674c8e..c3206767 100644
--- a/src/Commands/CompareRevisions.cs
+++ b/src/Commands/CompareRevisions.cs
@@ -6,8 +6,10 @@ namespace SourceGit.Commands
{
public partial class CompareRevisions : Command
{
- [GeneratedRegex(@"^(\s?[\w\?]{1,4})\s+(.+)$")]
+ [GeneratedRegex(@"^([MADC])\s+(.+)$")]
private static partial Regex REG_FORMAT();
+ [GeneratedRegex(@"^R[0-9]{0,4}\s+(.+)$")]
+ private static partial Regex REG_RENAME_FORMAT();
public CompareRevisions(string repo, string start, string end)
{
@@ -18,6 +20,15 @@ namespace SourceGit.Commands
Args = $"diff --name-status {based} {end}";
}
+ public CompareRevisions(string repo, string start, string end, string path)
+ {
+ WorkingDirectory = repo;
+ Context = repo;
+
+ var based = string.IsNullOrEmpty(start) ? "-R" : start;
+ Args = $"diff --name-status {based} {end} -- \"{path}\"";
+ }
+
public List Result()
{
Exec();
@@ -29,7 +40,17 @@ namespace SourceGit.Commands
{
var match = REG_FORMAT().Match(line);
if (!match.Success)
+ {
+ match = REG_RENAME_FORMAT().Match(line);
+ if (match.Success)
+ {
+ var renamed = new Models.Change() { Path = match.Groups[1].Value };
+ renamed.Set(Models.ChangeState.Renamed);
+ _changes.Add(renamed);
+ }
+
return;
+ }
var change = new Models.Change() { Path = match.Groups[2].Value };
var status = match.Groups[1].Value;
@@ -48,10 +69,6 @@ namespace SourceGit.Commands
change.Set(Models.ChangeState.Deleted);
_changes.Add(change);
break;
- case 'R':
- change.Set(Models.ChangeState.Renamed);
- _changes.Add(change);
- break;
case 'C':
change.Set(Models.ChangeState.Copied);
_changes.Add(change);
diff --git a/src/Commands/Config.cs b/src/Commands/Config.cs
index 2fb83325..49e8fcb7 100644
--- a/src/Commands/Config.cs
+++ b/src/Commands/Config.cs
@@ -29,7 +29,7 @@ namespace SourceGit.Commands
var rs = new Dictionary();
if (output.IsSuccess)
{
- var lines = output.StdOut.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
+ var lines = output.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
foreach (var line in lines)
{
var idx = line.IndexOf('=', StringComparison.Ordinal);
diff --git a/src/Commands/CountLocalChangesWithoutUntracked.cs b/src/Commands/CountLocalChangesWithoutUntracked.cs
index afb62840..0ba508f8 100644
--- a/src/Commands/CountLocalChangesWithoutUntracked.cs
+++ b/src/Commands/CountLocalChangesWithoutUntracked.cs
@@ -8,7 +8,7 @@ namespace SourceGit.Commands
{
WorkingDirectory = repo;
Context = repo;
- Args = "status -uno --ignore-submodules=dirty --porcelain";
+ Args = "--no-optional-locks status -uno --ignore-submodules=dirty --porcelain";
}
public int Result()
@@ -16,7 +16,7 @@ namespace SourceGit.Commands
var rs = ReadToEnd();
if (rs.IsSuccess)
{
- var lines = rs.StdOut.Split('\n', StringSplitOptions.RemoveEmptyEntries);
+ var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
return lines.Length;
}
diff --git a/src/Commands/Diff.cs b/src/Commands/Diff.cs
index da971e58..8ae6350f 100644
--- a/src/Commands/Diff.cs
+++ b/src/Commands/Diff.cs
@@ -68,6 +68,18 @@ namespace SourceGit.Commands
return;
}
+ if (line.StartsWith("deleted file mode ", StringComparison.Ordinal))
+ {
+ _result.OldMode = line.Substring(18);
+ return;
+ }
+
+ if (line.StartsWith("new file mode ", StringComparison.Ordinal))
+ {
+ _result.NewMode = line.Substring(14);
+ return;
+ }
+
if (_result.IsBinary)
return;
diff --git a/src/Commands/ExecuteCustomAction.cs b/src/Commands/ExecuteCustomAction.cs
index a10f5387..000c8fd1 100644
--- a/src/Commands/ExecuteCustomAction.cs
+++ b/src/Commands/ExecuteCustomAction.cs
@@ -8,7 +8,26 @@ namespace SourceGit.Commands
{
public static class ExecuteCustomAction
{
- public static void Run(string repo, string file, string args, Action outputHandler)
+ public static void Run(string repo, string file, string args)
+ {
+ var start = new ProcessStartInfo();
+ start.FileName = file;
+ start.Arguments = args;
+ start.UseShellExecute = false;
+ start.CreateNoWindow = true;
+ start.WorkingDirectory = repo;
+
+ try
+ {
+ Process.Start(start);
+ }
+ catch (Exception e)
+ {
+ Dispatcher.UIThread.Invoke(() => App.RaiseException(repo, e.Message));
+ }
+ }
+
+ public static void RunAndWait(string repo, string file, string args, Action outputHandler)
{
var start = new ProcessStartInfo();
start.FileName = file;
@@ -21,14 +40,6 @@ namespace SourceGit.Commands
start.StandardErrorEncoding = Encoding.UTF8;
start.WorkingDirectory = repo;
- // Force using en_US.UTF-8 locale to avoid GCM crash
- if (OperatingSystem.IsLinux())
- start.Environment.Add("LANG", "en_US.UTF-8");
-
- // Fix macOS `PATH` env
- if (OperatingSystem.IsMacOS() && !string.IsNullOrEmpty(Native.OS.CustomPathEnv))
- start.Environment.Add("PATH", Native.OS.CustomPathEnv);
-
var proc = new Process() { StartInfo = start };
var builder = new StringBuilder();
@@ -57,19 +68,14 @@ namespace SourceGit.Commands
var exitCode = proc.ExitCode;
if (exitCode != 0)
{
- var errMsg = builder.ToString();
- Dispatcher.UIThread.Invoke(() =>
- {
- App.RaiseException(repo, errMsg);
- });
+ var errMsg = builder.ToString().Trim();
+ if (!string.IsNullOrEmpty(errMsg))
+ Dispatcher.UIThread.Invoke(() => App.RaiseException(repo, errMsg));
}
}
catch (Exception e)
{
- Dispatcher.UIThread.Invoke(() =>
- {
- App.RaiseException(repo, e.Message);
- });
+ Dispatcher.UIThread.Invoke(() => App.RaiseException(repo, e.Message));
}
proc.Close();
diff --git a/src/Commands/Fetch.cs b/src/Commands/Fetch.cs
index 1c3e78cb..06ae8cb6 100644
--- a/src/Commands/Fetch.cs
+++ b/src/Commands/Fetch.cs
@@ -4,7 +4,7 @@ namespace SourceGit.Commands
{
public class Fetch : Command
{
- public Fetch(string repo, string remote, bool noTags, bool prune, bool force, Action outputHandler)
+ public Fetch(string repo, string remote, bool noTags, bool force, Action outputHandler)
{
_outputHandler = outputHandler;
WorkingDirectory = repo;
@@ -21,9 +21,6 @@ namespace SourceGit.Commands
if (force)
Args += "--force ";
- if (prune)
- Args += "--prune ";
-
Args += remote;
}
diff --git a/src/Commands/GenerateCommitMessage.cs b/src/Commands/GenerateCommitMessage.cs
index e4f25f38..df61fdd2 100644
--- a/src/Commands/GenerateCommitMessage.cs
+++ b/src/Commands/GenerateCommitMessage.cs
@@ -3,6 +3,8 @@ using System.Collections.Generic;
using System.Text;
using System.Threading;
+using Avalonia.Threading;
+
namespace SourceGit.Commands
{
///
@@ -20,82 +22,78 @@ namespace SourceGit.Commands
}
}
- public GenerateCommitMessage(Models.OpenAIService service, string repo, List changes, CancellationToken cancelToken, Action onProgress)
+ public GenerateCommitMessage(Models.OpenAIService service, string repo, List changes, CancellationToken cancelToken, Action onResponse)
{
_service = service;
_repo = repo;
_changes = changes;
_cancelToken = cancelToken;
- _onProgress = onProgress;
+ _onResponse = onResponse;
}
- public string Result()
+ public void Exec()
{
try
{
- var summarybuilder = new StringBuilder();
- var bodyBuilder = new StringBuilder();
+ _onResponse?.Invoke("Waiting for pre-file analyzing to completed...\n\n");
+
+ var responseBuilder = new StringBuilder();
+ var summaryBuilder = new StringBuilder();
foreach (var change in _changes)
{
if (_cancelToken.IsCancellationRequested)
- return "";
+ return;
- _onProgress?.Invoke($"Analyzing {change.Path}...");
+ responseBuilder.Append("- ");
+ summaryBuilder.Append("- ");
- var summary = GenerateChangeSummary(change);
- summarybuilder.Append("- ");
- summarybuilder.Append(summary);
- summarybuilder.Append("(file: ");
- summarybuilder.Append(change.Path);
- summarybuilder.Append(")");
- summarybuilder.AppendLine();
+ var rs = new GetDiffContent(_repo, new Models.DiffOption(change, false)).ReadToEnd();
+ if (rs.IsSuccess)
+ {
+ _service.Chat(
+ _service.AnalyzeDiffPrompt,
+ $"Here is the `git diff` output: {rs.StdOut}",
+ _cancelToken,
+ update =>
+ {
+ responseBuilder.Append(update);
+ summaryBuilder.Append(update);
- bodyBuilder.Append("- ");
- bodyBuilder.Append(summary);
- bodyBuilder.AppendLine();
+ _onResponse?.Invoke($"Waiting for pre-file analyzing to completed...\n\n{responseBuilder}");
+ });
+ }
+
+ responseBuilder.Append("\n");
+ summaryBuilder.Append("(file: ");
+ summaryBuilder.Append(change.Path);
+ summaryBuilder.Append(")\n");
}
if (_cancelToken.IsCancellationRequested)
- return "";
+ return;
- _onProgress?.Invoke($"Generating commit message...");
-
- var body = bodyBuilder.ToString();
- var subject = GenerateSubject(summarybuilder.ToString());
- return string.Format("{0}\n\n{1}", subject, body);
+ var responseBody = responseBuilder.ToString();
+ var subjectBuilder = new StringBuilder();
+ _service.Chat(
+ _service.GenerateSubjectPrompt,
+ $"Here are the summaries changes:\n{summaryBuilder}",
+ _cancelToken,
+ update =>
+ {
+ subjectBuilder.Append(update);
+ _onResponse?.Invoke($"{subjectBuilder}\n\n{responseBody}");
+ });
}
catch (Exception e)
{
- App.RaiseException(_repo, $"Failed to generate commit message: {e}");
- return "";
+ Dispatcher.UIThread.Post(() => App.RaiseException(_repo, $"Failed to generate commit message: {e}"));
}
}
- private string GenerateChangeSummary(Models.Change change)
- {
- var rs = new GetDiffContent(_repo, new Models.DiffOption(change, false)).ReadToEnd();
- var diff = rs.IsSuccess ? rs.StdOut : "unknown change";
-
- var rsp = _service.Chat(_service.AnalyzeDiffPrompt, $"Here is the `git diff` output: {diff}", _cancelToken);
- if (rsp != null && rsp.Choices.Count > 0)
- return rsp.Choices[0].Message.Content;
-
- return string.Empty;
- }
-
- private string GenerateSubject(string summary)
- {
- var rsp = _service.Chat(_service.GenerateSubjectPrompt, $"Here are the summaries changes:\n{summary}", _cancelToken);
- if (rsp != null && rsp.Choices.Count > 0)
- return rsp.Choices[0].Message.Content;
-
- return string.Empty;
- }
-
private Models.OpenAIService _service;
private string _repo;
private List _changes;
private CancellationToken _cancelToken;
- private Action _onProgress;
+ private Action _onResponse;
}
}
diff --git a/src/Commands/IsBareRepository.cs b/src/Commands/IsBareRepository.cs
new file mode 100644
index 00000000..f92d0888
--- /dev/null
+++ b/src/Commands/IsBareRepository.cs
@@ -0,0 +1,24 @@
+using System.IO;
+
+namespace SourceGit.Commands
+{
+ public class IsBareRepository : Command
+ {
+ public IsBareRepository(string path)
+ {
+ WorkingDirectory = path;
+ Args = "rev-parse --is-bare-repository";
+ }
+
+ public bool Result()
+ {
+ if (!Directory.Exists(Path.Combine(WorkingDirectory, "refs")) ||
+ !Directory.Exists(Path.Combine(WorkingDirectory, "objects")) ||
+ !File.Exists(Path.Combine(WorkingDirectory, "HEAD")))
+ return false;
+
+ var rs = ReadToEnd();
+ return rs.IsSuccess && rs.StdOut.Trim() == "true";
+ }
+ }
+}
diff --git a/src/Commands/IsCommitSHA.cs b/src/Commands/IsCommitSHA.cs
new file mode 100644
index 00000000..1b0c50e3
--- /dev/null
+++ b/src/Commands/IsCommitSHA.cs
@@ -0,0 +1,17 @@
+namespace SourceGit.Commands
+{
+ public class IsCommitSHA : Command
+ {
+ public IsCommitSHA(string repo, string hash)
+ {
+ WorkingDirectory = repo;
+ Args = $"cat-file -t {hash}";
+ }
+
+ public bool Result()
+ {
+ var rs = ReadToEnd();
+ return rs.IsSuccess && rs.StdOut.Trim().Equals("commit");
+ }
+ }
+}
diff --git a/src/Commands/LFS.cs b/src/Commands/LFS.cs
index c9ab7b41..f7e56486 100644
--- a/src/Commands/LFS.cs
+++ b/src/Commands/LFS.cs
@@ -7,7 +7,7 @@ namespace SourceGit.Commands
{
public partial class LFS
{
- [GeneratedRegex(@"^(.+)\s+(\w+)\s+\w+:(\d+)$")]
+ [GeneratedRegex(@"^(.+)\s+([\w.]+)\s+\w+:(\d+)$")]
private static partial Regex REG_LOCK();
class SubCmd : Command
@@ -82,7 +82,7 @@ namespace SourceGit.Commands
var rs = cmd.ReadToEnd();
if (rs.IsSuccess)
{
- var lines = rs.StdOut.Split(new[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
+ var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
foreach (var line in lines)
{
var match = REG_LOCK().Match(line);
diff --git a/src/Commands/MergeTool.cs b/src/Commands/MergeTool.cs
index d3478d59..f67f5e48 100644
--- a/src/Commands/MergeTool.cs
+++ b/src/Commands/MergeTool.cs
@@ -13,9 +13,12 @@ namespace SourceGit.Commands
cmd.Context = repo;
cmd.RaiseError = true;
+ // NOTE: If no names are specified, 'git mergetool' will run the merge tool program on every file with merge conflicts.
+ var fileArg = string.IsNullOrEmpty(file) ? "" : $"\"{file}\"";
+
if (toolType == 0)
{
- cmd.Args = $"mergetool \"{file}\"";
+ cmd.Args = $"mergetool {fileArg}";
return cmd.Exec();
}
@@ -32,7 +35,7 @@ namespace SourceGit.Commands
return false;
}
- cmd.Args = $"-c mergetool.sourcegit.cmd=\"\\\"{toolPath}\\\" {supported.Cmd}\" -c mergetool.writeToTemp=true -c mergetool.keepBackup=false -c mergetool.trustExitCode=true mergetool --tool=sourcegit \"{file}\"";
+ cmd.Args = $"-c mergetool.sourcegit.cmd=\"\\\"{toolPath}\\\" {supported.Cmd}\" -c mergetool.writeToTemp=true -c mergetool.keepBackup=false -c mergetool.trustExitCode=true mergetool --tool=sourcegit {fileArg}";
return cmd.Exec();
}
diff --git a/src/Commands/Pull.cs b/src/Commands/Pull.cs
index 732530f5..35a6289a 100644
--- a/src/Commands/Pull.cs
+++ b/src/Commands/Pull.cs
@@ -4,21 +4,20 @@ namespace SourceGit.Commands
{
public class Pull : Command
{
- public Pull(string repo, string remote, string branch, bool useRebase, bool noTags, bool prune, Action outputHandler)
+ public Pull(string repo, string remote, string branch, bool useRebase, bool noTags, Action outputHandler)
{
_outputHandler = outputHandler;
WorkingDirectory = repo;
Context = repo;
TraitErrorAsOutput = true;
SSHKey = new Config(repo).Get($"remote.{remote}.sshkey");
- Args = "pull --verbose --progress --tags ";
+ Args = "pull --verbose --progress ";
if (useRebase)
- Args += "--rebase ";
+ Args += "--rebase=true ";
+
if (noTags)
Args += "--no-tags ";
- if (prune)
- Args += "--prune ";
Args += $"{remote} {branch}";
}
diff --git a/src/Commands/Push.cs b/src/Commands/Push.cs
index 69b859ab..dc81f606 100644
--- a/src/Commands/Push.cs
+++ b/src/Commands/Push.cs
@@ -26,7 +26,7 @@ namespace SourceGit.Commands
Args += $"{remote} {local}:{remoteBranch}";
}
- public Push(string repo, string remote, string tag, bool isDelete)
+ public Push(string repo, string remote, string refname, bool isDelete)
{
WorkingDirectory = repo;
Context = repo;
@@ -36,7 +36,7 @@ namespace SourceGit.Commands
if (isDelete)
Args += "--delete ";
- Args += $"{remote} refs/tags/{tag}";
+ Args += $"{remote} {refname}";
}
protected override void OnReadline(string line)
diff --git a/src/Commands/QueryBranches.cs b/src/Commands/QueryBranches.cs
index 95f97214..8dbc4055 100644
--- a/src/Commands/QueryBranches.cs
+++ b/src/Commands/QueryBranches.cs
@@ -24,12 +24,23 @@ namespace SourceGit.Commands
if (!rs.IsSuccess)
return branches;
- var lines = rs.StdOut.Split('\n', StringSplitOptions.RemoveEmptyEntries);
+ var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
+ var remoteBranches = new HashSet();
foreach (var line in lines)
{
var b = ParseLine(line);
if (b != null)
+ {
branches.Add(b);
+ if (!b.IsLocal)
+ remoteBranches.Add(b.FullName);
+ }
+ }
+
+ foreach (var b in branches)
+ {
+ if (b.IsLocal && !string.IsNullOrEmpty(b.Upstream))
+ b.IsUpsteamGone = !remoteBranches.Contains(b.Upstream);
}
return branches;
@@ -75,6 +86,7 @@ namespace SourceGit.Commands
branch.Head = parts[1];
branch.IsCurrent = parts[2] == "*";
branch.Upstream = parts[3];
+ branch.IsUpsteamGone = false;
if (branch.IsLocal && !string.IsNullOrEmpty(parts[4]) && !parts[4].Equals("=", StringComparison.Ordinal))
branch.TrackStatus = new QueryTrackStatus(WorkingDirectory, branch.Name, branch.Upstream).Result();
diff --git a/src/Commands/QueryCommitChildren.cs b/src/Commands/QueryCommitChildren.cs
index bef09abb..31fb34f8 100644
--- a/src/Commands/QueryCommitChildren.cs
+++ b/src/Commands/QueryCommitChildren.cs
@@ -9,10 +9,10 @@ namespace SourceGit.Commands
WorkingDirectory = repo;
Context = repo;
_commit = commit;
- Args = $"rev-list -{max} --parents --branches --remotes ^{commit}";
+ Args = $"rev-list -{max} --parents --branches --remotes --ancestry-path ^{commit}";
}
- public IEnumerable Result()
+ public List Result()
{
Exec();
return _lines;
diff --git a/src/Commands/QueryCommitFullMessage.cs b/src/Commands/QueryCommitFullMessage.cs
index c8f1867d..36b6d1c7 100644
--- a/src/Commands/QueryCommitFullMessage.cs
+++ b/src/Commands/QueryCommitFullMessage.cs
@@ -6,7 +6,7 @@ namespace SourceGit.Commands
{
WorkingDirectory = repo;
Context = repo;
- Args = $"show --no-show-signature --pretty=format:%B -s {sha}";
+ Args = $"show --no-show-signature --format=%B -s {sha}";
}
public string Result()
diff --git a/src/Commands/QueryCommitSignInfo.cs b/src/Commands/QueryCommitSignInfo.cs
index 5c81cf57..133949af 100644
--- a/src/Commands/QueryCommitSignInfo.cs
+++ b/src/Commands/QueryCommitSignInfo.cs
@@ -7,7 +7,7 @@
WorkingDirectory = repo;
Context = repo;
- const string baseArgs = "show --no-show-signature --pretty=format:\"%G?%n%GS%n%GK\" -s";
+ const string baseArgs = "show --no-show-signature --format=%G?%n%GS%n%GK -s";
const string fakeSignersFileArg = "-c gpg.ssh.allowedSignersFile=/dev/null";
Args = $"{(useFakeSignersFile ? fakeSignersFileArg : string.Empty)} {baseArgs} {sha}";
}
@@ -18,7 +18,7 @@
if (!rs.IsSuccess)
return null;
- var raw = rs.StdOut.Trim();
+ var raw = rs.StdOut.Trim().ReplaceLineEndings("\n");
if (raw.Length <= 1)
return null;
@@ -29,7 +29,6 @@
Signer = lines[1],
Key = lines[2]
};
-
}
}
}
diff --git a/src/Commands/QueryCommits.cs b/src/Commands/QueryCommits.cs
index 6318f331..dd3c39b4 100644
--- a/src/Commands/QueryCommits.cs
+++ b/src/Commands/QueryCommits.cs
@@ -10,7 +10,7 @@ namespace SourceGit.Commands
{
WorkingDirectory = repo;
Context = repo;
- Args = $"log --no-show-signature --decorate=full --pretty=format:%H%n%P%n%D%n%aN±%aE%n%at%n%cN±%cE%n%ct%n%s {limits}";
+ Args = $"log --no-show-signature --decorate=full --format=%H%n%P%n%D%n%aN±%aE%n%at%n%cN±%cE%n%ct%n%s {limits}";
_findFirstMerged = needFindHead;
}
@@ -18,9 +18,13 @@ namespace SourceGit.Commands
{
string search = onlyCurrentBranch ? string.Empty : "--branches --remotes ";
- if (method == Models.CommitSearchMethod.ByUser)
+ if (method == Models.CommitSearchMethod.ByAuthor)
{
- search += $"-i --author=\"{filter}\" --committer=\"{filter}\"";
+ search += $"-i --author=\"{filter}\"";
+ }
+ else if (method == Models.CommitSearchMethod.ByCommitter)
+ {
+ search += $"-i --committer=\"{filter}\"";
}
else if (method == Models.CommitSearchMethod.ByFile)
{
@@ -31,7 +35,7 @@ namespace SourceGit.Commands
var argsBuilder = new StringBuilder();
argsBuilder.Append(search);
- var words = filter.Split(new[] { ' ', '\t', '\r' }, StringSplitOptions.RemoveEmptyEntries);
+ var words = filter.Split([' ', '\t', '\r'], StringSplitOptions.RemoveEmptyEntries);
foreach (var word in words)
{
var escaped = word.Trim().Replace("\"", "\\\"", StringComparison.Ordinal);
@@ -44,7 +48,7 @@ namespace SourceGit.Commands
WorkingDirectory = repo;
Context = repo;
- Args = $"log -1000 --date-order --no-show-signature --decorate=full --pretty=format:%H%n%P%n%D%n%aN±%aE%n%at%n%cN±%cE%n%ct%n%s " + search;
+ Args = $"log -1000 --date-order --no-show-signature --decorate=full --format=%H%n%P%n%D%n%aN±%aE%n%at%n%cN±%cE%n%ct%n%s " + search;
_findFirstMerged = false;
}
@@ -120,7 +124,7 @@ namespace SourceGit.Commands
Args = $"log --since=\"{_commits[^1].CommitterTimeStr}\" --format=\"%H\"";
var rs = ReadToEnd();
- var shas = rs.StdOut.Split('\n', StringSplitOptions.RemoveEmptyEntries);
+ var shas = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
if (shas.Length == 0)
return;
diff --git a/src/Commands/QueryCommitsWithFullMessage.cs b/src/Commands/QueryCommitsForInteractiveRebase.cs
similarity index 84%
rename from src/Commands/QueryCommitsWithFullMessage.cs
rename to src/Commands/QueryCommitsForInteractiveRebase.cs
index c15cdbe1..615060a5 100644
--- a/src/Commands/QueryCommitsWithFullMessage.cs
+++ b/src/Commands/QueryCommitsForInteractiveRebase.cs
@@ -3,18 +3,18 @@ using System.Collections.Generic;
namespace SourceGit.Commands
{
- public class QueryCommitsWithFullMessage : Command
+ public class QueryCommitsForInteractiveRebase : Command
{
- public QueryCommitsWithFullMessage(string repo, string args)
+ public QueryCommitsForInteractiveRebase(string repo, string on)
{
_boundary = $"----- BOUNDARY OF COMMIT {Guid.NewGuid()} -----";
WorkingDirectory = repo;
Context = repo;
- Args = $"log --date-order --no-show-signature --decorate=full --pretty=format:\"%H%n%P%n%D%n%aN±%aE%n%at%n%cN±%cE%n%ct%n%B%n{_boundary}\" {args}";
+ Args = $"log --date-order --no-show-signature --decorate=full --format=\"%H%n%P%n%D%n%aN±%aE%n%at%n%cN±%cE%n%ct%n%B%n{_boundary}\" {on}..HEAD";
}
- public List Result()
+ public List Result()
{
var rs = ReadToEnd();
if (!rs.IsSuccess)
@@ -29,7 +29,7 @@ namespace SourceGit.Commands
switch (nextPartIdx)
{
case 0:
- _current = new Models.CommitWithMessage();
+ _current = new Models.InteractiveCommit();
_current.Commit.SHA = line;
_commits.Add(_current);
break;
@@ -52,7 +52,7 @@ namespace SourceGit.Commands
_current.Commit.CommitterTime = ulong.Parse(line);
break;
default:
- var boundary = rs.StdOut.IndexOf(_boundary, end + 1);
+ var boundary = rs.StdOut.IndexOf(_boundary, end + 1, StringComparison.Ordinal);
if (boundary > end)
{
_current.Message = rs.StdOut.Substring(start, boundary - start - 1);
@@ -88,8 +88,8 @@ namespace SourceGit.Commands
_current.Commit.Parents.AddRange(data.Split(separator: ' ', options: StringSplitOptions.RemoveEmptyEntries));
}
- private List _commits = new List();
- private Models.CommitWithMessage _current = null;
+ private List _commits = [];
+ private Models.InteractiveCommit _current = null;
private string _boundary = "";
}
}
diff --git a/src/Commands/QueryGitCommonDir.cs b/src/Commands/QueryGitCommonDir.cs
new file mode 100644
index 00000000..1076243e
--- /dev/null
+++ b/src/Commands/QueryGitCommonDir.cs
@@ -0,0 +1,26 @@
+using System.IO;
+
+namespace SourceGit.Commands
+{
+ public class QueryGitCommonDir : Command
+ {
+ public QueryGitCommonDir(string workDir)
+ {
+ WorkingDirectory = workDir;
+ Args = "rev-parse --git-common-dir";
+ RaiseError = false;
+ }
+
+ public string Result()
+ {
+ var rs = ReadToEnd().StdOut;
+ if (string.IsNullOrEmpty(rs))
+ return null;
+
+ rs = rs.Trim();
+ if (Path.IsPathRooted(rs))
+ return rs;
+ return Path.GetFullPath(Path.Combine(WorkingDirectory, rs));
+ }
+ }
+}
diff --git a/src/Commands/QueryLocalChanges.cs b/src/Commands/QueryLocalChanges.cs
index ea422215..9458e5f5 100644
--- a/src/Commands/QueryLocalChanges.cs
+++ b/src/Commands/QueryLocalChanges.cs
@@ -13,7 +13,7 @@ namespace SourceGit.Commands
{
WorkingDirectory = repo;
Context = repo;
- Args = $"status -u{UNTRACKED[includeUntracked ? 1 : 0]} --ignore-submodules=dirty --porcelain";
+ Args = $"--no-optional-locks status -u{UNTRACKED[includeUntracked ? 1 : 0]} --ignore-submodules=dirty --porcelain";
}
public List Result()
diff --git a/src/Commands/QueryRefsContainsCommit.cs b/src/Commands/QueryRefsContainsCommit.cs
index 82e9b341..cabe1b50 100644
--- a/src/Commands/QueryRefsContainsCommit.cs
+++ b/src/Commands/QueryRefsContainsCommit.cs
@@ -20,7 +20,7 @@ namespace SourceGit.Commands
if (!output.IsSuccess)
return rs;
- var lines = output.StdOut.Split('\n');
+ var lines = output.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
foreach (var line in lines)
{
if (line.EndsWith("/HEAD", StringComparison.Ordinal))
diff --git a/src/Commands/QueryRevisionByRefName.cs b/src/Commands/QueryRevisionByRefName.cs
new file mode 100644
index 00000000..7fb4ecfa
--- /dev/null
+++ b/src/Commands/QueryRevisionByRefName.cs
@@ -0,0 +1,21 @@
+namespace SourceGit.Commands
+{
+ public class QueryRevisionByRefName : Command
+ {
+ public QueryRevisionByRefName(string repo, string refname)
+ {
+ WorkingDirectory = repo;
+ Context = repo;
+ Args = $"rev-parse {refname}";
+ }
+
+ public string Result()
+ {
+ var rs = ReadToEnd();
+ if (rs.IsSuccess && !string.IsNullOrEmpty(rs.StdOut))
+ return rs.StdOut.Trim();
+
+ return null;
+ }
+ }
+}
diff --git a/src/Commands/QueryRevisionFileNames.cs b/src/Commands/QueryRevisionFileNames.cs
index d2d69614..c6fd7373 100644
--- a/src/Commands/QueryRevisionFileNames.cs
+++ b/src/Commands/QueryRevisionFileNames.cs
@@ -1,4 +1,6 @@
-namespace SourceGit.Commands
+using System.Collections.Generic;
+
+namespace SourceGit.Commands
{
public class QueryRevisionFileNames : Command
{
@@ -9,13 +11,17 @@
Args = $"ls-tree -r -z --name-only {revision}";
}
- public string[] Result()
+ public List Result()
{
var rs = ReadToEnd();
- if (rs.IsSuccess)
- return rs.StdOut.Split('\0', System.StringSplitOptions.RemoveEmptyEntries);
+ if (!rs.IsSuccess)
+ return [];
- return [];
+ var lines = rs.StdOut.Split('\0', System.StringSplitOptions.RemoveEmptyEntries);
+ var outs = new List();
+ foreach (var line in lines)
+ outs.Add(line);
+ return outs;
}
}
}
diff --git a/src/Commands/QuerySingleCommit.cs b/src/Commands/QuerySingleCommit.cs
index 1e1c9ea4..35289ec5 100644
--- a/src/Commands/QuerySingleCommit.cs
+++ b/src/Commands/QuerySingleCommit.cs
@@ -8,7 +8,7 @@ namespace SourceGit.Commands
{
WorkingDirectory = repo;
Context = repo;
- Args = $"show --no-show-signature --decorate=full --pretty=format:%H%n%P%n%D%n%aN±%aE%n%at%n%cN±%cE%n%ct%n%s -s {sha}";
+ Args = $"show --no-show-signature --decorate=full --format=%H%n%P%n%D%n%aN±%aE%n%at%n%cN±%cE%n%ct%n%s -s {sha}";
}
public Models.Commit Result()
diff --git a/src/Commands/QueryStagedChangesWithAmend.cs b/src/Commands/QueryStagedChangesWithAmend.cs
index f5c9659f..cfea5e35 100644
--- a/src/Commands/QueryStagedChangesWithAmend.cs
+++ b/src/Commands/QueryStagedChangesWithAmend.cs
@@ -24,7 +24,7 @@ namespace SourceGit.Commands
if (rs.IsSuccess)
{
var changes = new List();
- var lines = rs.StdOut.Split('\n', StringSplitOptions.RemoveEmptyEntries);
+ var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
foreach (var line in lines)
{
var match = REG_FORMAT2().Match(line);
diff --git a/src/Commands/QueryStashChanges.cs b/src/Commands/QueryStashChanges.cs
index 3b8d2db6..1f6c5b4f 100644
--- a/src/Commands/QueryStashChanges.cs
+++ b/src/Commands/QueryStashChanges.cs
@@ -1,60 +1,76 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
using System.Text.RegularExpressions;
namespace SourceGit.Commands
{
+ ///
+ /// Query stash changes. Requires git >= 2.32.0
+ ///
public partial class QueryStashChanges : Command
{
- [GeneratedRegex(@"^(\s?[\w\?]{1,4})\s+(.+)$")]
+ [GeneratedRegex(@"^([MADC])\s+(.+)$")]
private static partial Regex REG_FORMAT();
+ [GeneratedRegex(@"^R[0-9]{0,4}\s+(.+)$")]
+ private static partial Regex REG_RENAME_FORMAT();
- public QueryStashChanges(string repo, string sha)
+ public QueryStashChanges(string repo, string stash)
{
WorkingDirectory = repo;
Context = repo;
- Args = $"diff --name-status --pretty=format: {sha}^ {sha}";
+ Args = $"stash show -u --name-status \"{stash}\"";
}
public List Result()
{
- Exec();
- return _changes;
- }
+ var rs = ReadToEnd();
+ if (!rs.IsSuccess)
+ return [];
- protected override void OnReadline(string line)
- {
- var match = REG_FORMAT().Match(line);
- if (!match.Success)
- return;
-
- var change = new Models.Change() { Path = match.Groups[2].Value };
- var status = match.Groups[1].Value;
-
- switch (status[0])
+ var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
+ var outs = new List();
+ foreach (var line in lines)
{
- case 'M':
- change.Set(Models.ChangeState.Modified);
- _changes.Add(change);
- break;
- case 'A':
- change.Set(Models.ChangeState.Added);
- _changes.Add(change);
- break;
- case 'D':
- change.Set(Models.ChangeState.Deleted);
- _changes.Add(change);
- break;
- case 'R':
- change.Set(Models.ChangeState.Renamed);
- _changes.Add(change);
- break;
- case 'C':
- change.Set(Models.ChangeState.Copied);
- _changes.Add(change);
- break;
- }
- }
+ var match = REG_FORMAT().Match(line);
+ if (!match.Success)
+ {
+ match = REG_RENAME_FORMAT().Match(line);
+ if (match.Success)
+ {
+ var renamed = new Models.Change() { Path = match.Groups[1].Value };
+ renamed.Set(Models.ChangeState.Renamed);
+ outs.Add(renamed);
+ }
- private readonly List _changes = new List();
+ continue;
+ }
+
+ var change = new Models.Change() { Path = match.Groups[2].Value };
+ var status = match.Groups[1].Value;
+
+ switch (status[0])
+ {
+ case 'M':
+ change.Set(Models.ChangeState.Modified);
+ outs.Add(change);
+ break;
+ case 'A':
+ change.Set(Models.ChangeState.Added);
+ outs.Add(change);
+ break;
+ case 'D':
+ change.Set(Models.ChangeState.Deleted);
+ outs.Add(change);
+ break;
+ case 'C':
+ change.Set(Models.ChangeState.Copied);
+ outs.Add(change);
+ break;
+ }
+ }
+
+ outs.Sort((l, r) => string.Compare(l.Path, r.Path, StringComparison.Ordinal));
+ return outs;
+ }
}
}
diff --git a/src/Commands/QueryStashes.cs b/src/Commands/QueryStashes.cs
index 6d089f8e..dd5d10cc 100644
--- a/src/Commands/QueryStashes.cs
+++ b/src/Commands/QueryStashes.cs
@@ -1,4 +1,5 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
namespace SourceGit.Commands
{
@@ -8,7 +9,7 @@ namespace SourceGit.Commands
{
WorkingDirectory = repo;
Context = repo;
- Args = "stash list --pretty=format:%H%n%ct%n%gd%n%s";
+ Args = "stash list --format=%H%n%P%n%ct%n%gd%n%s";
}
public List Result()
@@ -26,21 +27,32 @@ namespace SourceGit.Commands
_stashes.Add(_current);
break;
case 1:
- _current.Time = ulong.Parse(line);
+ ParseParent(line);
break;
case 2:
- _current.Name = line;
+ _current.Time = ulong.Parse(line);
break;
case 3:
+ _current.Name = line;
+ break;
+ case 4:
_current.Message = line;
break;
}
_nextLineIdx++;
- if (_nextLineIdx > 3)
+ if (_nextLineIdx > 4)
_nextLineIdx = 0;
}
+ private void ParseParent(string data)
+ {
+ if (data.Length < 8)
+ return;
+
+ _current.Parents.AddRange(data.Split(separator: ' ', options: StringSplitOptions.RemoveEmptyEntries));
+ }
+
private readonly List _stashes = new List();
private Models.Stash _current = null;
private int _nextLineIdx = 0;
diff --git a/src/Commands/QuerySubmodules.cs b/src/Commands/QuerySubmodules.cs
index 5fd6e3d5..6016b0be 100644
--- a/src/Commands/QuerySubmodules.cs
+++ b/src/Commands/QuerySubmodules.cs
@@ -24,11 +24,9 @@ namespace SourceGit.Commands
{
var submodules = new List();
var rs = ReadToEnd();
- if (!rs.IsSuccess)
- return submodules;
var builder = new StringBuilder();
- var lines = rs.StdOut.Split('\n', System.StringSplitOptions.RemoveEmptyEntries);
+ var lines = rs.StdOut.Split(['\r', '\n'], System.StringSplitOptions.RemoveEmptyEntries);
foreach (var line in lines)
{
var match = REG_FORMAT1().Match(line);
@@ -51,13 +49,13 @@ namespace SourceGit.Commands
if (submodules.Count > 0)
{
- Args = $"status -uno --porcelain -- {builder}";
+ Args = $"--no-optional-locks status -uno --porcelain -- {builder}";
rs = ReadToEnd();
if (!rs.IsSuccess)
return submodules;
var dirty = new HashSet();
- lines = rs.StdOut.Split('\n', System.StringSplitOptions.RemoveEmptyEntries);
+ lines = rs.StdOut.Split(['\r', '\n'], System.StringSplitOptions.RemoveEmptyEntries);
foreach (var line in lines)
{
var match = REG_FORMAT_STATUS().Match(line);
diff --git a/src/Commands/QueryTrackStatus.cs b/src/Commands/QueryTrackStatus.cs
index 0bf9746f..e7e1f1c9 100644
--- a/src/Commands/QueryTrackStatus.cs
+++ b/src/Commands/QueryTrackStatus.cs
@@ -19,7 +19,7 @@ namespace SourceGit.Commands
if (!rs.IsSuccess)
return status;
- var lines = rs.StdOut.Split(new char[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
+ var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
foreach (var line in lines)
{
if (line[0] == '>')
diff --git a/src/Commands/SaveChangesAsPatch.cs b/src/Commands/SaveChangesAsPatch.cs
index 461bbfb5..b10037a1 100644
--- a/src/Commands/SaveChangesAsPatch.cs
+++ b/src/Commands/SaveChangesAsPatch.cs
@@ -37,6 +37,19 @@ namespace SourceGit.Commands
return true;
}
+ public static bool ProcessStashChanges(string repo, List opts, string saveTo)
+ {
+ using (var sw = File.Create(saveTo))
+ {
+ foreach (var opt in opts)
+ {
+ if (!ProcessSingleChange(repo, opt, sw))
+ return false;
+ }
+ }
+ return true;
+ }
+
private static bool ProcessSingleChange(string repo, Models.DiffOption opt, FileStream writer)
{
var starter = new ProcessStartInfo();
diff --git a/src/Commands/Stash.cs b/src/Commands/Stash.cs
index 40c917dd..7d1a269b 100644
--- a/src/Commands/Stash.cs
+++ b/src/Commands/Stash.cs
@@ -11,16 +11,26 @@ namespace SourceGit.Commands
Context = repo;
}
- public bool Push(string message)
+ public bool Push(string message, bool includeUntracked = true, bool keepIndex = false)
{
- Args = $"stash push -m \"{message}\"";
+ var builder = new StringBuilder();
+ builder.Append("stash push ");
+ if (includeUntracked)
+ builder.Append("--include-untracked ");
+ if (keepIndex)
+ builder.Append("--keep-index ");
+ builder.Append("-m \"");
+ builder.Append(message);
+ builder.Append("\"");
+
+ Args = builder.ToString();
return Exec();
}
public bool Push(string message, List changes, bool keepIndex)
{
var builder = new StringBuilder();
- builder.Append("stash push ");
+ builder.Append("stash push --include-untracked ");
if (keepIndex)
builder.Append("--keep-index ");
builder.Append("-m \"");
@@ -37,7 +47,7 @@ namespace SourceGit.Commands
public bool Push(string message, string pathspecFromFile, bool keepIndex)
{
var builder = new StringBuilder();
- builder.Append("stash push --pathspec-from-file=\"");
+ builder.Append("stash push --include-untracked --pathspec-from-file=\"");
builder.Append(pathspecFromFile);
builder.Append("\" ");
if (keepIndex)
@@ -63,21 +73,22 @@ namespace SourceGit.Commands
return Exec();
}
- public bool Apply(string name)
+ public bool Apply(string name, bool restoreIndex)
{
- Args = $"stash apply -q {name}";
+ var opts = restoreIndex ? "--index" : string.Empty;
+ Args = $"stash apply -q {opts} \"{name}\"";
return Exec();
}
public bool Pop(string name)
{
- Args = $"stash pop -q {name}";
+ Args = $"stash pop -q --index \"{name}\"";
return Exec();
}
public bool Drop(string name)
{
- Args = $"stash drop -q {name}";
+ Args = $"stash drop -q \"{name}\"";
return Exec();
}
diff --git a/src/Commands/Statistics.cs b/src/Commands/Statistics.cs
index 511c43e8..41b3889e 100644
--- a/src/Commands/Statistics.cs
+++ b/src/Commands/Statistics.cs
@@ -8,7 +8,7 @@ namespace SourceGit.Commands
{
WorkingDirectory = repo;
Context = repo;
- Args = $"log --date-order --branches --remotes -{max} --pretty=format:\"%ct$%aN\"";
+ Args = $"log --date-order --branches --remotes -{max} --format=%ct$%aN±%aE";
}
public Models.Statistics Result()
diff --git a/src/Commands/Tag.cs b/src/Commands/Tag.cs
index fa11e366..23dbb11c 100644
--- a/src/Commands/Tag.cs
+++ b/src/Commands/Tag.cs
@@ -48,9 +48,7 @@ namespace SourceGit.Commands
if (remotes != null)
{
foreach (var r in remotes)
- {
- new Push(repo, r.Name, name, true).Exec();
- }
+ new Push(repo, r.Name, $"refs/tags/{name}", true).Exec();
}
return true;
diff --git a/src/Commands/Worktree.cs b/src/Commands/Worktree.cs
index 7516b1e3..960d5501 100644
--- a/src/Commands/Worktree.cs
+++ b/src/Commands/Worktree.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.IO;
namespace SourceGit.Commands
{
@@ -20,12 +21,13 @@ namespace SourceGit.Commands
var last = null as Models.Worktree;
if (rs.IsSuccess)
{
- var lines = rs.StdOut.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
+ var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
foreach (var line in lines)
{
if (line.StartsWith("worktree ", StringComparison.Ordinal))
{
last = new Models.Worktree() { FullPath = line.Substring(9).Trim() };
+ last.RelativePath = Path.GetRelativePath(WorkingDirectory, last.FullPath);
worktrees.Add(last);
}
else if (line.StartsWith("bare", StringComparison.Ordinal))
@@ -73,6 +75,8 @@ namespace SourceGit.Commands
if (!string.IsNullOrEmpty(tracking))
Args += tracking;
+ else if (!string.IsNullOrEmpty(name) && !createNew)
+ Args += name;
_outputHandler = outputHandler;
return Exec();
diff --git a/src/Converters/BoolConverters.cs b/src/Converters/BoolConverters.cs
index 2d738700..3563fb37 100644
--- a/src/Converters/BoolConverters.cs
+++ b/src/Converters/BoolConverters.cs
@@ -1,4 +1,5 @@
using Avalonia.Data.Converters;
+using Avalonia.Media;
namespace SourceGit.Converters
{
@@ -6,5 +7,8 @@ namespace SourceGit.Converters
{
public static readonly FuncValueConverter ToPageTabWidth =
new FuncValueConverter(x => x ? 200 : double.NaN);
+
+ public static readonly FuncValueConverter IsBoldToFontWeight =
+ new FuncValueConverter(x => x ? FontWeight.Bold : FontWeight.Normal);
}
}
diff --git a/src/Converters/IntConverters.cs b/src/Converters/IntConverters.cs
index 17a88da2..f21c5d24 100644
--- a/src/Converters/IntConverters.cs
+++ b/src/Converters/IntConverters.cs
@@ -23,10 +23,10 @@ namespace SourceGit.Converters
new FuncValueConverter(v => v != 1);
public static readonly FuncValueConverter IsSubjectLengthBad =
- new FuncValueConverter(v => v > ViewModels.Preference.Instance.SubjectGuideLength);
+ new FuncValueConverter(v => v > ViewModels.Preferences.Instance.SubjectGuideLength);
public static readonly FuncValueConverter IsSubjectLengthGood =
- new FuncValueConverter(v => v <= ViewModels.Preference.Instance.SubjectGuideLength);
+ new FuncValueConverter(v => v <= ViewModels.Preferences.Instance.SubjectGuideLength);
public static readonly FuncValueConverter ToTreeMargin =
new FuncValueConverter(v => new Thickness(v * 16, 0, 0, 0));
diff --git a/src/Converters/StringConverters.cs b/src/Converters/StringConverters.cs
index e6f4237c..bcadfae9 100644
--- a/src/Converters/StringConverters.cs
+++ b/src/Converters/StringConverters.cs
@@ -78,5 +78,11 @@ namespace SourceGit.Converters
return v.Substring(13);
return v;
});
+
+ public static readonly FuncValueConverter ContainsSpaces =
+ new FuncValueConverter(v => v != null && v.Contains(' '));
+
+ public static readonly FuncValueConverter IsNotNullOrWhitespace =
+ new FuncValueConverter(v => v != null && v.Trim().Length > 0);
}
}
diff --git a/src/Models/ApplyWhiteSpaceMode.cs b/src/Models/ApplyWhiteSpaceMode.cs
index 6fbce0b2..aad45f57 100644
--- a/src/Models/ApplyWhiteSpaceMode.cs
+++ b/src/Models/ApplyWhiteSpaceMode.cs
@@ -2,14 +2,22 @@
{
public class ApplyWhiteSpaceMode
{
+ public static readonly ApplyWhiteSpaceMode[] Supported =
+ [
+ new ApplyWhiteSpaceMode("No Warn", "Turns off the trailing whitespace warning", "nowarn"),
+ new ApplyWhiteSpaceMode("Warn", "Outputs warnings for a few such errors, but applies", "warn"),
+ new ApplyWhiteSpaceMode("Error", "Raise errors and refuses to apply the patch", "error"),
+ new ApplyWhiteSpaceMode("Error All", "Similar to 'error', but shows more", "error-all"),
+ ];
+
public string Name { get; set; }
public string Desc { get; set; }
public string Arg { get; set; }
public ApplyWhiteSpaceMode(string n, string d, string a)
{
- Name = App.Text(n);
- Desc = App.Text(d);
+ Name = n;
+ Desc = d;
Arg = a;
}
}
diff --git a/src/Models/AvatarManager.cs b/src/Models/AvatarManager.cs
index 9f0bceaf..a506d886 100644
--- a/src/Models/AvatarManager.cs
+++ b/src/Models/AvatarManager.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
@@ -196,8 +196,8 @@ namespace SourceGit.Models
private string GetEmailHash(string email)
{
var lowered = email.ToLower(CultureInfo.CurrentCulture).Trim();
- var hash = MD5.Create().ComputeHash(Encoding.Default.GetBytes(lowered));
- var builder = new StringBuilder();
+ var hash = MD5.HashData(Encoding.Default.GetBytes(lowered).AsSpan());
+ var builder = new StringBuilder(hash.Length * 2);
foreach (var c in hash)
builder.Append(c.ToString("x2"));
return builder.ToString();
diff --git a/src/Models/Branch.cs b/src/Models/Branch.cs
index 0ba320c1..2d0ae5b2 100644
--- a/src/Models/Branch.cs
+++ b/src/Models/Branch.cs
@@ -34,6 +34,7 @@ namespace SourceGit.Models
public string Upstream { get; set; }
public BranchTrackStatus TrackStatus { get; set; }
public string Remote { get; set; }
+ public bool IsUpsteamGone { get; set; }
public string FriendlyName => IsLocal ? Name : $"{Remote}/{Name}";
}
diff --git a/src/Models/Change.cs b/src/Models/Change.cs
index 36fe20ac..e9d07181 100644
--- a/src/Models/Change.cs
+++ b/src/Models/Change.cs
@@ -36,7 +36,7 @@ namespace SourceGit.Models
public string OriginalPath { get; set; } = "";
public ChangeDataForAmend DataForAmend { get; set; } = null;
- public bool IsConflit
+ public bool IsConflict
{
get
{
diff --git a/src/Models/Commit.cs b/src/Models/Commit.cs
index 5f401a14..edda603f 100644
--- a/src/Models/Commit.cs
+++ b/src/Models/Commit.cs
@@ -10,7 +10,9 @@ namespace SourceGit.Models
{
public enum CommitSearchMethod
{
- ByUser,
+ BySHA = 0,
+ ByAuthor,
+ ByCommitter,
ByMessage,
ByFile,
}
@@ -43,6 +45,7 @@ namespace SourceGit.Models
public string AuthorTimeStr => DateTime.UnixEpoch.AddSeconds(AuthorTime).ToLocalTime().ToString(DateTimeFormat.Actived.DateTime);
public string CommitterTimeStr => DateTime.UnixEpoch.AddSeconds(CommitterTime).ToLocalTime().ToString(DateTimeFormat.Actived.DateTime);
public string AuthorTimeShortStr => DateTime.UnixEpoch.AddSeconds(AuthorTime).ToLocalTime().ToString(DateTimeFormat.Actived.DateOnly);
+ public string CommitterTimeShortStr => DateTime.UnixEpoch.AddSeconds(CommitterTime).ToLocalTime().ToString(DateTimeFormat.Actived.DateOnly);
public bool IsMerged { get; set; } = false;
public bool IsCommitterVisible => !Author.Equals(Committer) || AuthorTime != CommitterTime;
@@ -149,9 +152,9 @@ namespace SourceGit.Models
}
}
- public class CommitWithMessage
+ public class CommitFullMessage
{
- public Commit Commit { get; set; } = new Commit();
- public string Message { get; set; } = "";
+ public string Message { get; set; } = string.Empty;
+ public List Links { get; set; } = [];
}
}
diff --git a/src/Models/CustomAction.cs b/src/Models/CustomAction.cs
index 8452a42d..a614961a 100644
--- a/src/Models/CustomAction.cs
+++ b/src/Models/CustomAction.cs
@@ -6,6 +6,7 @@ namespace SourceGit.Models
{
Repository,
Commit,
+ Branch,
}
public class CustomAction : ObservableObject
@@ -34,9 +35,16 @@ namespace SourceGit.Models
set => SetProperty(ref _arguments, value);
}
+ public bool WaitForExit
+ {
+ get => _waitForExit;
+ set => SetProperty(ref _waitForExit, value);
+ }
+
private string _name = string.Empty;
private CustomActionScope _scope = CustomActionScope.Repository;
private string _executable = string.Empty;
private string _arguments = string.Empty;
+ private bool _waitForExit = true;
}
}
diff --git a/src/Models/DateTimeFormat.cs b/src/Models/DateTimeFormat.cs
index 4e71a74f..4e8aa550 100644
--- a/src/Models/DateTimeFormat.cs
+++ b/src/Models/DateTimeFormat.cs
@@ -32,17 +32,17 @@ namespace SourceGit.Models
public static readonly List Supported = new List
{
- new DateTimeFormat("yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss"),
- new DateTimeFormat("yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss"),
- new DateTimeFormat("yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss"),
- new DateTimeFormat("MM/dd/yyyy", "MM/dd/yyyy HH:mm:ss"),
- new DateTimeFormat("MM.dd.yyyy", "MM.dd.yyyy HH:mm:ss"),
- new DateTimeFormat("MM-dd-yyyy", "MM-dd-yyyy HH:mm:ss"),
- new DateTimeFormat("dd/MM/yyyy", "dd/MM/yyyy HH:mm:ss"),
- new DateTimeFormat("dd.MM.yyyy", "dd.MM.yyyy HH:mm:ss"),
- new DateTimeFormat("dd-MM-yyyy", "dd-MM-yyyy HH:mm:ss"),
- new DateTimeFormat("MMM d yyyy", "MMM d yyyy HH:mm:ss"),
- new DateTimeFormat("d MMM yyyy", "d MMM yyyy HH:mm:ss"),
+ new DateTimeFormat("yyyy/MM/dd", "yyyy/MM/dd, HH:mm:ss"),
+ new DateTimeFormat("yyyy.MM.dd", "yyyy.MM.dd, HH:mm:ss"),
+ new DateTimeFormat("yyyy-MM-dd", "yyyy-MM-dd, HH:mm:ss"),
+ new DateTimeFormat("MM/dd/yyyy", "MM/dd/yyyy, HH:mm:ss"),
+ new DateTimeFormat("MM.dd.yyyy", "MM.dd.yyyy, HH:mm:ss"),
+ new DateTimeFormat("MM-dd-yyyy", "MM-dd-yyyy, HH:mm:ss"),
+ new DateTimeFormat("dd/MM/yyyy", "dd/MM/yyyy, HH:mm:ss"),
+ new DateTimeFormat("dd.MM.yyyy", "dd.MM.yyyy, HH:mm:ss"),
+ new DateTimeFormat("dd-MM-yyyy", "dd-MM-yyyy, HH:mm:ss"),
+ new DateTimeFormat("MMM d yyyy", "MMM d yyyy, HH:mm:ss"),
+ new DateTimeFormat("d MMM yyyy", "d MMM yyyy, HH:mm:ss"),
};
private static readonly DateTime _example = new DateTime(2025, 1, 31, 8, 0, 0, DateTimeKind.Local);
diff --git a/src/Models/DealWithLocalChanges.cs b/src/Models/DealWithLocalChanges.cs
deleted file mode 100644
index f308a90c..00000000
--- a/src/Models/DealWithLocalChanges.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-namespace SourceGit.Models
-{
- public enum DealWithLocalChanges
- {
- DoNothing,
- StashAndReaply,
- Discard,
- }
-}
diff --git a/src/Models/DiffResult.cs b/src/Models/DiffResult.cs
index e0ae82e0..88992e10 100644
--- a/src/Models/DiffResult.cs
+++ b/src/Models/DiffResult.cs
@@ -681,6 +681,18 @@ namespace SourceGit.Models
public TextDiff TextDiff { get; set; } = null;
public LFSDiff LFSDiff { get; set; } = null;
- public string FileModeChange => string.IsNullOrEmpty(OldMode) ? string.Empty : $"{OldMode} → {NewMode}";
+ public string FileModeChange
+ {
+ get
+ {
+ if (string.IsNullOrEmpty(OldMode) && string.IsNullOrEmpty(NewMode))
+ return string.Empty;
+
+ var oldDisplay = string.IsNullOrEmpty(OldMode) ? "0" : OldMode;
+ var newDisplay = string.IsNullOrEmpty(NewMode) ? "0" : NewMode;
+
+ return $"{oldDisplay} → {newDisplay}";
+ }
+ }
}
}
diff --git a/src/Models/ExternalMerger.cs b/src/Models/ExternalMerger.cs
index 49d31df5..d97d3933 100644
--- a/src/Models/ExternalMerger.cs
+++ b/src/Models/ExternalMerger.cs
@@ -42,6 +42,7 @@ namespace SourceGit.Models
new ExternalMerger(7, "win_merge", "WinMerge", "WinMergeU.exe", "\"$MERGED\"", "-u -e -sw \"$LOCAL\" \"$REMOTE\""),
new ExternalMerger(8, "codium", "VSCodium", "VSCodium.exe", "-n --wait \"$MERGED\"", "-n --wait --diff \"$LOCAL\" \"$REMOTE\""),
new ExternalMerger(9, "p4merge", "P4Merge", "p4merge.exe", "-tw 4 \"$BASE\" \"$LOCAL\" \"$REMOTE\" \"$MERGED\"", "-tw 4 \"$LOCAL\" \"$REMOTE\""),
+ new ExternalMerger(10, "plastic_merge", "Plastic SCM", "mergetool.exe", "-s=\"$REMOTE\" -b=\"$BASE\" -d=\"$LOCAL\" -r=\"$MERGED\" --automatic", "-s=\"$LOCAL\" -d=\"$REMOTE\""),
};
}
else if (OperatingSystem.IsMacOS())
diff --git a/src/Models/GitVersions.cs b/src/Models/GitVersions.cs
index 394a9518..92fd8c59 100644
--- a/src/Models/GitVersions.cs
+++ b/src/Models/GitVersions.cs
@@ -13,13 +13,18 @@
public static readonly System.Version ADD_WITH_PATHSPECFILE = new System.Version(2, 25, 0);
///
- /// The minimal version of Git that supports the `stash` command with the `--pathspec-from-file` option.
+ /// The minimal version of Git that supports the `stash push` command with the `--pathspec-from-file` option.
///
- public static readonly System.Version STASH_WITH_PATHSPECFILE = new System.Version(2, 26, 0);
+ public static readonly System.Version STASH_PUSH_WITH_PATHSPECFILE = new System.Version(2, 26, 0);
///
- /// The minimal version of Git that supports the `stash` command with the `--staged` option.
+ /// The minimal version of Git that supports the `stash push` command with the `--staged` option.
///
- public static readonly System.Version STASH_ONLY_STAGED = new System.Version(2, 35, 0);
+ public static readonly System.Version STASH_PUSH_ONLY_STAGED = new System.Version(2, 35, 0);
+
+ ///
+ /// The minimal version of Git that supports the `stash show` command with the `-u` option.
+ ///
+ public static readonly System.Version STASH_SHOW_WITH_UNTRACKED = new System.Version(2, 32, 0);
}
}
diff --git a/src/Models/IRepository.cs b/src/Models/IRepository.cs
index 12b1adba..0224d81f 100644
--- a/src/Models/IRepository.cs
+++ b/src/Models/IRepository.cs
@@ -2,9 +2,6 @@
{
public interface IRepository
{
- string FullPath { get; set; }
- string GitDir { get; set; }
-
void RefreshBranches();
void RefreshWorktrees();
void RefreshTags();
diff --git a/src/Models/InteractiveRebase.cs b/src/Models/InteractiveRebase.cs
index 0980587a..691aadeb 100644
--- a/src/Models/InteractiveRebase.cs
+++ b/src/Models/InteractiveRebase.cs
@@ -12,6 +12,12 @@ namespace SourceGit.Models
Drop,
}
+ public class InteractiveCommit
+ {
+ public Commit Commit { get; set; } = new Commit();
+ public string Message { get; set; } = string.Empty;
+ }
+
public class InteractiveRebaseJob
{
public string SHA { get; set; } = string.Empty;
diff --git a/src/Models/Locales.cs b/src/Models/Locales.cs
index d5e1534c..a7884e8b 100644
--- a/src/Models/Locales.cs
+++ b/src/Models/Locales.cs
@@ -17,6 +17,8 @@ namespace SourceGit.Models
new Locale("Русский", "ru_RU"),
new Locale("简体中文", "zh_CN"),
new Locale("繁體中文", "zh_TW"),
+ new Locale("日本語", "ja_JP"),
+ new Locale("தமிழ் (Tamil)", "ta_IN"),
};
public Locale(string name, string key)
diff --git a/src/Models/MergeMode.cs b/src/Models/MergeMode.cs
index 15e3f7e9..5dc70030 100644
--- a/src/Models/MergeMode.cs
+++ b/src/Models/MergeMode.cs
@@ -5,8 +5,9 @@
public static readonly MergeMode[] Supported =
[
new MergeMode("Default", "Fast-forward if possible", ""),
+ new MergeMode("Fast-forward", "Refuse to merge when fast-forward is not possible", "--ff-only"),
new MergeMode("No Fast-forward", "Always create a merge commit", "--no-ff"),
- new MergeMode("Squash", "Use '--squash'", "--squash"),
+ new MergeMode("Squash", "Squash merge", "--squash"),
new MergeMode("Don't commit", "Merge without commit", "--no-ff --no-commit"),
];
diff --git a/src/Models/OpenAI.cs b/src/Models/OpenAI.cs
index df67ff66..22fbcd51 100644
--- a/src/Models/OpenAI.cs
+++ b/src/Models/OpenAI.cs
@@ -1,79 +1,99 @@
using System;
+using System.ClientModel;
using System.Collections.Generic;
-using System.Net.Http;
using System.Text;
-using System.Text.Json;
-using System.Text.Json.Serialization;
+using System.Text.RegularExpressions;
using System.Threading;
-
+using Azure.AI.OpenAI;
using CommunityToolkit.Mvvm.ComponentModel;
+using OpenAI;
+using OpenAI.Chat;
namespace SourceGit.Models
{
- public class OpenAIChatMessage
+ public partial class OpenAIResponse
{
- [JsonPropertyName("role")]
- public string Role
+ public OpenAIResponse(Action onUpdate)
{
- get;
- set;
+ _onUpdate = onUpdate;
}
- [JsonPropertyName("content")]
- public string Content
+ public void Append(string text)
{
- get;
- set;
- }
- }
+ var buffer = text;
- public class OpenAIChatChoice
- {
- [JsonPropertyName("index")]
- public int Index
- {
- get;
- set;
+ if (_thinkTail.Length > 0)
+ {
+ _thinkTail.Append(buffer);
+ buffer = _thinkTail.ToString();
+ _thinkTail.Clear();
+ }
+
+ buffer = REG_COT().Replace(buffer, "");
+
+ var startIdx = buffer.IndexOf('<', StringComparison.Ordinal);
+ if (startIdx >= 0)
+ {
+ if (startIdx > 0)
+ OnReceive(buffer.Substring(0, startIdx));
+
+ var endIdx = buffer.IndexOf(">", startIdx + 1, StringComparison.Ordinal);
+ if (endIdx <= startIdx)
+ {
+ if (buffer.Length - startIdx <= 15)
+ _thinkTail.Append(buffer.Substring(startIdx));
+ else
+ OnReceive(buffer.Substring(startIdx));
+ }
+ else if (endIdx < startIdx + 15)
+ {
+ var tag = buffer.Substring(startIdx + 1, endIdx - startIdx - 1);
+ if (_thinkTags.Contains(tag))
+ _thinkTail.Append(buffer.Substring(startIdx));
+ else
+ OnReceive(buffer.Substring(startIdx));
+ }
+ else
+ {
+ OnReceive(buffer.Substring(startIdx));
+ }
+ }
+ else
+ {
+ OnReceive(buffer);
+ }
}
- [JsonPropertyName("message")]
- public OpenAIChatMessage Message
+ public void End()
{
- get;
- set;
- }
- }
-
- public class OpenAIChatResponse
- {
- [JsonPropertyName("choices")]
- public List Choices
- {
- get;
- set;
- } = [];
- }
-
- public class OpenAIChatRequest
- {
- [JsonPropertyName("model")]
- public string Model
- {
- get;
- set;
+ if (_thinkTail.Length > 0)
+ {
+ OnReceive(_thinkTail.ToString());
+ _thinkTail.Clear();
+ }
}
- [JsonPropertyName("messages")]
- public List Messages
+ private void OnReceive(string text)
{
- get;
- set;
- } = [];
+ if (!_hasTrimmedStart)
+ {
+ text = text.TrimStart();
+ if (string.IsNullOrEmpty(text))
+ return;
- public void AddMessage(string role, string content)
- {
- Messages.Add(new OpenAIChatMessage { Role = role, Content = content });
+ _hasTrimmedStart = true;
+ }
+
+ _onUpdate.Invoke(text);
}
+
+ [GeneratedRegex(@"<(think|thought|thinking|thought_chain)>.*?\1>", RegexOptions.Singleline)]
+ private static partial Regex REG_COT();
+
+ private Action _onUpdate = null;
+ private StringBuilder _thinkTail = new StringBuilder();
+ private HashSet _thinkTags = ["think", "thought", "thinking", "thought_chain"];
+ private bool _hasTrimmedStart = false;
}
public class OpenAIService : ObservableObject
@@ -102,6 +122,12 @@ namespace SourceGit.Models
set => SetProperty(ref _model, value);
}
+ public bool Streaming
+ {
+ get => _streaming;
+ set => SetProperty(ref _streaming, value);
+ }
+
public string AnalyzeDiffPrompt
{
get => _analyzeDiffPrompt;
@@ -147,45 +173,54 @@ namespace SourceGit.Models
""";
}
- public OpenAIChatResponse Chat(string prompt, string question, CancellationToken cancellation)
+ public void Chat(string prompt, string question, CancellationToken cancellation, Action onUpdate)
{
- var chat = new OpenAIChatRequest() { Model = Model };
- chat.AddMessage("user", prompt);
- chat.AddMessage("user", question);
-
- var client = new HttpClient() { Timeout = TimeSpan.FromSeconds(60) };
- if (!string.IsNullOrEmpty(ApiKey))
+ var server = new Uri(_server);
+ var key = new ApiKeyCredential(_apiKey);
+ var client = null as ChatClient;
+ if (_server.Contains("openai.azure.com/", StringComparison.Ordinal))
{
- if (Server.Contains("openai.azure.com/", StringComparison.Ordinal))
- client.DefaultRequestHeaders.Add("api-key", ApiKey);
- else
- client.DefaultRequestHeaders.Add("Authorization", $"Bearer {ApiKey}");
+ var azure = new AzureOpenAIClient(server, key);
+ client = azure.GetChatClient(_model);
+ }
+ else
+ {
+ var openai = new OpenAIClient(key, new() { Endpoint = server });
+ client = openai.GetChatClient(_model);
}
- var req = new StringContent(JsonSerializer.Serialize(chat, JsonCodeGen.Default.OpenAIChatRequest), Encoding.UTF8, "application/json");
+ var messages = new List();
+ messages.Add(_model.Equals("o1-mini", StringComparison.Ordinal) ? new UserChatMessage(prompt) : new SystemChatMessage(prompt));
+ messages.Add(new UserChatMessage(question));
+
try
{
- var task = client.PostAsync(Server, req, cancellation);
- task.Wait(cancellation);
+ var rsp = new OpenAIResponse(onUpdate);
- var rsp = task.Result;
- var reader = rsp.Content.ReadAsStringAsync(cancellation);
- reader.Wait(cancellation);
-
- var body = reader.Result;
- if (!rsp.IsSuccessStatusCode)
+ if (_streaming)
{
- throw new Exception($"AI service returns error code {rsp.StatusCode}. Body: {body ?? string.Empty}");
+ var updates = client.CompleteChatStreaming(messages, null, cancellation);
+
+ foreach (var update in updates)
+ {
+ if (update.ContentUpdate.Count > 0)
+ rsp.Append(update.ContentUpdate[0].Text);
+ }
+ }
+ else
+ {
+ var completion = client.CompleteChat(messages, null, cancellation);
+
+ if (completion.Value.Content.Count > 0)
+ rsp.Append(completion.Value.Content[0].Text);
}
- return JsonSerializer.Deserialize(reader.Result, JsonCodeGen.Default.OpenAIChatResponse);
+ rsp.End();
}
catch
{
- if (cancellation.IsCancellationRequested)
- return null;
-
- throw;
+ if (!cancellation.IsCancellationRequested)
+ throw;
}
}
@@ -193,6 +228,7 @@ namespace SourceGit.Models
private string _server;
private string _apiKey;
private string _model;
+ private bool _streaming = true;
private string _analyzeDiffPrompt;
private string _generateSubjectPrompt;
}
diff --git a/src/Models/Remote.cs b/src/Models/Remote.cs
index 3c452460..ec9b8f20 100644
--- a/src/Models/Remote.cs
+++ b/src/Models/Remote.cs
@@ -8,12 +8,12 @@ namespace SourceGit.Models
{
[GeneratedRegex(@"^https?://([-a-zA-Z0-9:%._\+~#=]+@)?[-a-zA-Z0-9:%._\+~#=]{1,256}(\.[a-zA-Z0-9()]{1,6})?(:[0-9]{1,5})?\b(/[-a-zA-Z0-9()@:%_\+.~#?&=]+)+(\.git)?$")]
private static partial Regex REG_HTTPS();
- [GeneratedRegex(@"^[\w\-]+@[\w\.\-]+(\:[0-9]+)?:[\w\-/~%]+/[\w\-\.%]+(\.git)?$")]
+ [GeneratedRegex(@"^[\w\-]+@[\w\.\-]+(\:[0-9]+)?:([a-zA-z0-9~%][\w\-\./~%]*)?[a-zA-Z0-9](\.git)?$")]
private static partial Regex REG_SSH1();
- [GeneratedRegex(@"^ssh://([\w\-]+@)?[\w\.\-]+(\:[0-9]+)?/[\w\-/~]+/[\w\-\.]+(\.git)?$")]
+ [GeneratedRegex(@"^ssh://([\w\-]+@)?[\w\.\-]+(\:[0-9]+)?/([a-zA-z0-9~%][\w\-\./~%]*)?[a-zA-Z0-9](\.git)?$")]
private static partial Regex REG_SSH2();
- [GeneratedRegex(@"^git@([\w\.\-]+):([\w\-/~]+/[\w\-\.]+)\.git$")]
+ [GeneratedRegex(@"^git@([\w\.\-]+):([\w\-/~%]+/[\w\-\.%]+)\.git$")]
private static partial Regex REG_TO_VISIT_URL_CAPTURE();
private static readonly Regex[] URL_FORMATS = [
diff --git a/src/Models/RepositorySettings.cs b/src/Models/RepositorySettings.cs
index 1d0b3c10..fc5e81b4 100644
--- a/src/Models/RepositorySettings.cs
+++ b/src/Models/RepositorySettings.cs
@@ -50,18 +50,6 @@ namespace SourceGit.Models
set;
} = true;
- public DealWithLocalChanges DealWithLocalChangesOnCheckoutBranch
- {
- get;
- set;
- } = DealWithLocalChanges.DoNothing;
-
- public bool EnablePruneOnFetch
- {
- get;
- set;
- } = false;
-
public bool EnableForceOnFetch
{
get;
@@ -74,12 +62,6 @@ namespace SourceGit.Models
set;
} = false;
- public DealWithLocalChanges DealWithLocalChangesOnPull
- {
- get;
- set;
- } = DealWithLocalChanges.DoNothing;
-
public bool PreferRebaseInsteadOfMerge
{
get;
@@ -110,11 +92,17 @@ namespace SourceGit.Models
set;
} = false;
- public DealWithLocalChanges DealWithLocalChangesOnCreateBranch
+ public bool PushToRemoteWhenCreateTag
{
get;
set;
- } = DealWithLocalChanges.DoNothing;
+ } = true;
+
+ public bool PushToRemoteWhenDeleteTag
+ {
+ get;
+ set;
+ } = false;
public bool CheckoutBranchOnCreateBranch
{
@@ -188,6 +176,12 @@ namespace SourceGit.Models
set;
} = false;
+ public bool AutoRestoreAfterStash
+ {
+ get;
+ set;
+ } = false;
+
public string PreferedOpenAIService
{
get;
@@ -230,6 +224,12 @@ namespace SourceGit.Models
set;
} = [];
+ public int PreferredMergeMode
+ {
+ get;
+ set;
+ } = 0;
+
public Dictionary CollectHistoriesFilters()
{
var map = new Dictionary();
@@ -309,128 +309,81 @@ namespace SourceGit.Models
public string BuildHistoriesFilter()
{
+ var includedRefs = new List();
var excludedBranches = new List();
var excludedRemotes = new List();
var excludedTags = new List();
- var includedBranches = new List();
- var includedRemotes = new List();
- var includedTags = new List();
foreach (var filter in HistoriesFilters)
{
if (filter.Type == FilterType.LocalBranch)
{
- var name = filter.Pattern.Substring(11);
- var b = $"{name.Substring(0, name.Length - 1)}[{name[^1]}]";
-
if (filter.Mode == FilterMode.Included)
- includedBranches.Add(b);
+ includedRefs.Add(filter.Pattern);
else if (filter.Mode == FilterMode.Excluded)
- excludedBranches.Add(b);
+ excludedBranches.Add($"--exclude=\"{filter.Pattern.Substring(11)}\" --decorate-refs-exclude=\"{filter.Pattern}\"");
}
else if (filter.Type == FilterType.LocalBranchFolder)
{
if (filter.Mode == FilterMode.Included)
- includedBranches.Add($"{filter.Pattern.Substring(11)}/*");
+ includedRefs.Add($"--branches={filter.Pattern.Substring(11)}/*");
else if (filter.Mode == FilterMode.Excluded)
- excludedBranches.Add($"{filter.Pattern.Substring(11)}/*");
+ excludedBranches.Add($"--exclude=\"{filter.Pattern.Substring(11)}/*\" --decorate-refs-exclude=\"{filter.Pattern}/*\"");
}
else if (filter.Type == FilterType.RemoteBranch)
{
- var name = filter.Pattern.Substring(13);
- var r = $"{name.Substring(0, name.Length - 1)}[{name[^1]}]";
-
if (filter.Mode == FilterMode.Included)
- includedRemotes.Add(r);
+ includedRefs.Add(filter.Pattern);
else if (filter.Mode == FilterMode.Excluded)
- excludedRemotes.Add(r);
+ excludedRemotes.Add($"--exclude=\"{filter.Pattern.Substring(13)}\" --decorate-refs-exclude=\"{filter.Pattern}\"");
}
else if (filter.Type == FilterType.RemoteBranchFolder)
{
if (filter.Mode == FilterMode.Included)
- includedRemotes.Add($"{filter.Pattern.Substring(13)}/*");
+ includedRefs.Add($"--remotes={filter.Pattern.Substring(13)}/*");
else if (filter.Mode == FilterMode.Excluded)
- excludedRemotes.Add($"{filter.Pattern.Substring(13)}/*");
+ excludedRemotes.Add($"--exclude=\"{filter.Pattern.Substring(13)}/*\" --decorate-refs-exclude=\"{filter.Pattern}/*\"");
}
else if (filter.Type == FilterType.Tag)
{
- var name = filter.Pattern;
- var t = $"{name.Substring(0, name.Length - 1)}[{name[^1]}]";
-
if (filter.Mode == FilterMode.Included)
- includedTags.Add(t);
+ includedRefs.Add($"refs/tags/{filter.Pattern}");
else if (filter.Mode == FilterMode.Excluded)
- excludedTags.Add(t);
+ excludedTags.Add($"--exclude=\"{filter.Pattern}\" --decorate-refs-exclude=\"refs/tags/{filter.Pattern}\"");
}
}
- bool hasIncluded = includedBranches.Count > 0 || includedRemotes.Count > 0 || includedTags.Count > 0;
- bool hasExcluded = excludedBranches.Count > 0 || excludedRemotes.Count > 0 || excludedTags.Count > 0;
-
var builder = new StringBuilder();
- if (hasIncluded)
+ if (includedRefs.Count > 0)
{
- foreach (var b in includedBranches)
+ foreach (var r in includedRefs)
+ {
+ builder.Append(r);
+ builder.Append(' ');
+ }
+ }
+ else if (excludedBranches.Count + excludedRemotes.Count + excludedTags.Count > 0)
+ {
+ foreach (var b in excludedBranches)
{
- builder.Append("--branches=");
builder.Append(b);
builder.Append(' ');
}
- foreach (var r in includedRemotes)
+ builder.Append("--exclude=HEAD --branches ");
+
+ foreach (var r in excludedRemotes)
{
- builder.Append("--remotes=");
builder.Append(r);
builder.Append(' ');
}
- foreach (var t in includedTags)
+ builder.Append("--exclude=origin/HEAD --remotes ");
+
+ foreach (var t in excludedTags)
{
- builder.Append("--tags=");
builder.Append(t);
builder.Append(' ');
}
- }
- else if (hasExcluded)
- {
- if (excludedBranches.Count > 0)
- {
- foreach (var b in excludedBranches)
- {
- builder.Append("--exclude=");
- builder.Append(b);
- builder.Append(" --decorate-refs-exclude=refs/heads/");
- builder.Append(b);
- builder.Append(' ');
- }
- }
-
- builder.Append("--exclude=HEA[D] --branches ");
-
- if (excludedRemotes.Count > 0)
- {
- foreach (var r in excludedRemotes)
- {
- builder.Append("--exclude=");
- builder.Append(r);
- builder.Append(" --decorate-refs-exclude=refs/remotes/");
- builder.Append(r);
- builder.Append(' ');
- }
- }
-
- builder.Append("--exclude=origin/HEA[D] --remotes ");
-
- if (excludedTags.Count > 0)
- {
- foreach (var t in excludedTags)
- {
- builder.Append("--exclude=");
- builder.Append(t);
- builder.Append(" --decorate-refs-exclude=refs/tags/");
- builder.Append(t);
- builder.Append(' ');
- }
- }
builder.Append("--tags ");
}
@@ -477,11 +430,7 @@ namespace SourceGit.Models
public CustomAction AddNewCustomAction()
{
- var act = new CustomAction()
- {
- Name = "Unnamed Custom Action",
- };
-
+ var act = new CustomAction() { Name = "Unnamed Action" };
CustomActions.Add(act);
return act;
}
diff --git a/src/Models/RevisionFile.cs b/src/Models/RevisionFile.cs
index f1f5265f..8cc1be2a 100644
--- a/src/Models/RevisionFile.cs
+++ b/src/Models/RevisionFile.cs
@@ -29,6 +29,6 @@ namespace SourceGit.Models
public class RevisionSubmodule
{
public Commit Commit { get; set; } = null;
- public string FullMessage { get; set; } = string.Empty;
+ public CommitFullMessage FullMessage { get; set; } = null;
}
}
diff --git a/src/Models/Version.cs b/src/Models/SelfUpdate.cs
similarity index 65%
rename from src/Models/Version.cs
rename to src/Models/SelfUpdate.cs
index 35c21778..e02f80d8 100644
--- a/src/Models/Version.cs
+++ b/src/Models/SelfUpdate.cs
@@ -1,4 +1,5 @@
-using System.Reflection;
+using System;
+using System.Reflection;
using System.Text.Json.Serialization;
namespace SourceGit.Models
@@ -32,5 +33,24 @@ namespace SourceGit.Models
}
}
- public class AlreadyUpToDate { }
+ public class AlreadyUpToDate
+ {
+ }
+
+ public class SelfUpdateFailed
+ {
+ public string Reason
+ {
+ get;
+ private set;
+ }
+
+ public SelfUpdateFailed(Exception e)
+ {
+ if (e.InnerException is { } inner)
+ Reason = inner.Message;
+ else
+ Reason = e.Message;
+ }
+ }
}
diff --git a/src/Models/ShellOrTerminal.cs b/src/Models/ShellOrTerminal.cs
index 1decdcfa..3ada2cf9 100644
--- a/src/Models/ShellOrTerminal.cs
+++ b/src/Models/ShellOrTerminal.cs
@@ -42,6 +42,7 @@ namespace SourceGit.Models
new ShellOrTerminal("mac-terminal", "Terminal", ""),
new ShellOrTerminal("iterm2", "iTerm", ""),
new ShellOrTerminal("warp", "Warp", ""),
+ new ShellOrTerminal("ghostty", "Ghostty", "")
};
}
else
@@ -56,6 +57,7 @@ namespace SourceGit.Models
new ShellOrTerminal("mate-terminal", "MATE Terminal", "mate-terminal"),
new ShellOrTerminal("foot", "Foot", "foot"),
new ShellOrTerminal("wezterm", "WezTerm", "wezterm"),
+ new ShellOrTerminal("ptyxis", "Ptyxis", "ptyxis"),
new ShellOrTerminal("custom", "Custom", ""),
};
}
diff --git a/src/Models/Stash.cs b/src/Models/Stash.cs
index 3d395a84..257b6d33 100644
--- a/src/Models/Stash.cs
+++ b/src/Models/Stash.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
namespace SourceGit.Models
{
@@ -6,6 +7,7 @@ namespace SourceGit.Models
{
public string Name { get; set; } = "";
public string SHA { get; set; } = "";
+ public List Parents { get; set; } = [];
public ulong Time { get; set; } = 0;
public string Message { get; set; } = "";
diff --git a/src/Models/Statistics.cs b/src/Models/Statistics.cs
index 969d3945..87a6eabd 100644
--- a/src/Models/Statistics.cs
+++ b/src/Models/Statistics.cs
@@ -18,9 +18,9 @@ namespace SourceGit.Models
ThisWeek,
}
- public class StaticsticsAuthor(string name, int count)
+ public class StaticsticsAuthor(User user, int count)
{
- public string Name { get; set; } = name;
+ public User User { get; set; } = user;
public int Count { get; set; } = count;
}
@@ -73,7 +73,7 @@ namespace SourceGit.Models
}
}
- public void AddCommit(DateTime time, string author)
+ public void AddCommit(DateTime time, User author)
{
Total++;
@@ -126,7 +126,7 @@ namespace SourceGit.Models
}
private StaticsticsMode _mode = StaticsticsMode.All;
- private Dictionary _mapUsers = new Dictionary();
+ private Dictionary _mapUsers = new Dictionary();
private Dictionary _mapSamples = new Dictionary();
}
@@ -150,14 +150,16 @@ namespace SourceGit.Models
public void AddCommit(string author, double timestamp)
{
+ var user = User.FindOrAdd(author);
+
var time = DateTime.UnixEpoch.AddSeconds(timestamp).ToLocalTime();
if (time >= _thisWeekStart)
- Week.AddCommit(time, author);
+ Week.AddCommit(time, user);
if (time >= _thisMonthStart)
- Month.AddCommit(time, author);
+ Month.AddCommit(time, user);
- All.AddCommit(time, author);
+ All.AddCommit(time, user);
}
public void Complete()
diff --git a/src/Models/TemplateEngine.cs b/src/Models/TemplateEngine.cs
index 6b5f525d..8472750c 100644
--- a/src/Models/TemplateEngine.cs
+++ b/src/Models/TemplateEngine.cs
@@ -313,7 +313,7 @@ namespace SourceGit.Models
private static bool IsNameChar(char c)
{
- return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9');
+ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_';
}
// (?) notice or log if variable is not found
diff --git a/src/Models/TextMateHelper.cs b/src/Models/TextMateHelper.cs
index 0eb5e489..b7efae72 100644
--- a/src/Models/TextMateHelper.cs
+++ b/src/Models/TextMateHelper.cs
@@ -21,10 +21,11 @@ namespace SourceGit.Models
{
private static readonly ExtraGrammar[] s_extraGrammars =
[
- new ExtraGrammar("source.toml", ".toml", "toml.json"),
- new ExtraGrammar("source.kotlin", ".kotlin", "kotlin.json"),
- new ExtraGrammar("source.hx", ".hx", "haxe.json"),
- new ExtraGrammar("source.hxml", ".hxml", "hxml.json"),
+ new ExtraGrammar("source.toml", [".toml"], "toml.json"),
+ new ExtraGrammar("source.kotlin", [".kotlin", ".kt", ".kts"], "kotlin.json"),
+ new ExtraGrammar("source.hx", [".hx"], "haxe.json"),
+ new ExtraGrammar("source.hxml", [".hxml"], "hxml.json"),
+ new ExtraGrammar("text.html.jsp", [".jsp", ".jspf", ".tag"], "jsp.json"),
];
public static string GetScope(string file, RegistryOptions reg)
@@ -36,13 +37,14 @@ namespace SourceGit.Models
extension = ".xml";
else if (extension == ".command")
extension = ".sh";
- else if (extension == ".kt" || extension == ".kts")
- extension = ".kotlin";
foreach (var grammar in s_extraGrammars)
{
- if (grammar.Extension.Equals(extension, StringComparison.OrdinalIgnoreCase))
- return grammar.Scope;
+ foreach (var ext in grammar.Extensions)
+ {
+ if (ext.Equals(extension, StringComparison.OrdinalIgnoreCase))
+ return grammar.Scope;
+ }
}
return reg.GetScopeByExtension(extension);
@@ -71,10 +73,10 @@ namespace SourceGit.Models
return reg.GetGrammar(scopeName);
}
- private record ExtraGrammar(string Scope, string Extension, string File)
+ private record ExtraGrammar(string Scope, List Extensions, string File)
{
public readonly string Scope = Scope;
- public readonly string Extension = Extension;
+ public readonly List Extensions = Extensions;
public readonly string File = File;
}
}
diff --git a/src/Models/User.cs b/src/Models/User.cs
index 850bcf2f..066ab747 100644
--- a/src/Models/User.cs
+++ b/src/Models/User.cs
@@ -43,6 +43,11 @@ namespace SourceGit.Models
return _caches.GetOrAdd(data, key => new User(key));
}
+ public override string ToString()
+ {
+ return $"{Name} <{Email}>";
+ }
+
private static ConcurrentDictionary _caches = new ConcurrentDictionary();
private readonly int _hash;
}
diff --git a/src/Models/Watcher.cs b/src/Models/Watcher.cs
index c63f0e55..3ccecad4 100644
--- a/src/Models/Watcher.cs
+++ b/src/Models/Watcher.cs
@@ -8,12 +8,12 @@ namespace SourceGit.Models
{
public class Watcher : IDisposable
{
- public Watcher(IRepository repo)
+ public Watcher(IRepository repo, string fullpath, string gitDir)
{
_repo = repo;
_wcWatcher = new FileSystemWatcher();
- _wcWatcher.Path = _repo.FullPath;
+ _wcWatcher.Path = fullpath;
_wcWatcher.Filter = "*";
_wcWatcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.DirectoryName | NotifyFilters.FileName | NotifyFilters.Size | NotifyFilters.CreationTime;
_wcWatcher.IncludeSubdirectories = true;
@@ -23,15 +23,8 @@ namespace SourceGit.Models
_wcWatcher.Deleted += OnWorkingCopyChanged;
_wcWatcher.EnableRaisingEvents = true;
- // If this repository is a worktree repository, just watch the main repository's gitdir.
- var gitDirNormalized = _repo.GitDir.Replace("\\", "/");
- var worktreeIdx = gitDirNormalized.IndexOf(".git/worktrees/", StringComparison.Ordinal);
- var repoWatchDir = _repo.GitDir;
- if (worktreeIdx > 0)
- repoWatchDir = _repo.GitDir.Substring(0, worktreeIdx + 4);
-
_repoWatcher = new FileSystemWatcher();
- _repoWatcher.Path = repoWatchDir;
+ _repoWatcher.Path = gitDir;
_repoWatcher.Filter = "*";
_repoWatcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.DirectoryName | NotifyFilters.FileName;
_repoWatcher.IncludeSubdirectories = true;
@@ -72,6 +65,11 @@ namespace SourceGit.Models
_updateBranch = DateTime.Now.ToFileTime() - 1;
}
+ public void MarkTagDirtyManually()
+ {
+ _updateTags = DateTime.Now.ToFileTime() - 1;
+ }
+
public void MarkWorkingCopyDirtyManually()
{
_updateWC = DateTime.Now.ToFileTime() - 1;
@@ -109,6 +107,7 @@ namespace SourceGit.Models
{
_updateBranch = 0;
_updateWC = 0;
+ _updateSubmodules = 0;
if (_updateTags > 0)
{
@@ -119,6 +118,7 @@ namespace SourceGit.Models
Task.Run(_repo.RefreshBranches);
Task.Run(_repo.RefreshCommits);
Task.Run(_repo.RefreshWorkingCopyChanges);
+ Task.Run(_repo.RefreshSubmodules);
Task.Run(_repo.RefreshWorktrees);
}
@@ -131,20 +131,20 @@ namespace SourceGit.Models
if (_updateSubmodules > 0 && now > _updateSubmodules)
{
_updateSubmodules = 0;
- _repo.RefreshSubmodules();
+ Task.Run(_repo.RefreshSubmodules);
}
if (_updateStashes > 0 && now > _updateStashes)
{
_updateStashes = 0;
- _repo.RefreshStashes();
+ Task.Run(_repo.RefreshStashes);
}
if (_updateTags > 0 && now > _updateTags)
{
_updateTags = 0;
- _repo.RefreshTags();
- _repo.RefreshCommits();
+ Task.Run(_repo.RefreshTags);
+ Task.Run(_repo.RefreshCommits);
}
}
@@ -173,12 +173,6 @@ namespace SourceGit.Models
(name.StartsWith("worktrees/", StringComparison.Ordinal) && name.EndsWith("/HEAD", StringComparison.Ordinal)))
{
_updateBranch = DateTime.Now.AddSeconds(.5).ToFileTime();
-
- lock (_lockSubmodule)
- {
- if (_submodules.Count > 0)
- _updateSubmodules = DateTime.Now.AddSeconds(1).ToFileTime();
- }
}
else if (name.StartsWith("objects/", StringComparison.Ordinal) || name.Equals("index", StringComparison.Ordinal))
{
diff --git a/src/Models/Worktree.cs b/src/Models/Worktree.cs
index f9ba14e4..bc40e320 100644
--- a/src/Models/Worktree.cs
+++ b/src/Models/Worktree.cs
@@ -6,6 +6,7 @@ namespace SourceGit.Models
{
public string Branch { get; set; } = string.Empty;
public string FullPath { get; set; } = string.Empty;
+ public string RelativePath { get; set; } = string.Empty;
public string Head { get; set; } = string.Empty;
public bool IsBare { get; set; } = false;
public bool IsDetached { get; set; } = false;
@@ -21,15 +22,15 @@ namespace SourceGit.Models
get
{
if (IsDetached)
- return $"(deteched HEAD at {Head.Substring(10)})";
+ return $"deteched HEAD at {Head.Substring(10)}";
if (Branch.StartsWith("refs/heads/", System.StringComparison.Ordinal))
- return $"({Branch.Substring(11)})";
+ return Branch.Substring(11);
if (Branch.StartsWith("refs/remotes/", System.StringComparison.Ordinal))
- return $"({Branch.Substring(13)})";
+ return Branch.Substring(13);
- return $"({Branch})";
+ return Branch;
}
}
diff --git a/src/Native/Linux.cs b/src/Native/Linux.cs
index a24f1b65..bfb98500 100644
--- a/src/Native/Linux.cs
+++ b/src/Native/Linux.cs
@@ -65,13 +65,16 @@ namespace SourceGit.Native
{
var home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
var cwd = string.IsNullOrEmpty(workdir) ? home : workdir;
+ var terminal = OS.ShellOrTerminal;
var startInfo = new ProcessStartInfo();
startInfo.WorkingDirectory = cwd;
- startInfo.FileName = OS.ShellOrTerminal;
+ startInfo.FileName = terminal;
- if (OS.ShellOrTerminal.EndsWith("wezterm", StringComparison.OrdinalIgnoreCase))
+ if (terminal.EndsWith("wezterm", StringComparison.OrdinalIgnoreCase))
startInfo.Arguments = $"start --cwd \"{cwd}\"";
+ else if (terminal.EndsWith("ptyxis", StringComparison.OrdinalIgnoreCase))
+ startInfo.Arguments = $"--new-window --working-directory=\"{cwd}\"";
try
{
diff --git a/src/Native/MacOS.cs b/src/Native/MacOS.cs
index c9e6abad..d7ef4701 100644
--- a/src/Native/MacOS.cs
+++ b/src/Native/MacOS.cs
@@ -18,9 +18,22 @@ namespace SourceGit.Native
DisableDefaultApplicationMenuItems = true,
});
+ // Fix `PATH` env on macOS.
+ var path = Environment.GetEnvironmentVariable("PATH");
+ if (string.IsNullOrEmpty(path))
+ path = "/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin";
+ else if (!path.Contains("/opt/homebrew/", StringComparison.Ordinal))
+ path = "/opt/homebrew/bin:/opt/homebrew/sbin:" + path;
+
var customPathFile = Path.Combine(OS.DataDir, "PATH");
if (File.Exists(customPathFile))
- OS.CustomPathEnv = File.ReadAllText(customPathFile).Trim();
+ {
+ var env = File.ReadAllText(customPathFile).Trim();
+ if (!string.IsNullOrEmpty(env))
+ path = env;
+ }
+
+ Environment.SetEnvironmentVariable("PATH", path);
}
public string FindGitExecutable()
@@ -44,6 +57,8 @@ namespace SourceGit.Native
return "iTerm";
case "warp":
return "Warp";
+ case "ghostty":
+ return "Ghostty";
}
return string.Empty;
diff --git a/src/Native/OS.cs b/src/Native/OS.cs
index 177bbf9f..320b5208 100644
--- a/src/Native/OS.cs
+++ b/src/Native/OS.cs
@@ -25,15 +25,10 @@ namespace SourceGit.Native
void OpenWithDefaultEditor(string file);
}
- public static string DataDir {
- get;
- private set;
- } = string.Empty;
-
- public static string CustomPathEnv
+ public static string DataDir
{
get;
- set;
+ private set;
} = string.Empty;
public static string GitExecutable
@@ -61,12 +56,14 @@ namespace SourceGit.Native
private set;
} = new Version(0, 0, 0);
- public static string ShellOrTerminal {
+ public static string ShellOrTerminal
+ {
get;
set;
} = string.Empty;
- public static List ExternalTools {
+ public static List ExternalTools
+ {
get;
set;
} = [];
@@ -165,6 +162,15 @@ namespace SourceGit.Native
_backend.OpenWithDefaultEditor(file);
}
+ public static string GetAbsPath(string root, string sub)
+ {
+ var fullpath = Path.Combine(root, sub);
+ if (OperatingSystem.IsWindows())
+ return fullpath.Replace('/', '\\');
+
+ return fullpath;
+ }
+
private static void UpdateGitVersion()
{
if (string.IsNullOrEmpty(_gitExecutable) || !File.Exists(_gitExecutable))
diff --git a/src/Native/Windows.cs b/src/Native/Windows.cs
index 10f2970a..eb354f10 100644
--- a/src/Native/Windows.cs
+++ b/src/Native/Windows.cs
@@ -8,6 +8,7 @@ using System.Text;
using Avalonia;
using Avalonia.Controls;
+using Avalonia.Threading;
namespace SourceGit.Native
{
@@ -152,7 +153,7 @@ namespace SourceGit.Native
public void OpenBrowser(string url)
{
- var info = new ProcessStartInfo("cmd", $"/c start {url}");
+ var info = new ProcessStartInfo("cmd", $"/c start \"\" \"{url}\"");
info.CreateNoWindow = true;
Process.Start(info);
}
@@ -214,12 +215,17 @@ namespace SourceGit.Native
private void FixWindowFrameOnWin10(Window w)
{
- var platformHandle = w.TryGetPlatformHandle();
- if (platformHandle == null)
- return;
+ // Schedule the DWM frame extension to run in the next render frame
+ // to ensure proper timing with the window initialization sequence
+ Dispatcher.UIThread.InvokeAsync(() =>
+ {
+ var platformHandle = w.TryGetPlatformHandle();
+ if (platformHandle == null)
+ return;
- var margins = new MARGINS { cxLeftWidth = 1, cxRightWidth = 1, cyTopHeight = 1, cyBottomHeight = 1 };
- DwmExtendFrameIntoClientArea(platformHandle.Handle, ref margins);
+ var margins = new MARGINS { cxLeftWidth = 1, cxRightWidth = 1, cyTopHeight = 1, cyBottomHeight = 1 };
+ DwmExtendFrameIntoClientArea(platformHandle.Handle, ref margins);
+ }, DispatcherPriority.Render);
}
#region EXTERNAL_EDITOR_FINDER
diff --git a/src/Resources/Grammars/haxe.json b/src/Resources/Grammars/haxe.json
index 12acc538..3f78154d 100644
--- a/src/Resources/Grammars/haxe.json
+++ b/src/Resources/Grammars/haxe.json
@@ -1,7 +1,9 @@
{
"information_for_contributors": [
"This file has been copied from https://github.com/vshaxe/haxe-TmLanguage/blob/ddad8b4c6d0781ac20be0481174ec1be772c5da5/haxe.tmLanguage",
- "and converted to JSON using https://marketplace.visualstudio.com/items?itemName=pedro-w.tmlanguage"
+ "and converted to JSON using https://marketplace.visualstudio.com/items?itemName=pedro-w.tmlanguage",
+ "The original file was licensed under the MIT License",
+ "https://github.com/vshaxe/haxe-TmLanguage/blob/ddad8b4c6d0781ac20be0481174ec1be772c5da5/LICENSE.md"
],
"fileTypes": [
"hx",
@@ -2485,4 +2487,4 @@
"name": "variable.other.hx"
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Resources/Grammars/hxml.json b/src/Resources/Grammars/hxml.json
index 829c403e..3be42577 100644
--- a/src/Resources/Grammars/hxml.json
+++ b/src/Resources/Grammars/hxml.json
@@ -1,7 +1,9 @@
{
"information_for_contributors": [
"This file has been copied from https://github.com/vshaxe/haxe-TmLanguage/blob/ddad8b4c6d0781ac20be0481174ec1be772c5da5/hxml.tmLanguage",
- "and converted to JSON using https://marketplace.visualstudio.com/items?itemName=pedro-w.tmlanguage"
+ "and converted to JSON using https://marketplace.visualstudio.com/items?itemName=pedro-w.tmlanguage",
+ "The original file was licensed under the MIT License",
+ "https://github.com/vshaxe/haxe-TmLanguage/blob/ddad8b4c6d0781ac20be0481174ec1be772c5da5/LICENSE.md"
],
"fileTypes": [
"hxml"
@@ -67,4 +69,4 @@
],
"scopeName": "source.hxml",
"uuid": "CB1B853A-C4C8-42C3-BA70-1B1605BE51C1"
-}
\ No newline at end of file
+}
diff --git a/src/Resources/Grammars/jsp.json b/src/Resources/Grammars/jsp.json
new file mode 100644
index 00000000..2fbfd97c
--- /dev/null
+++ b/src/Resources/Grammars/jsp.json
@@ -0,0 +1,100 @@
+{
+ "information_for_contributors": [
+ "This file has been copied from https://github.com/samuel-weinhardt/vscode-jsp-lang/blob/0e89ecdb13650dbbe5a1e85b47b2e1530bf2f355/syntaxes/jsp.tmLanguage.json",
+ "The original file was licensed under the MIT License",
+ "https://github.com/samuel-weinhardt/vscode-jsp-lang/blob/0e89ecdb13650dbbe5a1e85b47b2e1530bf2f355/LICENSE"
+ ],
+ "$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json",
+ "name": "Jakarta Server Pages",
+ "fileTypes": ["jsp", "jspf", "tag"],
+ "scopeName": "text.html.jsp",
+ "patterns": [
+ { "include": "#comment" },
+ { "include": "#directive" },
+ { "include": "#expression" },
+ { "include": "text.html.derivative" }
+ ],
+ "injections": {
+ "L:text.html.jsp -comment -meta.tag.directive.jsp -meta.tag.scriptlet.jsp": {
+ "patterns": [
+ { "include": "#scriptlet" }
+ ],
+ "comment": "allow scriptlets anywhere except comments and nested"
+ },
+ "L:meta.attribute (string.quoted.single.html | string.quoted.double.html) -string.template.expression.jsp": {
+ "patterns": [
+ { "include": "#expression" },
+ { "include": "text.html.derivative" }
+ ],
+ "comment": "allow expressions and tags within HTML attributes (not nested)"
+ }
+ },
+ "repository": {
+ "comment": {
+ "name": "comment.block.jsp",
+ "begin": "<%--",
+ "end": "--%>"
+ },
+ "directive": {
+ "name": "meta.tag.directive.jsp",
+ "begin": "(<)(%@)",
+ "end": "(%)(>)",
+ "beginCaptures": {
+ "1": { "name": "punctuation.definition.tag.jsp" },
+ "2": { "name": "entity.name.tag.jsp" }
+ },
+ "endCaptures": {
+ "1": { "name": "entity.name.tag.jsp" },
+ "2": { "name": "punctuation.definition.tag.jsp" }
+ },
+ "patterns": [
+ {
+ "match": "\\b(attribute|include|page|tag|taglib|variable)\\b(?!\\s*=)",
+ "name": "keyword.control.directive.jsp"
+ },
+ { "include": "text.html.basic#attribute" }
+ ]
+ },
+ "scriptlet": {
+ "name": "meta.tag.scriptlet.jsp",
+ "contentName": "meta.embedded.block.java",
+ "begin": "(<)(%[\\s!=])",
+ "end": "(%)(>)",
+ "beginCaptures": {
+ "1": { "name": "punctuation.definition.tag.jsp" },
+ "2": { "name": "entity.name.tag.jsp" }
+ },
+ "endCaptures": {
+ "1": { "name": "entity.name.tag.jsp" },
+ "2": { "name": "punctuation.definition.tag.jsp" }
+ },
+ "patterns": [
+ {
+ "match": "\\{(?=\\s*(%>|$))",
+ "comment": "consume trailing curly brackets for fragmented scriptlets"
+ },
+ { "include": "source.java" }
+ ]
+ },
+ "expression": {
+ "name": "string.template.expression.jsp",
+ "contentName": "meta.embedded.block.java",
+ "begin": "[$#]\\{",
+ "end": "\\}",
+ "beginCaptures": {
+ "0": { "name": "punctuation.definition.template-expression.begin.jsp" }
+ },
+ "endCaptures": {
+ "0": { "name": "punctuation.definition.template-expression.end.jsp" }
+ },
+ "patterns": [
+ { "include": "#escape" },
+ { "include": "source.java" }
+ ]
+ },
+ "escape": {
+ "match": "\\\\.",
+ "name": "constant.character.escape.jsp"
+ }
+ }
+}
diff --git a/src/Resources/Grammars/kotlin.json b/src/Resources/Grammars/kotlin.json
index e8f844d0..2857f717 100644
--- a/src/Resources/Grammars/kotlin.json
+++ b/src/Resources/Grammars/kotlin.json
@@ -1,6 +1,8 @@
{
"information_for_contributors": [
- "This file has been copied from https://github.com/eclipse/buildship/blob/6bb773e7692f913dec27105129ebe388de34e68b/org.eclipse.buildship.kotlindsl.provider/kotlin.tmLanguage.json"
+ "This file has been copied from https://github.com/eclipse/buildship/blob/6bb773e7692f913dec27105129ebe388de34e68b/org.eclipse.buildship.kotlindsl.provider/kotlin.tmLanguage.json",
+ "The original file was licensed under the Eclipse Public License, Version 1.0",
+ "https://github.com/eclipse-buildship/buildship/blob/6bb773e7692f913dec27105129ebe388de34e68b/README.md"
],
"$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json",
"name": "Kotlin",
@@ -698,4 +700,4 @@
"name": "variable.language.this.kotlin"
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Resources/Grammars/toml.json b/src/Resources/Grammars/toml.json
index 86c2ef87..6be4678f 100644
--- a/src/Resources/Grammars/toml.json
+++ b/src/Resources/Grammars/toml.json
@@ -3,7 +3,10 @@
"scopeName": "source.toml",
"uuid": "8b4e5008-c50d-11ea-a91b-54ee75aeeb97",
"information_for_contributors": [
- "Originally was maintained by aster (galaster@foxmail.com). This notice is only kept here for the record, please don't send e-mails about bugs and other issues."
+ "Originally was maintained by aster (galaster@foxmail.com). This notice is only kept here for the record, please don't send e-mails about bugs and other issues.",
+ "This file has been copied from https://github.com/kkiyama117/coc-toml/blob/main/toml.tmLanguage.json",
+ "The original file was licensed under the MIT License",
+ "https://github.com/kkiyama117/coc-toml/blob/main/LICENSE"
],
"patterns": [
{
diff --git a/src/Resources/Icons.axaml b/src/Resources/Icons.axaml
index c0c9d8ff..66589440 100644
--- a/src/Resources/Icons.axaml
+++ b/src/Resources/Icons.axaml
@@ -5,12 +5,16 @@
M71 1024V0h661L953 219V1024H71zm808-731-220-219H145V951h735V293zM439 512h-220V219h220V512zm-74-219H292v146h74v-146zm0 512h74v73h-220v-73H292v-146H218V585h147v219zm294-366h74V512H512v-73h74v-146H512V219h147v219zm74 439H512V585h220v293zm-74-219h-74v146h74v-146z
M128 256h192a64 64 0 110 128H128a64 64 0 110-128zm576 192h192a64 64 0 010 128h-192a64 64 0 010-128zm-576 192h192a64 64 0 010 128H128a64 64 0 010-128zm576 0h192a64 64 0 010 128h-192a64 64 0 010-128zm0-384h192a64 64 0 010 128h-192a64 64 0 010-128zM128 448h192a64 64 0 110 128H128a64 64 0 110-128zm384-320a64 64 0 0164 64v640a64 64 0 01-128 0V192a64 64 0 0164-64z
M832 64H192c-18 0-32 14-32 32v832c0 18 14 32 32 32h640c18 0 32-14 32-32V96c0-18-14-32-32-32zM736 596 624 502 506 596V131h230v318z
+ M509 546 780 275 871 366 509 728 147 366 238 275zM509 728h-362v128h724v-128z
M757 226a143 143 0 00-55 276 96 96 0 01-88 59h-191a187 187 0 00-96 27V312a143 143 0 10-96 0v399a143 143 0 10103 2 96 96 0 0188-59h191a191 191 0 00187-151 143 143 0 00-43-279zM280 130a48 48 0 110 96 48 48 0 010-96zm0 764a48 48 0 110-96 48 48 0 010 96zM757 417a48 48 0 110-96 48 48 0 010 96z
M896 128h-64V64c0-35-29-64-64-64s-64 29-64 64v64h-64c-35 0-64 29-64 64s29 64 64 64h64v64c0 35 29 64 64 64s64-29 64-64V256h64c35 0 64-29 64-64s-29-64-64-64zm-204 307C673 481 628 512 576 512H448c-47 0-90 13-128 35V372C394 346 448 275 448 192c0-106-86-192-192-192S64 86 64 192c0 83 54 154 128 180v280c-74 26-128 97-128 180c0 106 86 192 192 192s192-86 192-192c0-67-34-125-84-159c22-20 52-33 84-33h128c122 0 223-85 249-199c-19 4-37 7-57 7c-26 0-51-5-76-13zM256 128c35 0 64 29 64 64s-29 64-64 64s-64-29-64-64s29-64 64-64zm0 768c-35 0-64-29-64-64s29-64 64-64s64 29 64 64s-29 64-64 64z
M512 597m-1 0a1 1 0 103 0a1 1 0 10-3 0ZM810 393 732 315 448 600 293 444 214 522l156 156 78 78 362-362z
+ M512 32C246 32 32 250 32 512s218 480 480 480 480-218 480-480S774 32 512 32zm269 381L496 698c-26 26-61 26-83 0L243 528c-26-26-26-61 0-83s61-26 83 0l128 128 240-240c26-26 61-26 83 0 26 19 26 54 3 80z
M747 467c29 0 56 4 82 12v-363c0-47-38-84-84-84H125c-47 0-84 38-84 84v707c0 47 38 84 84 84h375a287 287 0 01-43-152c0-160 129-289 289-289zm-531-250h438c19 0 34 15 34 34s-15 34-34 34H216c-19 0-34-15-34-34s15-34 34-34zm0 179h263c19 0 34 15 34 34s-15 34-34 34H216c-19 0-34-15-34-34s15-34 34-34zm131 247h-131c-19 0-34-15-34-34s15-34 34-34h131c19 0 34 15 34 34s-15 34-34 34zM747 521c-130 0-236 106-236 236S617 992 747 992s236-106 236-236S877 521 747 521zm11 386v-65h-130c-12 0-22-10-22-22s10-22 22-22h260l-130 108zm108-192H606l130-108v65h130c12 0 22 10 22 22s-10 22-22 22z
M529 511c115 0 212 79 239 185h224a62 62 0 017 123l-7 0-224 0a247 247 0 01-479 0H65a62 62 0 01-7-123l7-0h224a247 247 0 01239-185zm0 124a124 124 0 100 247 124 124 0 000-247zm0-618c32 0 58 24 61 55l0 7V206c89 11 165 45 225 103a74 74 0 0122 45l0 9v87a62 62 0 01-123 7l-0-7v-65l-6-4c-43-33-97-51-163-53l-17-0c-74 0-133 18-180 54l-6 4v65a62 62 0 01-55 61l-7 0a62 62 0 01-61-55l-0-7V362c0-20 8-39 23-53 60-58 135-92 224-103V79c0-34 28-62 62-62z
+ M512 926c-229 0-414-186-414-414S283 98 512 98s414 186 414 414-186 414-414 414zm0-73c189 0 341-153 341-341S701 171 512 171 171 323 171 512s153 341 341 341zm-6-192L284 439l52-52 171 171 171-171L728 439l-222 222z
M512 57c251 0 455 204 455 455S763 967 512 967 57 763 57 512 261 57 512 57zm181 274c-11-11-29-11-40 0L512 472 371 331c-11-11-29-11-40 0-11 11-11 29 0 40L471 512 331 653c-11 11-11 29 0 40 11 11 29 11 40 0l141-141 141 141c11 11 29 11 40 0 11-11 11-29 0-40L552 512l141-141c11-11 11-29 0-40z
+ M591 907A85 85 0 01427 875h114a299 299 0 0050 32zM725 405c130 0 235 105 235 235s-105 235-235 235-235-105-235-235 105-235 235-235zM512 64a43 43 0 0143 43v24c126 17 229 107 264 225A298 298 0 00725 341l-4 0A235 235 0 00512 213l-5 0c-125 4-224 104-228 229l-0 6v167a211 211 0 01-26 101l-4 7-14 23h211a298 298 0 0050 85l-276-0a77 77 0 01-66-39c-13-22-14-50-2-73l2-4 22-36c10-17 16-37 17-57l0-7v-167C193 287 313 153 469 131V107a43 43 0 0139-43zm345 505L654 771a149 149 0 00202-202zM725 491a149 149 0 00-131 220l202-202A149 149 0 00725 491z
M797 829a49 49 0 1049 49 49 49 0 00-49-49zm147-114A49 49 0 10992 764a49 49 0 00-49-49zM928 861a49 49 0 1049 49A49 49 0 00928 861zm-5-586L992 205 851 64l-71 71a67 67 0 00-94 0l235 235a67 67 0 000-94zm-853 128a32 32 0 00-32 50 1291 1291 0 0075 112L288 552c20 0 25 21 8 37l-93 86a1282 1282 0 00120 114l100-32c19-6 28 15 14 34l-40 55c26 19 53 36 82 53a89 89 0 00115-20 1391 1391 0 00256-485l-188-188s-306 224-595 198z
M1280 704c0 141-115 256-256 256H288C129 960 0 831 0 672c0-126 80-232 192-272A327 327 0 01192 384c0-177 143-320 320-320 119 0 222 64 277 160C820 204 857 192 896 192c106 0 192 86 192 192 0 24-5 48-13 69C1192 477 1280 580 1280 704zm-493-128H656V352c0-18-14-32-32-32h-96c-18 0-32 14-32 32v224h-131c-29 0-43 34-23 55l211 211c12 12 33 12 45 0l211-211c20-20 6-55-23-55z
M853 102H171C133 102 102 133 102 171v683C102 891 133 922 171 922h683C891 922 922 891 922 853V171C922 133 891 102 853 102zM390 600l-48 48L205 512l137-137 48 48L301 512l88 88zM465 819l-66-18L559 205l66 18L465 819zm218-171L634 600 723 512l-88-88 48-48L819 512 683 649z
@@ -50,6 +54,7 @@
M939 94v710L512 998 85 805V94h-64A21 21 0 010 73v-0C0 61 10 51 21 51h981c12 0 21 10 21 21v0c0 12-10 21-21 21h-64zm-536 588L512 624l109 58c6 3 13 4 20 3a32 32 0 0026-37l-21-122 88-87c5-5 8-11 9-18a32 32 0 00-27-37l-122-18-54-111a32 32 0 00-57 0l-54 111-122 18c-7 1-13 4-18 9a33 33 0 001 46l88 87-21 122c-1 7-0 14 3 20a32 32 0 0043 14z
M236 542a32 32 0 109 63l86-12a180 180 0 0022 78l-71 47a32 32 0 1035 53l75-50a176 176 0 00166 40L326 529zM512 16C238 16 16 238 16 512s222 496 496 496 496-222 496-496S786 16 512 16zm0 896c-221 0-400-179-400-400a398 398 0 0186-247l561 561A398 398 0 01512 912zm314-154L690 622a179 179 0 004-29l85 12a32 32 0 109-63l-94-13v-49l94-13a32 32 0 10-9-63l-87 12a180 180 0 00-20-62l71-47A32 32 0 10708 252l-75 50a181 181 0 00-252 10l-115-115A398 398 0 01512 112c221 0 400 179 400 400a398 398 0 01-86 247z
M884 159l-18-18a43 43 0 00-38-12l-235 43a166 166 0 00-101 60L400 349a128 128 0 00-148 47l-120 171a21 21 0 005 29l17 12a128 128 0 00178-32l27-38 124 124-38 27a128 128 0 00-32 178l12 17a21 21 0 0029 5l171-120a128 128 0 0047-148l117-92A166 166 0 00853 431l43-235a43 43 0 00-12-38zm-177 249a64 64 0 110-90 64 64 0 010 90zm-373 312a21 21 0 010 30l-139 139a21 21 0 01-30 0l-30-30a21 21 0 010-30l139-139a21 21 0 0130 0z
+ M525 0C235 0 0 235 0 525c0 232 150 429 359 498 26 5 36-11 36-25 0-12-1-54-1-97-146 31-176-63-176-63-23-61-58-76-58-76-48-32 3-32 3-32 53 3 81 54 81 54 47 80 123 57 153 43 4-34 18-57 33-70-116-12-239-57-239-259 0-57 21-104 54-141-5-13-23-67 5-139 0 0 44-14 144 54 42-11 87-17 131-17s90 6 131 17C756 203 801 217 801 217c29 72 10 126 5 139 34 37 54 83 54 141 0 202-123 246-240 259 19 17 36 48 36 97 0 70-1 127-1 144 0 14 10 30 36 25 209-70 359-266 359-498C1050 235 814 0 525 0z
M590 74 859 342V876c0 38-31 68-68 68H233c-38 0-68-31-68-68V142c0-38 31-68 68-68h357zm-12 28H233a40 40 0 00-40 38L193 142v734a40 40 0 0038 40L233 916h558a40 40 0 0040-38L831 876V354L578 102zM855 371h-215c-46 0-83-36-84-82l0-2V74h28v213c0 30 24 54 54 55l2 0h215v28zM57 489m28 0 853 0q28 0 28 28l0 284q0 28-28 28l-853 0q-28 0-28-28l0-284q0-28 28-28ZM157 717c15 0 29-6 37-13v-51h-41v22h17v18c-2 2-6 3-10 3-21 0-30-13-30-34 0-21 12-34 28-34 9 0 15 4 20 9l14-17C184 610 172 603 156 603c-29 0-54 21-54 57 0 37 24 56 54 56zM245 711v-108h-34v108h34zm69 0v-86H341V603H262v22h28V711h24zM393 711v-108h-34v108h34zm66 6c15 0 29-6 37-13v-51h-41v22h17v18c-2 2-6 3-10 3-21 0-30-13-30-34 0-21 12-34 28-34 9 0 15 4 20 9l14-17C485 610 474 603 458 603c-29 0-54 21-54 57 0 37 24 56 54 56zm88-6v-36c0-13-2-28-3-40h1l10 24 25 52H603v-108h-23v36c0 13 2 28 3 40h-1l-10-24L548 603H523v108h23zM677 717c30 0 51-22 51-57 0-36-21-56-51-56-30 0-51 20-51 56 0 36 21 57 51 57zm3-23c-16 0-26-12-26-32 0-19 10-31 26-31 16 0 26 11 26 31S696 694 680 694zm93 17v-38h13l21 38H836l-25-43c12-5 19-15 19-31 0-26-20-34-44-34H745v108h27zm16-51H774v-34h15c16 0 25 4 25 16s-9 18-25 18zM922 711v-22h-43v-23h35v-22h-35V625h41V603H853v108h68z
M30 271l241 0 0-241-241 0 0 241zM392 271l241 0 0-241-241 0 0 241zM753 30l0 241 241 0 0-241-241 0zM30 632l241 0 0-241-241 0 0 241zM392 632l241 0 0-241-241 0 0 241zM753 632l241 0 0-241-241 0 0 241zM30 994l241 0 0-241-241 0 0 241zM392 994l241 0 0-241-241 0 0 241zM753 994l241 0 0-241-241 0 0 241z
M0 512M1024 512M512 0M512 1024M955 323q0 23-16 39l-414 414-78 78q-16 16-39 16t-39-16l-78-78-207-207q-16-16-16-39t16-39l78-78q16-16 39-16t39 16l168 169 375-375q16-16 39-16t39 16l78 78q16 16 16 39z
@@ -86,6 +91,7 @@
m186 532 287 0 0 287c0 11 9 20 20 20s20-9 20-20l0-287 287 0c11 0 20-9 20-20s-9-20-20-20l-287 0 0-287c0-11-9-20-20-20s-20 9-20 20l0 287-287 0c-11 0-20 9-20 20s9 20 20 20z
M432 0h160c27 0 48 21 48 48v336h175c36 0 53 43 28 68L539 757c-15 15-40 15-55 0L180 452c-25-25-7-68 28-68H384V48c0-27 21-48 48-48zm592 752v224c0 27-21 48-48 48H48c-27 0-48-21-48-48V752c0-27 21-48 48-48h293l98 98c40 40 105 40 145 0l98-98H976c27 0 48 21 48 48zm-248 176c0-22-18-40-40-40s-40 18-40 40s18 40 40 40s40-18 40-40zm128 0c0-22-18-40-40-40s-40 18-40 40s18 40 40 40s40-18 40-40z
M592 768h-160c-27 0-48-21-48-48V384h-175c-36 0-53-43-28-68L485 11c15-15 40-15 55 0l304 304c25 25 7 68-28 68H640v336c0 27-21 48-48 48zm432-16v224c0 27-21 48-48 48H48c-27 0-48-21-48-48V752c0-27 21-48 48-48h272v16c0 62 50 112 112 112h160c62 0 112-50 112-112v-16h272c27 0 48 21 48 48zm-248 176c0-22-18-40-40-40s-40 18-40 40s18 40 40 40s40-18 40-40zm128 0c0-22-18-40-40-40s-40 18-40 40s18 40 40 40s40-18 40-40z
+ M563 555c0 28-23 51-51 51-28 0-51-23-51-51L461 113c0-28 23-51 51-51s51 23 51 51L563 555 563 555zM85 535c0-153 81-287 201-362 24-15 55-8 70 16C371 214 363 245 340 260 248 318 187 419 187 535c0 180 146 325 325 325 180-0 325-146 325-325 0-119-64-223-160-280-24-14-32-46-18-70 14-24 46-32 70-18 125 74 210 211 210 367 0 236-191 427-427 427C276 963 85 772 85 535
M277 85a149 149 0 00-43 292v230a32 32 0 0064 0V555h267A160 160 0 00725 395v-12a149 149 0 10-64-5v17a96 96 0 01-96 96H299V383A149 149 0 00277 85zM228 720a32 32 0 00-37-52 150 150 0 00-53 68 32 32 0 1060 23 85 85 0 0130-39zm136-52a32 32 0 00-37 52 86 86 0 0130 39 32 32 0 1060-23 149 149 0 00-53-68zM204 833a32 32 0 10-55 32 149 149 0 0063 58 32 32 0 0028-57 85 85 0 01-36-33zm202 32a32 32 0 00-55-32 85 85 0 01-36 33 32 32 0 0028 57 149 149 0 0063-58z
M467 556c0-0 0-1 0-1C467 555 467 556 467 556zM467 556c0-0 0-0 0-0C467 556 467 556 467 556zM467 556c-0 0-0 0-0 0C467 557 467 557 467 556zM468 549C468 532 468 541 468 549L468 549zM468 549c0 1-0 1-0 2C468 551 468 550 468 549zM468 552c-0 1-0 2-0 3C467 554 468 553 468 552zM736 549C736 532 736 541 736 549L736 549zM289 378l0 179 89 0c-1 80-89 89-89 89l45 45c0 0 129-15 134-134L467 378 289 378zM959 244l0 536c0 99-80 179-179 179L244 959c-99 0-179-80-179-179L65 244c0-99 80-179 179-179l536 0C879 65 959 145 959 244zM869 289c0-74-60-134-134-134L289 155c-74 0-134 60-134 134l0 447c0 74 60 134 134 134l447 0c74 0 134-60 134-134L869 289zM557 557l89 0c-1 80-89 89-89 89l45 45c0 0 129-15 134-134L735 378 557 378 557 557z
m224 154a166 166 0 00-166 166v192a166 166 0 00166 166h64v-76h-64a90 90 0 01-90-90v-192a90 90 0 0190-90h320a90 90 0 0190 90v192a90 90 0 01-90 90h-128v77h128a166 166 0 00166-167v-192a166 166 0 00-166-166h-320zm166 390a90 90 0 0190-90h128v-76h-128a166 166 0 00-166 166v192a166 166 0 00166 166h320a166 166 0 00166-166v-192a166 166 0 00-166-166h-64v77h64a90 90 0 0190 90v192a90 90 0 01-90 90h-320a90 90 0 01-90-90v-192z
@@ -115,6 +121,7 @@
M996 452 572 28A96 96 0 00504 0H96C43 0 0 43 0 96v408a96 96 0 0028 68l424 424c37 37 98 37 136 0l408-408c37-37 37-98 0-136zM224 320c-53 0-96-43-96-96s43-96 96-96 96 43 96 96-43 96-96 96zm1028 268L844 996c-37 37-98 37-136 0l-1-1L1055 647c34-34 53-79 53-127s-19-93-53-127L663 0h97a96 96 0 0168 28l424 424c37 37 37 98 0 136z
M765 118 629 239l-16 137-186 160 54 59 183-168 144 4 136-129 47-43-175-12L827 67zM489 404c-66 0-124 55-124 125s54 121 124 121c66 0 120-55 120-121H489l23-121c-8-4-16-4-23-4zM695 525c0 114-93 207-206 207s-206-94-206-207 93-207 206-207c16 0 27 0 43 4l43-207c-27-4-54-8-85-8-229 0-416 188-416 419s187 419 416 419c225 0 408-180 416-403v-12l-210-4z
M144 112h736c18 0 32 14 32 32v736c0 18-14 32-32 32H144c-18 0-32-14-32-32V144c0-18 14-32 32-32zm112 211v72a9 9 0 003 7L386 509 259 615a9 9 0 00-3 7v72a9 9 0 0015 7L493 516a9 9 0 000-14l-222-186a9 9 0 00-15 7zM522 624a10 10 0 00-10 10v60a10 10 0 0010 10h237a10 10 0 0010-10v-60a10 10 0 00-10-10H522z
+ M170 831 513 489 855 831 960 726 512 278 64 726 170 831zM512 278h448v-128h-896v128h448z
M897 673v13c0 51-42 93-93 93h-10c-1 0-2 0-2 0H220c-23 0-42 19-42 42v13c0 23 19 42 42 42h552c14 0 26 12 26 26 0 14-12 26-26 26H220c-51 0-93-42-93-93v-13c0-51 42-93 93-93h20c1-0 2-0 2-0h562c23 0 42-19 42-42v-13c0-11-5-22-13-29-8-7-17-11-28-10H660c-14 0-26-12-26-26 0-14 12-26 26-26h144c24-1 47 7 65 24 18 17 29 42 29 67zM479 98c-112 0-203 91-203 203 0 44 14 85 38 118l132 208c15 24 50 24 66 0l133-209c23-33 37-73 37-117 0-112-91-203-203-203zm0 327c-68 0-122-55-122-122s55-122 122-122 122 55 122 122-55 122-122 122z
M912 800a48 48 0 1 1 0 96h-416a48 48 0 1 1 0-96h416z m-704-704A112 112 0 0 1 256 309.184V480h80a48 48 0 0 1 0 96H256v224h81.664a48 48 0 1 1 0 96H256a96 96 0 0 1-96-96V309.248A112 112 0 0 1 208 96z m704 384a48 48 0 1 1 0 96h-416a48 48 0 0 1 0-96h416z m0-320a48 48 0 1 1 0 96h-416a48 48 0 0 1 0-96h416z
M30 0 30 30 0 15z
diff --git a/src/Resources/Images/ExternalToolIcons/plastic_merge.png b/src/Resources/Images/ExternalToolIcons/plastic_merge.png
new file mode 100644
index 00000000..0d82fc86
Binary files /dev/null and b/src/Resources/Images/ExternalToolIcons/plastic_merge.png differ
diff --git a/src/Resources/Images/ShellIcons/ghostty.png b/src/Resources/Images/ShellIcons/ghostty.png
new file mode 100644
index 00000000..e394a517
Binary files /dev/null and b/src/Resources/Images/ShellIcons/ghostty.png differ
diff --git a/src/Resources/Images/ShellIcons/ptyxis.png b/src/Resources/Images/ShellIcons/ptyxis.png
new file mode 100644
index 00000000..9202f6e1
Binary files /dev/null and b/src/Resources/Images/ShellIcons/ptyxis.png differ
diff --git a/src/Resources/Locales/de_DE.axaml b/src/Resources/Locales/de_DE.axaml
index a8a585d5..25b54c60 100644
--- a/src/Resources/Locales/de_DE.axaml
+++ b/src/Resources/Locales/de_DE.axaml
@@ -2,41 +2,34 @@
+
Info
Über SourceGit
- • Erstellt mit
- • Grafik gerendert durch
- © 2024 sourcegit-scm
- • Texteditor von
- • Monospace-Schriftarten von
- • Quelltext findest du auf
Open Source & freier Git GUI Client
Worktree hinzufügen
- Was auschecken:
- Existierender Branch
- Neuen Branch erstellen
Ordner:
Pfad für diesen Worktree. Relativer Pfad wird unterstützt.
Branch Name:
Optional. Standard ist der Zielordnername.
Branch verfolgen:
Remote-Branch verfolgen
+ Was auschecken:
+ Neuen Branch erstellen
+ Existierender Branch
OpenAI Assistent
+ Neu generieren
Verwende OpenAI, um Commit-Nachrichten zu generieren
+ Als Commit-Nachricht verwenden
Patch
- Fehler
- Fehler werfen und anwenden des Patches verweigern
- Alle Fehler
- Ähnlich wie 'Fehler', zeigt aber mehr an
Patch-Datei:
Wähle die anzuwendende .patch-Datei
Ignoriere Leerzeichenänderungen
- Keine Warnungen
- Keine Warnung vor Leerzeichen am Zeilenende
Patch anwenden
- Warnen
- Gibt eine Warnung für ein paar solcher Fehler aus, aber wendet es an
Leerzeichen:
+ Stash anwenden
+ Nach dem Anwenden löschen
+ Änderungen des Index wiederherstellen
+ Stash:
Archivieren...
Speichere Archiv in:
Wähle Archivpfad aus
@@ -50,10 +43,10 @@
Blame
BLAME WIRD BEI DIESER DATEI NICHT UNTERSTÜTZT!!!
Auschecken von ${0}$...
- Mit Branch vergleichen
Mit HEAD vergleichen
Mit Worktree vergleichen
Branch-Namen kopieren
+ Benutzerdefinierte Aktion
Lösche ${0}$...
Lösche alle ausgewählten {0} Branches
Alle Änderungen verwerfen
@@ -71,8 +64,8 @@
Branch Vergleich
Bytes
ABBRECHEN
- Auf diese Revision zurücksetzen
Auf Vorgänger-Revision zurücksetzen
+ Auf diese Revision zurücksetzen
Generiere Commit-Nachricht
ANZEIGE MODUS ÄNDERN
Zeige als Datei- und Ordnerliste
@@ -80,13 +73,12 @@
Zeige als Dateisystembaum
Branch auschecken
Commit auschecken
- Warnung: Beim Auschecken eines Commits wird dein HEAD losgelöst (detached) sein!
Commit:
- Branch:
+ Warnung: Beim Auschecken eines Commits wird dein HEAD losgelöst (detached) sein!
Lokale Änderungen:
Verwerfen
- Nichts tun
Stashen & wieder anwenden
+ Branch:
Cherry Pick
Quelle an Commit-Nachricht anhängen
Commit(s):
@@ -101,12 +93,13 @@
Lokaler Name:
Repository-Name. Optional.
Übergeordneter Ordner:
+ Submodule initialisieren und aktualisieren
Repository URL:
SCHLIESSEN
Editor
+ Commit auschecken
Diesen Commit cherry-picken
Mehrere cherry-picken
- Commit auschecken
Mit HEAD vergleichen
Mit Worktree vergleichen
Info kopieren
@@ -141,18 +134,19 @@
REFS
SHA
Im Browser öffnen
- Commit-Nachricht
Details
+ Commit-Nachricht
Repository Einstellungen
COMMIT TEMPLATE
- Template Name:
Template Inhalt:
+ Template Name:
BENUTZERDEFINIERTE AKTION
Argumente:
${REPO} - Repository Pfad; ${SHA} - SHA-Wert des selektierten Commits
Ausführbare Datei:
Name:
Geltungsbereich:
+ Branch
Commit
Repository
Email Adresse
@@ -161,13 +155,13 @@
Remotes automatisch fetchen
Minute(n)
Standard Remote
- Aktivere --prune beim fetchen
- Aktiviere --signoff für Commits
TICKETSYSTEM
+ Beispiel für Gitee Issue Regel einfügen
+ Beispiel für Gitee Pull Request Regel einfügen
Beispiel für Github-Regel hinzufügen
- Beispiel für Jira-Regel hinzufügen
Beispiel für Gitlab Issue Regel einfügen
Beispiel für Gitlab Merge Request einfügen
+ Beispiel für Jira-Regel hinzufügen
Neue Regel
Ticketnummer Regex-Ausdruck:
Name:
@@ -193,16 +187,15 @@
Kopieren
Kopiere gesamten Text
Pfad kopieren
- Dateinamen kopieren
Branch erstellen...
Basierend auf:
Erstellten Branch auschecken
Lokale Änderungen:
Verwerfen
- Nichts tun
Stashen & wieder anwenden
Neuer Branch-Name:
Branch-Namen eingeben.
+ Leerzeichen werden durch Bindestriche ersetzt.
Lokalen Branch erstellen
Tag erstellen...
Neuer Tag auf:
@@ -226,7 +219,10 @@
Du versuchst mehrere Branches auf einmal zu löschen. Kontrolliere noch einmal vor dem Fortfahren!
Remote löschen
Remote:
+ Pfad:
Ziel:
+ Alle Nachfolger werden aus der Liste entfernt.
+ Dadurch wird es nur aus der Liste entfernt, nicht von der Festplatte!
Bestätige löschen von Gruppe
Bestätige löschen von Repository
Lösche Submodul
@@ -294,11 +290,11 @@
Unstage
{0} Dateien unstagen
Änderungen in ausgewählten Zeilen unstagen
- "Ihre" verwenden (checkout --theirs)
"Meine" verwenden (checkout --ours)
+ "Ihre" verwenden (checkout --theirs)
Datei Historie
- INHALT
ÄNDERUNGEN
+ INHALT
Git-Flow
Development-Branch:
Feature:
@@ -328,8 +324,8 @@
Eigenes Muster:
Verfolgungsmuster zu Git LFS hinzufügen
Fetch
- LFS Objekte fetchen
Führt `git lfs fetch` aus um Git LFS Objekte herunterzuladen. Das aktualisiert nicht die Arbeitskopie.
+ LFS Objekte fetchen
Installiere Git LFS Hooks
Sperren anzeigen
Keine gesperrten Dateien
@@ -341,11 +337,11 @@
Prune
Führt `git lfs prune` aus um alte LFS Dateien von lokalem Speicher zu löschen
Pull
- LFS Objekte pullen
Führt `git lfs pull` aus um alle Git LFS Dasteien für aktuellen Ref & Checkout herunterzuladen
+ LFS Objekte pullen
Push
- LFS Objekte pushen
Pushe große Dateien in der Warteschlange zum Git LFS Endpunkt
+ LFS Objekte pushen
Remote:
Verfolge alle '{0}' Dateien
Verfolge alle *{0} Dateien
@@ -364,10 +360,10 @@
Aktuelles Popup schließen
Klone neues Repository
Aktuellen Tab schließen
- Zum vorherigen Tab wechseln
Zum nächsten Tab wechseln
+ Zum vorherigen Tab wechseln
Neuen Tab erstellen
- Einstellungen öffnen
+ Einstellungen öffnen
REPOSITORY
Gestagte Änderungen committen
Gestagte Änderungen committen und pushen
@@ -376,11 +372,11 @@
Ausgewählte Änderungen verwerfen
Fetch, wird direkt ausgeführt
Dashboard Modus (Standard)
+ Commit-Suchmodus
Pull, wird direkt ausgeführt
Push, wird direkt ausgeführt
Erzwinge Neuladen des Repositorys
Ausgewählte Änderungen stagen/unstagen
- Commit-Suchmodus
Wechsle zu 'Änderungen'
Wechsle zu 'Verlauf'
Wechsle zu 'Stashes'
@@ -389,9 +385,9 @@
Suche nächste Übereinstimmung
Suche vorherige Übereinstimmung
Öffne Suchpanel
+ Verwerfen
Stagen
Unstagen
- Verwerfen
Initialisiere Repository
Pfad:
Cherry-Pick wird durchgeführt.
@@ -403,10 +399,10 @@
Revert wird durchgeführt.
Reverte commit
Interaktiver Rebase
- Ziel Branch:
Auf:
- In Browser öffnen
+ Ziel Branch:
Link kopieren
+ In Browser öffnen
FEHLER
INFO
Branch mergen
@@ -432,78 +428,81 @@
Kopiere Repository-Pfad
Repositories
Einfügen
- Gerade eben
- Vor {0} Minuten
- Vor {0} Stunden
- Gestern
Vor {0} Tagen
+ Vor 1 Stunde
+ Vor {0} Stunden
+ Gerade eben
Letzter Monat
- Vor {0} Monaten
Leztes Jahr
+ Vor {0} Minuten
+ Vor {0} Monaten
Vor {0} Jahren
- Einstellungen
- OPEN AI
- Analysierung des Diff Befehl
- API Schlüssel
- Generiere Nachricht Befehl
- Name
- Server
- Modell
- DARSTELLUNG
- Standardschriftart
- Schriftgröße
- Standard
- Texteditor
- Monospace-Schriftart
- Verwende die Monospace-Schriftart nur im Texteditor
- Design
- Design-Anpassungen
- Fixe Tab-Breite in Titelleiste
- Verwende nativen Fensterrahmen
- DIFF/MERGE TOOL
- Installationspfad
- Installationspfad zum Diff/Merge Tool
- Tool
- ALLGEMEIN
- Beim Starten nach Updates suchen
- Sprache
- Commit-Historie
- Zeige Autor Zeitpunkt anstatt Commit Zeitpunkt
- Zeige Nachfolger in den Commit Details
- Längenvorgabe für Commit-Nachrichten
- GIT
- Aktiviere Auto-CRLF
- Klon Standardordner
- Benutzer Email
- Globale Git Benutzer Email
- Installationspfad
- Benutzername
- Globaler Git Benutzername
- Git Version
- Diese App setzt Git (>= 2.23.0) voraus
- GPG SIGNIERUNG
- Commit-Signierung
- Tag-Signierung
- GPG Format
- GPG Installationspfad
- Installationspfad zum GPG Programm
- Benutzer Signierungsschlüssel
- GPG Benutzer Signierungsschlüssel
- EINBINDUNGEN
- SHELL/TERMINAL
- Shell/Terminal
- Pfad
+ Gestern
+ Einstellungen
+ OPEN AI
+ Analysierung des Diff Befehl
+ API Schlüssel
+ Generiere Nachricht Befehl
+ Modell
+ Name
+ Server
+ DARSTELLUNG
+ Standardschriftart
+ Schriftgröße
+ Standard
+ Texteditor
+ Monospace-Schriftart
+ Verwende die Monospace-Schriftart nur im Texteditor
+ Design
+ Design-Anpassungen
+ Fixe Tab-Breite in Titelleiste
+ Verwende nativen Fensterrahmen
+ DIFF/MERGE TOOL
+ Installationspfad
+ Installationspfad zum Diff/Merge Tool
+ Tool
+ ALLGEMEIN
+ Beim Starten nach Updates suchen
+ Datumsformat
+ Sprache
+ Commit-Historie
+ Zeige Autor Zeitpunkt anstatt Commit Zeitpunkt
+ Zeige Nachfolger in den Commit Details
+ Längenvorgabe für Commit-Nachrichten
+ GIT
+ Aktiviere Auto-CRLF
+ Klon Standardordner
+ Benutzer Email
+ Globale Git Benutzer Email
+ Aktivere --prune beim fetchen
+ Diese App setzt Git (>= 2.23.0) voraus
+ Installationspfad
+ Aktiviere HTTP SSL Verifizierung
+ Benutzername
+ Globaler Git Benutzername
+ Git Version
+ GPG SIGNIERUNG
+ Commit-Signierung
+ GPG Format
+ GPG Installationspfad
+ Installationspfad zum GPG Programm
+ Tag-Signierung
+ Benutzer Signierungsschlüssel
+ GPG Benutzer Signierungsschlüssel
+ EINBINDUNGEN
+ SHELL/TERMINAL
+ Pfad
+ Shell/Terminal
Remote löschen
Ziel:
Worktrees löschen
- Worktree Informationen in `$GIT_DIR/worktrees` löschen
+ Worktree Informationen in `$GIT_COMMON_DIR/worktrees` löschen
Pull
Remote-Branch:
Alle Branches fetchen
Lokaler Branch:
Lokale Änderungen:
Verwerfen
- Nichts tun
Stashen & wieder anwenden
Ohne Tags fetchen
Remote:
@@ -563,22 +562,29 @@
Aufheben
Im Graph ausblenden
Im Graph filtern
- Commit Zeitpunkt (--date-order)
- Topologie (--topo-order)
+ Aktiviere '--first-parent' Option
+ LAYOUT
+ Horizontal
+ Vertikal
+ COMMIT SORTIERUNG
+ Commit Zeitpunkt
+ Topologie
LOKALE BRANCHES
Zum HEAD wechseln
- Aktiviere '--first-parent' Option
Erstelle Branch
+ BENACHRICHTIGUNGEN LÖSCHEN
+ Nur aktuellen Branch im Graphen hervorheben
Öffne in {0}
Öffne in externen Tools
Aktualisiern
REMOTES
REMOTE HINZUFÜGEN
Commit suchen
+ Autor
+ Committer
Dateiname
Commit-Nachricht
SHA
- Autor & Committer
Aktueller Branch
Zeige Tags als Baum
ÜBERSPRINGEN
@@ -588,7 +594,12 @@
SUBMODUL AKTUALISIEREN
TAGS
NEUER TAG
+ Nach Erstellungsdatum
+ Nach Namen (Aufsteigend)
+ Nach Namen (Absteigend)
+ Sortiere
Öffne im Terminal
+ Verwende relative Zeitangaben in Verlauf
WORKTREES
WORKTREE HINZUFÜGEN
PRUNE
@@ -616,6 +627,10 @@
Diese Version überspringen
Software Update
Es sind momentan kein Updates verfügbar.
+ Setze verfolgten Branch
+ Branch:
+ Upstream Verfolgung aufheben
+ Upstream:
SHA kopieren
Zum Commit wechseln
Squash Commits
@@ -624,6 +639,8 @@
Pfad zum privaten SSH Schlüssel
START
Stash
+ Automatisch wiederherstellen nach dem Stashen
+ Die Arbeitsdateien bleiben unverändert, aber ein Stash wird gespeichert.
Inklusive nicht-verfolgter Dateien
Behalte gestagte Dateien
Name:
@@ -633,7 +650,6 @@
Lokale Änderungen stashen
Anwenden
Entfernen
- Anwenden und entfernen
Stash entfernen
Entfernen:
Stashes
@@ -642,11 +658,11 @@
Statistiken
COMMITS
COMMITTER
+ ÜBERSICHT
MONAT
WOCHE
- COMMITS:
AUTOREN:
- ÜBERSICHT
+ COMMITS:
SUBMODULE
Submodul hinzufügen
Relativen Pfad kopieren
@@ -661,13 +677,13 @@
Lösche ${0}$...
Merge ${0}$ in ${1}$ hinein...
Pushe ${0}$...
- URL:
Submodule aktualisieren
Alle Submodule
Initialisiere wenn nötig
Rekursiv
Submodul:
Verwende `--remote` Option
+ URL:
Warnung
Willkommensseite
Erstelle Gruppe
@@ -680,7 +696,7 @@
Öffne alle Repositories
Öffne Repository
Öffne Terminal
- Klon Standardordner erneut nach Repositories durchsuchen
+ Klon Standardordner erneut nach Repositories durchsuchen
Suche Repositories...
Sortieren
Änderungen
@@ -697,12 +713,13 @@
Klick-Ereignis auslösen
Commit (Bearbeitung)
Alle Änderungen stagen und committen
- Leerer Commit erkannt! Fortfahren (--allow-empty)?
KONFLIKTE ERKANNT
DATEI KONFLIKTE GELÖST
NICHT-VERFOLGTE DATEIEN INKLUDIEREN
KEINE BISHERIGEN COMMIT-NACHRICHTEN
KEINE COMMIT TEMPLATES
+ Rechtsklick auf selektierte Dateien und wähle die Konfliktlösungen aus.
+ SignOff
GESTAGED
UNSTAGEN
ALLES UNSTAGEN
@@ -711,7 +728,6 @@
ALLES STAGEN
ALS UNVERÄNDERT ANGENOMMENE ANZEIGEN
Template: ${0}$
- Rechtsklick auf selektierte Dateien und wähle die Konfliktlösungen aus.
ARBEITSPLATZ:
Arbeitsplätze konfigurieren...
WORKTREE
diff --git a/src/Resources/Locales/en_US.axaml b/src/Resources/Locales/en_US.axaml
index 218be9a3..94f8c938 100644
--- a/src/Resources/Locales/en_US.axaml
+++ b/src/Resources/Locales/en_US.axaml
@@ -1,12 +1,6 @@
About
About SourceGit
- • Build with
- • Chart is rendered by
- © 2024 sourcegit-scm
- • TextEditor from
- • Monospace fonts come from
- • Source code can be found at
Opensource & Free Git GUI Client
Add Worktree
What to Checkout:
@@ -19,21 +13,19 @@
Track Branch:
Tracking remote branch
AI Assistant
+ RE-GENERATE
Use AI to generate commit message
+ APPLY AS COMMIT MESSAGE
Patch
- Error
- Raise errors and refuses to apply the patch
- Error All
- Similar to 'error', but shows more
Patch File:
Select .patch file to apply
Ignore whitespace changes
- No Warn
- Turns off the trailing whitespace warning
Apply Patch
- Warn
- Outputs warnings for a few such errors, but applies
Whitespace:
+ Apply Stash
+ Delete after applying
+ Reinstate the index's changes
+ Stash:
Archive...
Save Archive To:
Select archive file path
@@ -47,10 +39,10 @@
Blame
BLAME ON THIS FILE IS NOT SUPPORTED!!!
Checkout ${0}$...
- Compare with Branch
Compare with HEAD
Compare with Worktree
Copy Branch Name
+ Custom Action
Delete ${0}$...
Delete selected {0} branches
Discard all changes
@@ -66,6 +58,7 @@
Rename ${0}$...
Set Tracking Branch...
Branch Compare
+ Invalid upstream!
Bytes
CANCEL
Reset to This Revision
@@ -82,7 +75,6 @@
Branch:
Local Changes:
Discard
- Do Nothing
Stash & Reapply
Cherry Pick
Append source to commit message
@@ -98,6 +90,7 @@
Local Name:
Repository name. Optional.
Parent Folder:
+ Initialize & update submodules
Repository URL:
CLOSE
Editor
@@ -147,20 +140,21 @@
Template Content:
CUSTOM ACTION
Arguments:
- ${REPO} - Repository's path; ${SHA} - Selected commit's SHA
+ ${REPO} - Repository's path; ${BRANCH} - Selected branch; ${SHA} - Selected commit's SHA
Executable File:
Name:
Scope:
+ Branch
Commit
Repository
+ Wait for action exit
Email Address
Email address
GIT
Fetch remotes automatically
Minute(s)
Default Remote
- Enable --prune on fetch
- Enable --signoff for commit
+ Preferred Merge Mode
ISSUE TRACKER
Add Sample Gitee Issue Rule
Add Sample Gitee Pull Request Rule
@@ -168,6 +162,7 @@
Add Sample GitLab Issue Rule
Add Sample GitLab Merge Request Rule
Add Sample Jira Rule
+ Add Sample Azure DevOps Rule
New Rule
Issue Regex Expression:
Rule Name:
@@ -183,6 +178,10 @@
Workspaces
Color
Restore tabs on startup
+ CONTINUE
+ Empty commit detected! Do you want to continue (--allow-empty)?
+ STAGE ALL & COMMIT
+ Empty commit detected! Do you want to continue (--allow-empty) or stage all then commit?
Conventional Commit Helper
Breaking Change:
Closed Issue:
@@ -193,16 +192,16 @@
Copy
Copy All Text
Copy Path
- Copy File Name
+ Copy Full Path
Create Branch...
Based On:
Check out the created branch
Local Changes:
Discard
- Do Nothing
Stash & Reapply
New Branch Name:
Enter branch name.
+ Spaces will be replaced with dashes.
Create Local Branch
Create Tag...
New Tag At:
@@ -226,8 +225,11 @@
You are trying to delete multiple branches at one time. Be sure to double-check before taking action!
Delete Remote
Remote:
+ Path:
Target:
+ All children will be removed from list.
Confirm Deleting Group
+ This will only remove it from list, not from disk!
Confirm Deleting Repository
Delete Submodule
Submodule Path:
@@ -239,7 +241,9 @@
OLD
Copy
File Mode Changed
+ First Difference
Ignore Whitespace Change
+ Last Difference
LFS OBJECT CHANGE
Next Difference
NO CHANGES OR ONLY EOL CHANGES
@@ -263,7 +267,7 @@
All local changes in working copy.
Changes:
Include ignored files
- Total {0} changes will be discard
+ {0} changes will be discarded
You can't undo this action!!!
Bookmark:
New Name:
@@ -275,7 +279,7 @@
Fast-Forward (without checkout)
Fetch
Fetch all remotes
- Override refs check
+ Force override local refs
Fetch without tags
Remote:
Fetch Remote Changes
@@ -367,7 +371,7 @@
Go to previous page
Go to next page
Create new page
- Open preference dialog
+ Open Preferences dialog
REPOSITORY
Commit staged changes
Commit and push staged changes
@@ -420,7 +424,7 @@
Move Repository Node
Select parent node for:
Name:
- Git has NOT been configured. Please to go [Preference] and configure it first.
+ Git has NOT been configured. Please to go [Preferences] and configure it first.
Open Data Storage Directory
Open with...
Optional.
@@ -434,6 +438,7 @@
Paste
Just now
{0} minutes ago
+ 1 hour ago
{0} hours ago
Yesterday
{0} days ago
@@ -441,71 +446,74 @@
{0} months ago
Last year
{0} years ago
- Preference
- AI
- Analyze Diff Prompt
- API Key
- Generate Subject Prompt
- Model
- Name
- Server
- APPEARANCE
- Default Font
- Font Size
- Default
- Editor
- Monospace Font
- Only use monospace font in text editor
- Theme
- Theme Overrides
- Use fixed tab width in titlebar
- Use native window frame
- DIFF/MERGE TOOL
- Install Path
- Input path for diff/merge tool
- Tool
- GENERAL
- Check for updates on startup
- Date Format
- Language
- History Commits
- Show author time instead of commit time in graph
- Show children in the commit details
- Subject Guide Length
- GIT
- Enable Auto CRLF
- Default Clone Dir
- User Email
- Global git user email
- Install Path
- Enable HTTP SSL Verify
- User Name
- Global git user name
- Git version
- Git (>= 2.23.0) is required by this app
- GPG SIGNING
- Commit GPG signing
- Tag GPG signing
- GPG Format
- Program Install Path
- Input path for installed gpg program
- User Signing Key
- User's gpg signing key
- INTEGRATION
- SHELL/TERMINAL
- Shell/Terminal
- Path
+ Preferences
+ AI
+ Analyze Diff Prompt
+ API Key
+ Generate Subject Prompt
+ Model
+ Name
+ Server
+ Enable Streaming
+ APPEARANCE
+ Default Font
+ Editor Tab Width
+ Font Size
+ Default
+ Editor
+ Monospace Font
+ Use monospace font only in text editor
+ Theme
+ Theme Overrides
+ Use fixed tab width in titlebar
+ Use native window frame
+ DIFF/MERGE TOOL
+ Install Path
+ Input path for diff/merge tool
+ Tool
+ GENERAL
+ Check for updates on startup
+ Date Format
+ Language
+ History Commits
+ Show author time instead of commit time in graph
+ Show children in the commit details
+ Show tags in commit graph
+ Subject Guide Length
+ GIT
+ Enable Auto CRLF
+ Default Clone Dir
+ User Email
+ Global git user email
+ Enable --prune on fetch
+ Install Path
+ Enable HTTP SSL Verify
+ User Name
+ Global git user name
+ Git version
+ Git (>= 2.23.0) is required by this app
+ GPG SIGNING
+ Commit GPG signing
+ Tag GPG signing
+ GPG Format
+ Program Install Path
+ Input path for installed gpg program
+ User Signing Key
+ User's gpg signing key
+ INTEGRATION
+ SHELL/TERMINAL
+ Shell/Terminal
+ Path
Prune Remote
Target:
Prune Worktrees
- Prune worktree information in `$GIT_DIR/worktrees`
+ Prune worktree information in `$GIT_COMMON_DIR/worktrees`
Pull
Remote Branch:
Fetch all branches
Into:
Local Changes:
Discard
- Do Nothing
Stash & Reapply
Fetch without tags
Remote:
@@ -565,16 +573,17 @@
Unset
Hide in commit graph
Filter in commit graph
+ Enable '--first-parent' Option
LAYOUT
Horizontal
Vertical
COMMITS ORDER
- Commit Date (--date-order)
- Topologically (--topo-order)
+ Commit Date
+ Topologically
LOCAL BRANCHES
Navigate to HEAD
- Enable '--first-parent' Option
Create Branch
+ CLEAR NOTIFICATIONS
Only highlight current branch in graph
Open in {0}
Open in External Tools
@@ -582,10 +591,11 @@
REMOTES
ADD REMOTE
Search Commit
+ Author
+ Committer
File
Message
SHA
- Author & Committer
Current Branch
Show Tags as Tree
SKIP
@@ -640,6 +650,8 @@
Private SSH key store path
START
Stash
+ Auto-restore after stashing
+ Your working files remain unchanged, but a stash is saved.
Include untracked files
Keep staged files
Message:
@@ -649,7 +661,7 @@
Stash Local Changes
Apply
Drop
- Pop
+ Save as Patch...
Drop Stash
Drop:
STASHES
@@ -713,12 +725,17 @@
Trigger click event
Commit (Edit)
Stage all changes and commit
- Empty commit detected! Do you want to continue (--allow-empty)?
+ You have staged {0} file(s) but only {1} file(s) displayed ({2} files are filtered out). Do you want to continue?
CONFLICTS DETECTED
+ OPEN EXTERNAL MERGETOOL
+ OPEN ALL CONFLICTS IN EXTERNAL MERGETOOL
FILE CONFLICTS ARE RESOLVED
+ USE MINE
+ USE THEIRS
INCLUDE UNTRACKED FILES
NO RECENT INPUT MESSAGES
NO COMMIT TEMPLATES
+ SignOff
STAGED
UNSTAGE
UNSTAGE ALL
diff --git a/src/Resources/Locales/es_ES.axaml b/src/Resources/Locales/es_ES.axaml
index 890ff563..e2af0860 100644
--- a/src/Resources/Locales/es_ES.axaml
+++ b/src/Resources/Locales/es_ES.axaml
@@ -2,41 +2,34 @@
+
Acerca de
Acerca de SourceGit
- • Construido con
- • El gráfico es renderizado por
- © 2024 sourcegit-scm
- • Editor de texto de
- • Las fuentes monoespaciadas provienen de
- • El código fuente se puede encontrar en
Cliente Git GUI de código abierto y gratuito
Agregar Worktree
- Qué Checkout:
- Rama Existente
- Crear Nueva Rama
Ubicación:
Ruta para este worktree. Se admite ruta relativa.
Nombre de la Rama:
Opcional. Por defecto es el nombre de la carpeta de destino.
Rama de Seguimiento:
Seguimiento de rama remota
+ Qué Checkout:
+ Crear Nueva Rama
+ Rama Existente
Asistente OpenAI
+ RE-GENERAR
Usar OpenAI para generar mensaje de commit
- Aplicar Patch
- Error
- Genera errores y se niega a aplicar el patch
- Error Todo
- Similar a 'error', pero muestra más
- Archivo Patch:
+ APLICAR CÓMO MENSAJE DE COMMIT
+ Aplicar Parche
+ Archivo del Parche:
Seleccionar archivo .patch para aplicar
Ignorar cambios de espacios en blanco
- Sin Advertencia
- Desactiva la advertencia de espacios en blanco al final
- Aplicar Patch
- Advertencia
- Genera advertencias para algunos de estos errores, pero aplica
+ Aplicar Parche
Espacios en Blanco:
+ Aplicar Stash
+ Borrar después de aplicar
+ Restaurar los cambios del índice
+ Stash:
Archivar...
Guardar Archivo en:
Seleccionar ruta del archivo
@@ -50,10 +43,10 @@
Blame
¡BLAME EN ESTE ARCHIVO NO SOPORTADO!
Checkout ${0}$...
- Comparar con Rama
Comparar con HEAD
Comparar con Worktree
Copiar Nombre de Rama
+ Acción personalizada
Eliminar ${0}$...
Eliminar {0} ramas seleccionadas
Descartar todos los cambios
@@ -69,10 +62,11 @@
Renombrar ${0}$...
Establecer Rama de Seguimiento...
Comparar Ramas
+ ¡Upstream inválido!
Bytes
CANCELAR
- Resetear a Esta Revisión
Resetear a Revisión Padre
+ Resetear a Esta Revisión
Generar mensaje de commit
CAMBIAR MODO DE VISUALIZACIÓN
Mostrar como Lista de Archivos y Directorios
@@ -80,13 +74,12 @@
Mostrar como Árbol de Sistema de Archivos
Checkout Rama
Checkout Commit
- Advertencia: Al hacer un checkout de commit, tu Head se separará
Commit:
- Rama:
+ Advertencia: Al hacer un checkout de commit, tu Head se separará
Cambios Locales:
Descartar
- No Hacer Nada
Stash & Reaplicar
+ Rama:
Cherry Pick
Añadir fuente al mensaje de commit
Commit(s):
@@ -101,12 +94,13 @@
Nombre Local:
Nombre del repositorio. Opcional.
Carpeta Padre:
+ Inicializar y actualizar submodulos
URL del Repositorio:
CERRAR
Editor
+ Checkout Commit
Cherry-Pick Este Commit
Cherry-Pick ...
- Checkout Commit
Comparar con HEAD
Comparar con Worktree
Copiar Información
@@ -119,7 +113,7 @@
Reset ${0}$ hasta Aquí
Revertir Commit
Reescribir
- Guardar como Patch...
+ Guardar como Parche...
Squash en Parent
Squash Commits Hijos hasta Aquí
CAMBIOS
@@ -141,35 +135,36 @@
REFS
SHA
Abrir en Navegador
- Introducir asunto del commit
Descripción
+ Introducir asunto del commit
Configurar Repositorio
PLANTILLA DE COMMIT
- Nombre de la Plantilla:
Contenido de la Plantilla:
+ Nombre de la Plantilla:
ACCIÓN PERSONALIZADA
Argumentos:
${REPO} - Ruta del repositorio; ${SHA} - SHA del commit seleccionado
Archivo Ejecutable:
Nombre:
Alcance:
+ Rama
Commit
Repositorio
+ Esperar la acción de salida
Dirección de Email
Dirección de email
GIT
Fetch remotos automáticamente
Minuto(s)
Remoto por Defecto
- Habilitar --prune para fetch
- Habilitar --signoff para commit
SEGUIMIENTO DE INCIDENCIAS
+ Añadir Regla de Ejemplo para Azure DevOps
Añadir Regla de Ejemplo para Incidencias de Gitee
Añadir Regla de Ejemplo para Pull Requests de Gitee
Añadir Regla de Ejemplo para Github
- Añadir Regla de Ejemplo para Jira
Añadir Regla de Ejemplo para Incidencias de GitLab
Añadir Regla de Ejemplo para Merge Requests de GitLab
+ Añadir Regla de Ejemplo para Jira
Nueva Regla
Expresión Regex para Incidencias:
Nombre de la Regla:
@@ -194,17 +189,17 @@
Tipo de Cambio:
Copiar
Copiar Todo el Texto
+ Copiar Ruta Completa
Copiar Ruta
- Copiar Nombre del Archivo
Crear Rama...
Basado En:
Checkout de la rama creada
Cambios Locales:
Descartar
- No Hacer Nada
Stash & Reaplicar
Nombre de la Nueva Rama:
Introduzca el nombre de la rama.
+ Los espacios serán reemplazados con guiones.
Crear Rama Local
Crear Etiqueta...
Nueva Etiqueta En:
@@ -228,7 +223,10 @@
Estás intentando eliminar múltiples ramas a la vez. ¡Asegúrate de revisar antes de tomar acción!
Eliminar Remoto
Remoto:
+ Ruta:
Destino:
+ Todos los hijos serán removidos de la lista.
+ ¡Esto solo lo removera de la lista, no del disco!
Confirmar Eliminación de Grupo
Confirmar Eliminación de Repositorio
Eliminar Submódulo
@@ -241,12 +239,14 @@
ANTIGUO
Copiar
Modo de Archivo Cambiado
+ Primera Diferencia
Ignorar Cambio de Espacios en Blanco
+ Última Diferencia
CAMBIO DE OBJETO LFS
Siguiente Diferencia
SIN CAMBIOS O SOLO CAMBIOS DE EOL
Diferencia Anterior
- Guardar como Patch
+ Guardar como Parche
Mostrar símbolos ocultos
Diferencia Lado a Lado
SUBMÓDULO
@@ -287,7 +287,7 @@
Descartar Cambios en Línea(s) Seleccionada(s)
Abrir Herramienta de Merge Externa
Resolver usando ${0}$
- Guardar Como Patch...
+ Guardar como Parche...
Stage
Stage {0} archivos
Stage Cambios en Línea(s) Seleccionada(s)
@@ -296,11 +296,11 @@
Unstage
Unstage {0} archivos
Unstage Cambios en Línea(s) Seleccionada(s)
- Usar Suyos (checkout --theirs)
Usar Míos (checkout --ours)
+ Usar Suyos (checkout --theirs)
Historial de Archivos
- CONTENIDO
CAMBIO
+ CONTENIDO
Git-Flow
Rama de Desarrollo:
Feature:
@@ -330,8 +330,8 @@
Patrón Personalizado:
Añadir Patrón de Seguimiento a Git LFS
Fetch
- Fetch Objetos LFS
Ejecuta `git lfs fetch` para descargar objetos Git LFS. Esto no actualiza la copia de trabajo.
+ Fetch Objetos LFS
Instalar hooks de Git LFS
Mostrar Bloqueos
No hay archivos bloqueados
@@ -343,11 +343,11 @@
Prune
Ejecuta `git lfs prune` para eliminar archivos LFS antiguos del almacenamiento local
Pull
- Pull Objetos LFS
Ejecuta `git lfs pull` para descargar todos los archivos Git LFS para la referencia actual y hacer checkout
+ Pull Objetos LFS
Push
- Push Objetos LFS
Push archivos grandes en cola al endpoint de Git LFS
+ Push Objetos LFS
Remoto:
Seguir archivos llamados '{0}'
Seguir todos los archivos *{0}
@@ -366,10 +366,10 @@
Cancelar popup actual
Clonar repositorio nuevo
Cerrar página actual
- Ir a la página anterior
Ir a la siguiente página
+ Ir a la página anterior
Crear nueva página
- Abrir diálogo de preferencias
+ Abrir diálogo de preferencias
REPOSITORIO
Commit cambios staged
Commit y push cambios staged
@@ -378,11 +378,11 @@
Descartar cambios seleccionados
Fetch, empieza directamente
Modo Dashboard (Por Defecto)
+ Modo de búsqueda de commits
Pull, empieza directamente
Push, empieza directamente
Forzar a recargar este repositorio
Stage/Unstage cambios seleccionados
- Modo de búsqueda de commits
Cambiar a 'Cambios'
Cambiar a 'Historias'
Cambiar a 'Stashes'
@@ -391,9 +391,9 @@
Buscar siguiente coincidencia
Buscar coincidencia anterior
Abrir panel de búsqueda
+ Descartar
Stage
Unstage
- Descartar
Inicializar Repositorio
Ruta:
Cherry-Pick en progreso.
@@ -405,10 +405,10 @@
Revert en progreso.
Haciendo revert del commit
Rebase Interactivo
- Rama Objetivo:
En:
- Abrir en el Navegador
+ Rama Objetivo:
Copiar Enlace
+ Abrir en el Navegador
ERROR
AVISO
Merge Rama
@@ -434,81 +434,85 @@
Copiar Ruta del Repositorio
Repositorios
Pegar
- Justo ahora
- Hace {0} minutos
- Hace {0} horas
- Ayer
Hace {0} días
+ Hace 1 hora
+ Hace {0} horas
+ Justo ahora
Último mes
- Hace {0} meses
Último año
+ Hace {0} minutos
+ Hace {0} meses
Hace {0} años
- Preferencias
- Opciones Avanzadas
- OPEN AI
- Analizar Diff Prompt
- Clave API
- Generar Subject Prompt
- Modelo
- Nombre
- Servidor
- APARIENCIA
- Fuente por defecto
- Tamaño de fuente
- Por defecto
- Editor
- Fuente Monospace
- Usar solo fuente monospace en el editor de texto
- Tema
- Sobreescritura de temas
- Usar ancho de pestaña fijo en la barra de título
- Usar marco de ventana nativo
- HERRAMIENTA DIFF/MERGE
- Ruta de instalación
- Introducir ruta para la herramienta diff/merge
- Herramienta
- GENERAL
- Buscar actualizaciones al iniciar
- Formato de Fecha
- Idioma
- Commits en el historial
- Mostrar hora del autor en lugar de la hora del commit en el gráfico
- Mostrar hijos en los detalles de commit
- Longitud de la guía del asunto
- GIT
- Habilitar Auto CRLF
- Directorio de clonado por defecto
- Email de usuario
- Email global del usuario git
- Ruta de instalación
- Habilitar verificación HTTP SSL
- Nombre de usuario
- Nombre global del usuario git
- Versión de Git
- Se requiere Git (>= 2.23.0) para esta aplicación
- FIRMA GPG
- Firma GPG en commit
- Firma GPG en etiqueta
- Formato GPG
- Ruta de instalación del programa
- Introducir ruta para el programa gpg instalado
- Clave de firma del usuario
- Clave de firma gpg del usuario
- INTEGRACIÓN
- SHELL/TERMINAL
- Shell/Terminal
- Ruta
+ Ayer
+ Preferencias
+ Opciones Avanzadas
+ OPEN AI
+ Analizar Diff Prompt
+ Clave API
+ Generar Subject Prompt
+ Modelo
+ Nombre
+ Servidor
+ Activar Transmisión
+ APARIENCIA
+ Fuente por defecto
+ Ancho de la Pestaña del Editor
+ Tamaño de fuente
+ Por defecto
+ Editor
+ Fuente Monospace
+ Usar solo fuente monospace en el editor de texto
+ Tema
+ Sobreescritura de temas
+ Usar ancho de pestaña fijo en la barra de título
+ Usar marco de ventana nativo
+ HERRAMIENTA DIFF/MERGE
+ Ruta de instalación
+ Introducir ruta para la herramienta diff/merge
+ Herramienta
+ GENERAL
+ Buscar actualizaciones al iniciar
+ Formato de Fecha
+ Idioma
+ Commits en el historial
+ Mostrar hora del autor en lugar de la hora del commit en el gráfico
+ Mostrar hijos en los detalles de commit
+ Mostrar etiquetas en el gráfico de commit
+ Longitud de la guía del asunto
+ GIT
+ Habilitar Auto CRLF
+ Directorio de clonado por defecto
+ Email de usuario
+ Email global del usuario git
+ Habilitar --prune para fetch
+ Se requiere Git (>= 2.23.0) para esta aplicación
+ Ruta de instalación
+ Habilitar verificación HTTP SSL
+ Nombre de usuario
+ Nombre global del usuario git
+ Versión de Git
+ FIRMA GPG
+ Firma GPG en commit
+ Formato GPG
+ Ruta de instalación del programa
+ Introducir ruta para el programa gpg instalado
+ Firma GPG en etiqueta
+ Clave de firma del usuario
+ Clave de firma gpg del usuario
+ INTEGRACIÓN
+ SHELL/TERMINAL
+ Ruta
+ Shell/Terminal
Podar Remoto
Destino:
Podar Worktrees
- Podar información de worktree en `$GIT_DIR/worktrees`
+ Podar información de worktree en `$GIT_COMMON_DIR/worktrees`
Pull
Rama Remota:
Fetch todas las ramas
En:
Cambios Locales:
Descartar
- No Hacer Nada
Stash & Reaplicar
Fetch sin etiquetas
Remoto:
@@ -568,16 +572,17 @@
Desestablecer
Ocultar en el Gráfico de Commits
Filtrar en el Gráfico de Commits
+ Habilitar Opción '--first-parent'
DISPOSICIÓN
Horizontal
Vertical
ORDEN DE COMMITS
- Fecha de Commit (--date-order)
- Topológicamente (--topo-order)
+ Fecha de Commit
+ Topológicamente
RAMAS LOCALES
Navegar a HEAD
- Habilitar Opción '--first-parent'
Crear Rama
+ LIMPIAR NOTIFICACIONES
Resaltar solo la rama actual en el gráfico
Abrir en {0}
Abrir en Herramientas Externas
@@ -585,10 +590,11 @@
REMOTOS
AÑADIR REMOTO
Buscar Commit
+ Autor
+ Committer
Archivo
Mensaje
SHA
- Autor & Committer
Rama Actual
Mostrar Etiquetas como Árbol
OMITIR
@@ -601,7 +607,7 @@
Por Fecha de Creación
Por Nombre (Ascendiente)
Por Nombre (Descendiente)
- Sort
+ Ordenar
Abrir en Terminal
Usar tiempo relativo en las historias
WORKTREES
@@ -621,7 +627,7 @@
Ejecutando. Por favor espera...
GUARDAR
Guardar Como...
- ¡El patch se ha guardado exitosamente!
+ ¡El parche se ha guardado exitosamente!
Escanear Repositorios
Directorio Raíz:
Buscar Actualizaciones...
@@ -643,6 +649,8 @@
Ruta de almacenamiento de la clave privada SSH
INICIAR
Stash
+ Restaurar automáticamente después del stashing
+ Tus archivos de trabajo permanecen sin cambios, pero se guarda un stash.
Incluir archivos no rastreados
Mantener archivos staged
Mensaje:
@@ -652,7 +660,7 @@
Stash Cambios Locales
Aplicar
Eliminar
- Pop
+ Guardar como Parche...
Eliminar Stash
Eliminar:
Stashes
@@ -661,11 +669,11 @@
Estadísticas
COMMITS
COMMITTER
+ GENERAL
MES
SEMANA
- COMMITS:
AUTORES:
- GENERAL
+ COMMITS:
SUBMÓDULOS
Añadir Submódulo
Copiar Ruta Relativa
@@ -680,13 +688,13 @@
Eliminar ${0}$...
Merge ${0}$ en ${1}$...
Push ${0}$...
- URL:
Actualizar Submódulos
Todos los submódulos
Inicializar según sea necesario
Recursivamente
Submódulo:
Usar opción --remote
+ URL:
Advertencia
Página de Bienvenida
Crear Grupo
@@ -708,7 +716,7 @@
Ignorar archivos *{0} en la misma carpeta
Ignorar archivos en la misma carpeta
Ignorar solo este archivo
- Enmendar (Amend)
+ Enmendar
Puedes stagear este archivo ahora.
COMMIT
COMMIT & PUSH
@@ -716,12 +724,13 @@
Activar evento de clic
Commit (Editar)
Stagear todos los cambios y commit
- ¡Commit vacío detectado! ¿Quieres continuar (--allow-empty)?
CONFLICTOS DETECTADOS
LOS CONFLICTOS DE ARCHIVOS ESTÁN RESUELTOS
INCLUIR ARCHIVOS NO RASTREADOS
NO HAY MENSAJES DE ENTRADA RECIENTES
NO HAY PLANTILLAS DE COMMIT
+ Haz clic derecho en el(los) archivo(s) seleccionado(s) y elige tu opción para resolver conflictos.
+ Firmar
STAGED
UNSTAGE
UNSTAGE TODO
@@ -730,7 +739,6 @@
STAGE TODO
VER ASSUME UNCHANGED
Plantilla: ${0}$
- Haz clic derecho en el(los) archivo(s) seleccionado(s) y elige tu opción para resolver conflictos.
ESPACIO DE TRABAJO:
Configura Espacios de Trabajo...
WORKTREE
diff --git a/src/Resources/Locales/fr_FR.axaml b/src/Resources/Locales/fr_FR.axaml
index 12b08d08..83d590f5 100644
--- a/src/Resources/Locales/fr_FR.axaml
+++ b/src/Resources/Locales/fr_FR.axaml
@@ -2,41 +2,34 @@
+
À propos
À propos de SourceGit
- • Compilé avec
- • Le graphique est rendu par
- © 2024 sourcegit-scm
- • TextEditor de
- • Les polices Monospace proviennent de
- • Le code source est disponible sur
Client Git Open Source et Gratuit
Ajouter un Worktree
- Que récupérer :
- Créer une nouvelle branche
- Branche existante
Emplacement :
Chemin vers ce worktree. Relatif supporté.
Nom de branche:
Optionnel. Nom du dossier de destination par défaut.
Suivre la branche :
Suivi de la branche distante
+ Que récupérer :
+ Créer une nouvelle branche
+ Branche existante
Assistant IA
+ RE-GÉNÉRER
Utiliser l'IA pour générer un message de commit
+ APPLIQUER COMME MESSAGE DE COMMIT
Appliquer
- Erreur
- Soulever les erreurs et refuser d'appliquer le patch
- Toutes les erreurs
- Similaire à 'Erreur', mais plus détaillé
Fichier de patch :
Selectionner le fichier .patch à appliquer
Ignorer les changements d'espaces blancs
- Pas d'avertissement
- Désactiver l'avertissement sur les espaces blancs terminaux
Appliquer le patch
- Avertissement
- Affiche des avertissements pour ce type d'erreurs tout en appliquant le patch
Espaces blancs :
+ Appliquer le Stash
+ Supprimer après application
+ Rétablir les changements de l'index
+ Stash:
Archiver...
Enregistrer l'archive sous :
Sélectionnez le chemin du fichier d'archive
@@ -50,10 +43,10 @@
Blâme
LE BLÂME SUR CE FICHIER N'EST PAS SUPPORTÉ!!!
Récupérer ${0}$...
- Comparer avec la branche
Comparer avec HEAD
Comparer avec le worktree
Copier le nom de la branche
+ Action personnalisée
Supprimer ${0}$...
Supprimer {0} branches sélectionnées
Rejeter tous les changements
@@ -61,6 +54,7 @@
Fetch ${0}$ vers ${1}$...
Git Flow - Terminer ${0}$
Fusionner ${0}$ dans ${1}$...
+ Fusionner les {0} branches sélectionnées dans celle en cours
Tirer ${0}$
Tirer ${0}$ dans ${1}$...
Pousser ${0}$
@@ -68,6 +62,7 @@
Renommer ${0}$...
Définir la branche de suivi...
Comparer les branches
+ Branche en amont invalide!
Octets
ANNULER
Réinitialiser à la révision parente
@@ -81,15 +76,16 @@
Récupérer ce commit
Commit :
Avertissement: une récupération vers un commit aboutiera vers un HEAD détaché
- Branche :
Changements locaux :
Annuler
- Ne rien faire
Mettre en stash et réappliquer
+ Branche :
Cherry-Pick de ce commit
+ Ajouter la source au message de commit
Commit :
Commit tous les changements
Ligne principale :
+ Habituellement, on ne peut pas cherry-pick un commit car on ne sait pas quel côté devrait être considéré comme principal. Cette option permet de rejouer les changements relatifs au parent spécifié.
Cherry Pick
Supprimer les stashes
Vous essayez de supprimer tous les stashes. Êtes-vous sûr de vouloir continuer ?
@@ -99,17 +95,21 @@
Nom local :
Nom de dépôt. Optionnel.
Dossier parent :
+ Initialiser et mettre à jour les sous-modules
URL du dépôt :
FERMER
Éditeur
Récupérer ce commit
Cherry-Pick ce commit
+ Cherry-Pick ...
Comparer avec HEAD
Comparer avec le worktree
Copier les informations
Copier le SHA
Action personnalisée
Rebase interactif de ${0}$ ici
+ Fusionner dans ${0}$
+ Fusionner ...
Rebaser ${0}$ ici
Réinitialiser ${0}$ ici
Annuler le commit
@@ -121,6 +121,7 @@
Rechercher les changements...
FICHIERS
Fichier LFS
+ Rechercher des fichiers...
Sous-module
INFORMATIONS
AUTEUR
@@ -135,33 +136,36 @@
REFS
SHA
Ouvrir dans le navigateur
- Entrez le message du commit
Description
+ Entrez le message du commit
Configurer le dépôt
MODÈLE DE COMMIT
- Nom de modèle:
Contenu de modèle:
+ Nom de modèle:
ACTION PERSONNALISÉE
Arguments :
${REPO} - Chemin du repository; ${SHA} - SHA du commit sélectionné
Fichier exécutable :
Nom :
Portée :
+ Branche
Commit
Repository
+ Attendre la fin de l'action
Adresse e-mail
Adresse e-mail
GIT
Fetch les dépôts distants automatiquement
minute(s)
Dépôt par défaut
- Activer --prune pour fetch
- Activer --signoff pour commit
SUIVI DES PROBLÈMES
+ Ajouter une règle d'exemple Azure DevOps
+ Ajouter une règle d'exemple Gitee
+ Ajouter une règle d'exemple pour Pull Request Gitee
Ajouter une règle d'exemple Github
- Ajouter une règle d'exemple Jira
Ajouter une règle d'exemple pour Incidents GitLab
Ajouter une règle d'exemple pour Merge Request GitLab
+ Ajouter une règle d'exemple Jira
Nouvelle règle
Issue Regex Expression:
Nom de règle :
@@ -186,17 +190,17 @@
Type de Changement :
Copier
Copier tout le texte
- Copier le nom de fichier
+ Copier le chemin complet
Copier le chemin
Créer une branche...
Basé sur :
Récupérer la branche créée
Changements locaux :
Rejeter
- Ne rien faire
Stash & Réappliquer
Nom de la nouvelle branche :
Entrez le nom de la branche.
+ Les espaces seront remplacés par des tirets.
Créer une branche locale
Créer un tag...
Nouveau tag à :
@@ -220,7 +224,10 @@
Vous essayez de supprimer plusieurs branches à la fois. Assurez-vous de revérifier avant de procéder !
Supprimer Remote
Remote :
+ Chemin:
Cible :
+ Tous les enfants seront retirés de la liste.
+ Cela le supprimera uniquement de la liste, pas du disque !
Confirmer la suppression du groupe
Confirmer la suppression du dépôt
Supprimer le sous-module
@@ -233,7 +240,9 @@
ANCIEN
Copier
Mode de fichier changé
+ Première différence
Ignorer les changements d'espaces
+ Dernière différence
CHANGEMENT D'OBJET LFS
Différence suivante
PAS DE CHANGEMENT OU SEULEMENT EN FIN DE LIGNE
@@ -246,6 +255,7 @@
Permuter
Coloration syntaxique
Retour à la ligne
+ Activer la navigation par blocs
Ouvrir dans l'outil de fusion
Voir toutes les lignes
Réduit le nombre de ligne visibles
@@ -268,6 +278,7 @@
Fast-Forward (sans récupération)
Fetch
Fetch toutes les branches distantes
+ Outrepasser les vérifications de refs
Fetch sans les tags
Remote :
Récupérer les changements distants
@@ -276,6 +287,7 @@
Rejeter {0} fichiers...
Rejeter les changements dans les lignes sélectionnées
Ouvrir l'outil de fusion externe
+ Résoudre en utilisant ${0}$
Enregistrer en tant que patch...
Indexer
Indexer {0} fichiers
@@ -288,8 +300,8 @@
Utiliser les miennes (checkout --ours)
Utiliser les leurs (checkout --theirs)
Historique du fichier
- CONTENU
MODIFICATION
+ CONTENU
Git-Flow
Branche de développement :
Feature:
@@ -319,8 +331,8 @@
Pattern personnalisé :
Ajouter un pattern de suivi à Git LFS
Fetch
- Fetch les objets LFS
Lancer `git lfs fetch` pour télécharger les objets Git LFS. Cela ne met pas à jour la copie de travail.
+ Fetch les objets LFS
Installer les hooks Git LFS
Afficher les verrous
Pas de fichiers verrouillés
@@ -329,14 +341,14 @@
Verrous LFS
Déverouiller
Forcer le déverouillage
- Prune
+ Elaguer
Lancer `git lfs prune` pour supprimer les anciens fichier LFS du stockage local
Pull
- Pull les objets LFS
Lancer `git lfs pull` pour télécharger tous les fichier Git LFS de la référence actuelle & récupérer
+ Pull les objets LFS
Pousser
- Pousser les objets LFS
Transférer les fichiers volumineux en file d'attente vers le point de terminaison Git LFS
+ Pousser les objets LFS
Dépôt :
Suivre les fichiers appelés '{0}'
Suivre tous les fichiers *{0}
@@ -353,11 +365,12 @@
Référence des raccourcis clavier
GLOBAL
Annuler le popup en cours
+ Cloner un nouveau dépôt
Fermer la page en cours
- Aller à la page précédente
Aller à la page suivante
+ Aller à la page précédente
Créer une nouvelle page
- Ouvrir le dialogue des préférences
+ Ouvrir le dialogue des préférences
DÉPÔT
Commit les changements de l'index
Commit et pousser les changements de l'index
@@ -366,11 +379,11 @@
Rejeter les changements sélectionnés
Fetch, démarre directement
Mode tableau de bord (Défaut)
+ Recherche de commit
Pull, démarre directement
Push, démarre directement
Forcer le rechargement du dépôt
Ajouter/Retirer les changements sélectionnés de l'index
- Recherche de commit
Basculer vers 'Changements'
Basculer vers 'Historique'
Basculer vers 'Stashes'
@@ -379,25 +392,34 @@
Trouver la prochaine correspondance
Trouver la correspondance précédente
Ouvrir le panneau de recherche
+ Rejeter
Indexer
Retirer de l'index
- Rejeter
Initialiser le repository
Chemin :
Cherry-Pick en cours.
+ Traitement du commit
Merge request en cours.
+ Fusionnement
Rebase en cours.
+ Arrêté à
Annulation en cours.
+ Annulation du commit
Rebase interactif
- Branche cible :
Sur :
- Ouvrir dans le navigateur
+ Branche cible :
Copier le lien
+ Ouvrir dans le navigateur
ERREUR
NOTICE
Merger la branche
Dans :
Option de merge:
+ Source:
+ Fusionner (Plusieurs)
+ Commit tous les changement
+ Stratégie:
+ Cibles:
Déplacer le noeud du repository
Sélectionnier le noeud parent pour :
Nom :
@@ -413,76 +435,86 @@
Copier le chemin vers le dépôt
Dépôts
Coller
- A l'instant
- il y a {0} minutes
- il y a {0} heures
- Hier
il y a {0} jours
+ il y a 1 heure
+ il y a {0} heures
+ A l'instant
Le mois dernier
- il y a {0} mois
L'an dernier
+ il y a {0} minutes
+ il y a {0} mois
il y a {0} ans
- Préférences
- IA
- Analyser Diff Prompt
- Clé d'API
- Générer le sujet de Prompt
- Modèle
- Nom
- Serveur
- APPARENCE
- Police par défaut
- Taille de police par défaut
- Taille de police de l'éditeur
- Police monospace
- N'utiliser que des polices monospace pour l'éditeur de texte
- Thème
- Dérogations de thème
- Utiliser des onglets de taille fixe dans la barre de titre
- Utiliser un cadre de fenêtre natif
- OUTIL DIFF/MERGE
- Chemin d'installation
- Saisir le chemin d'installation de l'outil diff/merge
- Outil
- GÉNÉRAL
- Vérifier les mises à jour au démarrage
- Language
- Historique de commits
- Afficher l'heure de l'auteur au lieu de l'heure de validation dans le graphique
- Guide de longueur du sujet
- GIT
- Activer auto CRLF
- Répertoire de clônage par défaut
- E-mail utilsateur
- E-mail utilsateur global
- Chemin d'installation
- Nom d'utilisateur
- Nom d'utilisateur global
- Version de Git
- Cette application requière Git (>= 2.23.0)
- SIGNATURE GPG
- Signature GPG de commit
- Signature GPG de tag
- Format GPG
- Chemin d'installation du programme
- Saisir le chemin d'installation vers le programme GPG
- Clé de signature de l'utilisateur
- Clé de signature GPG de l'utilisateur
- INTEGRATION
- SHELL/TERMINAL
- Shell/Terminal
- Chemin
- Élaguer une branche distant
+ Hier
+ Préférences
+ IA
+ Analyser Diff Prompt
+ Clé d'API
+ Générer le sujet de Prompt
+ Modèle
+ Nom
+ Serveur
+ Activer le streaming
+ APPARENCE
+ Police par défaut
+ Taille de police par défaut
+ Taille de police de l'éditeur
+ Largeur de tab dans l'éditeur
+ Taille de police
+ Défaut
+ Éditeur
+ Police monospace
+ N'utiliser que des polices monospace pour l'éditeur de texte
+ Thème
+ Dérogations de thème
+ Utiliser des onglets de taille fixe dans la barre de titre
+ Utiliser un cadre de fenêtre natif
+ OUTIL DIFF/MERGE
+ Chemin d'installation
+ Saisir le chemin d'installation de l'outil diff/merge
+ Outil
+ GÉNÉRAL
+ Vérifier les mises à jour au démarrage
+ Format de date
+ Language
+ Historique de commits
+ Afficher l'heure de l'auteur au lieu de l'heure de validation dans le graphique
+ Afficher les enfants dans les détails du commit
+ Afficher les tags dans le graphique des commits
+ Guide de longueur du sujet
+ GIT
+ Activer auto CRLF
+ Répertoire de clônage par défaut
+ E-mail utilsateur
+ E-mail utilsateur global
+ Activer --prune pour fetch
+ Cette application requière Git (>= 2.23.0)
+ Chemin d'installation
+ Activer la vérification HTTP SSL
+ Nom d'utilisateur
+ Nom d'utilisateur global
+ Version de Git
+ SIGNATURE GPG
+ Signature GPG de commit
+ Format GPG
+ Chemin d'installation du programme
+ Saisir le chemin d'installation vers le programme GPG
+ Signature GPG de tag
+ Clé de signature de l'utilisateur
+ Clé de signature GPG de l'utilisateur
+ INTEGRATION
+ SHELL/TERMINAL
+ Chemin
+ Shell/Terminal
+ Élaguer une branche distant
Cible :
Élaguer les Worktrees
- Élaguer les information de worktree dans `$GIT_DIR/worktrees`
+ Élaguer les information de worktree dans `$GIT_COMMON_DIR/worktrees`
Pull
Branche distante :
Fetch toutes les branches
Dans :
Changements locaux :
Rejeter
- Ne rien faire
Stash & Réappliquer
Fetch sans les tags
Dépôt distant :
@@ -518,7 +550,7 @@
Editer...
Fetch
Ouvrir dans le navigateur
- Prune
+ Elaguer
Confirmer la suppression du Worktree
Activer l'option `--force`
Cible :
@@ -528,41 +560,61 @@
Branche :
ABORT
Fetch automatique des changements depuis les dépôts...
- Nettoyage(GC & Prune)
+ Nettoyage(GC & Elaguage)
Lancer `git gc` pour ce repository.
Tout effacer
Configurer ce repository
CONTINUER
+ Actions personnalisées
Pas d'actions personnalisées
Activer l'option '--reflog'
Ouvrir dans l'explorateur de fichiers
Rechercher Branches/Tags/Submodules
+ Visibilité dans le graphique
+ Réinitialiser
+ Cacher dans le graphique des commits
+ Filtrer dans le graphique des commits
+ Activer l'option '--first-parent'
+ DISPOSITION
+ Horizontal
+ Vertical
+ ORDRE DES COMMITS
+ Date du commit
+ Topologiquement
BRANCHES LOCALES
Naviguer vers le HEAD
- Activer l'option '--first-parent'
Créer une branche
+ EFFACER LES NOTIFICATIONS
+ Mettre la branche courante en surbrillance dans le graph
Ouvrir dans {0}
Ouvrir dans un outil externe
Rafraîchir
DEPOTS DISTANTS
AJOUTER DEPOT DISTANT
Rechercher un commit
+ Auteur
+ Committer
Fichier
Message
SHA
- Auteur & Committer
Branche actuelle
Voir les Tags en tant qu'arbre
+ PASSER
Statistiques
SUBMODULES
AJOUTER SUBMODULE
METTRE A JOUR SUBMODULE
TAGS
NOUVEAU TAG
+ Par date de créateur
+ Par nom (Croissant)
+ Par nom (Décroissant)
+ Trier
Ouvrir dans un terminal
+ Utiliser le temps relatif dans les historiques
WORKTREES
AJOUTER WORKTREE
- PRUNE
+ ELAGUER
URL du repository Git
Reset branche actuelle à la révision
Reset Mode:
@@ -578,6 +630,7 @@
SAUVEGARDER
Sauvegarder en tant que...
Le patch a été sauvegardé !
+ Analyser les repositories
Dossier racine :
Rechercher des mises à jour...
Une nouvelle version du logiciel est disponible :
@@ -586,13 +639,20 @@
Passer cette version
Mise à jour du logiciel
Il n'y a pas de mise à jour pour le moment.
+ Définir la branche suivie
+ Branche:
+ Retirer la branche amont
+ En amont:
Copier le SHA
- Squash Commits
+ Aller à
+ Squash les commits
Dans :
Clé privée SSH :
Chemin du magasin de clés privées SSH
START
Stash
+ Auto-restauration après le stash
+ Vos fichiers de travail restent inchangés, mais une sauvegarde est enregistrée.
Inclure les fichiers non-suivis
Garder les fichiers indexés
Message :
@@ -602,7 +662,7 @@
Stash les changements locaux
Appliquer
Effacer
- Extraire
+ Sauver comme Patch...
Effacer le Stash
Effacer :
Stashes
@@ -611,11 +671,11 @@
Statistiques
COMMITS
COMMITTER
+ APERCU
MOIS
SEMAINE
- COMMITS:
AUTEURS :
- APERCU
+ COMMITS:
SOUS-MODULES
Ajouter un sous-module
Copier le chemin relatif
@@ -630,13 +690,13 @@
Supprimer ${0}$...
Fusionner ${0}$ dans ${1}$...
Pousser ${0}$...
- URL :
Actualiser les sous-modules
Tous les sous-modules
Initialiser au besoin
Récursivement
Sous-module :
Utiliser l'option --remote
+ URL :
Avertissement
Page d'accueil
Créer un groupe
@@ -664,13 +724,15 @@
COMMIT & POUSSER
Modèles/Historiques
Trigger click event
+ Commit (Modifier)
Indexer tous les changements et commit
- Un commit vide a été détecté ! Voulez-vous continuer (--allow-empty) ?
CONFLITS DÉTECTÉS
LES CONFLITS DE FICHIER SONT RÉSOLUS
INCLURE LES FICHIERS NON-SUIVIS
PAS DE MESSAGE D'ENTRÉE RÉCENT
PAS DE MODÈLES DE COMMIT
+ Faites un clique droit sur les fichiers sélectionnés et faites vos choix pour la résoluion des conflits.
+ SignOff
INDEXÉ
RETIRER DE L'INDEX
RETIRER TOUT DE L'INDEX
@@ -679,7 +741,6 @@
INDEXER TOUT
VOIR LES FICHIERS PRÉSUMÉS INCHANGÉS
Modèle: ${0}$
- Faites un clique droit sur les fichiers sélectionnés et faites vos choix pour la résoluion des conflits.
ESPACE DE TRAVAIL :
Configurer les espaces de travail...
WORKTREE
diff --git a/src/Resources/Locales/it_IT.axaml b/src/Resources/Locales/it_IT.axaml
index 3022ffe9..59bf3028 100644
--- a/src/Resources/Locales/it_IT.axaml
+++ b/src/Resources/Locales/it_IT.axaml
@@ -2,41 +2,34 @@
+
Informazioni
Informazioni su SourceGit
- • Creato con
- • Il grafico è reso da
- © 2024 sourcegit-scm
- • Editor di testo da
- • I font monospaziati provengono da
- • Il codice sorgente è disponibile su
Client GUI Git open source e gratuito
Aggiungi Worktree
- Cosa fare il checkout:
- Branch esistente
- Crea nuovo branch
Posizione:
Percorso per questo worktree. Supportato il percorso relativo.
Nome Branch:
Facoltativo. Predefinito è il nome della cartella di destinazione.
Traccia Branch:
Traccia branch remoto
+ Di cosa fare il checkout:
+ Crea nuovo branch
+ Branch esistente
Assistente AI
+ RIGENERA
Usa AI per generare il messaggio di commit
+ APPLICA COME MESSAGGIO DI COMMIT
Applica
- Errore
- Genera errori e si rifiuta di applicare la patch
- Tutti gli errori
- Simile a 'errore', ma mostra di più
File Patch:
Seleziona file .patch da applicare
Ignora modifiche agli spazi
- Nessun avviso
- Disattiva l'avviso sugli spazi finali
Applica Patch
- Avviso
- Mostra avvisi per alcuni errori, ma applica comunque
Spazi:
+ Applica lo stash
+ Rimuovi dopo aver applicato
+ Ripristina le modifiche all'indice
+ Stash:
Archivia...
Salva Archivio In:
Seleziona il percorso del file archivio
@@ -50,10 +43,10 @@
Attribuisci
L'ATTRIBUZIONE SU QUESTO FILE NON È SUPPORTATA!!!
Checkout ${0}$...
- Confronta con Branch
Confronta con HEAD
Confronta con Worktree
Copia Nome Branch
+ Azione personalizzata
Elimina ${0}$...
Elimina i {0} branch selezionati
Scarta tutte le modifiche
@@ -61,37 +54,38 @@
Recupera ${0}$ in ${1}$...
Git Flow - Completa ${0}$
Unisci ${0}$ in ${1}$...
- Recupera ${0}$
- Recupera ${0}$ in ${1}$...
+ Unisci i {0} branch selezionati in quello corrente
+ Scarica ${0}$
+ Scarica ${0}$ in ${1}$...
Invia ${0}$
Riallinea ${0}$ su ${1}$...
Rinomina ${0}$...
Imposta Branch di Tracciamento...
Confronto Branch
+ Upstream non valido
Byte
ANNULLA
- Ripristina Questa Revisione
Ripristina la Revisione Padre
+ Ripristina Questa Revisione
Genera messaggio di commit
CAMBIA MODALITÀ DI VISUALIZZAZIONE
- Mostra come elenco di file e directory
+ Mostra come elenco di file e cartelle
Mostra come elenco di percorsi
Mostra come albero del filesystem
Checkout Branch
Checkout Commit
- Avviso: Effettuando un checkout del commit, la tua HEAD sarà separata
Commit:
- Branch:
+ Avviso: Effettuando un checkout del commit, la tua HEAD sarà separata
Modifiche Locali:
Scarta
- Non fare nulla
- Stash e Ripristina
+ Stasha e Ripristina
+ Branch:
Cherry Pick
Aggiungi sorgente al messaggio di commit
Commit(s):
Conferma tutte le modifiche
Mainline:
- Di solito non è possibile cherry-pick su una fusione perché non si sa quale lato della fusione deve essere considerato il mainline. Questa opzione consente di riprodurre la modifica relativa al genitore specificato.
+ Di solito non è possibile fare cherry-pick sdi una unione perché non si sa quale lato deve essere considerato il mainline. Questa opzione consente di riprodurre la modifica relativa al genitore specificato.
Cancella Stash
Stai per cancellare tutti gli stash. Sei sicuro di voler continuare?
Clona Repository Remoto
@@ -100,33 +94,38 @@
Nome Locale:
Nome del repository. Facoltativo.
Cartella Principale:
+ Inizializza e aggiorna i sottomoduli
URL del Repository:
CHIUDI
Editor
+ Checkout Commit
Cherry-Pick Questo Commit
Cherry-Pick...
- Checkout Commit
Confronta con HEAD
Confronta con Worktree
Copia Info
Copia SHA
Azione Personalizzata
- Rebase Interattivo ${0}$ fino a Qui
+ Riallinea Interattivamente ${0}$ fino a Qui
+ Unisci a ${0}$
+ Unisci ...
Riallinea ${0}$ fino a Qui
Ripristina ${0}$ fino a Qui
Annulla Commit
Modifica
Salva come Patch...
- Unisci al Genitore
- Unisci Commit Figli fino a Qui
+ Compatta nel Genitore
+ Compatta Commit Figli fino a Qui
MODIFICHE
Cerca Modifiche...
FILE
File LFS
+ Cerca File...
Sottomodulo
INFORMAZIONI
AUTORE
MODIFICATO
+ FIGLI
CHI HA COMMITTATO
Controlla i riferimenti che contengono questo commit
IL COMMIT È CONTENUTO DA
@@ -136,41 +135,44 @@
RIFERIMENTI
SHA
Apri nel Browser
- Inserisci l'oggetto del commit
Descrizione
+ Inserisci l'oggetto del commit
Configura Repository
TEMPLATE DI COMMIT
- Nome Template:
Contenuto Template:
+ Nome Template:
AZIONE PERSONALIZZATA
Argomenti:
${REPO} - Percorso del repository; ${SHA} - SHA del commit selezionato
File Eseguibile:
Nome:
Ambito:
+ Branch
Commit
Repository
+ Attendi la fine dell'azione
Indirizzo Email
Indirizzo email
GIT
Recupera automaticamente i remoti
Minuto/i
Remoto Predefinito
- Abilita --prune durante il fetch
- Abilita --signoff per i commit
TRACCIAMENTO ISSUE
- Aggiungi Regola Esempio per GitHub
- Aggiungi Regola Esempio per Jira
- Aggiungi Regola Esempio per Issue GitLab
- Aggiungi Regola Esempio per Merge Request GitLab
+ Aggiungi una regola di esempio per Azure DevOps
+ Aggiungi una regola di esempio per un Issue Gitee
+ Aggiungi una regola di esempio per un Pull Request Gitee
+ Aggiungi una regola di esempio per GitHub
+ Aggiungi una regola di esempio per Issue GitLab
+ Aggiungi una regola di esempio per una Merge Request GitLab
+ Aggiungi una regola di esempio per Jira
Nuova Regola
Espressione Regex Issue:
Nome Regola:
URL Risultato:
Utilizza $1, $2 per accedere ai valori dei gruppi regex.
AI
- Servizio Preferito:
- Se il 'Servizio Preferito' è impostato, SourceGit utilizzerà solo quello per questo repository. In caso contrario, se sono disponibili più servizi, verrà mostrato un menu contestuale per sceglierne uno.
+ Servizio preferito:
+ Se il 'Servizio Preferito' é impostato, SourceGit utilizzerà solo quello per questo repository. Altrimenti, se ci sono più servizi disponibili, verrà mostrato un menu contestuale per sceglierne uno.
Proxy HTTP
Proxy HTTP usato da questo repository
Nome Utente
@@ -188,16 +190,15 @@
Copia
Copia Tutto il Testo
Copia Percorso
- Copia Nome File
Crea Branch...
Basato Su:
Checkout del Branch Creato
Modifiche Locali:
Scarta
- Non Fare Nulla
- Stash e Ripristina
+ Stasha e Ripristina
Nome Nuovo Branch:
Inserisci il nome del branch.
+ Gli spazi verranno rimpiazzati con dei trattini.
Crea Branch Locale
Crea Tag...
Nuovo Tag Su:
@@ -221,7 +222,10 @@
Stai per eliminare più branch contemporaneamente. Controlla attentamente prima di procedere!
Elimina Remoto
Remoto:
+ Percorso:
Destinazione:
+ Tutti i figli verranno rimossi dalla lista.
+ Lo rimuoverà solamente dalla lista, non dal disco!
Conferma Eliminazione Gruppo
Conferma Eliminazione Repository
Elimina Sottomodulo
@@ -234,7 +238,9 @@
VECCHIO
Copia
Modalità File Modificata
+ Prima differenza
Ignora Modifiche agli Spazi
+ Ultima differenza
MODIFICA OGGETTO LFS
Differenza Successiva
NESSUNA MODIFICA O SOLO CAMBIAMENTI DI FINE LINEA
@@ -247,6 +253,7 @@
Scambia
Evidenziazione Sintassi
Avvolgimento delle Parole
+ Abilita la navigazione a blocchi
Apri nello Strumento di Merge
Mostra Tutte le Righe
Diminuisci Numero di Righe Visibili
@@ -269,6 +276,7 @@
Avanzamento Veloce (senza verifica)
Recupera
Recupera da tutti i remoti
+ Forza la sovrascrittura dei riferimenti locali
Recupera senza tag
Remoto:
Recupera Modifiche Remote
@@ -277,20 +285,21 @@
Scarta {0} file...
Scarta Modifiche nelle Righe Selezionate
Apri Strumento di Merge Esterno
+ Risolvi Usando ${0}$
Salva come Patch...
- Staging
- Staging {0} file
- Staging Modifiche nelle Righe Selezionate
- Stash...
- Stash {0} file...
- Rimuovi dallo Staging
- Rimuovi dallo Staging {0} file
- Rimuovi dallo Staging Modifiche nelle Righe Selezionate
- Usa Il Loro (checkout --theirs)
+ Stage
+ Stage di {0} file
+ Stage delle Modifiche nelle Righe Selezionate
+ Stasha...
+ Stasha {0} file...
+ Rimuovi da Stage
+ Rimuovi da Stage {0} file
+ Rimuovi le Righe Selezionate da Stage
Usa Il Mio (checkout --ours)
+ Usa Il Loro (checkout --theirs)
Cronologia File
- CONTENUTO
MODIFICA
+ CONTENUTO
FILTRO
Git-Flow
Branch di Sviluppo:
@@ -298,22 +307,22 @@
Prefisso Feature:
FLOW - Completa Feature
FLOW - Completa Hotfix
- FLOW - Completa Release
+ FLOW - Completa Rilascio
Target:
Hotfix:
Prefisso Hotfix:
Inizializza Git-Flow
Mantieni branch
Branch di Produzione:
- Release:
- Prefisso Release:
+ Rilascio:
+ Prefisso Rilascio:
Inizia Feature...
FLOW - Inizia Feature
Inizia Hotfix...
FLOW - Inizia Hotfix
Inserisci nome
- Inizia Release...
- FLOW - Inizia Release
+ Inizia Rilascio...
+ FLOW - Inizia Rilascio
Prefisso Tag Versione:
Git LFS
Aggiungi Modello di Tracciamento...
@@ -321,31 +330,31 @@
Modello Personalizzato:
Aggiungi Modello di Tracciamento a Git LFS
Recupera
- Recupera Oggetti LFS
Esegui `git lfs fetch` per scaricare gli oggetti Git LFS. Questo non aggiorna la copia di lavoro.
+ Recupera Oggetti LFS
Installa hook di Git LFS
- Mostra Bloccaggi
+ Mostra Blocchi
Nessun File Bloccato
Blocca
- Mostra solo i miei bloccaggi
- Bloccaggi LFS
+ Mostra solo i miei blocchi
+ Blocchi LFS
Sblocca
Forza Sblocco
Elimina
Esegui `git lfs prune` per eliminare vecchi file LFS dallo storage locale
- Pull
- Pull Oggetti LFS
+ Scarica
Esegui `git lfs pull` per scaricare tutti i file LFS per il ref corrente e fare il checkout
- Push
- Push Oggetti LFS
+ Scarica Oggetti LFS
+ Invia
Invia grandi file in coda al punto finale di Git LFS
+ Invia Oggetti LFS
Remoto:
Traccia file con nome '{0}'
Traccia tutti i file *{0}
- Storico
+ STORICO
AUTORE
ORA AUTORE
- GRAFICO & OGGETTO
+ GRAFICO E OGGETTO
SHA
ORA COMMIT
{0} COMMIT SELEZIONATI
@@ -357,23 +366,23 @@
Annulla il popup corrente
Clona una nuova repository
Chiudi la pagina corrente
- Vai alla pagina precedente
Vai alla pagina successiva
+ Vai alla pagina precedente
Crea una nuova pagina
- Apri la finestra di preferenze
+ Apri la finestra delle preferenze
REPOSITORY
- Conferma le modifiche in fase
- Conferma e invia le modifiche in fase
- Aggiungi tutte le modifiche e conferma
+ Committa le modifiche in tsage
+ Committa e invia le modifiche in stage
+ Fai lo stage di tutte le modifiche e committa
Crea un nuovo branch dal commit selezionato
Scarta le modifiche selezionate
Recupera, avvia direttamente
Modalità Dashboard (Predefinita)
- Recupera e integra, avvia direttamente
- Invia, avvia direttamente
- Forza il ricaricamento di questo repository
- Aggiungi/Rimuovi le modifiche selezionate
Modalità ricerca commit
+ Scarica, avvia direttamente
+ Invia, avvia direttamente
+ Forza l'aggiornamento di questo repository
+ Aggiungi/Rimuovi da stage le modifiche selezionate
Passa a 'Modifiche'
Passa a 'Storico'
Passa a 'Stashes'
@@ -382,29 +391,38 @@
Trova il prossimo risultato
Trova il risultato precedente
Apri il pannello di ricerca
- Aggiungi
- Rimuovi
Scarta
+ Aggiungi in stage
+ Rimuovi
Inizializza Repository
Percorso:
Cherry-Pick in corso.
- Richiesta di merge in corso.
- Rebase in corso.
- Revert in corso.
- Rebase Interattivo
- Branch di destinazione:
+ Elaborando il commit
+ Unione in corso.
+ Unendo
+ Riallineamento in corso.
+ Interrotto a
+ Ripristino in corso.
+ Ripristinando il commit
+ Riallinea Interattivamente
Su:
- Apri nel Browser
+ Branch di destinazione:
Copia il Link
+ Apri nel Browser
ERRORE
AVVISO
Unisci Branch
In:
- Opzione di Merge:
+ Opzione di Unione:
+ Sorgente:
+ Unione (multipla)
+ Commit di tutte le modifiche
+ Strategia:
+ Obiettivi:
Sposta Nodo Repository
Seleziona nodo padre per:
Nome:
- Git NON è configurato. Vai su [Preferenze] e configurarlo prima.
+ Git NON è configurato. Prima vai su [Preferenze] per configurarlo.
Apri Cartella Dati App
Apri con...
Opzionale.
@@ -416,85 +434,91 @@
Copia Percorso Repository
Repository
Incolla
- Proprio ora
- {0} minuti fa
- {0} ore fa
- Ieri
{0} giorni fa
+ 1 ora fa
+ {0} ore fa
+ Proprio ora
Il mese scorso
- {0} mesi fa
L'anno scorso
+ {0} minuti fa
+ {0} mesi fa
{0} anni fa
- Preferenze
- AI
- Analizza il Prompt Differenza
- Chiave API
- Genera Prompt Soggetto
- Modello
- Nome
- Server
- ASPETTO
- Font Predefinito
- Font Size
- Dimensione Font Predefinita
- Dimensione Font Editor
- Font Monospaziato
- Usa solo font monospaziato nell'editor
- Tema
- Sostituzioni Tema
- Usa larghezza fissa per i tab nella barra del titolo
- Usa cornice finestra nativa
- STRUMENTO DI DIFFERENZA/UNIONE
- Percorso Installazione
- Inserisci il percorso per lo strumento di differenza/unione
- Strumento
- GENERALE
- Controlla aggiornamenti all'avvio
- Lingua
- Numero massimo di commit nella cronologia
- Mostra l'orario dell'autore anziché quello del commit nel grafico
- Lunghezza Guida Soggetto
- GIT
- Abilita Auto CRLF
- Cartella predefinita per cloni
- Email Utente
- Email globale utente Git
- Percorso Installazione
- Nome Utente
- Nome globale utente Git
- Versione di Git
- Git (>= 2.23.0) è richiesto da questa applicazione
- FIRMA GPG
- Firma GPG per commit
- Firma GPG per tag
- Formato GPG
- Percorso Programma Installato
- Inserisci il percorso per il programma GPG installato
- Chiave Firma Utente
- Chiave GPG dell'utente per la firma
- INTEGRAZIONE
- SHELL/TERMINALE
- Shell/Terminale
- Percorso
+ Ieri
+ Preferenze
+ AI
+ Analizza il Prompt Differenza
+ Chiave API
+ Genera Prompt Oggetto
+ Modello
+ Nome
+ Server
+ Abilita streaming
+ ASPETTO
+ Font Predefinito
+ Larghezza della Tab Editor
+ Dimensione Font
+ Dimensione Font Predefinita
+ Dimensione Font Editor
+ Font Monospaziato
+ Usa solo font monospaziato nell'editor
+ Tema
+ Sostituzioni Tema
+ Usa larghezza fissa per i tab nella barra del titolo
+ Usa cornice finestra nativa
+ STRUMENTO DI DIFFERENZA/UNIONE
+ Percorso Installazione
+ Inserisci il percorso per lo strumento di differenza/unione
+ Strumento
+ GENERALE
+ Controlla aggiornamenti all'avvio
+ Formato data
+ Lingua
+ Numero massimo di commit nella cronologia
+ Mostra nel grafico l'orario dell'autore anziché quello del commit
+ Mostra i figli nei dettagli del commit
+ Lunghezza Guida Oggetto
+ GIT
+ Abilita Auto CRLF
+ Cartella predefinita per cloni
+ Email Utente
+ Email utente Git globale
+ Abilita --prune durante il fetch
+ Questa applicazione richiede Git (>= 2.23.0)
+ Percorso Installazione
+ Abilita la verifica HTTP SSL
+ Nome Utente
+ Nome utente Git globale
+ Versione di Git
+ FIRMA GPG
+ Firma GPG per commit
+ Formato GPG
+ Percorso Programma Installato
+ Inserisci il percorso per il programma GPG installato
+ Firma GPG per tag
+ Chiave Firma Utente
+ Chiave GPG dell'utente per la firma
+ INTEGRAZIONE
+ SHELL/TERMINALE
+ Percorso
+ Shell/Terminale
Potatura Remota
Destinazione:
Potatura Worktrees
- Potatura delle informazioni di worktree in `$GIT_DIR/worktrees`
- Pull
+ Potatura delle informazioni di worktree in `$GIT_COMMON_DIR/worktrees`
+ Scarica
Branch Remoto:
Recupera tutti i branch
In:
Modifiche Locali:
Scarta
- Non fare nulla
- Accantona e Riapplica
+ Stasha e Riapplica
Recupera senza tag
Remoto:
- Pull (Fetch & Merge)
- Usa rebase anziché merge
- Push
- Assicurati che i submoduli siano stati spinti
- Forza il push
+ Scarica (Recupera e Unisci)
+ Riallineare anziché unire
+ Invia
+ Assicurati che i sottomoduli siano stati inviati
+ Forza l'invio
Branch Locale:
Remoto:
Invia modifiche al remoto
@@ -506,10 +530,10 @@
Remoto:
Tag:
Esci
- Rebase Branch Corrente
- Accantona & Riapplica modifiche locali
+ Riallinea Branch Corrente
+ Stasha e Riapplica modifiche locali
Su:
- Rebase:
+ Riallinea:
Aggiorna
Aggiungi Remoto
Modifica Remoto
@@ -532,7 +556,7 @@
Branch:
ANNULLA
Recupero automatico delle modifiche dai remoti...
- Pulizia (GC & Potatura)
+ Pulizia (GC e Potatura)
Esegui il comando `git gc` per questo repository.
Cancella tutto
Configura questo repository
@@ -540,32 +564,51 @@
Azioni Personalizzate
Nessuna Azione Personalizzata
Abilita opzione '--reflog'
- Apri nel Browser File
- Cerca Branch/Tag/Submodule
+ Apri nell'Esplora File
+ Cerca Branch/Tag/Sottomodulo
FILTRATO DA:
+ Visibilità nel grafico
+ Non impostato
+ Nascondi nel grafico dei commit
+ Filtra nel grafico dei commit
+ Abilita opzione '--first-parent'
+ LAYOUT
+ Orizzontale
+ Verticale
+ Ordine dei commit
+ Per data del commit
+ Topologicamente
BRANCH LOCALI
Vai a HEAD
- Abilita opzione '--first-parent'
Crea Branch
+ CANCELLA LE NOTIFICHE
+ Evidenzia nel grafico solo il branch corrente
Apri in {0}
Apri in Strumenti Esterni
Aggiorna
REMOTI
AGGIUNGI REMOTO
Cerca Commit
+ Autore
+ Committente
File
Messaggio
SHA
- Autore & Committente
Branch Corrente
Mostra Tag come Albero
+ SALTA
Statistiche
- SUBMODULE
- AGGIUNGI SUBMODULE
- AGGIORNA SUBMODULE
+ SOTTOMODULI
+ AGGIUNGI SOTTOMODULI
+ AGGIORNA SOTTOMODULI
TAG
NUOVO TAG
+ Per data di creazione
+ Per nome (ascendente)
+ Per nome (discendente)
+ Ordina
Apri nel Terminale
+ Usa tempo relativo nello storico
WORKTREE
AGGIUNGI WORKTREE
POTATURA
@@ -574,10 +617,10 @@
Modalità Reset:
Sposta a:
Branch Corrente:
- Mostra nel File Explorer
- Revert Commit
+ Mostra nell'Esplora File
+ Ripristina Commit
Commit:
- Commit delle modifiche di revert
+ Commit delle modifiche di ripristino
Modifica Messaggio di Commit
Usa 'Shift+Enter' per inserire una nuova riga. 'Enter' è il tasto rapido per il pulsante OK
In esecuzione. Attendere...
@@ -593,63 +636,71 @@
Salta questa versione
Aggiornamento Software
Non ci sono aggiornamenti disponibili.
- Squash Commit
+ Imposta il Branch
+ Branch:
+ Rimuovi upstream
+ Upstream:
+ Copia SHA
+ Vai a
+ Compatta Commit
In:
Chiave Privata SSH:
Percorso per la chiave SSH privata
AVVIA
- Accantona
+ Stasha
+ Auto-ripristino dopo lo stash
+ I tuoi file di lavoro rimangono inalterati, ma viene salvato uno stash.
Includi file non tracciati
- Mantieni file indicizzati
+ Mantieni file in stage
Messaggio:
- Opzionale. Nome di questo accantonamento
- Solo modifiche indicizzate
- Sia le modifiche indicizzate che quelle non indicizzate dei file selezionati saranno accantonate!!!
- Accantona Modifiche Locali
+ Opzionale. Nome di questo stash
+ Solo modifiche in stage
+ Sia le modifiche in stage che quelle non in stage dei file selezionati saranno stashate!!!
+ Stasha Modifiche Locali
Applica
Elimina
- Estrai
- Elimina Accantonamento
+ Salva come Patch...
+ Elimina Stash
Elimina:
- Accantonamenti
+ STASH
MODIFICHE
- ACCANTONAMENTI
+ STASH
Statistiche
COMMIT
COMMITTER
+ PANORAMICA
MESE
SETTIMANA
- COMMIT:
AUTORI:
- PANORAMICA
- SUBMODULE
- Aggiungi Submodule
+ COMMIT:
+ SOTTOMODULI
+ Aggiungi Sottomodulo
Copia Percorso Relativo
- Recupera submodule annidati
- Apri Repository Submodule
+ Recupera sottomoduli annidati
+ Apri Repository del Sottomodulo
Percorso Relativo:
Cartella relativa per memorizzare questo modulo.
- Elimina Submodule
+ Elimina Sottomodulo
OK
Copia Nome Tag
Copia Messaggio Tag
Elimina ${0}$...
Unisci ${0}$ in ${1}$...
Invia ${0}$...
- URL:
- Aggiorna Submodule
- Tutti i submodule
+ Aggiorna Sottomoduli
+ Tutti i sottomoduli
Inizializza se necessario
Ricorsivamente
- Submodule:
+ Sottomodulo:
Usa opzione --remote
+ URL:
Avviso
Pagina di Benvenuto
Crea Gruppo
Crea Sottogruppo
Clona Repository
Elimina
- TRASCINA & RILASCIA CARTELLA SUPPORTATO. RAGGRUPPAMENTI PERSONALIZZATI SUPPORTATI.
+ TRASCINA E RILASCIA CARTELLA SUPPORTATO. RAGGRUPPAMENTI PERSONALIZZATI SUPPORTATI.
Modifica
Sposta in un Altro Gruppo
Apri Tutti i Repository
@@ -658,34 +709,35 @@
Riscansiona Repository nella Cartella Clone Predefinita
Cerca Repository...
Ordina
- Modifiche
+ MODIFICHE LOCALI
Git Ignore
Ignora tutti i file *{0}
Ignora i file *{0} nella stessa cartella
Ignora i file nella stessa cartella
Ignora solo questo file
Modifica
- Puoi indicizzare questo file ora.
+ Puoi aggiungere in stage questo file ora.
COMMIT
- COMMIT & PUSH
+ COMMIT E INVIA
Template/Storico
Attiva evento click
- Indica tutte le modifiche e fai il commit
- Commit vuoto rilevato! Vuoi continuare (--allow-empty)?
+ Commit (Modifica)
+ Stage di tutte le modifiche e fai il commit
CONFLITTI RILEVATI
CONFLITTI NEI FILE RISOLTI
INCLUDI FILE NON TRACCIATI
NESSUN MESSAGGIO RECENTE INSERITO
NESSUN TEMPLATE DI COMMIT
- INDICIZZATI
- RIMUOVI DALL'INDICIZZAZIONE
- RIMUOVI TUTTO DALL'INDICIZZAZIONE
- NON INDICIZZATI
- INDICIZZA
- INDICIZZA TUTTO
+ Clicca con il tasto destro sul(i) file selezionato, quindi scegli come risolvere i conflitti.
+ SignOff
+ IN STAGE
+ RIMUOVI DA STAGE
+ RIMUOVI TUTTO DA STAGE
+ NON IN STAGE
+ FAI LO STAGE
+ FAI LO STAGE DI TUTTO
VISUALIZZA COME NON MODIFICATO
Template: ${0}$
- Clicca con il tasto destro sul file(i) selezionato, quindi scegli come risolvere i conflitti.
WORKSPACE:
Configura Workspaces...
WORKTREE
diff --git a/src/Resources/Locales/ja_JP.axaml b/src/Resources/Locales/ja_JP.axaml
new file mode 100644
index 00000000..fe643b5e
--- /dev/null
+++ b/src/Resources/Locales/ja_JP.axaml
@@ -0,0 +1,747 @@
+
+
+
+
+
+ 概要
+ SourceGitについて
+ オープンソース & フリーなGit GUIクライアント
+ ワークツリーを追加
+ 場所:
+ ワークツリーのパスを入力してください。相対パスも使用することができます。
+ ブランチの名前:
+ 任意。デフォルトでは宛先フォルダ名が使用されます。
+ 追跡するブランチ:
+ 追跡中のリモートブランチ
+ チェックアウトする内容:
+ 新しいブランチを作成
+ 既存のブランチ
+ OpenAI アシスタント
+ 再生成
+ OpenAIを使用してコミットメッセージを生成
+ コミットメッセージとして適用
+ 適用
+ パッチファイル:
+ 適用する .patchファイルを選択
+ 空白文字の変更を無視
+ パッチを適用
+ 空白文字:
+ スタッシュを適用
+ 適用後に削除
+ インデックスの変更を復元
+ スタッシュ:
+ アーカイブ...
+ アーカイブの保存先:
+ アーカイブファイルのパスを選択
+ リビジョン:
+ アーカイブ
+ SourceGit Askpass
+ 変更されていないとみなされるファイル
+ 変更されていないとみなされるファイルはありません
+ 削除
+ バイナリファイルはサポートされていません!!!
+ Blame
+ BLAMEではこのファイルはサポートされていません!!!
+ ${0}$ をチェックアウトする...
+ HEADと比較
+ ワークツリーと比較
+ ブランチ名をコピー
+ カスタムアクション
+ ${0}$を削除...
+ 選択中の{0}個のブランチを削除
+ すべての変更を破棄
+ ${0}$ へ早送りする
+ ${0}$ から ${1}$ へフェッチする
+ Git Flow - Finish ${0}$
+ ${0}$ を ${1}$ にマージする...
+ 選択中の{0}個のブランチを現在のブランチにマージする
+ ${0}$ をプルする
+ ${0}$ を ${1}$ にプルする...
+ ${0}$ をプッシュする
+ ${0}$ を ${1}$ でリベースする...
+ ${0}$ をリネームする...
+ トラッキングブランチを設定...
+ ブランチの比較
+ 無効な上流ブランチ!
+ バイト
+ キャンセル
+ 親リビジョンにリセット
+ このリビジョンにリセット
+ コミットメッセージを生成
+ 変更表示の切り替え
+ ファイルとディレクトリのリストを表示
+ パスのリストを表示
+ ファイルシステムのツリーを表示
+ ブランチをチェックアウト
+ コミットをチェックアウト
+ コミット:
+ 警告: コミットをチェックアウトするとHEADが切断されます
+ ローカルの変更:
+ 破棄
+ スタッシュして再適用
+ ブランチ:
+ チェリーピック
+ ソースをコミットメッセージに追加
+ コミット(複数可):
+ すべての変更をコミット
+ メインライン:
+ 通常、マージをチェリーピックすることはできません。どちらのマージ元をメインラインとして扱うべきかが分からないためです。このオプションを使用すると、指定した親に対して変更を再適用する形でチェリーピックを実行できます。
+ スタッシュをクリア
+ すべてのスタッシュをクリアします。続行しますか?
+ リモートリポジトリをクローン
+ 追加の引数:
+ リポジトリをクローンする際の追加パラメータ(任意)。
+ ローカル名:
+ リポジトリの名前(任意)。
+ 親フォルダ:
+ サブモジュールを初期化して更新
+ リポジトリのURL:
+ 閉じる
+ エディタ
+ コミットをチェックアウト
+ このコミットをチェリーピック
+ チェリーピック...
+ HEADと比較
+ ワークツリーと比較
+ 情報をコピー
+ SHAをコピー
+ カスタムアクション
+ ${0}$ ブランチをここにインタラクティブリベース
+ ${0}$ にマージ
+ マージ...
+ ${0}$ をここにリベース
+ ${0}$ ブランチをここにリセット
+ コミットを戻す
+ 書き直す
+ パッチとして保存...
+ 親にスカッシュ
+ 子コミットをここにスカッシュ
+ 変更
+ 変更を検索...
+ ファイル
+ LFSファイル
+ ファイルを検索...
+ サブモジュール
+ コミットの情報
+ 著者
+ 変更
+ 子
+ コミッター
+ このコミットを含む参照を確認
+ コミットが含まれるか確認
+ 最初の100件の変更のみが表示されています。すべての変更は'変更'タブで確認できます。
+ メッセージ
+ 親
+ 参照
+ SHA
+ ブラウザで開く
+ 説明
+ コミットのタイトルを入力
+ リポジトリの設定
+ コミットテンプレート
+ テンプレート内容:
+ テンプレート名:
+ カスタムアクション
+ 引数:
+ ${REPO} - リポジトリのパス; ${BRANCH} - 選択中のブランチ; ${SHA} - 選択中のコミットのSHA
+ 実行ファイル:
+ 名前:
+ スコープ:
+ ブランチ
+ コミット
+ リポジトリ
+ アクションの終了を待機
+ Eメールアドレス
+ Eメールアドレス
+ GIT
+ 自動的にリモートからフェッチ 間隔:
+ 分(s)
+ リモートの初期値
+ ISSUEトラッカー
+ サンプルのAzure DevOpsルールを追加
+ サンプルのGitee Issueルールを追加
+ サンプルのGiteeプルリクエストルールを追加
+ サンプルのGithubルールを追加
+ サンプルのGitLab Issueルールを追加
+ サンプルのGitLabマージリクエストルールを追加
+ サンプルのJiraルールを追加
+ 新しいルール
+ Issueの正規表現:
+ ルール名:
+ リザルトURL:
+ 正規表現のグループ値に$1, $2を使用してください。
+ AI
+ 優先するサービス:
+ 優先するサービスが設定されている場合、SourceGitはこのリポジトリでのみそれを使用します。そうでない場合で複数サービスが利用できる場合は、そのうちの1つを選択するためのコンテキストメニューが表示されます。
+ HTTP プロキシ
+ このリポジトリで使用するHTTPプロキシ
+ ユーザー名
+ このリポジトリにおけるユーザー名
+ ワークスペース
+ 色
+ 起動時にタブを復元
+ Conventional Commitヘルパー
+ 破壊的変更:
+ 閉じたIssue:
+ 詳細な変更:
+ スコープ:
+ 短い説明:
+ 変更の種類:
+ コピー
+ すべてのテキストをコピー
+ 絶対パスをコピー
+ パスをコピー
+ ブランチを作成...
+ 派生元:
+ 作成したブランチにチェックアウト
+ ローカルの変更:
+ 破棄
+ スタッシュして再適用
+ 新しいブランチの名前:
+ ブランチの名前を入力
+ スペースはダッシュに置き換えられます。
+ ローカルブランチを作成
+ タグを作成...
+ 付与されるコミット:
+ GPG署名を使用
+ タグメッセージ:
+ 任意。
+ タグの名前:
+ 推奨フォーマット: v1.0.0-alpha
+ 作成後にすべてのリモートにプッシュ
+ 新しいタグを作成
+ 種類:
+ 注釈付き
+ 軽量
+ Ctrlキーを押しながらクリックで実行
+ 切り取り
+ ブランチを削除
+ ブランチ:
+ リモートブランチを削除しようとしています!!!
+ もしリモートブランチを削除する場合、${0}$も削除します。
+ 複数のブランチを削除
+ 一度に複数のブランチを削除しようとしています! 操作を行う前に再度確認してください!
+ リモートを削除
+ リモート:
+ パス:
+ 対象:
+ すべての子ノードがリストから削除されます。
+ これはリストからのみ削除され、ディスクには保存されません!
+ グループを削除
+ リポジトリを削除
+ サブモジュールを削除
+ サブモジュールのパス:
+ タグを削除
+ タグ:
+ リモートリポジトリから削除
+ バイナリの差分
+ NEW
+ OLD
+ コピー
+ ファイルモードが変更されました
+ 先頭の差分
+ 空白の変更を無視
+ 最後の差分
+ LFSオブジェクトの変更
+ 次の差分
+ 変更がない、もしくはEOLの変更のみ
+ 前の差分
+ パッチとして保存
+ 隠されたシンボルを表示
+ 差分の分割表示
+ サブモジュール
+ 新規
+ スワップ
+ シンタックスハイライト
+ 行の折り返し
+ ブロックナビゲーションを有効化
+ マージツールで開く
+ すべての行を表示
+ 表示する行数を減らす
+ 表示する行数を増やす
+ ファイルを選択すると、変更内容が表示されます
+ マージツールで開く
+ 変更を破棄
+ ワーキングディレクトリのすべての変更を破棄
+ 変更:
+ 無視したファイルを含める
+ {0}個の変更を破棄します。
+ この操作を元に戻すことはできません!!!
+ ブックマーク:
+ 新しい名前:
+ 対象:
+ 選択中のグループを編集
+ 選択中のリポジトリを編集
+ カスタムアクションを実行
+ アクション名:
+ (チェックアウトせずに)ブランチを早送りする
+ フェッチ
+ すべてのリモートをフェッチ
+ ローカル参照を強制的に上書き
+ タグなしでフェッチ
+ リモート:
+ リモートの変更をフェッチ
+ 変更されていないとみなされる
+ 破棄...
+ {0}個のファイルを破棄...
+ 選択された行の変更を破棄
+ 外部マージツールで開く
+ ${0}$ を使用して解決
+ パッチとして保存...
+ ステージ
+ {0}個のファイルをステージ...
+ 選択された行の変更をステージ
+ スタッシュ...
+ {0}個のファイルをスタッシュ...
+ アンステージ
+ {0}個のファイルをアンステージ...
+ 選択された行の変更をアンステージ
+ 自分の変更を使用 (checkout --ours)
+ 相手の変更を使用 (checkout --theirs)
+ ファイルの履歴
+ 変更
+ コンテンツ
+ Git-Flow
+ 開発ブランチ:
+ Feature:
+ Feature プレフィックス:
+ FLOW - Finish Feature
+ FLOW - Finish Hotfix
+ FLOW - Finish Release
+ 対象:
+ Hotfix:
+ Hotfix プレフィックス:
+ Git-Flowを初期化
+ ブランチを保持
+ プロダクション ブランチ:
+ Release:
+ Release プレフィックス:
+ Start Feature...
+ FLOW - Start Feature
+ Start Hotfix...
+ FLOW - Start Hotfix
+ 名前を入力
+ Start Release...
+ FLOW - Start Release
+ Versionタグ プレフィックス:
+ Git LFS
+ トラックパターンを追加...
+ パターンをファイル名として扱う
+ カスタム パターン:
+ Git LFSにトラックパターンを追加
+ フェッチ
+ `git lfs fetch`を実行して、Git LFSオブジェクトをダウンロードします。ワーキングコピーは更新されません。
+ LFSオブジェクトをフェッチ
+ Git LFSフックをインストール
+ ロックを表示
+ ロックされているファイルはありません
+ ロック
+ 私のロックのみ表示
+ LFSロック
+ ロック解除
+ 強制的にロック解除
+ 削除
+ `git lfs prune`を実行して、ローカルの保存領域から古いLFSファイルを削除します。
+ プル
+ `git lfs pull`を実行して、現在の参照とチェックアウトのすべてのGit LFSファイルをダウンロードします。
+ LFSオブジェクトをプル
+ プッシュ
+ キュー内の大容量ファイルをGit LFSエンドポイントにプッシュします。
+ LFSオブジェクトをプッシュ
+ リモート:
+ {0}という名前のファイルをトラック
+ すべての*{0}ファイルをトラック
+ 履歴
+ 著者
+ 著者時間
+ グラフ & コミットのタイトル
+ SHA
+ 日時
+ {0} コミットを選択しました
+ 'Ctrl'キーまたは'Shift'キーを押すと、複数のコミットを選択できます。
+ ⌘ または ⇧ キーを押して複数のコミットを選択します。
+ TIPS:
+ キーボードショートカットを確認
+ 総合
+ 現在のポップアップをキャンセル
+ 新しくリポジトリをクローン
+ 現在のページを閉じる
+ 次のページに移動
+ 前のページに移動
+ 新しいページを作成
+ 設定ダイアログを開く
+ リポジトリ
+ ステージ済みの変更をコミット
+ ステージ済みの変更をコミットしてプッシュ
+ 全ての変更をステージしてコミット
+ 選択中のコミットから新たなブランチを作成
+ 選択した変更を破棄
+ 直接フェッチを実行
+ ダッシュボードモード (初期値)
+ コミット検索モード
+ 直接プルを実行
+ 直接プッシュを実行
+ 現在のリポジトリを強制的に再読み込み
+ 選択中の変更をステージ/アンステージ
+ '変更'に切り替える
+ '履歴'に切り替える
+ 'スタッシュ'に切り替える
+ テキストエディタ
+ 検索パネルを閉じる
+ 次のマッチを検索
+ 前のマッチを検索
+ 検索パネルを開く
+ 破棄
+ ステージ
+ アンステージ
+ リポジトリの初期化
+ パス:
+ チェリーピックが進行中です。'中止'を押すと元のHEADが復元されます。
+ コミットを処理中
+ マージリクエストが進行中です。'中止'を押すと元のHEADが復元されます。
+ マージ中
+ リベースが進行中です。'中止'を押すと元のHEADが復元されます。
+ 停止しました
+ 元に戻す処理が進行中です。'中止'を押すと元のHEADが復元されます。
+ コミットを元に戻しています
+ インタラクティブ リベース
+ On:
+ 対象のブランチ:
+ リンクをコピー
+ ブラウザで開く
+ エラー
+ 通知
+ ブランチのマージ
+ 宛先:
+ マージオプション:
+ ソースブランチ:
+ マージ (複数)
+ すべての変更をコミット
+ マージ戦略:
+ 対象:
+ リポジトリノードの移動
+ 親ノードを選択:
+ 名前:
+ Gitが設定されていません。まず[設定]に移動して設定を行ってください。
+ アプリケーションデータのディレクトリを開く
+ 外部ツールで開く...
+ 任意。
+ 新しいページを開く
+ ブックマーク
+ タブを閉じる
+ 他のタブを閉じる
+ 右のタブを閉じる
+ リポジトリパスをコピー
+ リポジトリ
+ 貼り付け
+ {0} 日前
+ 1 時間前
+ {0} 時間前
+ たった今
+ 先月
+ 昨年
+ {0} 分前
+ {0} ヶ月前
+ {0} 年前
+ 昨日
+ 設定
+ AI
+ 差分分析プロンプト
+ APIキー
+ タイトル生成プロンプト
+ モデル
+ 名前
+ サーバー
+ ストリーミングを有効化
+ 外観
+ デフォルトのフォント
+ エディタのタブ幅
+ フォントサイズ
+ デフォルト
+ エディタ
+ 等幅フォント
+ テキストエディタでは等幅フォントのみを使用する
+ テーマ
+ テーマの上書き
+ タイトルバーの固定タブ幅を使用
+ ネイティブウィンドウフレームを使用
+ 差分/マージ ツール
+ インストール パス
+ 差分/マージ ツールのパスを入力
+ ツール
+ 総合
+ 起動時にアップデートを確認
+ 日時のフォーマット
+ 言語
+ コミット履歴
+ グラフにコミット時間の代わりに著者の時間を表示する
+ コミット詳細に子コミットを表示
+ コミットグラフにタグを表示
+ コミットタイトル枠の大きさ
+ GIT
+ 自動CRLFを有効化
+ デフォルトのクローンディレクトリ
+ ユーザー Eメールアドレス
+ グローバルgitのEメールアドレス
+ フェッチ時に--pruneを有効化
+ Git (>= 2.23.0) はこのアプリで必要です
+ インストール パス
+ HTTP SSL 検証を有効にする
+ ユーザー名
+ グローバルのgitユーザー名
+ Gitバージョン
+ GPG 署名
+ コミットにGPG署名を行う
+ GPGフォーマット
+ プログラムのインストールパス
+ インストールされたgpgプログラムのパスを入力
+ タグにGPG署名を行う
+ ユーザー署名キー
+ ユーザーのGPG署名キー
+ 統合
+ シェル/ターミナル
+ パス
+ シェル/ターミナル
+ リモートを削除
+ 対象:
+ 作業ツリーを削除
+ `$GIT_DIR/worktrees` の作業ツリー情報を削除
+ プル
+ ブランチ:
+ すべてのブランチをフェッチ
+ 宛先:
+ ローカルの変更:
+ 破棄
+ スタッシュして再適用
+ タグなしでフェッチ
+ リモート:
+ プル (フェッチ & マージ)
+ マージの代わりにリベースを使用
+ プッシュ
+ サブモジュールがプッシュされていることを確認
+ 強制的にプッシュ
+ ローカル ブランチ:
+ リモート:
+ 変更をリモートにプッシュ
+ リモート ブランチ:
+ 追跡ブランチとして設定
+ すべてのタグをプッシュ
+ リモートにタグをプッシュ
+ すべてのリモートにプッシュ
+ リモート:
+ タグ:
+ 終了
+ 現在のブランチをリベース
+ ローカルの変更をスタッシュして再適用
+ On:
+ リベース:
+ 更新
+ リモートを追加
+ リモートを編集
+ 名前:
+ リモートの名前
+ リポジトリのURL:
+ リモートのgitリポジトリのURL
+ URLをコピー
+ 削除...
+ 編集...
+ フェッチ
+ ブラウザで開く
+ 削除
+ ワークツリーの削除を確認
+ `--force` オプションを有効化
+ 対象:
+ ブランチの名前を編集
+ 新しい名前:
+ このブランチにつける一意な名前
+ ブランチ:
+ 中止
+ リモートから変更を自動取得中...
+ クリーンアップ(GC & Prune)
+ このリポジトリに対して`git gc`コマンドを実行します。
+ すべてのフィルターをクリア
+ リポジトリの設定
+ 続ける
+ カスタムアクション
+ カスタムアクションがありません
+ `--reflog` オプションを有効化
+ ファイルブラウザーで開く
+ ブランチ/タグ/サブモジュールを検索
+ 解除
+ コミットグラフで非表示
+ コミットグラフでフィルター
+ `--first-parent` オプションを有効化
+ レイアウト
+ 水平
+ 垂直
+ コミットの並び順
+ 日時
+ トポロジカルソート
+ ローカル ブランチ
+ HEADに移動
+ ブランチを作成
+ 通知をクリア
+ グラフで現在のブランチを強調表示
+ {0} で開く
+ 外部ツールで開く
+ 更新
+ リモート
+ リモートを追加
+ コミットを検索
+ 著者
+ コミッター
+ ファイル
+ メッセージ
+ SHA
+ 現在のブランチ
+ タグをツリーとして表示
+ スキップ
+ 統計
+ サブモジュール
+ サブモジュールを追加
+ サブモジュールを更新
+ タグ
+ 新しいタグを作成
+ 作成者日時
+ 名前 (昇順)
+ 名前 (降順)
+ ソート
+ ターミナルで開く
+ 履歴に相対時間を使用
+ ワークツリー
+ ワークツリーを追加
+ 削除
+ GitリポジトリのURL
+ 現在のブランチをリビジョンにリセット
+ リセットモード:
+ 移動先:
+ 現在のブランチ:
+ ファイルエクスプローラーで表示
+ コミットを戻す
+ コミット:
+ コミットの変更を戻す
+ コミットメッセージを書き直す
+ 改行には'Shift+Enter'キーを使用します。 'Enter"はOKボタンのホットキーとして機能します。
+ 実行中です。しばらくお待ちください...
+ 保存
+ 名前を付けて保存...
+ パッチが正常に保存されました!
+ リポジトリをスキャン
+ ルートディレクトリ:
+ 更新を確認
+ 新しいバージョンのソフトウェアが利用可能です:
+ 更新の確認に失敗しました!
+ ダウンロード
+ このバージョンをスキップ
+ ソフトウェアの更新
+ 利用可能なアップデートはありません
+ トラッキングブランチを設定
+ ブランチ:
+ 上流ブランチを解除
+ 上流ブランチ:
+ SHAをコピー
+ Go to
+ スカッシュコミット
+ 宛先:
+ SSH プライベートキー:
+ プライベートSSHキーストアのパス
+ スタート
+ スタッシュ
+ スタッシュ後に自動で復元
+ 作業ファイルは変更されず、スタッシュが保存されます。
+ 追跡されていないファイルを含める
+ ステージされたファイルを保持
+ メッセージ:
+ オプション. このスタッシュの名前を入力
+ ステージされた変更のみ
+ 選択したファイルの、ステージされた変更とステージされていない変更の両方がスタッシュされます!!!
+ ローカルの変更をスタッシュ
+ 適用
+ 破棄
+ パッチとして保存
+ スタッシュを破棄
+ 破棄:
+ スタッシュ
+ 変更
+ スタッシュ
+ 統計
+ コミット
+ コミッター
+ 概要
+ 月間
+ 週間
+ 著者:
+ コミット:
+ サブモジュール
+ サブモジュールを追加
+ 相対パスをコピー
+ ネストされたサブモジュールを取得する
+ サブモジュールのリポジトリを開く
+ 相対パス:
+ このモジュールを保存するフォルダの相対パス
+ サブモジュールを削除
+ OK
+ タグ名をコピー
+ タグメッセージをコピー
+ ${0}$ を削除...
+ ${0}$ を ${1}$ にマージ...
+ ${0}$ をプッシュ...
+ サブモジュールを更新
+ すべてのサブモジュール
+ 必要に応じて初期化
+ 再帰的に更新
+ サブモジュール:
+ --remoteオプションを使用
+ URL:
+ 警告
+ ようこそ
+ グループを作成
+ サブグループを作成
+ リポジトリをクローンする
+ 削除
+ ドラッグ & ドロップでフォルダを追加できます. グループを作成したり、変更したりできます。
+ 編集
+ 別のグループに移動
+ すべてのリポジトリを開く
+ リポジトリを開く
+ ターミナルを開く
+ デフォルトのクローンディレクトリ内のリポジトリを再スキャン
+ リポジトリを検索...
+ ソート
+ 変更
+ Git Ignore
+ すべての*{0}ファイルを無視
+ 同じフォルダ内の*{0}ファイルを無視
+ 同じフォルダ内のファイルを無視
+ このファイルのみを無視
+ Amend
+ このファイルを今すぐステージできます。
+ コミット
+ コミットしてプッシュ
+ メッセージのテンプレート/履歴
+ クリックイベントをトリガー
+ コミット (Edit)
+ すべての変更をステージしてコミット
+ 競合が検出されました
+ ファイルの競合は解決されました
+ 追跡されていないファイルを含める
+ 最近の入力メッセージはありません
+ コミットテンプレートはありません
+ 選択したファイルを右クリックし、競合を解決する操作を選択してください。
+ サインオフ
+ ステージしたファイル
+ ステージを取り消し
+ すべてステージを取り消し
+ 未ステージのファイル
+ ステージへ移動
+ すべてステージへ移動
+ 変更されていないとみなしたものを表示
+ テンプレート: ${0}$
+ ワークスペース:
+ ワークスペースを設定...
+ ワークツリー
+ パスをコピー
+ ロック
+ 削除
+ ロック解除
+
diff --git a/src/Resources/Locales/pt_BR.axaml b/src/Resources/Locales/pt_BR.axaml
index fb3694ef..3caac3cc 100644
--- a/src/Resources/Locales/pt_BR.axaml
+++ b/src/Resources/Locales/pt_BR.axaml
@@ -3,64 +3,26 @@
-
-
Sobre
Sobre o SourceGit
- • Construído com
- • Gráfico desenhado por
- © 2024 sourcegit-scm
- • Editor de Texto de
- • Fontes monoespaçadas de
- • Código-fonte pode ser encontrado em
Cliente Git GUI Livre e de Código Aberto
Adicionar Worktree
- O que Checar:
- Branch Existente
- Criar Novo Branch
Localização:
Caminho para este worktree. Caminho relativo é suportado.
Nome do Branch:
Opcional. O padrão é o nome da pasta de destino.
Rastrear Branch:
Rastreando branch remoto
+ O que Checar:
+ Criar Novo Branch
+ Branch Existente
Assietente IA
Utilizar IA para gerar mensagem de commit
Patch
- Erro
- Erros levantados e se recusa a aplicar o patch
- Erro Total
- Semelhante a 'erro', mas mostra mais
Arquivo de Patch:
Selecione o arquivo .patch para aplicar
Ignorar mudanças de espaço em branco
- Sem Aviso
- Desativa o aviso de espaço em branco no final
Aplicar Patch
- Aviso
- Emite avisos para alguns erros, mas aplica
Espaço em Branco:
Arquivar...
Salvar Arquivo Como:
@@ -75,7 +37,6 @@
Blame
BLAME NESTE ARQUIVO NÃO É SUPORTADO!!!
Checkout ${0}$...
- Comparar com Branch
Comparar com HEAD
Comparar com Worktree
Copiar Nome do Branch
@@ -95,8 +56,8 @@
Comparação de Branches
Bytes
CANCELAR
- Resetar para Esta Revisão
Resetar para Revisão Pai
+ Resetar para Esta Revisão
Gerar mensagem de commit
ALTERAR MODO DE EXIBIÇÃO
Exibir como Lista de Arquivos e Diretórios
@@ -104,13 +65,12 @@
Exibir como Árvore de Sistema de Arquivos
Checkout Branch
Checkout Commit
- Aviso: Ao fazer o checkout de um commit, seu Head ficará desanexado
Commit:
- Branch:
+ Aviso: Ao fazer o checkout de um commit, seu Head ficará desanexado
Alterações Locais:
Descartar
- Nada
Stash & Reaplicar
+ Branch:
Cherry-Pick
Adicionar origem à mensagem de commit
Commit(s):
@@ -128,9 +88,9 @@
URL do Repositório:
FECHAR
Editor
+ Checar Commit
Cherry-Pick este commit
Cherry-Pick ...
- Checar Commit
Comparar com HEAD
Comparar com Worktree
Copiar Informações
@@ -161,12 +121,12 @@
REFERÊNCIAS
SHA
Abrir no navegador
- Insira o assunto do commit
Descrição
+ Insira o assunto do commit
Configurar Repositório
TEMPLATE DE COMMIT
- Nome do Template:
Conteúdo do Template:
+ Nome do Template:
AÇÃO CUSTOMIZADA
Argumentos:
${REPO} - Caminho do repositório; ${SHA} - SHA do commit selecionado
@@ -181,13 +141,12 @@
Buscar remotos automaticamente
Minuto(s)
Remoto padrão
- Habilita --prune ao buscar
- Habilita --signoff para commits
RASTREADOR DE PROBLEMAS
+ Adicionar Regra de Exemplo do Azure DevOps
Adicionar Regra de Exemplo do Github
- Adicionar Regra de Exemplo do Jira
Adicionar Regra de Exemplo do GitLab
Adicionar regra de exemplo de Merge Request do GitLab
+ Adicionar Regra de Exemplo do Jira
Nova Regra
Expressão Regex de Issue:
Nome da Regra:
@@ -213,13 +172,11 @@
Copiar
Copiar todo o texto
Copiar Caminho
- Copiar Nome do Arquivo
Criar Branch...
Baseado Em:
Checar o branch criado
Alterações Locais:
Descartar
- Não Fazer Nada
Guardar & Reaplicar
Nome do Novo Branch:
Insira o nome do branch.
@@ -311,11 +268,11 @@
Desfazer Preparação
Desfazer Preparação de {0} arquivos
Desfazer Preparação nas Linhas Selecionadas
- Usar Deles (checkout --theirs)
Usar Meu (checkout --ours)
+ Usar Deles (checkout --theirs)
Histórico de Arquivos
- CONTEUDO
MUDANÇA
+ CONTEUDO
Git-Flow
Branch de Desenvolvimento:
Feature:
@@ -345,8 +302,8 @@
Padrão Personalizado:
Adicionar Padrão de Rastreamento ao Git LFS
Buscar
- Buscar Objetos LFS
Execute `git lfs fetch` para baixar objetos Git LFS. Isso não atualiza a cópia de trabalho.
+ Buscar Objetos LFS
Instalar hooks do Git LFS
Exibir bloqueios
Sem Arquivos Bloqueados
@@ -358,11 +315,11 @@
Prune
Execute `git lfs prune` para excluir arquivos LFS antigos do armazenamento local
Puxar
- Puxar Objetos LFS
Execute `git lfs pull` para baixar todos os arquivos Git LFS para a referência atual e checkout
+ Puxar Objetos LFS
Enviar
- Enviar Objetos LFS
Envie arquivos grandes enfileirados para o endpoint Git LFS
+ Enviar Objetos LFS
Remoto:
Rastrear arquivos nomeados '{0}'
Rastrear todos os arquivos *{0}
@@ -380,10 +337,10 @@
GLOBAL
Cancelar popup atual
Fechar página atual
- Ir para a página anterior
Ir para a próxima página
+ Ir para a página anterior
Criar nova página
- Abrir diálogo de preferências
+ Abrir diálogo de preferências
REPOSITÓRIO
Commitar mudanças preparadas
Commitar e enviar mudanças preparadas
@@ -392,11 +349,11 @@
Descartar mudanças selecionadas
Buscar, imediatamente
Modo de Dashboard (Padrão)
+ Modo de busca de commits
Puxar, imediatamente
Enviar, imediatamente
Forçar recarregamento deste repositório
Preparar/Despreparar mudanças selecionadas
- Modo de busca de commits
Alternar para 'Mudanças'
Alternar para 'Históricos'
Alternar para 'Stashes'
@@ -405,9 +362,9 @@
Encontrar próxima correspondência
Encontrar correspondência anterior
Abrir painel de busca
+ Descartar
Preparar
Despreparar
- Descartar
Inicializar Repositório
Caminho:
Cherry-Pick em andamento.
@@ -415,10 +372,10 @@
Rebase em andamento.
Revert em andamento.
Rebase Interativo
- Ramo Alvo:
Em:
- Abrir no navegador
+ Ramo Alvo:
Copiar link
+ Abrir no navegador
ERRO
AVISO
Mesclar Ramo
@@ -439,77 +396,78 @@
Copiar Caminho do Repositório
Repositórios
Colar
- Agora mesmo
- {0} minutos atrás
- {0} horas atrás
- Ontem
{0} dias atrás
+ 1 hora atrás
+ {0} horas atrás
+ Agora mesmo
Mês passado
- {0} meses atrás
Ano passado
+ {0} minutos atrás
+ {0} meses atrás
{0} anos atrás
- Preferências
- INTELIGÊNCIA ARTIFICIAL
- Prompt para Analisar Diff
- Chave da API
- Prompt para Gerar Título
- Modelo
- Nome
- Servidor
- APARÊNCIA
- Fonte Padrão
- Tamanho da Fonte
- Padrão
- Editor
- Fonte Monoespaçada
- Usar fonte monoespaçada apenas no editor de texto
- Tema
- Substituições de Tema
- Usar largura fixa de aba na barra de título
- Usar moldura de janela nativa
- FERRAMENTA DE DIFF/MERGE
- Caminho de Instalação
- Insira o caminho para a ferramenta de diff/merge
- Ferramenta
- GERAL
- Verificar atualizações na inicialização
- Idioma
- Commits do Histórico
- Exibir data do autor em vez da data do commit no gráfico
- Comprimento do Guia de Assunto
- GIT
- Habilitar Auto CRLF
- Diretório de Clone Padrão
- Email do Usuário
- Email global do usuário git
- Caminho de Instalação
- Nome do Usuário
- Nome global do usuário git
- Versão do Git
- Git (>= 2.23.0) é necessário para este aplicativo
- ASSINATURA GPG
- Assinatura GPG de commit
- Assinatura GPG de tag
- Formato GPG
- Caminho de Instalação do Programa
- Insira o caminho para o programa gpg instalado
- Chave de Assinatura do Usuário
- Chave de assinatura gpg do usuário
- INTEGRAÇÃO
- SHELL/TERMINAL
- Shell/Terminal
- Caminho
+ Ontem
+ Preferências
+ INTELIGÊNCIA ARTIFICIAL
+ Prompt para Analisar Diff
+ Chave da API
+ Prompt para Gerar Título
+ Modelo
+ Nome
+ Servidor
+ APARÊNCIA
+ Fonte Padrão
+ Tamanho da Fonte
+ Padrão
+ Editor
+ Fonte Monoespaçada
+ Usar fonte monoespaçada apenas no editor de texto
+ Tema
+ Substituições de Tema
+ Usar largura fixa de aba na barra de título
+ Usar moldura de janela nativa
+ FERRAMENTA DE DIFF/MERGE
+ Caminho de Instalação
+ Insira o caminho para a ferramenta de diff/merge
+ Ferramenta
+ GERAL
+ Verificar atualizações na inicialização
+ Idioma
+ Commits do Histórico
+ Exibir data do autor em vez da data do commit no gráfico
+ Comprimento do Guia de Assunto
+ GIT
+ Habilitar Auto CRLF
+ Diretório de Clone Padrão
+ Email do Usuário
+ Email global do usuário git
+ Habilita --prune ao buscar
+ Git (>= 2.23.0) é necessário para este aplicativo
+ Caminho de Instalação
+ Nome do Usuário
+ Nome global do usuário git
+ Versão do Git
+ ASSINATURA GPG
+ Assinatura GPG de commit
+ Formato GPG
+ Caminho de Instalação do Programa
+ Insira o caminho para o programa gpg instalado
+ Assinatura GPG de tag
+ Chave de Assinatura do Usuário
+ Chave de assinatura gpg do usuário
+ INTEGRAÇÃO
+ SHELL/TERMINAL
+ Caminho
+ Shell/Terminal
Prunar Remoto
Alvo:
Podar Worktrees
- Podar informações de worktree em `$GIT_DIR/worktrees`
+ Podar informações de worktree em `$GIT_COMMON_DIR/worktrees`
Puxar
Branch Remoto:
Buscar todos os branches
Para:
Alterações Locais:
Descartar
- Não Fazer Nada
Guardar & Reaplicar
Buscar sem tags
Remoto:
@@ -568,11 +526,11 @@
Desfazer
Esconder no gráfico de commit
Incluir no gráfico de commit
- Data do Commit (--date-order)
- Topologicamente (--topo-order)
+ Habilitar opção '--first-parent'
+ Data do Commit
+ Topologicamente
BRANCHES LOCAIS
Navegar para HEAD
- Habilitar opção '--first-parent'
Criar Branch
Abrir em {0}
Abrir em Ferramentas Externas
@@ -580,10 +538,11 @@
REMOTOS
ADICIONAR REMOTO
Pesquisar Commit
+ Autor
+ Committer
Arquivo
Mensagem
SHA
- Autor & Committer
Branch Atual
Exibir Tags como Árvore
Estatísticas
@@ -636,7 +595,6 @@
Guardar Alterações Locais
Aplicar
Descartar
- Pop
Descartar Stash
Descartar:
Stashes
@@ -645,11 +603,11 @@
Estatísticas
COMMITS
COMMITTER
+ VISÃO GERAL
MÊS
SEMANA
- COMMITS:
AUTORES:
- VISÃO GERAL
+ COMMITS:
SUBMÓDULOS
Adicionar Submódulo
Copiar Caminho Relativo
@@ -664,13 +622,13 @@
Excluir ${0}$...
Mesclar ${0}$ em ${1}$...
Enviar ${0}$...
- URL:
Atualizar Submódulos
Todos os submódulos
Inicializar conforme necessário
Recursivamente
Submódulo:
Usar opção --remote
+ URL:
Aviso
Página de Boas-vindas
Criar Grupo Raíz
@@ -699,12 +657,12 @@
Modelo/Históricos
Acionar evento de clique
Preparar todas as mudanças e commitar
- Commit vazio detectado! Deseja continuar (--allow-empty)?
CONFLITOS DETECTADOS
CONFLITOS DE ARQUIVO RESOLVIDOS
INCLUIR ARQUIVOS NÃO RASTREADOS
SEM MENSAGENS DE ENTRADA RECENTES
SEM MODELOS DE COMMIT
+ Clique com o botão direito nos arquivos selecionados e escolha como resolver conflitos.
STAGED
UNSTAGE
UNSTAGE TODOS
@@ -713,7 +671,6 @@
STAGE TODOS
VER SUPOR NÃO ALTERADO
Template: ${0}$
- Clique com o botão direito nos arquivos selecionados e escolha como resolver conflitos.
Workspaces:
Configurar workspaces...
WORKTREE
diff --git a/src/Resources/Locales/ru_RU.axaml b/src/Resources/Locales/ru_RU.axaml
index ee84d679..b26532ae 100644
--- a/src/Resources/Locales/ru_RU.axaml
+++ b/src/Resources/Locales/ru_RU.axaml
@@ -2,41 +2,34 @@
+
О программе
О SourceGit
- • Сборка с
- • Диаграмма отображается с помощью
- © 2024 sourcegit-scm
- • Текстовый редактор от
- • Моноширинные шрифты взяты из
- • Исходный код можно найти по адресу
Бесплатный графический клиент Git с исходным кодом
Добавить рабочий каталог
- Что проверить:
- Существующую ветку
- Создать новую ветку
Расположение:
Путь к рабочему каталогу (поддерживается относительный путь)
Имя ветки:
Имя целевого каталога по умолчанию. (необязательно)
Отслеживание ветки:
Отслеживание внешней ветки
- OpenAI Ассистент
+ Переключиться на:
+ создать новую ветку
+ ветку из списка
+ Помощник OpenAI
+ ПЕРЕСОЗДАТЬ
Использовать OpenAI для создания сообщения о ревизии
+ ПРИМЕНИТЬ КАК СООБЩЕНИЕ РЕВИЗИИ
Исправить
- Ошибка
- Выдает ошибки и отказывается применять исправление
- Все ошибки
- Аналогично «ошибке», но показывает больше
- Файл исправлений:
+ Файл заплатки:
Выберите файл .patch для применения
Игнорировать изменения пробелов
- Нет предупреждений
- Отключить предупреждения о пробелах в конце
- Применить исправление
- Предупреждать
- Выдавать предупреждения о нескольких таких ошибках, но применять
+ Применить заплатку
Пробел:
+ Отложить
+ Удалить после применения
+ Восстановить изменения индекса
+ Отложенный:
Архивировать...
Сохранить архив в:
Выберите путь к архивному файлу
@@ -50,10 +43,10 @@
Расследование
РАССЛЕДОВАНИЕ В ЭТОМ ФАЙЛЕ НЕ ПОДДЕРЖИВАЕТСЯ!!!
Проверить ${0}$...
- Сравнить с веткой
- Сравнить с ГОЛОВОЙ (HEAD)
+ Сравнить с ГОЛОВОЙ (HEAD)
Сравнить с рабочим каталогом
Копировать имя ветки
+ Изменить действие
Удалить ${0}$...
Удалить выбранные {0} ветки
Отклонить все изменения.
@@ -69,10 +62,11 @@
Переименовать ${0}$...
Отслеживать ветку...
Сравнение веток
+ Недопустимая основная ветка!
Байты
ОТМЕНА
- Сбросить эту ревизию
Сбросить родительскую ревизию
+ Сбросить эту ревизию
Произвести сообщение о ревизии
ИЗМЕНИТЬ РЕЖИМ ОТОБРАЖЕНИЯ
Показывать в виде списка файлов и каталогов
@@ -80,13 +74,12 @@
Показывать в виде дерева файловой системы
Переключить ветку
Переключение ревизии
- Предупреждение: После переключения ревизии ваша Голова (HEAD) будет отсоединена
Ревизия:
- Ветка:
+ Предупреждение: После переключения ревизии ваша Голова (HEAD) будет отсоединена
Локальные изменения:
Отклонить
- Ничего не делать
Отложить и примненить повторно
+ Ветка:
Частичный выбор
Добавить источник для ревизии сообщения
Ревизия(и):
@@ -101,12 +94,13 @@
Локальное имя:
Имя репозитория. (необязательно).
Родительский каталог:
+ Создать и обновить подмодуль
Адрес репозитория:
ЗАКРЫТЬ
Редактор
+ Переключиться на эту ревизию
Применить эту ревизию (cherry-pick)
Применить несколько ревизий ...
- Переключиться на эту ревизию
Сравнить c ГОЛОВОЙ (HEAD)
Сравнить с рабочим каталогом
Копировать информацию
@@ -114,12 +108,12 @@
Пользовательское действие
Интерактивное перемещение (rebase -i) ${0}$ сюда
Влить в ${0}$
- Влить ветки...
+ Влить ...
Переместить ${0}$ сюда
Сбросить ${0}$ сюда
Отменить ревизию
Изменить комментарий
- Сохранить как patch-файл...
+ Сохранить как заплатки...
Объединить с предыдущей ревизией
Объединить все следующие ревизии с этим
ИЗМЕНЕНИЯ
@@ -132,7 +126,7 @@
АВТОР
ИЗМЕНЁННЫЙ
ДОЧЕРНИЙ
- ИСПОЛНИТЕЛЬ
+ РЕВИЗОР (ИСПОЛНИТЕЛЬ)
Найти все ветки с этой ревизией
ВЕТКИ С ЭТОЙ РЕВИЗИЕЙ
Отображаются только первые 100 изменений. Смотрите все изменения на вкладке ИЗМЕНЕНИЯ.
@@ -141,35 +135,36 @@
ССЫЛКИ
SHA
Открыть в браузере
- Введите тему ревизии
Описание
+ Введите тему ревизии
Настройка репозитория
ШАБЛОН РЕВИЗИИ
- Название:
Cодержание:
+ Название:
ПОЛЬЗОВАТЕЛЬСКОЕ ДЕЙСТВИЕ
Аргументы:
${REPO} - Путь к репозиторию; ${SHA} - SHA ревизий
Исполняемый файл:
Имя:
Диапазон:
+ Ветка
Ревизия
Репозиторий
+ Ждать для выполения выхода
Адрес электронной почты
Адрес электронной почты
GIT
- Автоматическое скачивание изменений
+ Автозагрузка изменений
Минут(а/ы)
- Разрешить '--signoff' для ревизии
Внешний репозиторий по умолчанию
- Разрешить '--prune' при скачивании
ОТСЛЕЖИВАНИЕ ПРОБЛЕМ
- Добавить пример правила для тем в Gitee
- Добавить пример правила запроса скачивания из Gitee
+ Добавить пример правила Azure DevOps
+ Добавить пример правила для тем в Gitea
+ Добавить пример правила запроса скачивания из Gitea
Добавить пример правила для Git
- Добавить пример правила Jira
Добавить пример правила выдачи GitLab
Добавить пример правила запроса на слияние в GitLab
+ Добавить пример правила Jira
Новое правило
Проблема с регулярным выражением:
Имя правила:
@@ -183,8 +178,8 @@
Имя пользователя
Имя пользователя репозитория
Рабочие пространства
- Имя
Цвет
+ Имя
Восстанавливать вкладки при запуске
Общепринятый помощник по ревизии
Кардинальные изменения:
@@ -195,31 +190,31 @@
Тип изменения:
Копировать
Копировать весь текст
+ Копировать полный путь
Копировать путь
- Копировать имя файла
Создать ветку...
Основан на:
Проверить созданную ветку
Локальные изменения:
Отклонить
- Ничего не делать
Отложить и применить повторно
Имя новой ветки:
Введите имя ветки.
+ Пробелы будут заменены на тире.
Создать локальную ветку
Создать метку...
Новая метка у:
GPG подпись
- Сообщение с меткой:
+ Сообщение с
меткой:
Необязательно.
Имя метки:
Рекомендуемый формат: v1.0.0-alpha
Выложить на все внешние репозитории после создания
Создать новую метку
Вид:
- Аннотированный
- Лёгкий
- Удерживайте Ctrl, чтобы начать сразу
+ С примечаниями
+ Простой
+ Удерживайте Ctrl, чтобы сразу начать
Вырезать
Удалить ветку
Ветка:
@@ -229,7 +224,10 @@
Вы пытаетесь удалить несколько веток одновременно. Обязательно перепроверьте, прежде чем предпринимать какие-либо действия!
Удалить внешний репозиторий
Внешний репозиторий:
+ Путь:
Цель:
+ Все дочерние элементы будут удалены из списка.
+ Будет удалён из списка. На диске останется.
Подтвердите удаление группы
Подтвердите удаление репозитория
Удалить подмодуль
@@ -242,14 +240,16 @@
СТАРЫЙ
Копировать
Режим файла изменён
+ Первое различие
Игнорировать изменение пробелов
- Показывать скрытые символы
+ Последнее различие
ИЗМЕНЕНИЕ ОБЪЕКТА LFS
Следующее различие
НИКАКИХ ИЗМЕНЕНИЙ ИЛИ МЕНЯЕТСЯ ТОЛЬКО EOL
Предыдущее различие
- Сохранить как исправление
- Различие бок о бок
+ Сохранить как заплатку
+ Показывать скрытые символы
+ Различие рядом
ПОДМОДУЛЬ
НОВЫЙ
Обмен
@@ -266,7 +266,7 @@
Все локальные изменения в рабочей копии.
Изменения:
Включить игнорируемые файлы
- Всего {0} изменений будут отменены
+ {0} изменений будут отменены
Вы не можете отменить это действие!!!
Закладка:
Новое имя:
@@ -278,7 +278,7 @@
Быстрая перемотка вперёд (без проверки)
Извлечь
Извлечь все внешние репозитории
- Разрешить опцию '--force'
+ Разрешить опцию (--force)
Извлечь без меток
Внешний репозиторий:
Извлечь внешние изменения
@@ -288,7 +288,7 @@
Отменить изменения в выбранной(ых) строке(ах)
Открыть расширенный инструмент слияния
Взять версию ${0}$
- Сохранить как patch-файл...
+ Сохранить как файл заплатки...
Подготовить
Подготовленные {0} файлы
Подготовленные изменения в выбранной(ых) строке(ах)
@@ -297,11 +297,11 @@
Снять подготовленный
Неподготовленные {0} файлы
Неподготовленные изменения в выбранной(ых) строке(ах)
- Использовать их (checkout --theirs)
Использовать мой (checkout --ours)
+ Использовать их (checkout --theirs)
История файлов
- СОДЕРЖИМОЕ
ИЗМЕНИТЬ
+ СОДЕРЖИМОЕ
Git-поток
Ветка разработчика:
Свойство:
@@ -312,7 +312,7 @@
Цель:
Исправление:
Префикс исправлений:
- Инициализировать Git-поток
+ Создать Git-поток
Держать ветку
Производственная ветка:
Выпуск:
@@ -331,8 +331,8 @@
Изменить шаблон:
Добавить шаблон отслеживания в LFS Git
Извлечь
+ Запустить (git lfs fetch), чтобы загрузить объекты LFS Git. При этом рабочая копия не обновляется.
Извлечь объекты LFS
- Запустить «git lfs fetch», чтобы загрузить объекты LFS Git. При этом рабочая копия не обновляется.
Установить перехват LFS Git
Показывать блокировки
Нет заблокированных файлов
@@ -342,13 +342,13 @@
Разблокировать
Принудительно разблокировать
Обрезать
- Запустить «git lfs prune», чтобы удалить старые файлы LFS из локального хранилища
+ Запустить (git lfs prune), чтобы удалить старые файлы LFS из локального хранилища
Забрать
+ Запустить (git lfs pull), чтобы загрузить все файлы LFS Git для текущей ссылки и проверить
Забрать объекты LFS
- Запустить «git lfs pull», чтобы загрузить все файлы LFS Git для текущей ссылки и проверить
Выложить
- Выложить объекты LFS
Отправляйте большие файлы, помещенные в очередь, в конечную точку LFS Git
+ Выложить объекты LFS
Внешнее хранилище:
Отслеживать файлы с именем «{0}»
Отслеживать все *{0} файлов
@@ -367,10 +367,10 @@
Закрыть окно
Клонировать репозиторий
Закрыть вкладку
- Перейти на предыдущую вкладку
Перейти на следующую вкладку
+ Перейти на предыдущую вкладку
Создать новую вкладку
- Открыть диалоговое окно настроек
+ Открыть диалоговое окно настроек
РЕПОЗИТОРИЙ
Зафиксировать подготовленные изменения
Зафиксировать и выложить подготовленные изменения
@@ -379,11 +379,11 @@
Отклонить выбранные изменения
Извлечение, запускается сразу
Режим доски (по умолчанию)
- Принудительно перезагрузить репозиторий
+ Режим поиска ревизий
Забрать, запускается сразу
Выложить, запускается сразу
+ Принудительно перезагрузить репозиторий
Подготовленные/Неподготовленные выбранные изменения
- Режим поиска ревизий
Переключить на «Изменения»
Переключить на «Истории»
Переключить на «Отложенные»
@@ -392,10 +392,10 @@
Найти следующее совпадение
Найти предыдущее совпадение
Открыть панель поиска
+ Отклонить
Подготовить
Снять из подготовленных
- Отклонить
- Инициализировать репозиторий
+ Создать репозиторий
Путь:
Выполняется частичный перенос ревизий (cherry-pick).
Обрабтка ревизии.
@@ -406,11 +406,11 @@
Выполняется отмена ревизии.
Выполняется отмена
Интерактивное перемещение
- Целевая ветка:
На:
- Открыть в браузере
+ Целевая ветка:
Копировать ссылку
- ОШИБКА
+ Открыть в браузере
+ ОШИБКА
УВЕДОМЛЕНИЕ
Влить ветку
В:
@@ -435,80 +435,84 @@
Копировать путь репозитория
Репозитории
Вставить
- Сейчас
- {0} минут назад
- {0} часов назад
- Вчера
{0} дней назад
+ 1 час назад
+ {0} часов назад
+ Сейчас
Последний месяц
- {0} месяцев назад
В прошлом году
+ {0} минут назад
+ {0} месяцев назад
{0} лет назад
- Параметры
- ОТКРЫТЬ ИИ
- Ключ API
- Запрос на анализ различий
- Произвести запрос на тему
- Модель
- Имя:
- Сервер
- ВИД
- Шрифт по умолчанию
- Размер шрифта
- По умолчанию
- Редактор
- Моноширный шрифт
- В текстовом редакторе используется только моноширный шрифт
- Тема
- Переопределение темы
- Использовать фиксированную ширину табуляции в строке заголовка.
- Использовать системное окно
- ИНСТРУМЕНТ РАЗЛИЧИЙ/СЛИЯНИЯ
- Путь установки
- Введите путь для инструмента различия/слияния
- Инструмент
- ОСНОВНЫЕ
- Проверить обновления при старте
- Формат даты
- Язык
- Максимальная длина истории
- Показывать время автора вместо времени ревизии на графике
- Показать наследника в деталях комментария
- Длина темы ревизии
- GIT
- Включить автозавершение CRLF
- Каталог клонирования по умолчанию
- Электроная почта пользователя
- Общая электроная почта пользователя git
- Путь установки
- Разрешить верификацию HTTP SSL
- Имя пользователя
- Общее имя пользователя git
- Версия Git
- Для работы программы требуется версия Git (>= 2.23.0)
- GPG ПОДПИСЬ
- GPG подпись ревизии
- GPG подпись метки
- Формат GPG
- Путь установки программы
- Введите путь для установленной программы GPG
- Ключ подписи пользователя
- Ключ GPG подписи пользователя
- ВНЕДРЕНИЕ
- ОБОЛОЧКА/ТЕРМИНАЛ
- Оболочка/Терминал
- Путь
+ Вчера
+ Параметры
+ ОТКРЫТЬ ИИ
+ Запрос на анализ различий
+ Ключ API
+ Произвести запрос на тему
+ Модель
+ Имя:
+ Сервер
+ Разрешить потоковую передачу
+ ВИД
+ Шрифт по умолчанию
+ Редактировать ширину вкладки
+ Размер шрифта
+ По умолчанию
+ Редактор
+ Моноширный шрифт
+ В текстовом редакторе используется только моноширный шрифт
+ Тема
+ Переопределение темы
+ Использовать фиксированную ширину табуляции в строке заголовка.
+ Использовать системное окно
+ ИНСТРУМЕНТ РАЗЛИЧИЙ/СЛИЯНИЯ
+ Путь установки
+ Введите путь для инструмента различия/слияния
+ Инструмент
+ ОСНОВНЫЕ
+ Проверить обновления при старте
+ Формат даты
+ Язык
+ Максимальная длина истории
+ Показывать время автора вместо времени ревизии на графике
+ Показать наследника в деталях комментария
+ Показывать метки на графике
+ Длина темы ревизии
+ GIT
+ Включить автозавершение CRLF
+ Каталог клонирования по умолчанию
+ Электроная почта пользователя
+ Общая электроная почта пользователя git
+ Разрешить (--prune) при скачивании
+ Для работы программы требуется версия Git (>= 2.23.0)
+ Путь установки
+ Разрешить верификацию HTTP SSL
+ Имя пользователя
+ Общее имя пользователя git
+ Версия Git
+ GPG ПОДПИСЬ
+ GPG подпись ревизии
+ Формат GPG
+ Путь установки программы
+ Введите путь для установленной программы GPG
+ GPG подпись метки
+ Ключ подписи пользователя
+ Ключ GPG подписи пользователя
+ ВНЕДРЕНИЕ
+ ОБОЛОЧКА/ТЕРМИНАЛ
+ Путь
+ Оболочка/Терминал
Удалить внешний репозиторий
Цель:
Удалить рабочий каталог
- Информация об обрезке рабочего каталога в «$GIT_DIR/worktrees»
+ Информация об обрезке рабочего каталога в «$GIT_COMMON_DIR/worktrees»
Забрать
Ветка внешнего репозитория:
Извлечь все ветки
В:
Локальные изменения:
Отклонить
- Ничего не делать
Отложить и применить повторно
Забрать без меток
Внешний репозиторий:
@@ -537,7 +541,7 @@
Редактировать внешний репозиторий
Имя:
Имя внешнего репозитория
- Адрес репозитория:
+ Адрес:
Адрес внешнего репозитория git
Копировать адрес
Удалить...
@@ -546,7 +550,7 @@
Открыть в браузере
Удалить
Подтвердить удаление рабочего каталога
- Включить опцию --force
+ Включить опцию (--force)
Цель:
Переименовать ветку
Новое имя:
@@ -555,7 +559,7 @@
Отказ
Автоматическое извлечение изменений с внешних репозиторий...
Очистить (Сбор мусора и удаление)
- Запустить команду «git gc» для данного репозитория.
+ Запустить команду (git gc) для данного репозитория.
Очистить всё
Настройка репозитория
ПРОДОЛЖИТЬ
@@ -569,16 +573,17 @@
Скрыть в графе ревизии
Фильтр в графе ревизии
ОТФИЛЬТРОВАНО:
+ Включить опцию (--first-parent)
РАСПОЛОЖЕНИЕ
Горизонтально
Вертикально
ЗАПРОС РЕВИЗИЙ
- Дата ревизии (--date-order)
- Топологически (--topo-order)
+ Дата ревизии
+ Топологически
ЛОКАЛЬНЫЕ ВЕТКИ
Навигация по ГОЛОВЕ (HEAD)
- Включить опцию --first-parent
Создать ветку
+ ОЧИСТКА УВЕДОМЛЕНИЙ
Выделять только текущую ветку на графике
Открыть в {0}
Открыть в расширенном инструменте
@@ -586,10 +591,11 @@
ВНЕШНИЕ РЕПОЗИТОРИИ
ДОБАВИТЬ ВНЕШНИЙ РЕПОЗИТОРИЙ
Поиск ревизии
+ Автор
+ Ревизор
Файл
Сообщение
SHA
- Автор и исполнитель
Текущая ветка
Показывать метки как катлог
ПРОПУСТИТЬ
@@ -622,11 +628,9 @@
Запуск. Подождите пожалуйста...
СОХРАНИТЬ
Сохранить как...
- Исправление успешно сохранено!
+ Заплатка успешно сохранена!
Сканирование репозиторий
Корневой каталог:
- Копировать SHA
- Перейти
Проверка для обновления...
Доступна новая версия программного обеспечения:
Не удалось проверить наличие обновлений!
@@ -638,22 +642,26 @@
Ветка:
Снять основную ветку
Основная ветка:
+ Копировать SHA
+ Перейти
Втиснуть ревизии
В:
Приватный ключ SSH:
Путь хранения приватного ключа SSH
- Только подготовленные изменения
- Подготовленные так и неподготовленные изменения выбранных файлов будут сохранены!!!
ЗАПУСК
Отложить
+ Автоматически восстанавливать после откладывания
+ Ваши рабочие файлы остаются неизменными, но отложенные сохранятся.
Включить неотслеживаемые файлы
Хранить отложенные файлы
Сообщение:
Имя тайника (необязательно)
+ Только подготовленные изменения
+ Подготовленные так и неподготовленные изменения выбранных файлов будут сохранены!!!
Отложить локальные изменения
Принять
Отбросить
- Применить
+ Сохранить как заплатку...
Отбросить тайник
Отбросить:
Отложенные
@@ -661,19 +669,19 @@
ОТЛОЖЕННЫЕ
Статистика
РЕВИЗИИ
- ИСПОЛНИТЕЛИ
+ РЕВИЗОРЫ (ИСПОЛНИТЕЛИ)
+ ОБЗОР
МЕСЯЦ
НЕДЕЛЯ
- РЕВИЗИИ:
АВТОРЫ:
- ОБЗОР
+ РЕВИЗИИ:
ПОДМОДУЛИ
Добавить подмодули
Копировать относительный путь
Извлечение вложенных подмодулей
Открыть подмодуль репозитория
- Относительный путь:
- Относительный каталог для хранения подмодуля.
+ Каталог:
+ Относительный путь для хранения подмодуля.
Удалить подмодуль
ОК
Копировать имя метки
@@ -681,13 +689,13 @@
Удалить ${0}$...
Влить ${0}$ в ${1}$...
Выложить ${0}$...
- Сетевой адрес:
Обновление подмодулей
Все подмодули
- Инициализировать по необходимости
+ Создавать по необходимости
Рекурсивно
Подмодуль:
- Использовать опцию '--remote'
+ Использовать опцию (--remote)
+ Сетевой адрес:
Предупреждение
Приветствие
Создать группу
@@ -700,7 +708,7 @@
Открыть все репозитории
Открыть репозиторий
Открыть терминал
- Повторное сканирование репозиториев в каталоге клонирования по умолчанию
+ Повторное сканирование репозиториев в каталоге клонирования по умолчанию
Поиск репозиториев...
Сортировка
Изменения
@@ -717,12 +725,13 @@
Запустить событие щелчка
Зафиксировать (Редактировать)
Подготовить все изменения и зафиксировать
- Обнаружена пустая ревизия! Вы хотите продолжить (--allow-empty)?
ОБНАРУЖЕНЫ КОНФЛИКТЫ
КОНФЛИКТЫ ФАЙЛОВ РАЗРЕШЕНЫ
ВКЛЮЧИТЬ НЕОТСЛЕЖИВАЕМЫЕ ФАЙЛЫ
НЕТ ПОСЛЕДНИХ ВХОДНЫХ СООБЩЕНИЙ
НЕТ ШАБЛОНОВ РЕВИЗИИ
+ Щёлкните правой кнопкой мыши выбранный файл(ы) и разрешите конфликты.
+ Завершение работы
ПОДГОТОВЛЕННЫЕ
СНЯТЬ ПОДГОТОВЛЕННЫЙ
СНЯТЬ ВСЕ ПОДГОТОВЛЕННЫЕ
@@ -731,7 +740,6 @@
ВСЕ ПОДГОТОВИТЬ
ОТКРЫТЬ СПИСОК НЕОТСЛЕЖИВАЕМЫХ ФАЙЛОВ
Шаблон: ${0}$
- Щёлкните правой кнопкой мыши выбранный файл(ы) и разрешите конфликты.
РАБОЧЕЕ ПРОСТРАНСТВО:
Настройка рабочего пространства...
РАБОЧИЙ КАТАЛОГ
diff --git a/src/Resources/Locales/ta_IN.axaml b/src/Resources/Locales/ta_IN.axaml
new file mode 100644
index 00000000..946a8d9c
--- /dev/null
+++ b/src/Resources/Locales/ta_IN.axaml
@@ -0,0 +1,749 @@
+
+
+
+
+
+ பற்றி
+ மூலஅறிவிலி பற்றி
+ திறந்தமூல & கட்டற்ற அறிவிலி இடைமுக வாடிக்கயாளர்
+ பணிமரத்தைச் சேர்
+ இடம்:
+ இந்த பணிமரத்திற்கான பாதை. தொடர்புடைய பாதை ஆதரிக்கப்படுகிறது.
+ கிளை பெயர்:
+ விருப்பத்தேர்வு. இயல்புநிலை இலக்கு கோப்புறை பெயர்.
+ கிளை கண்காணி:
+ தொலை கிளையைக் கண்காணித்தல்
+ என்ன சரிபார்க்க வேண்டும்:
+ புதிய கிளையை உருவாக்கு
+ ஏற்கனவே உள்ள கிளை
+ செநு உதவியாளர்
+ மறு-உருவாக்கு
+ உறுதிமொழி செய்தியை உருவாக்க செநுவைப் பயன்படுத்து
+ உறுதிமொழி செய்தி என இடு
+ ஒட்டு
+ ஒட்டு கோப்பு:
+ .ஒட்டு இடுவதற்கு கோப்பைத் தேர்ந்தெடு
+ வெள்ளைவெளி மாற்றங்களைப் புறக்கணி
+ ஒட்டு இடு
+ வெள்ளைவெளி:
+ பதுக்கிவைத்ததை இடு
+ பயன்படுத்திய பின் நீக்கு
+ குறியீட்டின் மாற்றங்களை மீண்டும் நிறுவு
+ பதுக்கிவை:
+ காப்பகம்...
+ இதற்கு காப்பகத்தை சேமி:
+ காப்பகக் கோப்பு பாதையைத் தேர்ந்தெடு
+ திருத்தம்:
+ காப்பகம்
+ மூலஅறிவிலி கடவுகேள்
+ கோப்புகள் மாற்றப்படவில்லை எனக் கருதப்படுகிறது
+ எந்த கோப்புகளும் மாற்றப்படவில்லை எனக் கருதப்படுகிறது
+ நீக்கு
+ இருமம் கோப்பு ஆதரிக்கப்படவில்லை!!!
+ குற்றச்சாட்டு
+ இந்த கோப்பில் குற்றம் சாட்ட ஆதரிக்கப்படவில்லை!!!
+ ${0}$ சரிபார்...
+ தலையுடன் ஒப்பிடுக
+ பணிமரத்துடன் ஒப்பிடுக
+ கிளை பெயரை நகலெடு
+ தனிப்பயன் செயல்
+ ${0}$ ஐ நீக்கு...
+ தேர்ந்தெடுக்கப்பட்ட {0} கிளைகளை நீக்கு
+ எல்லா மாற்றங்களையும் நிராகரி
+ ${0}$ இதற்கு வேகமாக முன்னோக்கிச் செல்
+ ${0}$ ஐ ${1}$இல் பெறு...
+ அறிவிலி ஓட்டம் - முடி ${0}$
+ ${0}$ ஐ ${1}$இல் இணை...
+ தேர்ந்தெடுக்கப்பட்ட {0} கிளைகளை தற்பொதையதில் இணை
+ இழு ${0}$
+ இழு ${0}$ஐ ${1}$-க்குள்...
+ தள்ளு ${0}$
+ மறுதளம் ${0}$ இதன்மேல் ${1}$...
+ மறுபெயரிடு ${0}$...
+ கண்காணிப்பு கிளையை அமை...
+ கிளை ஒப்பிடு
+ தவறான மேல்ஓடை!
+ எண்மங்கள்
+ விடு
+ பெற்றோர் திருத்தத்திற்கு மீட்டமை
+ இந்த திருத்தத்திற்கு மீட்டமை
+ உறுதிமொழி செய்தி உருவாக்கு
+ காட்சி பயன்முறையை மாற்று
+ கோப்பு மற்றும் கோப்புறை பட்டியலாக காட்டு
+ பாதை பட்டியலாகக் காட்டு
+ கோப்பு முறைமை மரமாகக் காட்டு
+ கிளை சரிபார்
+ உறுதிமொழி சரிபார்
+ உறுதிமொழி:
+ முன்னறிவிப்பு: ஒரு உறுதிமொழி சரிபார்பதன் மூலம், உங்கள் தலை பிரிக்கப்படும்
+ உள்ளக மாற்றங்கள்:
+ நிராகரி
+ பதுக்கிவை & மீண்டும் இடு
+ கிளை:
+ கனி பறி
+ உறுதிமொழி செய்திக்கு மூலத்தைச் சேர்
+ உறுதிமொழி(கள்):
+ அனைத்து மாற்றங்களையும் உறுதிமொழி
+ முதன்மைகோடு:
+ பொதுவாக நீங்கள் ஒரு ஒன்றிணையை கனி-பறிக்க முடியாது, ஏனெனில் இணைப்பின் எந்தப் பக்கத்தை முதன்மையாகக் கருத வேண்டும் என்பது உங்களுக்குத் தெரியாது. இந்த விருப்பம் குறிப்பிட்ட பெற்றோருடன் தொடர்புடைய மாற்றத்தை மீண்டும் இயக்க கனி-பறி அனுமதிக்கிறது.
+ பதுக்கிவைத்தையும் அழி
+ நீங்கள் அனைத்து பதுக்கிவைத்தையும் அழிக்க முயற்சிக்கிறீர்கள் தொடர விரும்புகிறீர்களா?
+ நகலி தொலை களஞ்சியம்
+ கூடுதல் அளவுருக்கள்:
+ நகலி களஞ்சியத்திற்கான கூடுதல் வாதங்கள். விருப்பத்தேர்வு.
+ உள்ளக பெயர்:
+ களஞ்சியப் பெயர். விருப்பத்தேர்வு.
+ பெற்றோர் கோப்புறை:
+ துவக்கு & துணை தொகுதிகளைப் புதுப்பி
+ களஞ்சிய முகவரி:
+ மூடு
+ திருத்தி
+ உறுதிமொழி சரிபார்
+ கனி-பறி உறுதிமொழி
+ கனி-பறி ...
+ தலையுடன் ஒப்பிடுக
+ பணிமரத்துடன் ஒப்பிடுக
+ தகவலை நகலெடு
+ பாகொவ-வை நகலெடு
+ தனிப்பயன் செயல்
+ இங்கே ${0}$ ஐ ஊடாடும் வகையில் மறுதளம்
+ ${0}$ இதற்கு ஒன்றிணை
+ ஒன்றிணை ...
+ இங்கே ${0}$ ஐ மறுதளம்
+ ${0}$ ஐ இங்கே மீட்டமை
+ உறுதிமொழி திரும்பபெறு
+ வேறுமொழி
+ ஒட்டாக சேமி...
+ பெற்றோர்களில் நொறுக்கு
+ நொறுக்கு குழந்தைகள் இங்கே சேர்
+ மாற்றங்கள்
+ மாற்றங்களைத் தேடு...
+ கோப்புகள்
+ பெகோஅ கோப்பு
+ கோப்புகளைத் தேடு...
+ துணைத்தொகுதி
+ தகவல்
+ ஆசிரியர்
+ மாற்றப்பட்டது
+ குழந்தைகள்
+ உறுதிமொழியாளர்
+ இந்த உறுதிமொழிடைக் கொண்ட குறிப்புகளைச் சரிபார்
+ உறுதிமொழி இதில் உள்ளது
+ முதல் 100 மாற்றங்களை மட்டும் காட்டுகிறது மாற்றங்கள் தாவலில் அனைத்து மாற்றங்களையும் காண்க.
+ செய்தி
+ பெற்றோர்கள்
+ குறிகள்
+ பாகொவ
+ உலாவியில் திற
+ விளக்கம்
+ உறுதிமொழி பொருளை உள்ளிடவும்
+ களஞ்சியம் உள்ளமை
+ உறுதிமொழி வளர்புரு
+ வார்ப்புரு உள்ளடக்கம்:
+ வார்ப்புரு பெயர்:
+ தனிப்பயன் செயல்
+ வாதங்கள்:
+ ${களஞ்சிய} - களஞ்சியத்தின் பாதை; ${கிளை} - தேர்ந்தெடுக்கப்பட்ட கிளை; ${பாகொவ} - தேர்ந்தெடுக்கப்பட்ட உறுதிமொழிடியின் பாகொவ
+ இயக்கக்கூடிய கோப்பு:
+ பெயர்:
+ நோக்கம்:
+ கிளை
+ உறுதிமொழி
+ களஞ்சியம்
+ செயல்பாட்டிலிருந்து வெளியேற காத்திரு
+ மின்னஞ்சல் முகவரி
+ மின்னஞ்சல் முகவரி
+ அறிவிலி
+ தொலைகளை தானாக எடு
+ நிமையங்கள்
+ இயல்புநிலை தொலை
+ சிக்கல் கண்காணி
+ மாதிரி அசூர் வளர்பணிகள் விதியைச் சேர்
+ மாதிரி அறிவிலிஈ சிக்கலுக்கான விதியைச் சேர்
+ மாதிரி அறிவிலிஈ இழு கோரிக்கை விதியைச் சேர்
+ மாதிரி அறிவிலிமையம் விதியைச் சேர்
+ மாதிரி அறிவிலிஆய்வு சிக்கலுக்கான விதியைச் சேர்
+ மாதிரி அறிவிலிஆய்வு இணைப்பு கோரிக்கை விதியைச் சேர்
+ மாதிரி சீரா விதியைச் சேர்
+ புதிய விதி
+ வழக்கவெளி வெளிப்பாடு வெளியீடு:
+ விதியின் பெயர்:
+ முடிவு முகவரி:
+ வழக்கவெளி குழுக்கள் மதிப்புகளை அணுக $1, $2 ஐப் பயன்படுத்து
+ செநு
+ விருப்பமான சேவை:
+ 'விருப்பமான சேவை' அமைக்கப்பட்டிருந்தால், மூலஅறிவிலி இந்த களஞ்சியத்தில் மட்டுமே அதைப் பயன்படுத்தும். இல்லையெனில், ஒன்றுக்கு மேற்பட்ட சேவைகள் இருந்தால், அவற்றில் ஒன்றைத் தேர்ந்தெடுப்பதற்கான சூழல் பட்டயல் காண்பிக்கப்படும்.
+ உஉபநெ பதிலாள்
+ இந்த களஞ்சியத்தால் பயன்படுத்தப்படும் உஉபநெ பதிலாள்
+ பயனர் பெயர்
+ இந்த களஞ்சியத்திற்கான பயனர் பெயர்
+ பணியிடங்கள்
+ நிறம்
+ தாவல்களை மீட்டமை
+ வழக்கமான உறுதிமொழி உதவியாளர்
+ உடைக்கும் மாற்றம்:
+ மூடப்பட்ட வெளியீடு சிக்கல்:
+ மாற்ற விவரங்கள்:
+ நோக்கம்:
+ குறுகிய விளக்கம்:
+ மாற்ற வகை:
+ நகல்
+ அனைத்து உரையையும் நகலெடு
+ முழு பாதையை நகலெடு
+ நகல் பாதை
+ கிளையை உருவாக்கு...
+ இதன் அடிப்படையில்:
+ உருவாக்கப்பட்ட கிளையைப் சரிபார்
+ உள்ளக மாற்றங்கள்:
+ நிராகரி
+ பதுக்கிவை & மீண்டும் இடு
+ புதிய கிளை பெயர்:
+ கிளை பெயரை உள்ளிடவும்.
+ இடைவெளிகள் கோடுகளால் மாற்றப்படும்.
+ உள்ளக கிளையை உருவாக்கு
+ குறிச்சொல்லை உருவாக்கு...
+ இங்கு புதிய குறிச்சொல்:
+ சீபிசீ கையொப்பமிடுதல்
+ குறிச்சொல் செய்தி:
+ விருப்பத்தேர்வு.
+ குறிச்சொல் பெயர்:
+ பரிந்துரைக்கப்பட்ட வடிவம்: ப1.0.0-ஆனா
+ உருவாக்கப்பட்ட பிறகு அனைத்து தொலைகளுக்கும் தள்ளு
+ புதிய குறிசொல் உருவாக்கு
+ வகை:
+ annotated
+ குறைந்தஎடை
+ நேரடியாகத் தொடங்க கட்டுப்பாட்டை அழுத்திப் பிடி
+ வெட்டு
+ கிளையை நீக்கு
+ கிளை:
+ நீங்கள் ஒரு தொலை கிளையை நீக்கப் போகிறீர்கள்!!!
+ தொலை ${0}$ கிளையையும் நீக்கு
+ பல கிளைகளை நீக்கு
+ நீங்கள் ஒரே நேரத்தில் பல கிளைகளை நீக்க முயற்சிக்கிறீர்கள் நடவடிக்கை எடுப்பதற்கு முன் மீண்டும் சரிபார்!
+ தொலையை நீக்கு
+ தொலை:
+ பாதை:
+ இலக்கு:
+ எல்லா குழந்தைகளும் பட்டியலிலிருந்து நீக்கப்படுவார்கள்.
+ இது பட்டியலிலிருந்து மட்டுமே அகற்றும், வட்டிலிருந்து அல்ல!
+ குழுவை நீக்குவதை உறுதிப்படுத்து
+ களஞ்சியத்தை நீக்குவதை உறுதிப்படுத்து
+ துணைத்தொகுதியை நீக்கு
+ துணைத்தொகுதி பாதை:
+ குறிச்சொல்லை நீக்கு
+ குறிசொல்:
+ தொலை களஞ்சியங்களிலிருந்து நீக்கு
+ இருமம் வேறுபாடு
+ புதிய
+ பழைய
+ நகல்
+ கோப்பு முறை மாற்றப்பட்டது
+ முதல் வேறுபாடு
+ வெள்ளைவெளி மாற்றத்தை புறக்கணி
+ கடைசி வேறுபாடு
+ பெகோஅ பொருள் மாற்றம்
+ அடுத்த வேறுபாடு
+ மாற்றங்கள் இல்லை அல்லது வரிமுடிவு மாற்றங்கள் மட்டும்
+ முந்தைய வேறுபாடு
+ ஒட்டாகச் சேமி
+ மறைக்கப்பட்ட சின்னங்களைக் காட்டு
+ பக்கவாட்டு வேறுபாடு
+ துணைத் தொகுதி
+ புதிய
+ இடமாற்று
+ தொடரியல் சிறப்பம்சமாக்கல்
+ வரி சொல் மடக்கு
+ தடுப்பு-வழிசெலுத்தலை இயக்கு
+ ஒன்றிணை கருவியில் திற
+ அனைத்து வரிகளையும் காட்டு
+ தெரியும் வரிகளின் எண்ணிக்கையைக் குறை
+ தெரியும் வரிகளின் எண்ணிக்கையை அதிகரி
+ மாற்றங்களைக் காண கோப்பைத் தேர்ந்தெடு
+ ஒன்றிணை கருவியில் திற
+ மாற்றங்களை நிராகரி
+ செயல்படும் நகலில் உள்ள அனைத்து உள்ளக மாற்றங்கள்.
+ மாற்றங்கள்:
+ புறக்கணிக்கப்பட்ட கோப்புகளைச் சேர்
+ {0} மாற்றங்கள் நிராகரிக்கப்படும்
+ இந்தச் செயலை நீங்கள் செயல்தவிர்க்க முடியாது!!!
+ புத்தகக்குறி:
+ புதிய பெயர்:
+ இலக்கு:
+ தேர்ந்தெடுக்கப்பட்ட குழுவைத் திருத்து
+ தேர்ந்தெடுக்கப்பட்ட களஞ்சியத்தைத் திருத்து
+ தனிப்பயன் செயலை இயக்கு
+ செயல் பெயர்:
+ வேகமாக முன்னோக்கி (சரிபார்க்காமல்)
+ பெறு
+ எல்லா தொலைகளையும் பெறு
+ உள்ளக குறிப்புகளை கட்டாயமாக மீறு
+ குறிச்சொற்கள் இல்லாமல் பெறு
+ தொலை:
+ தொலை மாற்றங்களைப் பெறு
+ மாறாமல் என கருது
+ நிராகரி...
+ {0} கோப்புகளை நிராகரி...
+ தேர்ந்தெடுக்கப்பட்ட வரிகளில் மாற்றங்களை நிராகரி
+ வெளிப்புற இணைப்பு கருவியைத் திற
+ ${0}$ஐப் பயன்படுத்தி தீர்
+ ஒட்டு என சேமி...
+ நிலைபடுத்து
+ {0} fகோப்புகள் நிலைபடுத்து
+ தேர்ந்தெடுக்கப்பட்ட வரிகளில் மாற்றங்களை நிலைபடுத்து
+ பதுக்கிவை...
+ {0} கோப்புகள் பதுக்கிவை...
+ நிலைநீக்கு
+ நிலைநீக்கு {0} கோப்புகள்
+ தேர்ந்தெடுக்கப்பட்ட வரிகளில் மாற்றங்களை நிலைநீக்கு
+ என்னுடையதைப் பயன்படுத்து (சரிபார் --நமது)
+ அவர்களுடையதைப் பயன்படுத்து (சரிபார் --அவர்களது)
+ கோப்பு வரலாறு
+ மாற்றம்
+ உள்ளடக்கம்
+ அறிவிலி-ஓட்டம்
+ மேம்பாட்டு கிளை:
+ நற்பொருத்தம்:
+ நற்பொருத்தம் முன்னொட்டு:
+ ஓட்டம் - நற்பொருத்தம் முடி
+ ஓட்டம் - சூடானதிருத்தம் முடி
+ ஓட்டம் - வெளியீட்டை முடி
+ இலக்கு:
+ சூடானதிருத்தம்:
+ சூடானதிருத்தம் முன்னொட்டு:
+ அறிவிலி-ஓட்டம் துவக்கு
+ கிளையை வைத்திரு
+ உற்பத்தி கிளை:
+ வெளியீடு:
+ வெளியீடு முன்னொட்டு:
+ நற்பொருத்தம் தொடங்கு...
+ ஓட்டம் - நற்பொருத்தம் தொடங்கு
+ சூடானதிருத்தம் தொடங்கு...
+ ஓட்டம் - சூடானதிருத்தம் தொடங்கு
+ பெயரை உள்ளிடு
+ வெளியீட்டைத் தொடங்கு...
+ ஓட்டம் - வெளியீட்டைத் தொடங்கு
+ பதிப்பு குறிச்சொல் முன்னொட்டு:
+ அறிவிலி பெகோஅ
+ அறிவிலி கண்காணி வடிவத்தைச் சேர்...
+ வடிவம் என்பது கோப்பு பெயர்
+ தனிப்பயன் வடிவம்:
+ அறிவிலி பெகோஅ இல் கண்காணி வடிவங்களைச் சேர்
+ பெறு
+ அறிவிலி பெகோஅ பொருள்களைப் பதிவிறக்க `அறிவிலி பெகோஅ பெறு` ஐ இயக்கவும் இது செயல்படும் நகலை புதுப்பிக்காது.
+ அறிவிலி பெகோஅ பொருள்களைப் பெறு
+ அறிவிலி பெகோஅ கொக்கிகளை நிறுவு
+ பூட்டுகளைக் காட்டு
+ பூட்டப்பட்ட கோப்புகள் இல்லை
+ பூட்டு
+ எனது பூட்டுகளை மட்டும் காட்டு
+ பெகோஅ பூட்டுகள்
+ திற
+ கட்டாயம் திற
+ கத்தரி
+ உள்ளக சேமிப்பகத்திலிருந்து பழைய பெகோஅ கோப்புகளை நீக்க `அறிவிலி பெகோஅ கத்தரி` ஐ இயக்கு
+ இழு
+ தற்போதைய குறிக்கு அனைத்து அறிவிலி பெகோஅ கோப்புகளையும் பதிவிறக்கி சரிபார்க்க `அறிவிலி பெகோஅ இழு`ஐ இயக்கு
+ பெகோஅ பொருள்களை இழு
+ தள்ளு
+ வரிசைப்படுத்தப்பட்ட பெரிய கோப்புகளை அறிவிலி பெகோஅ முடிவுபுள்ளிக்கு தள்ளு
+ பெகோஅ பொருள்கள் தள்ளு
+ தொலை:
+ '{0}' என பெயரிடப்பட்ட கோப்புகளைக் கண்காணி
+ அனைத்து *{0} கோப்புகளையும் கண்காணி
+ வரலாறு
+ ஆசிரியர்
+ ஆசிரியர் நேரம்
+ வரைபடம் & பொருள்
+ பாகொவ
+ உறுதிமொழி நேரம்
+ தேர்ந்தெடுக்கப்பட்ட {0} உறுதிமொழிகள்
+ பல உறுதிமொழிகளைத் தேர்ந்தெடுக்க 'கட்டுப்பாடு' அல்லது 'உயர்த்து'ஐ அழுத்திப் பிடி.
+ பல உறுதிமொழிகளைத் தேர்ந்தெடுக்க ⌘ அல்லது ⇧ ஐ அழுத்திப் பிடி.
+ குறிப்புகள்:
+ விசைப்பலகை குறுக்குவழிகள் குறிப்பு
+ உலகளாவிய
+ தற்போதைய மேல்தோன்றலை Cancel
+ புதிய களஞ்சியத்தை நகலி செய்
+ தற்போதைய பக்கத்தை மூடு
+ அடுத்த பக்கத்திற்குச் செல்
+ முந்தைய பக்கத்திற்குச் செல்
+ புதிய பக்கத்தை உருவாக்கு
+ விருப்பத்தேர்வுகள் உரையாடலைத் திற
+ களஞ்சியம்
+ நிலைபடுத்திய மாற்றங்களை உறுதிமொழி
+ நிலைபடுத்திய மாற்றங்களை உறுதிமொழி மற்றும் தள்ளு
+ அனைத்து மாற்றங்களையும் நிலைபடுத்தி உறுதிமொழி
+ தேர்ந்தெடுக்கப்பட்ட உறுதிமொழியின் அடிப்படையில் ஒரு புதிய கிளையை உருவாக்குகிறது
+ தேர்ந்தெடுக்கப்பட்ட மாற்றங்களை நிராகரி
+ எடு, நேரடியாகத் தொடங்குகிறது
+ முகப்பலகை பயன்முறை (இயல்புநிலை)
+ உறுதிமொழி தேடல் பயன்முறை
+ இழு, நேரடியாகத் தொடங்குகிறது
+ தள்ளு, நேரடியாகத் தொடங்குகிறது
+ இந்த களஞ்சியத்தை மீண்டும் ஏற்ற கட்டாயப்படுத்து
+ தேர்ந்தெடுக்கப்பட்ட மாற்றங்களை நிலைபடுத்து/நிலைநீக்கு
+ 'மாற்றங்கள்' என்பதற்கு மாறு
+ 'வரலாறுகள்' என்பதற்கு மாறு
+ 'பதுகிவைத்தவை' என்பதற்கு மாறு
+ உரை திருத்தி
+ தேடல் பலகத்தை மூடு
+ அடுத்த பொருத்தத்தைக் கண்டறி
+ முந்தைய பொருத்தத்தைக் கண்டறி
+ தேடல் பலகத்தைத் திற
+ நிராகரி
+ நிலைபடுத்து
+ நிலைநீக்கு
+ களஞ்சியத்தைத் துவக்கு
+ பாதை:
+ கனி-பறி செயல்பாட்டில் உள்ளது.
+ உறுதிமொழி செயலாக்குதல்
+ இணைத்தல் செயல்பாட்டில் உள்ளது.
+ இணைத்தல்
+ மறுதளம் செயல்பாட்டில் உள்ளது
+ இல் நிறுத்தப்பட்டது
+ திரும்ப்பெறும் செயல்பாட்டில் உள்ளது.
+ திரும்பபெறும் உறுதிமொழி
+ ஊடாடும் மறுதளம்
+ மேல்:
+ இலக்கு கிளை:
+ இணைப்பை நகலெடு
+ உலாவியில் திற
+ பிழை
+ அறிவிப்பு
+ கிளையை ஒன்றிணை
+ Into:
+ இணைப்பு விருப்பம்:
+ இதனுள்:
+ ஒன்றிணை (பல)
+ அனைத்து மாற்றங்களையும் உறுதிமொழி
+ சூழ்ச்சிமுறை:
+ இலக்குகள்:
+ களஞ்சிய முனையை நகர்த்து
+ இதற்கான பெற்றோர் முனையைத் தேர்ந்தெடு
+ பெயர்:
+ அறிவிலி உள்ளமைக்கப்படவில்லை. [விருப்பத்தேர்வுகள்]க்குச் சென்று முதலில் அதை உள்ளமை.
+ தரவு சேமிப்பக கோப்பகத்தைத் திற
+ இதனுடன் திற...
+ விருப்பத்தேர்வு.
+ புதிய பக்கத்தை உருவாக்கு
+ புத்தகக்குறி
+ மூடு தாவல்
+ பிற தாவல்களை மூடு
+ வலதுபுறத்தில் உள்ள தாவல்களை மூடு
+ களஞ்சிய பாதை நகலெடு
+ களஞ்சியங்கள்
+ ஒட்டு
+ {0} நாட்களுக்கு முன்பு
+ 1 மணி நேரத்திற்கு முன்பு
+ {0} மணி நேரத்திற்கு முன்பு
+ சற்றுமுன்
+ கடந்த திங்கள்
+ கடந்த ஆண்டு
+ {0} நிமையங்களுக்கு முன்பு
+ {0} திங்களுக்கு முன்பு
+ {0} ஆண்டுகளுக்கு முன்பு
+ நேற்று
+ விருப்பத்தேர்வுகள்
+ செநு
+ வேறுபாடு உடனடியாக பகுப்பாய்வு செய்
+ பநிஇ திறவுகோல்
+ பொருள் உடனடியாக உருவாக்கு
+ மாதிரி
+ பெயர்
+ சேவையகம்
+ ஓடையை இயக்கு
+ தோற்றம்
+ இயல்புநிலை எழுத்துரு
+ திருத்தி தாவல் அகலம்
+ எழுத்துரு அளவு
+ இயல்புநிலை
+ திருத்தி
+ ஒற்றைவெளி எழுத்துரு
+ ஒற்றைவெளி எழுத்துருவை உரை திருத்தியில் மட்டும் பயன்படுத்து
+ கருப்பொருள்
+ கருப்பொருள் மேலெழுதப்படுகிறது
+ தலைப்புப்பட்டியில் நிலையான தாவல் அகலத்தைப் பயன்படுத்து
+ சொந்த சாளர சட்டத்தைப் பயன்படுத்து
+ நிறுவல் பாதை
+ வேறு/ஒன்றிணை கருவி
+ வேறு/ஒன்றிணை கருவிக்கான பாதை உள்ளிடு
+ கருவி
+ பொது
+ தொடக்கத்தில் புதுப்பிப்புகளைச் சரிபார்
+ தேதி வடிவம்
+ மொழி
+ வரலாற்று உறுதிமொழிகள்
+ வரைபடத்தில் உறுதிமொழி நேரத்திற்குப் பதிலாக ஆசிரியர் நேரத்தைக் காட்டு
+ உறுதிமொழி விவரங்களில் குழந்தைகளைக் காட்டு
+ உறுதிமொழி வரைபடத்தில் குறிச்சொற்களைக் காட்டு
+ பொருள் வழிகாட்டி நீளம்
+ அறிவிலி
+ தானியங்கி வரிமுடிவை இயக்கு
+ இயல்புநிலை நகலி அடைவு
+ பயனர் மின்னஞ்சல்
+ உலகளாவிய அறிவிலி பயனர் மின்னஞ்சல்
+ --prune எடுக்கும்போது இயக்கு
+ அறிவிலி (>= 2.23.0) இந்த பயன்பாட்டிற்கு தேவைப்படுகிறது
+ நிறுவல் பாதை
+ உஉபநெ பாகுஅ சரிபார்ப்பை இயக்கு
+ பயனர் பெயர்
+ உலகளாவிய அறிவிலி பயனர் பெயர்
+ அறிவிலி பதிப்பு
+ சிபிசி கையொப்பமிடுதல்
+ சிபிசி கையொப்பமிடுதல் உறுதிமொழி
+ சிபிசி வடிவம்
+ நிரல் நிறுவல் பாதை
+ நிறுவப்பட்ட சிபிசி நிரலுக்கான உள்ளீட்டு பாதை
+ சிபிசி கையொப்பமிடுதலை குறிச்சொலிடு
+ பயனர் கையொப்பமிடும் திறவுகோல்
+ பயனரின் கையொப்பமிடும் திறவுகோல்
+ ஒருங்கிணைப்பு
+ ஓடு/முனையம்
+ பாதை
+ ஓடு/முனையம்
+ தொலை கத்தரி
+ இலக்கு:
+ பணிமரங்கள் கத்தரி
+ `$GIT_COMMON_DIR/பணிமரங்கள்` இதில் பணிமரம் தகவலை கத்தரி
+ இழு
+ தொலை கிளை:
+ எல்லா கிளைகளையும் எடு
+ இதனுள்:
+ உள்ளக மாற்றங்கள்:
+ நிராகரி
+ பதுக்கிவை & மீண்டும் இடு
+ குறிச்சொற்கள் இல்லாமல் பெறு
+ தொலை:
+ இழு (எடுத்து ஒன்றிணை)
+ ஒன்றிணை என்பதற்குப் பதிலாக மறுதளத்தைப் பயன்படுத்து
+ தள்ளு
+ துணைத் தொகுதிகள் தள்ளப்பட்டது என்பதை உறுதிசெய்
+ கட்டாயமாக தள்ளு
+ உள்ளக கிளை:
+ தொலை:
+ மாற்றங்களை தொலைக்கு தள்ளு
+ தொலை கிளை:
+ கண்காணிப்பு கிளையாக அமை
+ அனைத்து குறிச்சொற்களையும் தள்ளு
+ தொலைக்கு குறிச்சொல்லை தள்ளு
+ அனைத்து தொலைகளுக்கும் தள்ளு
+ தொலை:
+ குறிச்சொல்:
+ வெளியேறு
+ தற்போதைய கிளையை மறுதளம் செய்
+ உள்ளக மாற்றங்களை பதுக்கிவை & மீண்டும் இடு
+ மேல்:
+ மறுதளம்:
+ புதுப்பி
+ தொலையைச் சேர்
+ தொலையைத் திருத்து
+ பெயர்:
+ களஞ்சிய பெயர்
+ களஞ்சிய முகவரி:
+ தொலை அறிவிலி களஞ்சிய முகவரி:
+ முகவரியை நகலெடு
+ நீக்கு...
+ திருத்து...
+ பெறு
+ உலாவியில் திற
+ கத்தரித்தல்
+ பணிமரத்தை அகற்றுவதை உறுதிப்படுத்து
+ `--கட்டாயம்` விருப்பத்தை இயக்கு
+ இலக்கு:
+ கிளையை மறுபெயரிடு
+ புதிய பெயர்:
+ இந்தக் கிளைக்கான தனித்துவமான பெயர்
+ கிளை:
+ நிறுத்து
+ தொலைகளிலிருந்து மாற்றங்களைத் தானாகப் பெறுதல்...
+ சுத்தப்படுத்தல்(சீசி & கத்தரித்தல்)
+ இந்த களஞ்சியத்திற்கு `அறிவிலி சீசி` கட்டளையை இயக்கு.
+ அனைத்தையும் அழி
+ இந்த களஞ்சியத்தை உள்ளமை
+ தொடர்க
+ தனிப்பயன் செயல்கள்
+ தனிப்பயன் செயல்கள் இல்லை
+ '--குறிபதிவு' விருப்பத்தை இயக்கு
+ கோப்பு உலாவியில் திற
+ கிளைகள்/குறிச்சொற்கள்/துணைத் தொகுதிகளைத் தேடு
+ வரைபடத்தில் தெரிவுநிலை
+ அமைவை நீக்கு
+ உறுதிமொழி வரைபடத்தில் மறை
+ உறுதிமொழி வரைபடத்தில் வடிகட்டு
+ '--first-parent' விருப்பம் இயக்கு
+ தளவமைப்பு
+ கிடைமட்டம்
+ செங்குத்து
+ உறுதிமொழி வரிசை
+ உறுதிமொழி தேதி
+ இடவியல் மூலமாக
+ உள்ளக கிளைகள்
+ தலைக்கு செல்
+ கிளையை உருவாக்கு
+ அறிவிப்புகளை அழி
+ வரைபடத்தில் தற்போதைய கிளையை மட்டும் முன்னிலை படுத்து
+ {0} இல் திற
+ வெளிப்புற கருவிகளில் திற
+ புதுப்பி
+ தொலைகள்
+ தொலையைச் சேர்
+ உறுதிமொழி தேடு
+ ஆசிரியர்
+ உறுதிமொழியாளர்
+ கோப்பு
+ செய்தி
+ பாகொவ
+ தற்போதைய கிளை
+ குறிச்சொற்களை மரமாகக் காட்டு
+ தவிர்
+ புள்ளிவிவரங்கள்
+ துணைத் தொகுதிகள்
+ துணைத் தொகுதியைச் சேர்
+ துணைத் தொகுதியைப் புதுப்பி
+ குறிசொற்கள்
+ புதிய குறிசொல்
+ படைப்பாளர் தேதியின்படி
+ பெயர் (ஏறுவரிசை) மூலம்
+ பெயர் (இறகுவரிசை) மூலம்
+ வரிசைப்படுத்து
+ முனையத்தில் திற
+ வரலாறுகளில் உறவு நேரத்தைப் பயன்படுத்து
+ பணிமரங்கள்
+ பணிமரத்தைச் சேர்
+ கத்தரித்தல்
+ அறிவிலி களஞ்சிய முகவரி
+ தற்போதைய கிளையை திருத்தத்திற்கு மீட்டமை
+ மீட்டமை பயன்முறை:
+ இதற்கு நகர்த்து:
+ தற்போதைய கிளை:
+ கோப்பு உலாவியில் வெளிப்படுத்து
+ பின்வாங்கு உறுதிமொழி
+ உறுதிமொழி:
+ பின்வாங்கு மாற்றங்களை உறுதிமொழி
+ மாறுசொல் உறுதிமொழி செய்தி
+ புதிய வரியை உள்ளிட 'உயர்த்து+நுழை' ஐப் பயன்படுத்தவும். 'நுழை' என்பது சரி பொத்தானின் சூடானவிசை ஆகும்
+ இயங்குகிறது. காத்திருக்கவும்...
+ சேமி
+ எனச் சேமி...
+ ஒட்டு வெற்றிகரமாக சேமிக்கப்பட்டது!
+ களஞ்சியங்களை வருடு
+ வேர் அடைவு:
+ புதுப்பிப்புகளைச் சரிபார்...
+ இந்த மென்பொருளின் புதிய பதிப்பு கிடைக்கிறது:
+ புதுப்பிப்புகளைச் சரிபார்க்க முடியவில்லை!
+ பதிவிறக்கம்
+ இந்தப் பதிப்பைத் தவிர்
+ மென்பொருள் புதுப்பி
+ தற்போது புதுப்பிப்புகள் எதுவும் கிடைக்கவில்லை.
+ கண்காணிப்பு கிளையை அமை
+ கிளை:
+ மேல்ஓடையை நீக்கு
+ மேல்ஓடை:
+ SHA ஐ நகலெடு
+ இதற்கு செல்
+ நொறுக்கு உறுதிமொழிகள்
+ இதில்:
+ பாஓடு தனியார் திறவுகோல்:
+ தனியார் பாஓடு திறவுகோல் கடை பாதை
+ தொடங்கு
+ பதுக்கிவை
+ பதுக்கிவைத்த பிறகு தானியங்கி மீட்டமை
+ உங்கள் செயல்படும் கோப்புகள் மாறாமல் இருக்கும், ஆனால் ஒரு பதுக்கிவைக்கப்படும்.
+ கண்காணிக்கப்படாத கோப்புகளைச் சேர்
+ நிலைப்படுத்தப்பட்ட கோப்புகளை வைத்திரு
+ செய்தி:
+ விருப்பத்தேர்வு. இந்த பதுக்கலின் பெயர்
+ நிலைப்படுத்தப்பட்ட மாற்றங்கள் மட்டும்
+ தேர்ந்தெடுக்கப்பட்ட கோப்புகளின் நிலைப்படுத்தப்பட்ட மற்றும் நிலைப்படுத்தப்படாத மாற்றங்கள் இரண்டும் பதுக்கிவைக்கப்படும்!!!
+ உள்ளக மாற்றங்களை பதுக்கிவை
+ இடு
+ கைவிடு
+ ஒட்டாகச் சேமி...
+ பதுக்கிவைத்தவை கைவிடு
+ கைவிடு:
+ பதுக்கிவைத்தவைகள்
+ மாற்றங்கள்
+ பதுக்கிவைத்தவைகள்
+ புள்ளிவிவரங்கள்
+ உறுதிமொழிகள்
+ உறுதிமொழியாளர்
+ மேலோட்டப் பார்வை
+ திங்கள்
+ வாரம்
+ ஆசிரியர்கள்:
+ உறுதிமொழிகள்:
+ துணைத் தொகுதி
+ துணைத் தொகுதியைச் சேர்
+ உறவு பாதையை நகலெடு
+ உள்ளமைக்கப்பட்ட துணைத் தொகுதிகளை எடு
+ துணைத் தொகுதி களஞ்சியத்தைத் திற
+ உறவு பாதை:
+ இந்த தொகுதியை சேமிப்பதற்கான தொடர்புடைய கோப்புறை.
+ துணை தொகுதியை நீக்கு
+ சரி
+ குறிச்சொல் பெயரை நகலெடு
+ குறிச்சொல் செய்தியை நகலெடு
+ நீக்கு ${0}$...
+ ${0}$ இதை ${1}$ இல் இணை...
+ தள்ளு ${0}$...
+ துணைத்தொகுதிகளைப் புதுப்பி
+ அனைத்து துணைத்தொகுதிகள்
+ தேவைக்கேற்றப துவக்கு
+ சுழற்சி முறையில்
+ --தொலை விருப்பத்தைப் பயன்படுத்து
+ முகவரி:
+ முன்னறிவிப்பு
+ வரவேற்பு பக்கம்
+ குழுவை உருவாக்கு
+ துணைக் குழுவை உருவாக்கு
+ நகலி களஞ்சியம்
+ நீக்கு
+ கோப்புறையை இழுத்து & விடு ஆதரிக்கப்படுகிறது. தனிப்பயன் குழுவாக்க ஆதரவு.
+ திருத்து
+ வேறொரு குழுவிற்கு நகர்த்து
+ அனைத்து களஞ்சியங்களையும் திற
+ களஞ்சியத்தைத் திற
+ முனையத்தைத் திற
+ இயல்புநிலை நகலி அடைவில் களஞ்சியங்களை மீண்டும் வருடு
+ களஞ்சியங்களைத் தேடு...
+ வரிசைப்படுத்து
+ உள்ளக மாற்றங்கள்
+ அறிவிலி புறக்கணி
+ எல்லா *{0} கோப்புகளையும் புறக்கணி
+ ஒரே கோப்புறையில் *{0} கோப்புகளைப் புறக்கணி
+ ஒரே கோப்புறையில் கோப்புகளைப் புறக்கணி
+ இந்த கோப்பை மட்டும் புறக்கணி
+ பின்னொட்டு
+ இந்த கோப்பை இப்போது நீங்கள் நிலைப்படுத்தலாம்.
+ உறுதிமொழி
+ உறுதிமொழி & தள்ளு
+ வளர்புரு/வரலாறுகள்
+ சொடுக்கு நிகழ்வைத் தூண்டு
+ உறுதிமொழி (திருத்து)
+ அனைத்து மாற்றங்களையும் நிலைப்படுத்தி உறுதிமொழி
+ நீங்கள் {0} கோப்புகளை நிலைப்படுத்தியுள்ளீர்கள், ஆனால் {1} கோப்புகள் மட்டுமே காட்டப்பட்டுள்ளன ({2} கோப்புகள் வடிகட்டப்பட்டுள்ளன). தொடர விரும்புகிறீர்களா?
+ காலி உறுதிமொழி கண்டறியப்பட்டது! தொடர விரும்புகிறீர்களா(--allow-empty)?
+ மோதல்கள் கண்டறியப்பட்டது
+ கோப்பு மோதல்கள் தீர்க்கப்பட்டது
+ கண்காணிக்கப்படாத கோப்புகளைச் சேர்
+ அண்மைக் கால உள்ளீட்டு செய்திகள் இல்லை
+ உறுதிமொழி வளர்புருகள் இல்லை
+ தேர்ந்தெடுக்கப்பட்ட கோப்பு(களை) வலது சொடுக்கு செய்து, முரண்பாடுகளைத் தீர்க்க உங்கள் விருப்பத்தைத் தேர்ந்தெடு.
+ கையெழுத்திடு
+ நிலைபடுத்தியது
+ நிலைநீக்கு
+ அனைத்தும் நிலைநீக்கு
+ நிலைநீக்கு
+ நிலைபடுத்து
+ அனைத்தும் நிலைபடுத்து
+ மாறாதது எனநினைப்பதை பார்
+ வளர்புரு: ${0}$
+ பணியிடம்:
+ பணியிடங்களை உள்ளமை...
+ பணிமரம்
+ பாதையை நகலெடு
+ பூட்டு
+ நீக்கு
+ திற
+
diff --git a/src/Resources/Locales/zh_CN.axaml b/src/Resources/Locales/zh_CN.axaml
index c7dede50..35a97b6e 100644
--- a/src/Resources/Locales/zh_CN.axaml
+++ b/src/Resources/Locales/zh_CN.axaml
@@ -2,41 +2,34 @@
+
关于软件
关于本软件
- • 项目依赖于
- • 图表绘制组件来自
- © 2024 sourcegit-scm
- • 文本编辑器使用
- • 等宽字体来自于
- • 项目源代码地址
开源免费的Git客户端
新增工作树
- 检出分支方式 :
- 已有分支
- 创建新分支
工作树路径 :
填写该工作树的路径。支持相对路径。
分支名 :
选填。默认使用目标文件夹名称。
跟踪分支
设置上游跟踪分支
+ 检出分支方式 :
+ 创建新分支
+ 已有分支
AI助手
+ 重新生成
使用AI助手生成提交信息
+ 应用本次生成
应用补丁(apply)
- 错误
- 输出错误,并终止应用补丁
- 更多错误
- 与【错误】级别相似,但输出内容更多
补丁文件 :
选择补丁文件
忽略空白符号
- 忽略
- 关闭所有警告
应用补丁
- 警告
- 应用补丁,输出关于空白符的警告
空白符号处理 :
+ 应用贮藏
+ 在成功应用后丢弃该贮藏
+ 恢复索引中已暂存的变化
+ 已选贮藏 :
存档(archive) ...
存档文件路径:
选择存档文件的存放路径
@@ -50,10 +43,10 @@
逐行追溯(blame)
选中文件不支持该操作!!!
检出(checkout) ${0}$...
- 与其他分支对比
与当前HEAD比较
与本地工作树比较
复制分支名
+ 自定义操作
删除 ${0}$...
删除选中的 {0} 个分支
放弃所有更改
@@ -69,10 +62,11 @@
重命名 ${0}$...
切换上游分支 ...
分支比较
+ 跟踪的上游分支不存在或已删除!
字节
取 消
- 重置文件到该版本
重置文件到上一版本
+ 重置文件到该版本
生成提交信息
切换变更显示模式
文件名+路径列表模式
@@ -80,13 +74,12 @@
文件目录树形结构模式
检出(checkout)分支
检出(checkout)提交
- 注意:执行该操作后,当前HEAD会变为游离(detached)状态!
提交 :
- 目标分支 :
+ 注意:执行该操作后,当前HEAD会变为游离(detached)状态!
未提交更改 :
丢弃更改
- 不做处理
贮藏并自动恢复
+ 目标分支 :
挑选提交
提交信息中追加来源信息
提交列表 :
@@ -101,12 +94,13 @@
本地仓库名 :
本地仓库目录的名字,选填。
父级目录 :
+ 初始化并更新子模块
远程仓库 :
关闭
提交信息编辑器
+ 检出此提交
挑选(cherry-pick)此提交
挑选(cherry-pick)...
- 检出此提交
与当前HEAD比较
与本地工作树比较
复制简要信息
@@ -141,29 +135,31 @@
相关引用
提交指纹
浏览器中查看
- 填写提交信息主题
详细描述
+ 填写提交信息主题
仓库配置
提交信息模板
- 模板名 :
模板内容 :
+ 模板名 :
自定义操作
命令行参数 :
- 请使用${REPO}代替仓库路径,${SHA}代替提交哈希
+ 请使用${REPO}代替仓库路径,${BRANCH}代替选中的分支,${SHA}代替提交哈希
可执行文件路径 :
名称 :
作用目标 :
+ 选中的分支
选中的提交
仓库
+ 等待操作执行完成
电子邮箱
邮箱地址
GIT配置
启用定时自动拉取远程更新
分钟
默认远程
- 提交信息追加署名 (--signoff)
- 拉取更新时启用修剪(--prune)
+ 默认合并方式
ISSUE追踪
+ 新增匹配Azure DevOps规则
新增匹配Gitee议题规则
新增匹配Gitee合并请求规则
新增匹配Github Issue规则
@@ -185,6 +181,10 @@
工作区
颜色
启动时恢复打开的仓库
+ 确认继续
+ 提交未包含变更文件!是否继续(--allow-empty)?
+ 自动暂存并提交
+ 提交未包含变更文件!是否继续(--allow-empty)或是自动暂存所有变更并提交?
规范化提交信息生成
破坏性更新:
关闭的ISSUE:
@@ -194,17 +194,17 @@
类型:
复制
复制全部文本
+ 复制完整路径
复制路径
- 复制文件名
新建分支 ...
新分支基于 :
完成后切换到新分支
未提交更改 :
丢弃更改
- 不做处理
贮藏并自动恢复
新分支名 :
填写分支名称。
+ 空格将被替换为'-'符号
创建本地分支
新建标签 ...
标签位于 :
@@ -228,7 +228,10 @@
您正在尝试一次性删除多个分支,请务必仔细检查后再执行操作!
删除远程确认
远程名 :
+ 路径 :
目标 :
+ 所有子节点将被同时从列表中移除。
+ 仅从列表中移除,不会删除硬盘中的文件!
删除分组确认
删除仓库确认
删除子模块确认
@@ -241,7 +244,9 @@
原始大小
复制
文件权限已变化
+ 首个差异
忽略空白符号变化
+ 最后一个差异
LFS对象变更
下一个差异
没有变更或仅有换行符差异
@@ -277,7 +282,7 @@
快进(fast-forward,无需checkout)
拉取(fetch)
拉取所有的远程仓库
- 覆盖REF检查
+ 强制覆盖本地REFs
不拉取远程标签
远程仓库 :
拉取远程仓库内容
@@ -296,11 +301,11 @@
从暂存中移除
从暂存中移除 {0} 个文件
从暂存中移除选中的更改
- 使用 THEIRS (checkout --theirs)
使用 MINE (checkout --ours)
+ 使用 THEIRS (checkout --theirs)
文件历史
- 文件内容
文件变更
+ 文件内容
GIT工作流
开发分支 :
特性分支 :
@@ -330,8 +335,8 @@
规则 :
添加LFS追踪文件规则
拉取LFS对象 (fetch)
- 拉取LFS对象
执行`git lfs prune`命令,下载远程LFS对象,但不会更新工作副本。
+ 拉取LFS对象
启用Git LFS支持
显示LFS对象锁
没有锁定的LFS文件
@@ -343,11 +348,11 @@
精简本地LFS对象存储
运行`git lfs prune`命令,从本地存储中精简当前版本不需要的LFS对象
拉回LFS对象 (pull)
- 拉回LFS对象
运行`git lfs pull`命令,下载远程LFS对象并更新工作副本。
+ 拉回LFS对象
推送
- 推送LFS对象
将排队的大文件推送到Git LFS远程服务
+ 推送LFS对象
远程 :
跟踪名为'{0}'的文件
跟踪所有 *{0} 文件
@@ -366,10 +371,10 @@
取消弹出面板
克隆远程仓库
关闭当前页面
- 切换到上一个页面
切换到下一个页面
+ 切换到上一个页面
新建页面
- 打开偏好设置面板
+ 打开偏好设置面板
仓库页面快捷键
提交暂存区更改
提交暂存区更改并推送
@@ -378,11 +383,11 @@
丢弃选中的更改
拉取 (fetch) 远程变更
切换左边栏为分支/标签等显示模式(默认)
+ 切换左边栏为提交搜索模式
拉回 (pull) 远程变更
推送本地变更到远程
重新加载仓库状态
将选中的变更暂存或从暂存列表中移除
- 切换左边栏为提交搜索模式
显示本地更改
显示历史记录
显示贮藏列表
@@ -391,9 +396,9 @@
定位到下一个匹配搜索的位置
定位到上一个匹配搜索的位置
打开搜索
+ 丢弃
暂存
移出暂存区
- 丢弃
初始化新仓库
路径 :
挑选(Cherry-Pick)操作进行中。
@@ -405,10 +410,10 @@
回滚提交操作进行中。
正在回滚提交
交互式变基
- 目标分支 :
起始提交 :
- 在浏览器中访问
+ 目标分支 :
复制链接地址
+ 在浏览器中访问
出错了
系统提示
合并分支
@@ -434,81 +439,85 @@
复制仓库路径
新标签页
粘贴
- 刚刚
- {0}分钟前
- {0}小时前
- 昨天
{0}天前
+ 1小时前
+ {0}小时前
+ 刚刚
上个月
- {0}个月前
一年前
+ {0}分钟前
+ {0}个月前
{0}年前
- 偏好设置
- AI
- Analyze Diff Prompt
- API密钥
- Generate Subject Prompt
- 模型
- 配置名称
- 服务地址
- 外观配置
- 缺省字体
- 字体大小
- 默认
- 代码编辑器
- 代码字体大小
- 等宽字体
- 仅在文本编辑器中使用等宽字体
- 主题
- 主题自定义
- 主标签使用固定宽度
- 使用系统默认窗体样式
- 对比/合并工具
- 安装路径
- 填写工具可执行文件所在位置
- 工具
- 通用配置
- 启动时检测软件更新
- 日期时间格式
- 显示语言
- 最大历史提交数
- 在提交路线图中显示修改时间而非提交时间
- 在提交详情页中显示子提交列表
- SUBJECT字数检测
- GIT配置
- 自动换行转换
- 默认克隆路径
- 邮箱
- 默认GIT用户邮箱
- 安装路径
- 启用HTTP SSL验证
- 用户名
- 默认GIT用户名
- Git 版本
- 本软件要求GIT最低版本为2.23.0
- GPG签名
- 启用提交签名
- 启用标签签名
- 签名格式
- 签名程序位置
- 签名程序所在路径
- 用户签名KEY
- 输入签名提交所使用的KEY
- 第三方工具集成
- 终端/SHELL
- 终端/SHELL
- 安装路径
+ 昨天
+ 偏好设置
+ AI
+ Analyze Diff Prompt
+ API密钥
+ Generate Subject Prompt
+ 模型
+ 配置名称
+ 服务地址
+ 启用流式输出
+ 外观配置
+ 缺省字体
+ 代码字体大小
+ 编辑器制表符宽度
+ 字体大小
+ 默认
+ 代码编辑器
+ 等宽字体
+ 仅在文本编辑器中使用等宽字体
+ 主题
+ 主题自定义
+ 主标签使用固定宽度
+ 使用系统默认窗体样式
+ 对比/合并工具
+ 安装路径
+ 填写工具可执行文件所在位置
+ 工具
+ 通用配置
+ 启动时检测软件更新
+ 日期时间格式
+ 显示语言
+ 最大历史提交数
+ 在提交路线图中显示修改时间而非提交时间
+ 在提交详情页中显示子提交列表
+ 在提交路线图中显示标签
+ SUBJECT字数检测
+ GIT配置
+ 自动换行转换
+ 默认克隆路径
+ 邮箱
+ 默认GIT用户邮箱
+ 拉取更新时启用修剪(--prune)
+ 本软件要求GIT最低版本为2.23.0
+ 安装路径
+ 启用HTTP SSL验证
+ 用户名
+ 默认GIT用户名
+ Git 版本
+ GPG签名
+ 启用提交签名
+ 签名格式
+ 签名程序位置
+ 签名程序所在路径
+ 启用标签签名
+ 用户签名KEY
+ 输入签名提交所使用的KEY
+ 第三方工具集成
+ 终端/SHELL
+ 安装路径
+ 终端/SHELL
清理远程已删除分支
目标 :
清理工作树
- 清理在`$GIT_DIR/worktrees`中的无效工作树信息
+ 清理在`$GIT_COMMON_DIR/worktrees`中的无效工作树信息
拉回(pull)
拉取分支 :
拉取远程中的所有分支变更
本地分支 :
未提交更改 :
丢弃更改
- 不做处理
贮藏并自动恢复
不拉取远程标签
远程 :
@@ -568,16 +577,17 @@
不指定
在提交列表中隐藏
使用其对提交列表过滤
+ 启用 --first-parent 过滤选项
布局方式
水平排布
竖直排布
提交列表排序规则
- 按提交时间 (--date-order)
- 按拓扑排序 (--topo-order)
+ 按提交时间
+ 按拓扑排序
本地分支
定位HEAD
- 启用 --first-parent 过滤选项
新建分支
+ 清空通知列表
提交路线图中仅高亮显示当前分支
在 {0} 中打开
使用外部工具打开
@@ -585,10 +595,11 @@
远程列表
添加远程
查找提交
+ 作者
+ 提交者
文件
提交信息
提交指纹
- 作者及提交者
仅在当前分支中查找
以树型结构展示
跳过此提交
@@ -643,6 +654,8 @@
SSH密钥文件
开 始
贮藏(stash)
+ 贮藏后自动恢复工作区
+ 工作区文件保持未修改状态,但贮藏内容已保存。
包含未跟踪的文件
保留暂存区文件
信息 :
@@ -652,7 +665,7 @@
贮藏本地变更
应用(apply)
删除(drop)
- 应用并删除(pop)
+ 另存为补丁...
丢弃贮藏确认
丢弃贮藏 :
贮藏列表
@@ -661,11 +674,11 @@
提交统计
提交次数
提交者
+ 总览
本月
本周
- 提交次数:
贡献者人数:
- 总览
+ 提交次数:
子模块
添加子模块
复制路径
@@ -680,13 +693,13 @@
删除 ${0}$...
合并 ${0}$ 到 ${1}$...
推送 ${0}$...
- 仓库地址 :
更新子模块
更新所有子模块
启用 '--init'
启用 '--recursive'
子模块 :
启用 '--remote'
+ 仓库地址 :
警告
起始页
新建分组
@@ -708,7 +721,7 @@
忽略同目录下所有 *{0} 文件
忽略同目录下所有文件
忽略本文件
- 修补(--amend)
+ 修补
现在您已可将其加入暂存区中
提交
提交并推送
@@ -716,12 +729,18 @@
触发点击事件
提交(修改原始提交)
自动暂存所有变更并提交
- 提交未包含变更文件!是否继续(--allow-empty)?
+ 当前有 {0} 个文件在暂存区中,但仅显示了 {1} 个文件({2} 个文件被过滤掉了),是否继续提交?
检测到冲突
+ 打开合并工具
+ 打开合并工具解决冲突
文件冲突已解决
+ 使用 MINE
+ 使用 THEIRS
显示未跟踪文件
没有提交信息记录
没有可应用的提交信息模板
+ 请选中冲突文件,打开右键菜单,选择合适的解决方式
+ 署名
已暂存
从暂存区移除选中
从暂存区移除所有
@@ -730,7 +749,6 @@
暂存所有
查看忽略变更文件
模板:${0}$
- 请选中冲突文件,打开右键菜单,选择合适的解决方式
工作区:
配置工作区...
本地工作树
diff --git a/src/Resources/Locales/zh_TW.axaml b/src/Resources/Locales/zh_TW.axaml
index 429febeb..d71281f7 100644
--- a/src/Resources/Locales/zh_TW.axaml
+++ b/src/Resources/Locales/zh_TW.axaml
@@ -2,41 +2,34 @@
+
關於
關於 SourceGit
- • 專案依賴於
- • 圖表繪製元件來自
- © 2024 sourcegit-scm
- • 文字編輯器使用
- • 等寬字型來自於
- • 專案原始碼網址
開源免費的 Git 客戶端
新增工作區
- 簽出分支方式:
- 已有分支
- 建立新分支
工作區路徑:
填寫該工作區的路徑。支援相對路徑。
分支名稱:
選填。預設使用目標資料夾名稱。
追蹤分支
設定遠端追蹤分支
+ 簽出分支方式:
+ 建立新分支
+ 已有分支
AI 助理
+ 重新產生
使用 AI 產生提交訊息
+ 套用為提交訊息
套用修補檔 (apply patch)
- 錯誤
- 輸出錯誤,並中止套用修補檔
- 更多錯誤
- 與 [錯誤] 級別相似,但輸出更多內容
修補檔:
選擇修補檔
忽略空白符號
- 忽略
- 關閉所有警告
套用修補檔
- 警告
- 套用修補檔,輸出關於空白字元的警告
空白字元處理:
+ 套用擱置變更
+ 套用擱置變更後刪除
+ 還原索引中已暫存的變更 (--index)
+ 已選擇擱置變更:
封存 (archive)...
封存檔案路徑:
選擇封存檔案的儲存路徑
@@ -50,10 +43,10 @@
逐行溯源 (blame)
所選擇的檔案不支援該操作!
簽出 (checkout) ${0}$...
- 與其他分支比較
與目前 HEAD 比較
與本機工作區比較
複製分支名稱
+ 自訂動作
刪除 ${0}$...
刪除所選的 {0} 個分支
捨棄所有變更
@@ -69,10 +62,11 @@
重新命名 ${0}$...
切換上游分支...
分支比較
+ 追蹤上游分支不存在或已刪除!
位元組
取 消
- 重設檔案為此版本
重設檔案到上一版本
+ 重設檔案為此版本
產生提交訊息
切換變更顯示模式
檔案名稱 + 路徑列表模式
@@ -80,13 +74,12 @@
檔案目錄樹狀結構模式
簽出 (checkout) 分支
簽出 (checkout) 提交
- 注意: 執行該操作後,目前 HEAD 會變為分離 (detached) 狀態!
提交:
- 目標分支:
+ 注意: 執行該操作後,目前 HEAD 會變為分離 (detached) 狀態!
未提交變更:
捨棄變更
- 不做處理
擱置變更並自動復原
+ 目標分支:
揀選提交
提交資訊中追加來源資訊
提交列表:
@@ -101,12 +94,13 @@
本機存放庫名稱:
本機存放庫目錄的名稱,選填。
父級目錄:
+ 初始化並更新子模組
遠端存放庫:
關閉
提交訊息編輯器
+ 簽出 (checkout) 此提交
揀選 (cherry-pick) 此提交
揀選 (cherry-pick)...
- 簽出 (checkout) 此提交
與目前 HEAD 比較
與本機工作區比較
複製摘要資訊
@@ -141,29 +135,31 @@
相關參照
提交編號
在瀏覽器中檢視
- 填寫提交訊息標題
詳細描述
+ 填寫提交訊息標題
存放庫設定
提交訊息範本
- 範本名稱:
範本內容:
+ 範本名稱:
自訂動作
指令參數:
- 使用 ${REPO} 表示存放庫路徑、${SHA} 表示所選的提交編號
+ 使用 ${REPO} 表示存放庫路徑、${BRANCH} 表示所選的分支、${SHA} 表示所選的提交編號
可執行檔案路徑:
名稱:
執行範圍:
+ 選取的分支
選取的提交
存放庫
+ 等待自訂動作執行結束
電子郵件
電子郵件地址
Git 設定
啟用定時自動提取 (fetch) 遠端更新
分鐘
預設遠端存放庫
- 提交訊息追加署名 (--signoff)
- 拉取變更時進行清理 (--prune)
+ 首選合併模式
Issue 追蹤
+ 新增符合 Azure DevOps 規則
新增符合 Gitee 議題規則
新增符合 Gitee 合併請求規則
新增符合 GitHub Issue 規則
@@ -185,6 +181,10 @@
工作區
顏色
啟動時還原上次開啟的存放庫
+ 确认继续
+ 未包含任何檔案變更! 您是否仍要提交 (--allow-empty)?
+ 自动暂存并提交
+ 未包含任何檔案變更! 您是否仍要提交 (--allow-empty)或者自動暫存全部變更並提交?
產生約定式提交訊息
破壞性變更:
關閉的 Issue:
@@ -194,17 +194,17 @@
類型:
複製
複製全部內容
+ 複製完整路徑
複製路徑
- 複製檔案名稱
新增分支...
新分支基於:
完成後切換到新分支
未提交變更:
捨棄變更
- 不做處理
擱置變更並自動復原
新分支名稱:
輸入分支名稱。
+ 空格將以英文破折號取代
建立本機分支
新增標籤...
標籤位於:
@@ -228,7 +228,10 @@
您正在嘗試一次性刪除多個分支,請務必仔細檢查後再刪除!
刪除遠端確認
遠端名稱:
+ 路徑:
目標:
+ 所有子節點都會從清單中移除。
+ 只會從清單中移除,而不會刪除磁碟中的檔案!
刪除群組確認
刪除存放庫確認
刪除子模組確認
@@ -241,7 +244,9 @@
原始大小
複製
檔案權限已變更
+ 第一個差異
忽略空白符號變化
+ 最後一個差異
LFS 物件變更
下一個差異
沒有變更或僅有換行字元差異
@@ -254,7 +259,7 @@
交換比對雙方
語法上色
自動換行
- 啟用基於變更區塊的導航
+ 區塊切換上/下一個差異
使用外部合併工具檢視
顯示檔案的全部內容
減少可見的行數
@@ -277,7 +282,7 @@
快進 (fast-forward,無需 checkout)
提取 (fetch)
提取所有的遠端存放庫
- 覆寫 REFs 檢查
+ 強制覆寫本機 REFs
不提取遠端標籤
遠端存放庫:
提取遠端存放庫內容
@@ -296,11 +301,11 @@
取消暫存
從暫存中移除 {0} 個檔案
取消暫存選取的變更
- 使用對方版本 (checkout --theirs)
使用我方版本 (checkout --ours)
+ 使用對方版本 (checkout --theirs)
檔案歷史
- 檔案内容
檔案變更
+ 檔案内容
Git 工作流
開發分支:
功能分支:
@@ -330,8 +335,8 @@
規則:
加入 LFS 追蹤檔案規則
提取 (fetch)
- 提取 LFS 物件
執行 `git lfs fetch` 以下載遠端 LFS 物件,但不會更新工作副本。
+ 提取 LFS 物件
啟用 Git LFS 支援
顯示 LFS 物件鎖
沒有鎖定的 LFS 物件
@@ -343,11 +348,11 @@
清理 (prune)
執行 `git lfs prune` 以從本機中清理目前版本不需要的 LFS 物件
拉取 (pull)
- 拉取 LFS 物件
執行 `git lfs pull` 以下載遠端 LFS 物件並更新工作副本。
+ 拉取 LFS 物件
推送 (push)
- 推送 LFS 物件
將大型檔案推送到 Git LFS 遠端服務
+ 推送 LFS 物件
遠端存放庫:
追蹤名稱為「{0}」的檔案
追蹤所有 *{0} 檔案
@@ -366,10 +371,10 @@
取消彈出面板
複製 (clone) 遠端存放庫
關閉目前頁面
- 切換到上一個頁面
切換到下一個頁面
+ 切換到上一個頁面
新增頁面
- 開啟偏好設定面板
+ 開啟偏好設定面板
存放庫頁面快速鍵
提交暫存區變更
提交暫存區變更並推送
@@ -378,11 +383,11 @@
捨棄選取的變更
提取 (fetch) 遠端的變更
切換左邊欄為分支/標籤等顯示模式 (預設)
+ 切換左邊欄為歷史搜尋模式
拉取 (pull) 遠端的變更
推送 (push) 本機變更到遠端存放庫
強制重新載入存放庫
暫存或取消暫存選取的變更
- 切換左邊欄為歷史搜尋模式
顯示本機變更
顯示歷史記錄
顯示擱置變更列表
@@ -391,9 +396,9 @@
前往下一個搜尋相符的位置
前往上一個搜尋相符的位置
開啟搜尋面板
+ 捨棄
暫存
取消暫存
- 捨棄
初始化存放庫
路徑:
揀選 (cherry-pick) 操作進行中。
@@ -401,21 +406,21 @@
合併操作進行中。
正在處理
重定基底 (rebase) 操作進行中。
- 当前停止于
+ 目前停止於
復原提交操作進行中。
正在復原提交
互動式重定基底
- 目標分支:
起始提交:
- 在瀏覽器中開啟連結
+ 目標分支:
複製連結
+ 在瀏覽器中開啟連結
發生錯誤
系統提示
合併分支
目標分支:
合併方式:
- 合併目標:
- 合併(多目標)
+ 合併來源:
+ 合併 (多個來源)
提交變更
合併策略:
目標列表:
@@ -434,80 +439,84 @@
複製存放庫路徑
新分頁
貼上
- 剛剛
- {0} 分鐘前
- {0} 小時前
- 昨天
{0} 天前
+ 1 小時前
+ {0} 小時前
+ 剛剛
上個月
- {0} 個月前
一年前
+ {0} 分鐘前
+ {0} 個月前
{0} 年前
- 偏好設定
- AI
- 伺服器
- API 金鑰
- 模型
- 名稱
- 分析變更差異提示詞
- 產生提交訊息提示詞
- 外觀設定
- 預設字型
- 字型大小
- 預設
- 程式碼
- 等寬字型
- 僅在文字編輯器中使用等寬字型
- 佈景主題
- 自訂主題
- 使用固定寬度的分頁標籤
- 使用系統原生預設視窗樣式
- 對比/合併工具
- 安裝路徑
- 填寫可執行檔案所在路徑
- 工具
- 一般設定
- 啟動時檢查軟體更新
- 日期時間格式
- 顯示語言
- 最大歷史提交數
- 在提交路線圖中顯示修改時間而非提交時間
- 在提交詳細資訊中顯示後續提交
- 提交標題字數偵測
- Git 設定
- 自動換行轉換
- 預設複製 (clone) 路徑
- 電子郵件
- 預設 Git 使用者電子郵件
- 安裝路徑
- 啟用 HTTP SSL 驗證
- 使用者名稱
- 預設 Git 使用者名稱
- Git 版本
- 本軟體要求 Git 最低版本為 2.23.0
- GPG 簽章
- 啟用提交簽章
- 啟用標籤簽章
- GPG 簽章格式
- 可執行檔案路徑
- 填寫 gpg.exe 所在路徑
- 使用者簽章金鑰
- 填寫簽章提交所使用的金鑰
- 第三方工具整合
- 終端機/Shell
- 終端機/Shell
- 安裝路徑
+ 昨天
+ 偏好設定
+ AI
+ 分析變更差異提示詞
+ API 金鑰
+ 產生提交訊息提示詞
+ 模型
+ 名稱
+ 伺服器
+ 啟用串流輸出
+ 外觀設定
+ 預設字型
+ 編輯器制表符寬度
+ 字型大小
+ 預設
+ 程式碼
+ 等寬字型
+ 僅在文字編輯器中使用等寬字型
+ 佈景主題
+ 自訂主題
+ 使用固定寬度的分頁標籤
+ 使用系統原生預設視窗樣式
+ 對比/合併工具
+ 安裝路徑
+ 填寫可執行檔案所在路徑
+ 工具
+ 一般設定
+ 啟動時檢查軟體更新
+ 日期時間格式
+ 顯示語言
+ 最大歷史提交數
+ 在提交路線圖中顯示修改時間而非提交時間
+ 在提交詳細資訊中顯示後續提交
+ 在路線圖中顯示標籤
+ 提交標題字數偵測
+ Git 設定
+ 自動換行轉換
+ 預設複製 (clone) 路徑
+ 電子郵件
+ 預設 Git 使用者電子郵件
+ 拉取變更時進行清理 (--prune)
+ 本軟體要求 Git 最低版本為 2.23.0
+ 安裝路徑
+ 啟用 HTTP SSL 驗證
+ 使用者名稱
+ 預設 Git 使用者名稱
+ Git 版本
+ GPG 簽章
+ 啟用提交簽章
+ GPG 簽章格式
+ 可執行檔案路徑
+ 填寫 gpg.exe 所在路徑
+ 啟用標籤簽章
+ 使用者簽章金鑰
+ 填寫簽章提交所使用的金鑰
+ 第三方工具整合
+ 終端機/Shell
+ 安裝路徑
+ 終端機/Shell
清理遠端已刪除分支
目標:
清理工作區
- 清理在 `$GIT_DIR/worktrees` 中的無效工作區資訊
+ 清理在 `$GIT_COMMON_DIR/worktrees` 中的無效工作區資訊
拉取 (pull)
拉取分支:
拉取遠端中的所有分支
本機分支:
未提交變更:
捨棄變更
- 不做處理
擱置變更並自動復原
不拉取遠端標籤
遠端:
@@ -567,27 +576,29 @@
取消指定
在提交列表中隱藏
以其篩選提交列表
- 佈局方式
+ 啟用 [--first-parent] 選項
+ 版面配置
橫向顯示
縱向顯示
提交顯示順序
- 依提交時間排序 (--date-order)
- 依拓撲排序 (--topo-order)
+ 依時間排序
+ 依拓撲排序
本機分支
回到 HEAD
- 啟用 [--first-parent] 選項
新增分支
- 提交圖表中僅高亮顯示目前分支
+ 清除所有通知
+ 在提交路線圖中僅對目前分支上色
在 {0} 中開啟
使用外部工具開啟
重新載入
遠端列表
新增遠端
搜尋提交
+ 作者
+ 提交者
檔案
提交訊息
提交編號
- 作者及提交者
僅搜尋目前分支
以樹型結構展示
跳過此提交
@@ -602,7 +613,7 @@
依名稱降序
排序
在終端機中開啟
- 在提交清單中使用相對時間
+ 在提交列表中使用相對時間
工作區列表
新增工作區
清理
@@ -642,6 +653,8 @@
SSH 金鑰檔案
開 始
擱置變更 (stash)
+ 擱置變更後自動復原工作區
+ 工作區檔案保持未修改,但擱置內容已儲存。
包含未追蹤的檔案
保留已暫存的變更
擱置變更訊息:
@@ -651,7 +664,7 @@
擱置本機變更
套用 (apply)
刪除 (drop)
- 套用並刪除 (pop)
+ 另存為修補檔 (patch)...
捨棄擱置變更確認
捨棄擱置變更:
擱置變更
@@ -660,11 +673,11 @@
提交統計
提交次數
提交者
+ 總覽
本月
本週
- 提交次數:
貢獻者人數:
- 總覽
+ 提交次數:
子模組
新增子模組
複製路徑
@@ -679,13 +692,13 @@
刪除 ${0}$...
合併 ${0}$ 到 ${1}$...
推送 ${0}$...
- 存放庫網址:
更新子模組
更新所有子模組
啟用 [--init] 選項
啟用 [--recursive] 選項
子模組:
啟用 [--remote] 選項
+ 存放庫網址:
警告
起始頁
新增群組
@@ -698,8 +711,8 @@
開啟所有包含存放庫
開啟本機存放庫
開啟終端機
- 快速搜尋存放庫...
重新掃描預設複製 (clone) 目錄下的存放庫
+ 快速搜尋存放庫...
排序
本機變更
加入至 .gitignore 忽略清單
@@ -707,20 +720,26 @@
忽略同路徑下所有 *{0} 檔案
忽略同路徑下所有檔案
忽略本檔案
- 修補 (--amend)
+ 修補
現在您已可將其加入暫存區中
提 交
提交並推送
歷史輸入/範本
觸發點擊事件
- 提交(修改現有提交)
+ 提交 (修改原始提交)
自動暫存全部變更並提交
- 未包含任何檔案變更! 您是否仍要提交 (--allow-empty)?
+ 您已暫存 {0} 檔案,但只顯示 {1} 檔案 ({2} 檔案被篩選器隱藏)。您要繼續嗎?
檢測到衝突
+ 使用外部合併工具開啟
+ 使用外部合併工具開啟
檔案衝突已解決
+ 使用 MINE
+ 使用 THEIRS
顯示未追蹤檔案
沒有提交訊息記錄
沒有可套用的提交訊息範本
+ 請選擇發生衝突的檔案,開啟右鍵選單,選擇合適的解決方式
+ 署名
已暫存
取消暫存選取的檔案
取消暫存所有檔案
@@ -729,7 +748,6 @@
暫存所有檔案
檢視不追蹤變更的檔案
範本: ${0}$
- 請選擇發生衝突的檔案,開啟右鍵選單,選擇合適的解決方式
工作區:
設定工作區...
本機工作區
diff --git a/src/Resources/Styles.axaml b/src/Resources/Styles.axaml
index 14423fc6..38321356 100644
--- a/src/Resources/Styles.axaml
+++ b/src/Resources/Styles.axaml
@@ -2,6 +2,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="using:SourceGit"
xmlns:vm="using:SourceGit.ViewModels"
+ xmlns:v="using:SourceGit.Views"
xmlns:c="using:SourceGit.Converters"
xmlns:ae="using:AvaloniaEdit"
xmlns:aee="using:AvaloniaEdit.Editing"
@@ -159,7 +160,7 @@
-
+
-
+
+ DoubleTapped="OnRowDoubleTapped"
+ ToolTip.Tip="{Binding FullPath}">
-
+
-
+
SetValue(ChangesProperty, value);
}
+ public static readonly StyledProperty AutoSelectFirstChangeProperty =
+ AvaloniaProperty.Register(nameof(AutoSelectFirstChange), false);
+
+ public bool AutoSelectFirstChange
+ {
+ get => GetValue(AutoSelectFirstChangeProperty);
+ set => SetValue(AutoSelectFirstChangeProperty, value);
+ }
+
public static readonly StyledProperty> SelectedChangesProperty =
AvaloniaProperty.Register>(nameof(SelectedChanges));
@@ -205,9 +214,9 @@ namespace SourceGit.Views
base.OnPropertyChanged(change);
if (change.Property == ViewModeProperty)
- UpdateDataSource(false);
- else if (change.Property == ChangesProperty)
UpdateDataSource(true);
+ else if (change.Property == ChangesProperty)
+ UpdateDataSource(false);
else if (change.Property == SelectedChangesProperty)
UpdateSelection();
}
@@ -292,9 +301,9 @@ namespace SourceGit.Views
}
}
- private void UpdateDataSource(bool disableEvents)
+ private void UpdateDataSource(bool onlyViewModeChange)
{
- _disableSelectionChangingEvent = disableEvents;
+ _disableSelectionChangingEvent = !onlyViewModeChange;
var changes = Changes;
if (changes == null || changes.Count == 0)
@@ -324,7 +333,19 @@ namespace SourceGit.Views
MakeTreeRows(rows, tree.Tree);
tree.Rows.AddRange(rows);
- if (selected.Count > 0)
+ if (!onlyViewModeChange && AutoSelectFirstChange)
+ {
+ foreach (var row in tree.Rows)
+ {
+ if (row.Change != null)
+ {
+ tree.SelectedRows.Add(row);
+ SetCurrentValue(SelectedChangesProperty, [row.Change]);
+ break;
+ }
+ }
+ }
+ else if (selected.Count > 0)
{
var sets = new HashSet();
foreach (var c in selected)
@@ -346,16 +367,34 @@ namespace SourceGit.Views
{
var grid = new ViewModels.ChangeCollectionAsGrid();
grid.Changes.AddRange(changes);
- if (selected.Count > 0)
+
+ if (!onlyViewModeChange && AutoSelectFirstChange)
+ {
+ grid.SelectedChanges.Add(changes[0]);
+ SetCurrentValue(SelectedChangesProperty, [changes[0]]);
+ }
+ else if (selected.Count > 0)
+ {
grid.SelectedChanges.AddRange(selected);
+ }
+
Content = grid;
}
else
{
var list = new ViewModels.ChangeCollectionAsList();
list.Changes.AddRange(changes);
- if (selected.Count > 0)
+
+ if (!onlyViewModeChange && AutoSelectFirstChange)
+ {
+ list.SelectedChanges.Add(changes[0]);
+ SetCurrentValue(SelectedChangesProperty, [changes[0]]);
+ }
+ else if (selected.Count > 0)
+ {
list.SelectedChanges.AddRange(selected);
+ }
+
Content = list;
}
diff --git a/src/Views/ChangeStatusIcon.cs b/src/Views/ChangeStatusIcon.cs
index 5d34be09..7dbd0beb 100644
--- a/src/Views/ChangeStatusIcon.cs
+++ b/src/Views/ChangeStatusIcon.cs
@@ -93,7 +93,7 @@ namespace SourceGit.Views
string indicator;
if (IsUnstagedChange)
{
- if (Change.IsConflit)
+ if (Change.IsConflict)
{
background = Brushes.OrangeRed;
indicator = "!";
@@ -139,7 +139,7 @@ namespace SourceGit.Views
}
if (isUnstaged)
- ToolTip.SetTip(this, c.IsConflit ? "Conflict" : TIPS[(int)c.WorkTree]);
+ ToolTip.SetTip(this, c.IsConflict ? "Conflict" : TIPS[(int)c.WorkTree]);
else
ToolTip.SetTip(this, TIPS[(int)c.Index]);
diff --git a/src/Views/ChangeViewModeSwitcher.axaml b/src/Views/ChangeViewModeSwitcher.axaml
index 4ded60c7..911fb41d 100644
--- a/src/Views/ChangeViewModeSwitcher.axaml
+++ b/src/Views/ChangeViewModeSwitcher.axaml
@@ -6,38 +6,38 @@
xmlns:v="using:SourceGit.Views"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="SourceGit.Views.ChangeViewModeSwitcher"
- x:DataType="v:ChangeViewModeSwitcher">
+ x:Name="ThisControl">
diff --git a/src/Views/ChangeViewModeSwitcher.axaml.cs b/src/Views/ChangeViewModeSwitcher.axaml.cs
index 0cb2c4a9..ed306619 100644
--- a/src/Views/ChangeViewModeSwitcher.axaml.cs
+++ b/src/Views/ChangeViewModeSwitcher.axaml.cs
@@ -1,5 +1,6 @@
using Avalonia;
using Avalonia.Controls;
+using Avalonia.Interactivity;
namespace SourceGit.Views
{
@@ -16,13 +17,25 @@ namespace SourceGit.Views
public ChangeViewModeSwitcher()
{
- DataContext = this;
InitializeComponent();
}
- public void SwitchMode(object param)
+ private void SwitchToList(object sender, RoutedEventArgs e)
{
- ViewMode = (Models.ChangeViewMode)param;
+ ViewMode = Models.ChangeViewMode.List;
+ e.Handled = true;
+ }
+
+ private void SwitchToGrid(object sender, RoutedEventArgs e)
+ {
+ ViewMode = Models.ChangeViewMode.Grid;
+ e.Handled = true;
+ }
+
+ private void SwitchToTree(object sender, RoutedEventArgs e)
+ {
+ ViewMode = Models.ChangeViewMode.Tree;
+ e.Handled = true;
}
}
}
diff --git a/src/Views/Checkout.axaml b/src/Views/Checkout.axaml
index eb1c9de0..3cdfd94e 100644
--- a/src/Views/Checkout.axaml
+++ b/src/Views/Checkout.axaml
@@ -18,7 +18,7 @@
-
+
-
-
+
-
-
+ Content="{DynamicResource Text.CreateBranch.LocalChanges.StashAndReply}"
+ IsChecked="{Binding !DiscardLocalChanges, Mode=TwoWay}"/>
+
diff --git a/src/Views/Checkout.axaml.cs b/src/Views/Checkout.axaml.cs
index da6e6b31..f8398a1d 100644
--- a/src/Views/Checkout.axaml.cs
+++ b/src/Views/Checkout.axaml.cs
@@ -1,5 +1,4 @@
using Avalonia.Controls;
-using Avalonia.Interactivity;
namespace SourceGit.Views
{
@@ -9,51 +8,5 @@ namespace SourceGit.Views
{
InitializeComponent();
}
-
- protected override void OnLoaded(RoutedEventArgs e)
- {
- base.OnLoaded(e);
-
- var vm = DataContext as ViewModels.Checkout;
- if (vm == null)
- return;
-
- switch (vm.PreAction)
- {
- case Models.DealWithLocalChanges.DoNothing:
- RadioDoNothing.IsChecked = true;
- break;
- case Models.DealWithLocalChanges.StashAndReaply:
- RadioStashAndReply.IsChecked = true;
- break;
- default:
- RadioDiscard.IsChecked = true;
- break;
- }
- }
-
- private void OnLocalChangeActionIsCheckedChanged(object sender, RoutedEventArgs e)
- {
- var vm = DataContext as ViewModels.Checkout;
- if (vm == null)
- return;
-
- if (RadioDoNothing.IsChecked == true)
- {
- if (vm.PreAction != Models.DealWithLocalChanges.DoNothing)
- vm.PreAction = Models.DealWithLocalChanges.DoNothing;
- return;
- }
-
- if (RadioStashAndReply.IsChecked == true)
- {
- if (vm.PreAction != Models.DealWithLocalChanges.StashAndReaply)
- vm.PreAction = Models.DealWithLocalChanges.StashAndReaply;
- return;
- }
-
- if (vm.PreAction != Models.DealWithLocalChanges.Discard)
- vm.PreAction = Models.DealWithLocalChanges.Discard;
- }
}
}
diff --git a/src/Views/CheckoutCommit.axaml b/src/Views/CheckoutCommit.axaml
index 3ee3943f..9b418823 100644
--- a/src/Views/CheckoutCommit.axaml
+++ b/src/Views/CheckoutCommit.axaml
@@ -30,16 +30,16 @@
+ Margin="0,0,8,0"
+ IsChecked="{Binding !DiscardLocalChanges, Mode=TwoWay}"/>
+ GroupName="LocalChanges"/>
-
-
+
-
-
+
diff --git a/src/Views/ChromelessWindow.cs b/src/Views/ChromelessWindow.cs
index 107a7ba3..647c657e 100644
--- a/src/Views/ChromelessWindow.cs
+++ b/src/Views/ChromelessWindow.cs
@@ -11,7 +11,7 @@ namespace SourceGit.Views
{
public bool UseSystemWindowFrame
{
- get => OperatingSystem.IsLinux() && ViewModels.Preference.Instance.UseSystemWindowFrame;
+ get => OperatingSystem.IsLinux() && ViewModels.Preferences.Instance.UseSystemWindowFrame;
}
protected override Type StyleKeyOverride => typeof(Window);
diff --git a/src/Views/Clone.axaml b/src/Views/Clone.axaml
index 25c46a00..8c7c9faf 100644
--- a/src/Views/Clone.axaml
+++ b/src/Views/Clone.axaml
@@ -10,15 +10,15 @@
-
-
+
-
-
-
-
+
+
diff --git a/src/Views/CommitBaseInfo.axaml b/src/Views/CommitBaseInfo.axaml
index b62ecc92..6162556e 100644
--- a/src/Views/CommitBaseInfo.axaml
+++ b/src/Views/CommitBaseInfo.axaml
@@ -19,14 +19,14 @@
-
-
-
-
-
+
+
+
+
+
@@ -35,14 +35,14 @@
-
-
-
-
-
+
+
+
+
+
@@ -55,9 +55,9 @@
-
-
-
+
+
@@ -133,8 +133,8 @@
-
-
+
+
@@ -173,8 +173,7 @@
-
-
+ TextWrapping="Wrap">
diff --git a/src/Views/CommitBaseInfo.axaml.cs b/src/Views/CommitBaseInfo.axaml.cs
index ea0c09d4..58e10cbb 100644
--- a/src/Views/CommitBaseInfo.axaml.cs
+++ b/src/Views/CommitBaseInfo.axaml.cs
@@ -1,8 +1,8 @@
using System;
+using System.Collections.Generic;
using System.Threading.Tasks;
using Avalonia;
-using Avalonia.Collections;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Interactivity;
@@ -12,13 +12,13 @@ namespace SourceGit.Views
{
public partial class CommitBaseInfo : UserControl
{
- public static readonly StyledProperty MessageProperty =
- AvaloniaProperty.Register(nameof(Message), string.Empty);
+ public static readonly StyledProperty FullMessageProperty =
+ AvaloniaProperty.Register(nameof(FullMessage));
- public string Message
+ public Models.CommitFullMessage FullMessage
{
- get => GetValue(MessageProperty);
- set => SetValue(MessageProperty, value);
+ get => GetValue(FullMessageProperty);
+ set => SetValue(FullMessageProperty, value);
}
public static readonly StyledProperty SignInfoProperty =
@@ -39,28 +39,19 @@ namespace SourceGit.Views
set => SetValue(SupportsContainsInProperty, value);
}
- public static readonly StyledProperty> WebLinksProperty =
- AvaloniaProperty.Register>(nameof(WebLinks));
+ public static readonly StyledProperty> WebLinksProperty =
+ AvaloniaProperty.Register>(nameof(WebLinks));
- public AvaloniaList WebLinks
+ public List WebLinks
{
get => GetValue(WebLinksProperty);
set => SetValue(WebLinksProperty, value);
}
- public static readonly StyledProperty> IssueTrackerRulesProperty =
- AvaloniaProperty.Register>(nameof(IssueTrackerRules));
+ public static readonly StyledProperty> ChildrenProperty =
+ AvaloniaProperty.Register>(nameof(Children));
- public AvaloniaList IssueTrackerRules
- {
- get => GetValue(IssueTrackerRulesProperty);
- set => SetValue(IssueTrackerRulesProperty, value);
- }
-
- public static readonly StyledProperty> ChildrenProperty =
- AvaloniaProperty.Register>(nameof(Children));
-
- public AvaloniaList Children
+ public List Children
{
get => GetValue(ChildrenProperty);
set => SetValue(ChildrenProperty, value);
diff --git a/src/Views/CommitChanges.axaml b/src/Views/CommitChanges.axaml
index 1c7b34bd..80f96c48 100644
--- a/src/Views/CommitChanges.axaml
+++ b/src/Views/CommitChanges.axaml
@@ -9,7 +9,7 @@
x:DataType="vm:CommitDetail">
-
+
@@ -19,7 +19,7 @@
+ ViewMode="{Binding Source={x:Static vm:Preferences.Instance}, Path=CommitChangeViewMode, Mode=TwoWay}"/>
diff --git a/src/Views/CommitDetail.axaml b/src/Views/CommitDetail.axaml
index d0d52473..e8c150a1 100644
--- a/src/Views/CommitDetail.axaml
+++ b/src/Views/CommitDetail.axaml
@@ -19,19 +19,18 @@
-
+ Children="{Binding Children}"/>
-
@@ -42,20 +41,20 @@
-
+
-
+
-
@@ -64,8 +63,8 @@
-
diff --git a/src/Views/CommitGraph.cs b/src/Views/CommitGraph.cs
new file mode 100644
index 00000000..015eaca5
--- /dev/null
+++ b/src/Views/CommitGraph.cs
@@ -0,0 +1,228 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Media;
+using Avalonia.VisualTree;
+
+namespace SourceGit.Views
+{
+ public class CommitGraph : Control
+ {
+ public static readonly StyledProperty GraphProperty =
+ AvaloniaProperty.Register(nameof(Graph));
+
+ public Models.CommitGraph Graph
+ {
+ get => GetValue(GraphProperty);
+ set => SetValue(GraphProperty, value);
+ }
+
+ public static readonly StyledProperty DotBrushProperty =
+ AvaloniaProperty.Register(nameof(DotBrush), Brushes.Transparent);
+
+ public IBrush DotBrush
+ {
+ get => GetValue(DotBrushProperty);
+ set => SetValue(DotBrushProperty, value);
+ }
+
+ public static readonly StyledProperty OnlyHighlightCurrentBranchProperty =
+ AvaloniaProperty.Register(nameof(OnlyHighlightCurrentBranch), true);
+
+ public bool OnlyHighlightCurrentBranch
+ {
+ get => GetValue(OnlyHighlightCurrentBranchProperty);
+ set => SetValue(OnlyHighlightCurrentBranchProperty, value);
+ }
+
+ static CommitGraph()
+ {
+ AffectsRender(GraphProperty, DotBrushProperty, OnlyHighlightCurrentBranchProperty);
+ }
+
+ public override void Render(DrawingContext context)
+ {
+ base.Render(context);
+
+ var graph = Graph;
+ if (graph == null)
+ return;
+
+ var histories = this.FindAncestorOfType();
+ if (histories == null)
+ return;
+
+ var list = histories.CommitListContainer;
+ if (list == null)
+ return;
+
+ // Calculate drawing area.
+ double width = Bounds.Width - 273 - histories.AuthorNameColumnWidth.Value;
+ double height = Bounds.Height;
+ double startY = list.Scroll?.Offset.Y ?? 0;
+ double endY = startY + height + 28;
+
+ // Apply scroll offset and clip.
+ using (context.PushClip(new Rect(0, 0, width, height)))
+ using (context.PushTransform(Matrix.CreateTranslation(0, -startY)))
+ {
+ // Draw contents
+ DrawCurves(context, graph, startY, endY);
+ DrawAnchors(context, graph, startY, endY);
+ }
+ }
+
+ private void DrawCurves(DrawingContext context, Models.CommitGraph graph, double top, double bottom)
+ {
+ var grayedPen = new Pen(new SolidColorBrush(Colors.Gray, 0.4), Models.CommitGraph.Pens[0].Thickness);
+ var onlyHighlightCurrentBranch = OnlyHighlightCurrentBranch;
+
+ if (onlyHighlightCurrentBranch)
+ {
+ foreach (var link in graph.Links)
+ {
+ if (link.IsMerged)
+ continue;
+ if (link.End.Y < top)
+ continue;
+ if (link.Start.Y > bottom)
+ break;
+
+ var geo = new StreamGeometry();
+ using (var ctx = geo.Open())
+ {
+ ctx.BeginFigure(link.Start, false);
+ ctx.QuadraticBezierTo(link.Control, link.End);
+ }
+
+ context.DrawGeometry(null, grayedPen, geo);
+ }
+ }
+
+ foreach (var line in graph.Paths)
+ {
+ var last = line.Points[0];
+ var size = line.Points.Count;
+
+ if (line.Points[size - 1].Y < top)
+ continue;
+ if (last.Y > bottom)
+ break;
+
+ var geo = new StreamGeometry();
+ var pen = Models.CommitGraph.Pens[line.Color];
+
+ using (var ctx = geo.Open())
+ {
+ var started = false;
+ var ended = false;
+ for (int i = 1; i < size; i++)
+ {
+ var cur = line.Points[i];
+ if (cur.Y < top)
+ {
+ last = cur;
+ continue;
+ }
+
+ if (!started)
+ {
+ ctx.BeginFigure(last, false);
+ started = true;
+ }
+
+ if (cur.Y > bottom)
+ {
+ cur = new Point(cur.X, bottom);
+ ended = true;
+ }
+
+ if (cur.X > last.X)
+ {
+ ctx.QuadraticBezierTo(new Point(cur.X, last.Y), cur);
+ }
+ else if (cur.X < last.X)
+ {
+ if (i < size - 1)
+ {
+ var midY = (last.Y + cur.Y) / 2;
+ ctx.CubicBezierTo(new Point(last.X, midY + 4), new Point(cur.X, midY - 4), cur);
+ }
+ else
+ {
+ ctx.QuadraticBezierTo(new Point(last.X, cur.Y), cur);
+ }
+ }
+ else
+ {
+ ctx.LineTo(cur);
+ }
+
+ if (ended)
+ break;
+ last = cur;
+ }
+ }
+
+ if (!line.IsMerged && onlyHighlightCurrentBranch)
+ context.DrawGeometry(null, grayedPen, geo);
+ else
+ context.DrawGeometry(null, pen, geo);
+ }
+
+ foreach (var link in graph.Links)
+ {
+ if (onlyHighlightCurrentBranch && !link.IsMerged)
+ continue;
+ if (link.End.Y < top)
+ continue;
+ if (link.Start.Y > bottom)
+ break;
+
+ var geo = new StreamGeometry();
+ using (var ctx = geo.Open())
+ {
+ ctx.BeginFigure(link.Start, false);
+ ctx.QuadraticBezierTo(link.Control, link.End);
+ }
+
+ context.DrawGeometry(null, Models.CommitGraph.Pens[link.Color], geo);
+ }
+ }
+
+ private void DrawAnchors(DrawingContext context, Models.CommitGraph graph, double top, double bottom)
+ {
+ var dotFill = DotBrush;
+ var dotFillPen = new Pen(dotFill, 2);
+ var grayedPen = new Pen(Brushes.Gray, Models.CommitGraph.Pens[0].Thickness);
+ var onlyHighlightCurrentBranch = OnlyHighlightCurrentBranch;
+
+ foreach (var dot in graph.Dots)
+ {
+ if (dot.Center.Y < top)
+ continue;
+ if (dot.Center.Y > bottom)
+ break;
+
+ var pen = Models.CommitGraph.Pens[dot.Color];
+ if (!dot.IsMerged && onlyHighlightCurrentBranch)
+ pen = grayedPen;
+
+ switch (dot.Type)
+ {
+ case Models.CommitGraph.DotType.Head:
+ context.DrawEllipse(dotFill, pen, dot.Center, 6, 6);
+ context.DrawEllipse(pen.Brush, null, dot.Center, 3, 3);
+ break;
+ case Models.CommitGraph.DotType.Merge:
+ context.DrawEllipse(pen.Brush, null, dot.Center, 6, 6);
+ context.DrawLine(dotFillPen, new Point(dot.Center.X, dot.Center.Y - 3), new Point(dot.Center.X, dot.Center.Y + 3));
+ context.DrawLine(dotFillPen, new Point(dot.Center.X - 3, dot.Center.Y), new Point(dot.Center.X + 3, dot.Center.Y));
+ break;
+ default:
+ context.DrawEllipse(dotFill, pen, dot.Center, 3, 3);
+ break;
+ }
+ }
+ }
+ }
+}
diff --git a/src/Views/CommitMessagePresenter.cs b/src/Views/CommitMessagePresenter.cs
index 0ae3d6cf..002beda1 100644
--- a/src/Views/CommitMessagePresenter.cs
+++ b/src/Views/CommitMessagePresenter.cs
@@ -1,10 +1,8 @@
using System;
using System.Collections.Generic;
-using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Avalonia;
-using Avalonia.Collections;
using Avalonia.Controls;
using Avalonia.Controls.Documents;
using Avalonia.Input;
@@ -13,27 +11,15 @@ using Avalonia.VisualTree;
namespace SourceGit.Views
{
- public partial class CommitMessagePresenter : SelectableTextBlock
+ public class CommitMessagePresenter : SelectableTextBlock
{
- [GeneratedRegex(@"\b([0-9a-fA-F]{10,40})\b")]
- private static partial Regex REG_SHA_FORMAT();
+ public static readonly StyledProperty FullMessageProperty =
+ AvaloniaProperty.Register(nameof(FullMessage));
- public static readonly StyledProperty MessageProperty =
- AvaloniaProperty.Register(nameof(Message));
-
- public string Message
+ public Models.CommitFullMessage FullMessage
{
- get => GetValue(MessageProperty);
- set => SetValue(MessageProperty, value);
- }
-
- public static readonly StyledProperty> IssueTrackerRulesProperty =
- AvaloniaProperty.Register>(nameof(IssueTrackerRules));
-
- public AvaloniaList IssueTrackerRules
- {
- get => GetValue(IssueTrackerRulesProperty);
- set => SetValue(IssueTrackerRulesProperty, value);
+ get => GetValue(FullMessageProperty);
+ set => SetValue(FullMessageProperty, value);
}
protected override Type StyleKeyOverride => typeof(SelectableTextBlock);
@@ -42,69 +28,36 @@ namespace SourceGit.Views
{
base.OnPropertyChanged(change);
- if (change.Property == MessageProperty || change.Property == IssueTrackerRulesProperty)
+ if (change.Property == FullMessageProperty)
{
Inlines!.Clear();
_inlineCommits.Clear();
- _matches = null;
_lastHover = null;
ClearHoveredIssueLink();
- var message = Message;
+ var message = FullMessage?.Message;
if (string.IsNullOrEmpty(message))
return;
- var matches = new List();
- if (IssueTrackerRules is { Count: > 0 } rules)
- {
- foreach (var rule in rules)
- rule.Matches(matches, message);
- }
-
- var shas = REG_SHA_FORMAT().Matches(message);
- for (int i = 0; i < shas.Count; i++)
- {
- var sha = shas[i];
- if (!sha.Success)
- continue;
-
- var start = sha.Index;
- var len = sha.Length;
- var intersect = false;
- foreach (var match in matches)
- {
- if (match.Intersect(start, len))
- {
- intersect = true;
- break;
- }
- }
-
- if (!intersect)
- matches.Add(new Models.Hyperlink(start, len, sha.Groups[1].Value, true));
- }
-
- if (matches.Count == 0)
+ var links = FullMessage?.Links;
+ if (links == null || links.Count == 0)
{
Inlines.Add(new Run(message));
return;
}
- matches.Sort((l, r) => l.Start - r.Start);
- _matches = matches;
-
var inlines = new List();
var pos = 0;
- foreach (var match in matches)
+ foreach (var link in links)
{
- if (match.Start > pos)
- inlines.Add(new Run(message.Substring(pos, match.Start - pos)));
+ if (link.Start > pos)
+ inlines.Add(new Run(message.Substring(pos, link.Start - pos)));
- var link = new Run(message.Substring(match.Start, match.Length));
- link.Classes.Add(match.IsCommitSHA ? "commit_link" : "issue_link");
- inlines.Add(link);
+ var run = new Run(message.Substring(link.Start, link.Length));
+ run.Classes.Add(link.IsCommitSHA ? "commit_link" : "issue_link");
+ inlines.Add(run);
- pos = match.Start + match.Length;
+ pos = link.Start + link.Length;
}
if (pos < message.Length)
@@ -134,7 +87,7 @@ namespace SourceGit.Views
scrollViewer.LineDown();
}
}
- else if (_matches != null)
+ else if (FullMessage is { Links: { Count: > 0 } links })
{
var point = e.GetPosition(this) - new Point(Padding.Left, Padding.Top);
var x = Math.Min(Math.Max(point.X, 0), Math.Max(TextLayout.WidthIncludingTrailingWhitespace, 0));
@@ -142,25 +95,25 @@ namespace SourceGit.Views
point = new Point(x, y);
var pos = TextLayout.HitTestPoint(point).TextPosition;
- foreach (var match in _matches)
+ foreach (var link in links)
{
- if (!match.Intersect(pos, 1))
+ if (!link.Intersect(pos, 1))
continue;
- if (match == _lastHover)
+ if (link == _lastHover)
return;
SetCurrentValue(CursorProperty, Cursor.Parse("Hand"));
- _lastHover = match;
- if (!match.IsCommitSHA)
+ _lastHover = link;
+ if (!link.IsCommitSHA)
{
- ToolTip.SetTip(this, match.Link);
+ ToolTip.SetTip(this, link.Link);
ToolTip.SetIsOpen(this, true);
}
else
{
- ProcessHoverCommitLink(match);
+ ProcessHoverCommitLink(link);
}
return;
@@ -172,8 +125,11 @@ namespace SourceGit.Views
protected override void OnPointerPressed(PointerPressedEventArgs e)
{
+ var point = e.GetCurrentPoint(this);
+
if (_lastHover != null)
{
+ var link = _lastHover.Link;
e.Pointer.Capture(null);
if (_lastHover.IsCommitSHA)
@@ -181,9 +137,6 @@ namespace SourceGit.Views
var parentView = this.FindAncestorOfType();
if (parentView is { DataContext: ViewModels.CommitDetail detail })
{
- var point = e.GetCurrentPoint(this);
- var link = _lastHover.Link;
-
if (point.Properties.IsLeftButtonPressed)
{
detail.NavigateTo(_lastHover.Link);
@@ -217,9 +170,6 @@ namespace SourceGit.Views
}
else
{
- var point = e.GetCurrentPoint(this);
- var link = _lastHover.Link;
-
if (point.Properties.IsLeftButtonPressed)
{
Native.OS.OpenBrowser(link);
@@ -255,6 +205,49 @@ namespace SourceGit.Views
return;
}
+ if (point.Properties.IsLeftButtonPressed && e.ClickCount == 3)
+ {
+ var text = Inlines?.Text;
+ if (string.IsNullOrEmpty(text))
+ {
+ e.Handled = true;
+ return;
+ }
+
+ var position = e.GetPosition(this) - new Point(Padding.Left, Padding.Top);
+ var x = Math.Min(Math.Max(position.X, 0), Math.Max(TextLayout.WidthIncludingTrailingWhitespace, 0));
+ var y = Math.Min(Math.Max(position.Y, 0), Math.Max(TextLayout.Height, 0));
+ position = new Point(x, y);
+
+ var textPos = TextLayout.HitTestPoint(position).TextPosition;
+ var lineStart = 0;
+ var lineEnd = text.IndexOf('\n', lineStart);
+ if (lineEnd <= 0)
+ {
+ lineEnd = text.Length;
+ }
+ else
+ {
+ while (lineEnd < textPos)
+ {
+ lineStart = lineEnd + 1;
+ lineEnd = text.IndexOf('\n', lineStart);
+ if (lineEnd == -1)
+ {
+ lineEnd = text.Length;
+ break;
+ }
+ }
+ }
+
+ SetCurrentValue(SelectionStartProperty, lineStart);
+ SetCurrentValue(SelectionEndProperty, lineEnd);
+
+ e.Pointer.Capture(this);
+ e.Handled = true;
+ return;
+ }
+
base.OnPointerPressed(e);
}
@@ -321,7 +314,6 @@ namespace SourceGit.Views
}
}
- private List _matches = null;
private Models.Hyperlink _lastHover = null;
private Dictionary _inlineCommits = new();
}
diff --git a/src/Views/CommitMessageTextBox.axaml b/src/Views/CommitMessageTextBox.axaml
index 88862a8a..5132521f 100644
--- a/src/Views/CommitMessageTextBox.axaml
+++ b/src/Views/CommitMessageTextBox.axaml
@@ -36,7 +36,7 @@
VerticalAlignment="Stretch"
IsHitTestVisible="False"
Fill="{DynamicResource Brush.Border2}"/>
-
+
-
+
-
+
SetValue(UseGraphColorProperty, value);
}
- public static readonly StyledProperty TagBackgroundProperty =
- AvaloniaProperty.Register(nameof(TagBackground), Brushes.White);
-
- public IBrush TagBackground
- {
- get => GetValue(TagBackgroundProperty);
- set => SetValue(TagBackgroundProperty, value);
- }
-
public static readonly StyledProperty AllowWrapProperty =
AvaloniaProperty.Register(nameof(AllowWrap));
@@ -82,6 +73,15 @@ namespace SourceGit.Views
set => SetValue(AllowWrapProperty, value);
}
+ public static readonly StyledProperty ShowTagsProperty =
+ AvaloniaProperty.Register(nameof(ShowTags), true);
+
+ public bool ShowTags
+ {
+ get => GetValue(ShowTagsProperty);
+ set => SetValue(ShowTagsProperty, value);
+ }
+
static CommitRefsPresenter()
{
AffectsMeasure(
@@ -89,8 +89,8 @@ namespace SourceGit.Views
FontSizeProperty,
ForegroundProperty,
UseGraphColorProperty,
- TagBackgroundProperty,
- BackgroundProperty);
+ BackgroundProperty,
+ ShowTagsProperty);
}
public override void Render(DrawingContext context)
@@ -171,15 +171,18 @@ namespace SourceGit.Views
var typefaceBold = new Typeface(FontFamily, FontStyle.Normal, FontWeight.Bold);
var fg = Foreground;
var normalBG = UseGraphColor ? commit.Brush : Brushes.Gray;
- var tagBG = UseGraphColor ? TagBackground : Brushes.Gray;
var labelSize = FontSize;
var requiredWidth = 0.0;
var requiredHeight = 16.0;
var x = 0.0;
var allowWrap = AllowWrap;
+ var showTags = ShowTags;
foreach (var decorator in refs)
{
+ if (!showTags && decorator.Type == Models.DecoratorType.Tag)
+ continue;
+
var isHead = decorator.Type == Models.DecoratorType.CurrentBranchHead ||
decorator.Type == Models.DecoratorType.CurrentCommitHead;
@@ -209,7 +212,7 @@ namespace SourceGit.Views
geo = this.FindResource("Icons.Remote") as StreamGeometry;
break;
case Models.DecoratorType.Tag:
- item.Brush = tagBG;
+ item.Brush = Brushes.Gray;
geo = this.FindResource("Icons.Tag") as StreamGeometry;
break;
default:
diff --git a/src/Views/CommitRelationTracking.axaml b/src/Views/CommitRelationTracking.axaml
index 5e3574d8..9d036e10 100644
--- a/src/Views/CommitRelationTracking.axaml
+++ b/src/Views/CommitRelationTracking.axaml
@@ -30,7 +30,7 @@
-
+
diff --git a/src/Views/CommitStatusIndicator.cs b/src/Views/CommitStatusIndicator.cs
new file mode 100644
index 00000000..c2f4184e
--- /dev/null
+++ b/src/Views/CommitStatusIndicator.cs
@@ -0,0 +1,90 @@
+using System;
+
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Media;
+
+namespace SourceGit.Views
+{
+ public class CommitStatusIndicator : Control
+ {
+ public static readonly StyledProperty CurrentBranchProperty =
+ AvaloniaProperty.Register(nameof(CurrentBranch));
+
+ public Models.Branch CurrentBranch
+ {
+ get => GetValue(CurrentBranchProperty);
+ set => SetValue(CurrentBranchProperty, value);
+ }
+
+ public static readonly StyledProperty AheadBrushProperty =
+ AvaloniaProperty.Register(nameof(AheadBrush));
+
+ public IBrush AheadBrush
+ {
+ get => GetValue(AheadBrushProperty);
+ set => SetValue(AheadBrushProperty, value);
+ }
+
+ public static readonly StyledProperty BehindBrushProperty =
+ AvaloniaProperty.Register(nameof(BehindBrush));
+
+ public IBrush BehindBrush
+ {
+ get => GetValue(BehindBrushProperty);
+ set => SetValue(BehindBrushProperty, value);
+ }
+
+ enum Status
+ {
+ Normal,
+ Ahead,
+ Behind,
+ }
+
+ public override void Render(DrawingContext context)
+ {
+ if (_status == Status.Normal)
+ return;
+
+ context.DrawEllipse(_status == Status.Ahead ? AheadBrush : BehindBrush, null, new Rect(0, 0, 5, 5));
+ }
+
+ protected override Size MeasureOverride(Size availableSize)
+ {
+ if (DataContext is Models.Commit commit && CurrentBranch is not null)
+ {
+ var sha = commit.SHA;
+ var track = CurrentBranch.TrackStatus;
+
+ if (track.Ahead.Contains(sha))
+ _status = Status.Ahead;
+ else if (track.Behind.Contains(sha))
+ _status = Status.Behind;
+ else
+ _status = Status.Normal;
+ }
+ else
+ {
+ _status = Status.Normal;
+ }
+
+ return _status == Status.Normal ? new Size(0, 0) : new Size(9, 5);
+ }
+
+ protected override void OnDataContextChanged(EventArgs e)
+ {
+ base.OnDataContextChanged(e);
+ InvalidateMeasure();
+ }
+
+ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
+ {
+ base.OnPropertyChanged(change);
+ if (change.Property == CurrentBranchProperty)
+ InvalidateMeasure();
+ }
+
+ private Status _status = Status.Normal;
+ }
+}
diff --git a/src/Views/CommitSubjectPresenter.cs b/src/Views/CommitSubjectPresenter.cs
new file mode 100644
index 00000000..32f6838d
--- /dev/null
+++ b/src/Views/CommitSubjectPresenter.cs
@@ -0,0 +1,189 @@
+using System;
+using System.Collections.Generic;
+using System.Text.RegularExpressions;
+using Avalonia;
+using Avalonia.Collections;
+using Avalonia.Controls;
+using Avalonia.Controls.Documents;
+using Avalonia.Input;
+using Avalonia.Media;
+using Avalonia.Media.TextFormatting;
+
+namespace SourceGit.Views
+{
+ public partial class CommitSubjectPresenter : TextBlock
+ {
+ public static readonly StyledProperty SubjectProperty =
+ AvaloniaProperty.Register(nameof(Subject));
+
+ public string Subject
+ {
+ get => GetValue(SubjectProperty);
+ set => SetValue(SubjectProperty, value);
+ }
+
+ public static readonly StyledProperty> IssueTrackerRulesProperty =
+ AvaloniaProperty.Register>(nameof(IssueTrackerRules));
+
+ public AvaloniaList IssueTrackerRules
+ {
+ get => GetValue(IssueTrackerRulesProperty);
+ set => SetValue(IssueTrackerRulesProperty, value);
+ }
+
+ protected override Type StyleKeyOverride => typeof(TextBlock);
+
+ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
+ {
+ base.OnPropertyChanged(change);
+
+ if (change.Property == SubjectProperty || change.Property == IssueTrackerRulesProperty)
+ {
+ Inlines!.Clear();
+ _matches = null;
+ ClearHoveredIssueLink();
+
+ var subject = Subject;
+ if (string.IsNullOrEmpty(subject))
+ return;
+
+ var keywordMatch = REG_KEYWORD_FORMAT1().Match(subject);
+ if (!keywordMatch.Success)
+ keywordMatch = REG_KEYWORD_FORMAT2().Match(subject);
+
+ var rules = IssueTrackerRules ?? [];
+ var matches = new List();
+ foreach (var rule in rules)
+ rule.Matches(matches, subject);
+
+ if (matches.Count == 0)
+ {
+ if (keywordMatch.Success)
+ {
+ Inlines.Add(new Run(subject.Substring(0, keywordMatch.Length)) { FontWeight = FontWeight.Bold });
+ Inlines.Add(new Run(subject.Substring(keywordMatch.Length)));
+ }
+ else
+ {
+ Inlines.Add(new Run(subject));
+ }
+ return;
+ }
+
+ matches.Sort((l, r) => l.Start - r.Start);
+ _matches = matches;
+
+ var inlines = new List();
+ var pos = 0;
+ foreach (var match in matches)
+ {
+ if (match.Start > pos)
+ {
+ if (keywordMatch.Success && pos < keywordMatch.Length)
+ {
+ if (keywordMatch.Length < match.Start)
+ {
+ inlines.Add(new Run(subject.Substring(pos, keywordMatch.Length - pos)) { FontWeight = FontWeight.Bold });
+ inlines.Add(new Run(subject.Substring(keywordMatch.Length, match.Start - keywordMatch.Length)));
+ }
+ else
+ {
+ inlines.Add(new Run(subject.Substring(pos, match.Start - pos)) { FontWeight = FontWeight.Bold });
+ }
+ }
+ else
+ {
+ inlines.Add(new Run(subject.Substring(pos, match.Start - pos)));
+ }
+ }
+
+ var link = new Run(subject.Substring(match.Start, match.Length));
+ link.Classes.Add("issue_link");
+ inlines.Add(link);
+
+ pos = match.Start + match.Length;
+ }
+
+ if (pos < subject.Length)
+ {
+ if (keywordMatch.Success && pos < keywordMatch.Length)
+ {
+ inlines.Add(new Run(subject.Substring(pos, keywordMatch.Length - pos)) { FontWeight = FontWeight.Bold });
+ inlines.Add(new Run(subject.Substring(keywordMatch.Length)));
+ }
+ else
+ {
+ inlines.Add(new Run(subject.Substring(pos)));
+ }
+ }
+
+ Inlines.AddRange(inlines);
+ }
+ }
+
+ protected override void OnPointerMoved(PointerEventArgs e)
+ {
+ base.OnPointerMoved(e);
+
+ if (_matches != null)
+ {
+ var point = e.GetPosition(this) - new Point(Padding.Left, Padding.Top);
+ var x = Math.Min(Math.Max(point.X, 0), Math.Max(TextLayout.WidthIncludingTrailingWhitespace, 0));
+ var y = Math.Min(Math.Max(point.Y, 0), Math.Max(TextLayout.Height, 0));
+ point = new Point(x, y);
+
+ var textPosition = TextLayout.HitTestPoint(point).TextPosition;
+ foreach (var match in _matches)
+ {
+ if (!match.Intersect(textPosition, 1))
+ continue;
+
+ if (match == _lastHover)
+ return;
+
+ _lastHover = match;
+ SetCurrentValue(CursorProperty, Cursor.Parse("Hand"));
+ ToolTip.SetTip(this, match.Link);
+ ToolTip.SetIsOpen(this, true);
+ e.Handled = true;
+ return;
+ }
+
+ ClearHoveredIssueLink();
+ }
+ }
+
+ protected override void OnPointerPressed(PointerPressedEventArgs e)
+ {
+ base.OnPointerPressed(e);
+
+ if (_lastHover != null)
+ Native.OS.OpenBrowser(_lastHover.Link);
+ }
+
+ protected override void OnPointerExited(PointerEventArgs e)
+ {
+ base.OnPointerExited(e);
+ ClearHoveredIssueLink();
+ }
+
+ private void ClearHoveredIssueLink()
+ {
+ if (_lastHover != null)
+ {
+ ToolTip.SetTip(this, null);
+ SetCurrentValue(CursorProperty, Cursor.Parse("Arrow"));
+ _lastHover = null;
+ }
+ }
+
+ [GeneratedRegex(@"^\[[\w\s]+\]")]
+ private static partial Regex REG_KEYWORD_FORMAT1();
+
+ [GeneratedRegex(@"^\S+([\<\(][\w\s_\-\*,]+[\>\)])?\!?\s?:\s")]
+ private static partial Regex REG_KEYWORD_FORMAT2();
+
+ private List _matches = null;
+ private Models.Hyperlink _lastHover = null;
+ }
+}
diff --git a/src/Views/CommitTimeTextBlock.cs b/src/Views/CommitTimeTextBlock.cs
new file mode 100644
index 00000000..db63e8a6
--- /dev/null
+++ b/src/Views/CommitTimeTextBlock.cs
@@ -0,0 +1,166 @@
+using System;
+
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Interactivity;
+using Avalonia.Threading;
+
+namespace SourceGit.Views
+{
+ public class CommitTimeTextBlock : TextBlock
+ {
+ public static readonly StyledProperty ShowAsDateTimeProperty =
+ AvaloniaProperty.Register(nameof(ShowAsDateTime), true);
+
+ public bool ShowAsDateTime
+ {
+ get => GetValue(ShowAsDateTimeProperty);
+ set => SetValue(ShowAsDateTimeProperty, value);
+ }
+
+ public static readonly StyledProperty DateTimeFormatProperty =
+ AvaloniaProperty.Register(nameof(DateTimeFormat), 0);
+
+ public int DateTimeFormat
+ {
+ get => GetValue(DateTimeFormatProperty);
+ set => SetValue(DateTimeFormatProperty, value);
+ }
+
+ public static readonly StyledProperty UseAuthorTimeProperty =
+ AvaloniaProperty.Register(nameof(UseAuthorTime), true);
+
+ public bool UseAuthorTime
+ {
+ get => GetValue(UseAuthorTimeProperty);
+ set => SetValue(UseAuthorTimeProperty, value);
+ }
+
+ protected override Type StyleKeyOverride => typeof(TextBlock);
+
+ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
+ {
+ base.OnPropertyChanged(change);
+
+ if (change.Property == UseAuthorTimeProperty)
+ {
+ SetCurrentValue(TextProperty, GetDisplayText());
+ }
+ else if (change.Property == ShowAsDateTimeProperty)
+ {
+ SetCurrentValue(TextProperty, GetDisplayText());
+
+ if (ShowAsDateTime)
+ StopTimer();
+ else
+ StartTimer();
+ }
+ else if (change.Property == DateTimeFormatProperty)
+ {
+ if (ShowAsDateTime)
+ SetCurrentValue(TextProperty, GetDisplayText());
+ }
+ }
+
+ protected override void OnLoaded(RoutedEventArgs e)
+ {
+ base.OnLoaded(e);
+
+ if (!ShowAsDateTime)
+ StartTimer();
+ }
+
+ protected override void OnUnloaded(RoutedEventArgs e)
+ {
+ base.OnUnloaded(e);
+ StopTimer();
+ }
+
+ protected override void OnDataContextChanged(EventArgs e)
+ {
+ base.OnDataContextChanged(e);
+ SetCurrentValue(TextProperty, GetDisplayText());
+ }
+
+ private void StartTimer()
+ {
+ if (_refreshTimer != null)
+ return;
+
+ _refreshTimer = DispatcherTimer.Run(() =>
+ {
+ Dispatcher.UIThread.Invoke(() =>
+ {
+ var text = GetDisplayText();
+ if (!text.Equals(Text, StringComparison.Ordinal))
+ Text = text;
+ });
+
+ return true;
+ }, TimeSpan.FromSeconds(10));
+ }
+
+ private void StopTimer()
+ {
+ if (_refreshTimer != null)
+ {
+ _refreshTimer.Dispose();
+ _refreshTimer = null;
+ }
+ }
+
+ private string GetDisplayText()
+ {
+ var commit = DataContext as Models.Commit;
+ if (commit == null)
+ return string.Empty;
+
+ if (ShowAsDateTime)
+ return UseAuthorTime ? commit.AuthorTimeStr : commit.CommitterTimeStr;
+
+ var timestamp = UseAuthorTime ? commit.AuthorTime : commit.CommitterTime;
+ var now = DateTime.Now;
+ var localTime = DateTime.UnixEpoch.AddSeconds(timestamp).ToLocalTime();
+ var span = now - localTime;
+ if (span.TotalMinutes < 1)
+ return App.Text("Period.JustNow");
+
+ if (span.TotalHours < 1)
+ return App.Text("Period.MinutesAgo", (int)span.TotalMinutes);
+
+ if (span.TotalDays < 1)
+ {
+ var hours = (int)span.TotalHours;
+ return hours == 1 ? App.Text("Period.HourAgo") : App.Text("Period.HoursAgo", hours);
+ }
+
+ var lastDay = now.AddDays(-1).Date;
+ if (localTime >= lastDay)
+ return App.Text("Period.Yesterday");
+
+ if ((localTime.Year == now.Year && localTime.Month == now.Month) || span.TotalDays < 28)
+ {
+ var diffDay = now.Date - localTime.Date;
+ return App.Text("Period.DaysAgo", (int)diffDay.TotalDays);
+ }
+
+ var lastMonth = now.AddMonths(-1).Date;
+ if (localTime.Year == lastMonth.Year && localTime.Month == lastMonth.Month)
+ return App.Text("Period.LastMonth");
+
+ if (localTime.Year == now.Year || localTime > now.AddMonths(-11))
+ {
+ var diffMonth = (12 + now.Month - localTime.Month) % 12;
+ return App.Text("Period.MonthsAgo", diffMonth);
+ }
+
+ var diffYear = now.Year - localTime.Year;
+ if (diffYear == 1)
+ return App.Text("Period.LastYear");
+
+ return App.Text("Period.YearsAgo", diffYear);
+ }
+
+ private IDisposable _refreshTimer = null;
+ }
+}
diff --git a/src/Views/ConfigureWorkspace.axaml b/src/Views/ConfigureWorkspace.axaml
index 9c18ad04..79eab390 100644
--- a/src/Views/ConfigureWorkspace.axaml
+++ b/src/Views/ConfigureWorkspace.axaml
@@ -66,11 +66,11 @@
-
diff --git a/src/Views/ConfigureWorkspace.axaml.cs b/src/Views/ConfigureWorkspace.axaml.cs
index e2cc1cb2..9e458f6f 100644
--- a/src/Views/ConfigureWorkspace.axaml.cs
+++ b/src/Views/ConfigureWorkspace.axaml.cs
@@ -11,8 +11,10 @@ namespace SourceGit.Views
protected override void OnClosing(WindowClosingEventArgs e)
{
- ViewModels.Preference.Instance.Save();
base.OnClosing(e);
+
+ if (!Design.IsDesignMode)
+ ViewModels.Preferences.Instance.Save();
}
}
}
diff --git a/src/Views/ConfirmCommitWithoutFiles.axaml b/src/Views/ConfirmCommit.axaml
similarity index 92%
rename from src/Views/ConfirmCommitWithoutFiles.axaml
rename to src/Views/ConfirmCommit.axaml
index a056f016..a835f0b6 100644
--- a/src/Views/ConfirmCommitWithoutFiles.axaml
+++ b/src/Views/ConfirmCommit.axaml
@@ -5,8 +5,8 @@
xmlns:v="using:SourceGit.Views"
xmlns:vm="using:SourceGit.ViewModels"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
- x:Class="SourceGit.Views.ConfirmCommitWithoutFiles"
- x:DataType="vm:ConfirmCommitWithoutFiles"
+ x:Class="SourceGit.Views.ConfirmCommit"
+ x:DataType="vm:ConfirmCommit"
x:Name="ThisControl"
Icon="/App.ico"
Title="{DynamicResource Text.Warn}"
@@ -38,7 +38,7 @@
-
+
@@ -52,7 +52,7 @@
HorizontalAlignment="Center"
HorizontalContentAlignment="Center"
VerticalContentAlignment="Center"/>
-
+
@@ -63,31 +56,33 @@
Text="{Binding Name, Mode=TwoWay}"
Watermark="{DynamicResource Text.CreateBranch.Name.Placeholder}"
v:AutoFocusBehaviour.IsEnabled="True"/>
+
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+ IsChecked="{Binding CheckoutAfterCreated, Mode=TwoWay}"
+ IsVisible="{Binding !IsBareRepository}"/>
diff --git a/src/Views/CreateBranch.axaml.cs b/src/Views/CreateBranch.axaml.cs
index 6499e1c7..6626871b 100644
--- a/src/Views/CreateBranch.axaml.cs
+++ b/src/Views/CreateBranch.axaml.cs
@@ -1,5 +1,4 @@
using Avalonia.Controls;
-using Avalonia.Interactivity;
namespace SourceGit.Views
{
@@ -9,51 +8,5 @@ namespace SourceGit.Views
{
InitializeComponent();
}
-
- protected override void OnLoaded(RoutedEventArgs e)
- {
- base.OnLoaded(e);
-
- var vm = DataContext as ViewModels.CreateBranch;
- if (vm == null)
- return;
-
- switch (vm.PreAction)
- {
- case Models.DealWithLocalChanges.DoNothing:
- RadioDoNothing.IsChecked = true;
- break;
- case Models.DealWithLocalChanges.StashAndReaply:
- RadioStashAndReply.IsChecked = true;
- break;
- default:
- RadioDiscard.IsChecked = true;
- break;
- }
- }
-
- private void OnLocalChangeActionIsCheckedChanged(object sender, RoutedEventArgs e)
- {
- var vm = DataContext as ViewModels.CreateBranch;
- if (vm == null)
- return;
-
- if (RadioDoNothing.IsChecked == true)
- {
- if (vm.PreAction != Models.DealWithLocalChanges.DoNothing)
- vm.PreAction = Models.DealWithLocalChanges.DoNothing;
- return;
- }
-
- if (RadioStashAndReply.IsChecked == true)
- {
- if (vm.PreAction != Models.DealWithLocalChanges.StashAndReaply)
- vm.PreAction = Models.DealWithLocalChanges.StashAndReaply;
- return;
- }
-
- if (vm.PreAction != Models.DealWithLocalChanges.Discard)
- vm.PreAction = Models.DealWithLocalChanges.Discard;
- }
}
}
diff --git a/src/Views/CreateTag.axaml b/src/Views/CreateTag.axaml
index 20b6798a..55b6052f 100644
--- a/src/Views/CreateTag.axaml
+++ b/src/Views/CreateTag.axaml
@@ -84,7 +84,7 @@
+ IsChecked="{Binding PushToRemotes, Mode=TwoWay}"/>
diff --git a/src/Views/DeleteBranch.axaml b/src/Views/DeleteBranch.axaml
index 05ec6e26..9239e47b 100644
--- a/src/Views/DeleteBranch.axaml
+++ b/src/Views/DeleteBranch.axaml
@@ -10,7 +10,7 @@
-
+
diff --git a/src/Views/DeleteRepositoryNode.axaml b/src/Views/DeleteRepositoryNode.axaml
index f4e041e5..5442dd19 100644
--- a/src/Views/DeleteRepositoryNode.axaml
+++ b/src/Views/DeleteRepositoryNode.axaml
@@ -17,12 +17,12 @@
Text="{DynamicResource Text.DeleteRepositoryNode.TitleForRepository}"
IsVisible="{Binding Node.IsRepository}"/>
-
-
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Views/DeleteTag.axaml b/src/Views/DeleteTag.axaml
index 702a7f2a..c5b4f507 100644
--- a/src/Views/DeleteTag.axaml
+++ b/src/Views/DeleteTag.axaml
@@ -23,7 +23,7 @@
-
+ IsChecked="{Binding PushToRemotes, Mode=TwoWay}"/>
+
diff --git a/src/Views/DiffView.axaml b/src/Views/DiffView.axaml
index 550265ab..c4da158d 100644
--- a/src/Views/DiffView.axaml
+++ b/src/Views/DiffView.axaml
@@ -30,10 +30,23 @@
-
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
-
+
@@ -60,44 +73,57 @@
ToolTip.Tip="{DynamicResource Text.Diff.Next}">
-
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
-
-
+
-
+
@@ -106,7 +132,7 @@
@@ -114,28 +140,29 @@
-
+
-
+
@@ -143,7 +170,7 @@
@@ -230,7 +257,7 @@
-
+
@@ -244,7 +271,7 @@
-
+
@@ -258,10 +285,9 @@
-
+
diff --git a/src/Views/DiffView.axaml.cs b/src/Views/DiffView.axaml.cs
index d9157a03..9dd27f24 100644
--- a/src/Views/DiffView.axaml.cs
+++ b/src/Views/DiffView.axaml.cs
@@ -11,18 +11,34 @@ namespace SourceGit.Views
InitializeComponent();
}
+ private void OnGotoFirstChange(object _, RoutedEventArgs e)
+ {
+ this.FindDescendantOfType()?.GotoFirstChange();
+ e.Handled = true;
+ }
+
private void OnGotoPrevChange(object _, RoutedEventArgs e)
{
- var textDiff = this.FindDescendantOfType();
- textDiff?.GotoPrevChange();
+ this.FindDescendantOfType()?.GotoPrevChange();
e.Handled = true;
}
private void OnGotoNextChange(object _, RoutedEventArgs e)
{
- var textDiff = this.FindDescendantOfType();
- textDiff?.GotoNextChange();
+ this.FindDescendantOfType()?.GotoNextChange();
e.Handled = true;
}
+
+ private void OnGotoLastChange(object _, RoutedEventArgs e)
+ {
+ this.FindDescendantOfType()?.GotoLastChange();
+ e.Handled = true;
+ }
+
+ private void OnBlockNavigationChanged(object sender, RoutedEventArgs e)
+ {
+ if (sender is TextDiffView textDiff)
+ BlockNavigationIndicator.Text = textDiff.BlockNavigation?.Indicator ?? string.Empty;
+ }
}
}
diff --git a/src/Views/Discard.axaml b/src/Views/Discard.axaml
index 23162060..1699b051 100644
--- a/src/Views/Discard.axaml
+++ b/src/Views/Discard.axaml
@@ -11,16 +11,16 @@
-
+
-
-
+
@@ -31,13 +31,13 @@
Text="{DynamicResource Text.Discard.Changes}"/>
-
+
-
+
-
+
-
diff --git a/src/Views/EditRepositoryNode.axaml b/src/Views/EditRepositoryNode.axaml
index ac8f50f3..615e3f11 100644
--- a/src/Views/EditRepositoryNode.axaml
+++ b/src/Views/EditRepositoryNode.axaml
@@ -43,7 +43,7 @@
Fill="{Binding Converter={x:Static c:IntConverters.ToBookmarkBrush}}"
HorizontalAlignment="Center" VerticalAlignment="Center"
Data="{StaticResource Icons.Bookmark}"/>
-
+
diff --git a/src/Views/EnhancedSelectableTextBlock.cs b/src/Views/EnhancedSelectableTextBlock.cs
new file mode 100644
index 00000000..183b7021
--- /dev/null
+++ b/src/Views/EnhancedSelectableTextBlock.cs
@@ -0,0 +1,20 @@
+using System;
+
+using Avalonia;
+using Avalonia.Controls;
+
+namespace SourceGit.Views
+{
+ public class EnhancedSelectableTextBlock : SelectableTextBlock
+ {
+ protected override Type StyleKeyOverride => typeof(SelectableTextBlock);
+
+ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
+ {
+ base.OnPropertyChanged(change);
+
+ if (change.Property == TextProperty)
+ UpdateLayout();
+ }
+ }
+}
diff --git a/src/Views/FileHistories.axaml b/src/Views/FileHistories.axaml
index b0706d24..e33156fb 100644
--- a/src/Views/FileHistories.axaml
+++ b/src/Views/FileHistories.axaml
@@ -37,7 +37,7 @@
Text="{DynamicResource Text.FileHistory}"
HorizontalAlignment="Center" VerticalAlignment="Center"
IsHitTestVisible="False"/>
-
+
@@ -56,8 +56,8 @@
Margin="8,4,4,8"
BorderBrush="{DynamicResource Brush.Border2}"
ItemsSource="{Binding Commits}"
- SelectedItem="{Binding SelectedCommit, Mode=TwoWay}"
- SelectionMode="Single"
+ SelectedItems="{Binding SelectedCommits, Mode=TwoWay}"
+ SelectionMode="Multiple"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollBarVisibility="Auto">
@@ -107,65 +107,134 @@
BorderThickness="1,0,0,0"
BorderBrush="{DynamicResource Brush.Border0}"/>
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
diff --git a/src/Views/FileHistories.axaml.cs b/src/Views/FileHistories.axaml.cs
index 9d74892b..be5affc3 100644
--- a/src/Views/FileHistories.axaml.cs
+++ b/src/Views/FileHistories.axaml.cs
@@ -1,6 +1,7 @@
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Interactivity;
+using Avalonia.Platform.Storage;
namespace SourceGit.Views
{
@@ -22,11 +23,11 @@ namespace SourceGit.Views
e.Handled = true;
}
- private void OnResetToSelectedRevision(object _, RoutedEventArgs e)
+ private void OnResetToSelectedRevision(object sender, RoutedEventArgs e)
{
- if (DataContext is ViewModels.FileHistories vm)
+ if (sender is Button { DataContext: ViewModels.FileHistoriesSingleRevision single })
{
- vm.ResetToSelectedRevision();
+ single.ResetToSelectedRevision();
NotifyDonePanel.IsVisible = true;
}
@@ -38,5 +39,23 @@ namespace SourceGit.Views
NotifyDonePanel.IsVisible = false;
e.Handled = true;
}
+
+ private async void OnSaveAsPatch(object sender, RoutedEventArgs e)
+ {
+ if (sender is Button { DataContext: ViewModels.FileHistoriesCompareRevisions compare })
+ {
+ var options = new FilePickerSaveOptions();
+ options.Title = App.Text("FileCM.SaveAsPatch");
+ options.DefaultExtension = ".patch";
+ options.FileTypeChoices = [new FilePickerFileType("Patch File") { Patterns = ["*.patch"] }];
+
+ var storageFile = await this.StorageProvider.SaveFilePickerAsync(options);
+ if (storageFile != null)
+ await compare.SaveAsPatch(storageFile.Path.LocalPath);
+
+ NotifyDonePanel.IsVisible = true;
+ e.Handled = true;
+ }
+ }
}
}
diff --git a/src/Views/FilterModeSwitchButton.axaml b/src/Views/FilterModeSwitchButton.axaml
index 0fbbbf8e..b202c434 100644
--- a/src/Views/FilterModeSwitchButton.axaml
+++ b/src/Views/FilterModeSwitchButton.axaml
@@ -5,7 +5,7 @@
xmlns:m="using:SourceGit.Models"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="SourceGit.Views.FilterModeSwitchButton"
- x:Name="ThisControl">
+ x:Name="ThisControl">
-
-
+
+
-
+
-
+
-
-
+
+
-
+
-
-
+
+
@@ -51,11 +51,11 @@
+ IsVisible="{Binding Source={x:Static vm:Preferences.Instance}, Path=ShowAuthorTimeInGraph, Converter={x:Static BoolConverters.Not}, Mode=OneWay}"/>
+ IsVisible="{Binding Source={x:Static vm:Preferences.Instance}, Path=ShowAuthorTimeInGraph, Mode=OneWay}"/>
@@ -121,14 +121,18 @@
-
-
+
+
-
+
-
@@ -159,7 +163,10 @@
-
+
-
-
+
+ UseAuthorTime="{Binding Source={x:Static vm:Preferences.Instance}, Path=ShowAuthorTimeInGraph, Mode=OneWay}"
+ ShowAsDateTime="{Binding Source={x:Static vm:Preferences.Instance}, Path=!DisplayTimeAsPeriodInHistories}"
+ DateTimeFormat="{Binding Source={x:Static vm:Preferences.Instance}, Path=DateTimeFormat}"/>
@@ -211,7 +218,7 @@
ClipToBounds="True"/>
-
+
@@ -221,7 +228,7 @@
HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
Background="{DynamicResource Brush.Window}"
BorderBrush="{DynamicResource Brush.Border0}"/>
-
+
-
+
@@ -264,5 +271,5 @@
-
+
diff --git a/src/Views/Histories.axaml.cs b/src/Views/Histories.axaml.cs
index 8b5142ad..84cfda2f 100644
--- a/src/Views/Histories.axaml.cs
+++ b/src/Views/Histories.axaml.cs
@@ -1,24 +1,18 @@
using System;
-using System.Collections.Generic;
using System.Text;
-using System.Text.RegularExpressions;
using Avalonia;
using Avalonia.Collections;
using Avalonia.Controls;
-using Avalonia.Controls.Documents;
using Avalonia.Input;
-using Avalonia.Interactivity;
-using Avalonia.Media;
-using Avalonia.Threading;
using Avalonia.VisualTree;
namespace SourceGit.Views
{
- public class LayoutableGrid : Grid
+ public class HistoriesLayout : Grid
{
public static readonly StyledProperty UseHorizontalProperty =
- AvaloniaProperty.Register(nameof(UseHorizontal));
+ AvaloniaProperty.Register(nameof(UseHorizontal), false);
public bool UseHorizontal
{
@@ -28,14 +22,17 @@ namespace SourceGit.Views
protected override Type StyleKeyOverride => typeof(Grid);
- static LayoutableGrid()
+ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
- UseHorizontalProperty.Changed.AddClassHandler((o, _) => o.RefreshLayout());
+ base.OnPropertyChanged(change);
+
+ if (change.Property == UseHorizontalProperty && IsLoaded)
+ RefreshLayout();
}
- public override void ApplyTemplate()
+ protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
{
- base.ApplyTemplate();
+ base.OnAttachedToVisualTree(e);
RefreshLayout();
}
@@ -74,639 +71,6 @@ namespace SourceGit.Views
}
}
- public class CommitStatusIndicator : Control
- {
- public static readonly StyledProperty CurrentBranchProperty =
- AvaloniaProperty.Register(nameof(CurrentBranch));
-
- public Models.Branch CurrentBranch
- {
- get => GetValue(CurrentBranchProperty);
- set => SetValue(CurrentBranchProperty, value);
- }
-
- public static readonly StyledProperty AheadBrushProperty =
- AvaloniaProperty.Register(nameof(AheadBrush));
-
- public IBrush AheadBrush
- {
- get => GetValue(AheadBrushProperty);
- set => SetValue(AheadBrushProperty, value);
- }
-
- public static readonly StyledProperty BehindBrushProperty =
- AvaloniaProperty.Register(nameof(BehindBrush));
-
- public IBrush BehindBrush
- {
- get => GetValue(BehindBrushProperty);
- set => SetValue(BehindBrushProperty, value);
- }
-
- enum Status
- {
- Normal,
- Ahead,
- Behind,
- }
-
- public override void Render(DrawingContext context)
- {
- if (_status == Status.Normal)
- return;
-
- context.DrawEllipse(_status == Status.Ahead ? AheadBrush : BehindBrush, null, new Rect(0, 0, 5, 5));
- }
-
- protected override Size MeasureOverride(Size availableSize)
- {
- if (DataContext is Models.Commit commit && CurrentBranch is not null)
- {
- var sha = commit.SHA;
- var track = CurrentBranch.TrackStatus;
-
- if (track.Ahead.Contains(sha))
- _status = Status.Ahead;
- else if (track.Behind.Contains(sha))
- _status = Status.Behind;
- else
- _status = Status.Normal;
- }
- else
- {
- _status = Status.Normal;
- }
-
- return _status == Status.Normal ? new Size(0, 0) : new Size(9, 5);
- }
-
- protected override void OnDataContextChanged(EventArgs e)
- {
- base.OnDataContextChanged(e);
- InvalidateMeasure();
- }
-
- protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
- {
- base.OnPropertyChanged(change);
- if (change.Property == CurrentBranchProperty)
- InvalidateMeasure();
- }
-
- private Status _status = Status.Normal;
- }
-
- public partial class CommitSubjectPresenter : TextBlock
- {
- public static readonly StyledProperty SubjectProperty =
- AvaloniaProperty.Register(nameof(Subject));
-
- public string Subject
- {
- get => GetValue(SubjectProperty);
- set => SetValue(SubjectProperty, value);
- }
-
- public static readonly StyledProperty> IssueTrackerRulesProperty =
- AvaloniaProperty.Register>(nameof(IssueTrackerRules));
-
- public AvaloniaList IssueTrackerRules
- {
- get => GetValue(IssueTrackerRulesProperty);
- set => SetValue(IssueTrackerRulesProperty, value);
- }
-
- protected override Type StyleKeyOverride => typeof(TextBlock);
-
- protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
- {
- base.OnPropertyChanged(change);
-
- if (change.Property == SubjectProperty || change.Property == IssueTrackerRulesProperty)
- {
- Inlines!.Clear();
- _matches = null;
- ClearHoveredIssueLink();
-
- var subject = Subject;
- if (string.IsNullOrEmpty(subject))
- return;
-
- var keywordMatch = REG_KEYWORD_FORMAT1().Match(subject);
- if (!keywordMatch.Success)
- keywordMatch = REG_KEYWORD_FORMAT2().Match(subject);
-
- var rules = IssueTrackerRules ?? [];
- var matches = new List();
- foreach (var rule in rules)
- rule.Matches(matches, subject);
-
- if (matches.Count == 0)
- {
- if (keywordMatch.Success)
- {
- Inlines.Add(new Run(subject.Substring(0, keywordMatch.Length)) { FontWeight = FontWeight.Bold });
- Inlines.Add(new Run(subject.Substring(keywordMatch.Length)));
- }
- else
- {
- Inlines.Add(new Run(subject));
- }
- return;
- }
-
- matches.Sort((l, r) => l.Start - r.Start);
- _matches = matches;
-
- var inlines = new List();
- var pos = 0;
- foreach (var match in matches)
- {
- if (match.Start > pos)
- {
- if (keywordMatch.Success && pos < keywordMatch.Length)
- {
- if (keywordMatch.Length < match.Start)
- {
- inlines.Add(new Run(subject.Substring(pos, keywordMatch.Length - pos)) { FontWeight = FontWeight.Bold });
- inlines.Add(new Run(subject.Substring(keywordMatch.Length, match.Start - keywordMatch.Length)));
- }
- else
- {
- inlines.Add(new Run(subject.Substring(pos, match.Start - pos)) { FontWeight = FontWeight.Bold });
- }
- }
- else
- {
- inlines.Add(new Run(subject.Substring(pos, match.Start - pos)));
- }
- }
-
- var link = new Run(subject.Substring(match.Start, match.Length));
- link.Classes.Add("issue_link");
- inlines.Add(link);
-
- pos = match.Start + match.Length;
- }
-
- if (pos < subject.Length)
- {
- if (keywordMatch.Success && pos < keywordMatch.Length)
- {
- inlines.Add(new Run(subject.Substring(pos, keywordMatch.Length - pos)) { FontWeight = FontWeight.Bold });
- inlines.Add(new Run(subject.Substring(keywordMatch.Length)));
- }
- else
- {
- inlines.Add(new Run(subject.Substring(pos)));
- }
- }
-
- Inlines.AddRange(inlines);
- }
- }
-
- protected override void OnPointerMoved(PointerEventArgs e)
- {
- base.OnPointerMoved(e);
-
- if (_matches != null)
- {
- var point = e.GetPosition(this) - new Point(Padding.Left, Padding.Top);
- var x = Math.Min(Math.Max(point.X, 0), Math.Max(TextLayout.WidthIncludingTrailingWhitespace, 0));
- var y = Math.Min(Math.Max(point.Y, 0), Math.Max(TextLayout.Height, 0));
- point = new Point(x, y);
-
- var textPosition = TextLayout.HitTestPoint(point).TextPosition;
- foreach (var match in _matches)
- {
- if (!match.Intersect(textPosition, 1))
- continue;
-
- if (match == _lastHover)
- return;
-
- _lastHover = match;
- SetCurrentValue(CursorProperty, Cursor.Parse("Hand"));
- ToolTip.SetTip(this, match.Link);
- ToolTip.SetIsOpen(this, true);
- e.Handled = true;
- return;
- }
-
- ClearHoveredIssueLink();
- }
- }
-
- protected override void OnPointerPressed(PointerPressedEventArgs e)
- {
- base.OnPointerPressed(e);
-
- if (_lastHover != null)
- Native.OS.OpenBrowser(_lastHover.Link);
- }
-
- protected override void OnPointerExited(PointerEventArgs e)
- {
- base.OnPointerExited(e);
- ClearHoveredIssueLink();
- }
-
- private void ClearHoveredIssueLink()
- {
- if (_lastHover != null)
- {
- ToolTip.SetTip(this, null);
- SetCurrentValue(CursorProperty, Cursor.Parse("Arrow"));
- _lastHover = null;
- }
- }
-
- [GeneratedRegex(@"^\[[\w\s]+\]")]
- private static partial Regex REG_KEYWORD_FORMAT1();
-
- [GeneratedRegex(@"^\S+([\<\(][\w\s_\-\*,]+[\>\)])?\!?\s?:\s")]
- private static partial Regex REG_KEYWORD_FORMAT2();
-
- private List _matches = null;
- private Models.Hyperlink _lastHover = null;
- }
-
- public class CommitTimeTextBlock : TextBlock
- {
- public static readonly StyledProperty ShowAsDateTimeProperty =
- AvaloniaProperty.Register(nameof(ShowAsDateTime), true);
-
- public bool ShowAsDateTime
- {
- get => GetValue(ShowAsDateTimeProperty);
- set => SetValue(ShowAsDateTimeProperty, value);
- }
-
- public static readonly StyledProperty DateTimeFormatProperty =
- AvaloniaProperty.Register(nameof(DateTimeFormat), 0);
-
- public int DateTimeFormat
- {
- get => GetValue(DateTimeFormatProperty);
- set => SetValue(DateTimeFormatProperty, value);
- }
-
- public static readonly StyledProperty UseAuthorTimeProperty =
- AvaloniaProperty.Register(nameof(UseAuthorTime), true);
-
- public bool UseAuthorTime
- {
- get => GetValue(UseAuthorTimeProperty);
- set => SetValue(UseAuthorTimeProperty, value);
- }
-
- protected override Type StyleKeyOverride => typeof(TextBlock);
-
- protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
- {
- base.OnPropertyChanged(change);
-
- if (change.Property == UseAuthorTimeProperty)
- {
- SetCurrentValue(TextProperty, GetDisplayText());
- }
- else if (change.Property == ShowAsDateTimeProperty)
- {
- SetCurrentValue(TextProperty, GetDisplayText());
-
- if (ShowAsDateTime)
- StopTimer();
- else
- StartTimer();
- }
- else if (change.Property == DateTimeFormatProperty)
- {
- if (ShowAsDateTime)
- SetCurrentValue(TextProperty, GetDisplayText());
- }
- }
-
- protected override void OnLoaded(RoutedEventArgs e)
- {
- base.OnLoaded(e);
-
- if (!ShowAsDateTime)
- StartTimer();
- }
-
- protected override void OnUnloaded(RoutedEventArgs e)
- {
- base.OnUnloaded(e);
- StopTimer();
- }
-
- protected override void OnDataContextChanged(EventArgs e)
- {
- base.OnDataContextChanged(e);
- SetCurrentValue(TextProperty, GetDisplayText());
- }
-
- private void StartTimer()
- {
- if (_refreshTimer != null)
- return;
-
- _refreshTimer = DispatcherTimer.Run(() =>
- {
- Dispatcher.UIThread.Invoke(() =>
- {
- var text = GetDisplayText();
- if (!text.Equals(Text, StringComparison.Ordinal))
- Text = text;
- });
-
- return true;
- }, TimeSpan.FromSeconds(10));
- }
-
- private void StopTimer()
- {
- if (_refreshTimer != null)
- {
- _refreshTimer.Dispose();
- _refreshTimer = null;
- }
- }
-
- private string GetDisplayText()
- {
- var commit = DataContext as Models.Commit;
- if (commit == null)
- return string.Empty;
-
- if (ShowAsDateTime)
- return UseAuthorTime ? commit.AuthorTimeStr : commit.CommitterTimeStr;
-
- var timestamp = UseAuthorTime ? commit.AuthorTime : commit.CommitterTime;
- var now = DateTime.Now;
- var localTime = DateTime.UnixEpoch.AddSeconds(timestamp).ToLocalTime();
- var span = now - localTime;
- if (span.TotalMinutes < 1)
- return App.Text("Period.JustNow");
-
- if (span.TotalHours < 1)
- return App.Text("Period.MinutesAgo", (int)span.TotalMinutes);
-
- if (span.TotalDays < 1)
- return App.Text("Period.HoursAgo", (int)span.TotalHours);
-
- var lastDay = now.AddDays(-1).Date;
- if (localTime >= lastDay)
- return App.Text("Period.Yesterday");
-
- if ((localTime.Year == now.Year && localTime.Month == now.Month) || span.TotalDays < 28)
- {
- var diffDay = now.Date - localTime.Date;
- return App.Text("Period.DaysAgo", (int)diffDay.TotalDays);
- }
-
- var lastMonth = now.AddMonths(-1).Date;
- if (localTime.Year == lastMonth.Year && localTime.Month == lastMonth.Month)
- return App.Text("Period.LastMonth");
-
- if (localTime.Year == now.Year || localTime > now.AddMonths(-11))
- {
- var diffMonth = (12 + now.Month - localTime.Month) % 12;
- return App.Text("Period.MonthsAgo", diffMonth);
- }
-
- var diffYear = now.Year - localTime.Year;
- if (diffYear == 1)
- return App.Text("Period.LastYear");
-
- return App.Text("Period.YearsAgo", diffYear);
- }
-
- private IDisposable _refreshTimer = null;
- }
-
- public class CommitGraph : Control
- {
- public static readonly StyledProperty GraphProperty =
- AvaloniaProperty.Register(nameof(Graph));
-
- public Models.CommitGraph Graph
- {
- get => GetValue(GraphProperty);
- set => SetValue(GraphProperty, value);
- }
-
- public static readonly StyledProperty DotBrushProperty =
- AvaloniaProperty.Register(nameof(DotBrush), Brushes.Transparent);
-
- public IBrush DotBrush
- {
- get => GetValue(DotBrushProperty);
- set => SetValue(DotBrushProperty, value);
- }
-
- public static readonly StyledProperty OnlyHighlightCurrentBranchProperty =
- AvaloniaProperty.Register(nameof(OnlyHighlightCurrentBranch), true);
-
- public bool OnlyHighlightCurrentBranch
- {
- get => GetValue(OnlyHighlightCurrentBranchProperty);
- set => SetValue(OnlyHighlightCurrentBranchProperty, value);
- }
-
- static CommitGraph()
- {
- AffectsRender(GraphProperty, DotBrushProperty, OnlyHighlightCurrentBranchProperty);
- }
-
- public override void Render(DrawingContext context)
- {
- base.Render(context);
-
- var graph = Graph;
- if (graph == null)
- return;
-
- var histories = this.FindAncestorOfType();
- if (histories == null)
- return;
-
- var list = histories.CommitListContainer;
- if (list == null)
- return;
-
- // Calculate drawing area.
- double width = Bounds.Width - 273 - histories.AuthorNameColumnWidth.Value;
- double height = Bounds.Height;
- double startY = list.Scroll?.Offset.Y ?? 0;
- double endY = startY + height + 28;
-
- // Apply scroll offset and clip.
- using (context.PushClip(new Rect(0, 0, width, height)))
- using (context.PushTransform(Matrix.CreateTranslation(0, -startY)))
- {
- // Draw contents
- DrawCurves(context, graph, startY, endY);
- DrawAnchors(context, graph, startY, endY);
- }
- }
-
- private void DrawCurves(DrawingContext context, Models.CommitGraph graph, double top, double bottom)
- {
- var grayedPen = new Pen(new SolidColorBrush(Colors.Gray, 0.4), Models.CommitGraph.Pens[0].Thickness);
- var onlyHighlightCurrentBranch = OnlyHighlightCurrentBranch;
-
- if (onlyHighlightCurrentBranch)
- {
- foreach (var link in graph.Links)
- {
- if (link.IsMerged)
- continue;
- if (link.End.Y < top)
- continue;
- if (link.Start.Y > bottom)
- break;
-
- var geo = new StreamGeometry();
- using (var ctx = geo.Open())
- {
- ctx.BeginFigure(link.Start, false);
- ctx.QuadraticBezierTo(link.Control, link.End);
- }
-
- context.DrawGeometry(null, grayedPen, geo);
- }
- }
-
- foreach (var line in graph.Paths)
- {
- var last = line.Points[0];
- var size = line.Points.Count;
-
- if (line.Points[size - 1].Y < top)
- continue;
- if (last.Y > bottom)
- break;
-
- var geo = new StreamGeometry();
- var pen = Models.CommitGraph.Pens[line.Color];
-
- using (var ctx = geo.Open())
- {
- var started = false;
- var ended = false;
- for (int i = 1; i < size; i++)
- {
- var cur = line.Points[i];
- if (cur.Y < top)
- {
- last = cur;
- continue;
- }
-
- if (!started)
- {
- ctx.BeginFigure(last, false);
- started = true;
- }
-
- if (cur.Y > bottom)
- {
- cur = new Point(cur.X, bottom);
- ended = true;
- }
-
- if (cur.X > last.X)
- {
- ctx.QuadraticBezierTo(new Point(cur.X, last.Y), cur);
- }
- else if (cur.X < last.X)
- {
- if (i < size - 1)
- {
- var midY = (last.Y + cur.Y) / 2;
- ctx.CubicBezierTo(new Point(last.X, midY + 4), new Point(cur.X, midY - 4), cur);
- }
- else
- {
- ctx.QuadraticBezierTo(new Point(last.X, cur.Y), cur);
- }
- }
- else
- {
- ctx.LineTo(cur);
- }
-
- if (ended)
- break;
- last = cur;
- }
- }
-
- if (!line.IsMerged && onlyHighlightCurrentBranch)
- context.DrawGeometry(null, grayedPen, geo);
- else
- context.DrawGeometry(null, pen, geo);
- }
-
- foreach (var link in graph.Links)
- {
- if (onlyHighlightCurrentBranch && !link.IsMerged)
- continue;
- if (link.End.Y < top)
- continue;
- if (link.Start.Y > bottom)
- break;
-
- var geo = new StreamGeometry();
- using (var ctx = geo.Open())
- {
- ctx.BeginFigure(link.Start, false);
- ctx.QuadraticBezierTo(link.Control, link.End);
- }
-
- context.DrawGeometry(null, Models.CommitGraph.Pens[link.Color], geo);
- }
- }
-
- private void DrawAnchors(DrawingContext context, Models.CommitGraph graph, double top, double bottom)
- {
- var dotFill = DotBrush;
- var dotFillPen = new Pen(dotFill, 2);
- var grayedPen = new Pen(Brushes.Gray, Models.CommitGraph.Pens[0].Thickness);
- var onlyHighlightCurrentBranch = OnlyHighlightCurrentBranch;
-
- foreach (var dot in graph.Dots)
- {
- if (dot.Center.Y < top)
- continue;
- if (dot.Center.Y > bottom)
- break;
-
- var pen = Models.CommitGraph.Pens[dot.Color];
- if (!dot.IsMerged && onlyHighlightCurrentBranch)
- pen = grayedPen;
-
- switch (dot.Type)
- {
- case Models.CommitGraph.DotType.Head:
- context.DrawEllipse(dotFill, pen, dot.Center, 6, 6);
- context.DrawEllipse(pen.Brush, null, dot.Center, 3, 3);
- break;
- case Models.CommitGraph.DotType.Merge:
- context.DrawEllipse(pen.Brush, null, dot.Center, 6, 6);
- context.DrawLine(dotFillPen, new Point(dot.Center.X, dot.Center.Y - 3), new Point(dot.Center.X, dot.Center.Y + 3));
- context.DrawLine(dotFillPen, new Point(dot.Center.X - 3, dot.Center.Y), new Point(dot.Center.X + 3, dot.Center.Y));
- break;
- default:
- context.DrawEllipse(dotFill, pen, dot.Center, 3, 3);
- break;
- }
- }
- }
- }
-
public partial class Histories : UserControl
{
public static readonly StyledProperty AuthorNameColumnWidthProperty =
@@ -754,36 +118,34 @@ namespace SourceGit.Views
set => SetValue(NavigationIdProperty, value);
}
- static Histories()
- {
- NavigationIdProperty.Changed.AddClassHandler((h, _) =>
- {
- if (h.DataContext == null)
- return;
-
- // Force scroll selected item (current head) into view. see issue #58
- var list = h.CommitListContainer;
- if (list != null && list.SelectedItems.Count == 1)
- list.ScrollIntoView(list.SelectedIndex);
- });
-
- AuthorNameColumnWidthProperty.Changed.AddClassHandler((h, _) =>
- {
- h.CommitGraph.InvalidateVisual();
- });
- }
-
public Histories()
{
InitializeComponent();
}
+ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
+ {
+ base.OnPropertyChanged(change);
+
+ if (change.Property == NavigationIdProperty)
+ {
+ if (DataContext is ViewModels.Histories)
+ {
+ var list = CommitListContainer;
+ if (list != null && list.SelectedItems.Count == 1)
+ list.ScrollIntoView(list.SelectedIndex);
+ }
+ }
+ }
+
private void OnCommitListLayoutUpdated(object _1, EventArgs _2)
{
var y = CommitListContainer.Scroll?.Offset.Y ?? 0;
- if (y != _lastScrollY)
+ var authorNameColumnWidth = AuthorNameColumnWidth.Value;
+ if (y != _lastScrollY || authorNameColumnWidth != _lastAuthorNameColumnWidth)
{
_lastScrollY = y;
+ _lastAuthorNameColumnWidth = authorNameColumnWidth;
CommitGraph.InvalidateVisual();
}
}
@@ -863,5 +225,6 @@ namespace SourceGit.Views
}
private double _lastScrollY = 0;
+ private double _lastAuthorNameColumnWidth = 0;
}
}
diff --git a/src/Views/Hotkeys.axaml b/src/Views/Hotkeys.axaml
index 19f9dc78..58472daf 100644
--- a/src/Views/Hotkeys.axaml
+++ b/src/Views/Hotkeys.axaml
@@ -19,7 +19,7 @@
-
+
-
+
-
-
+
+
@@ -66,18 +66,21 @@
+
+
+
-
+
@@ -92,13 +95,13 @@
-
+
-
+
@@ -124,7 +127,7 @@
@@ -141,6 +144,6 @@
-
+
diff --git a/src/Views/ImageContainer.cs b/src/Views/ImageContainer.cs
index aecea0b2..b62746ed 100644
--- a/src/Views/ImageContainer.cs
+++ b/src/Views/ImageContainer.cs
@@ -92,6 +92,20 @@ namespace SourceGit.Views
return availableSize;
}
+
+ protected override Size ArrangeOverride(Size finalSize)
+ {
+ if (Image is { } image)
+ {
+ var imageSize = image.Size;
+ var scaleW = finalSize.Width / imageSize.Width;
+ var scaleH = finalSize.Height / imageSize.Height;
+ var scale = Math.Min(scaleW, scaleH);
+ return new Size(scale * imageSize.Width, scale * imageSize.Height);
+ }
+
+ return base.ArrangeOverride(finalSize);
+ }
}
public class ImageSwipeControl : ImageContainer
diff --git a/src/Views/ImageDiffView.axaml b/src/Views/ImageDiffView.axaml
index 18d8cef9..c3e0f772 100644
--- a/src/Views/ImageDiffView.axaml
+++ b/src/Views/ImageDiffView.axaml
@@ -40,7 +40,7 @@
-
+
@@ -67,7 +67,7 @@
-
+
@@ -86,13 +86,13 @@
-
+
+ RenderOptions.BitmapInterpolationMode="HighQuality"/>
@@ -103,7 +103,7 @@
-
+
@@ -135,7 +135,7 @@
-
+
-
+
-
+
@@ -59,31 +59,45 @@
SelectionMode="Single"
SelectedItem="{Binding SelectedItem, Mode=OneWayToSource}"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
- ScrollViewer.VerticalScrollBarVisibility="Auto">
-
+ ScrollViewer.VerticalScrollBarVisibility="Auto"
+ Grid.IsSharedSizeScope="True">
+
-
+
-
+
-
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
-
@@ -188,47 +202,45 @@
-
-
-
+
+
-
-
+
+
+
+
-
-
-
-
+
+
+
+
-
-
-
-
+
+
+
+
-
-
-
-
+
+
+
+
-
-
-
-
-
+
+
+
+
-
+
@@ -246,7 +258,7 @@
HorizontalAlignment="Center"
Fill="{DynamicResource Brush.FG2}"
IsVisible="{Binding SelectedItem, Converter={x:Static ObjectConverters.IsNull}}"/>
-
+
@@ -260,12 +272,12 @@
-
diff --git a/src/Views/LFSFetch.axaml b/src/Views/LFSFetch.axaml
index 12556b2f..83e55e22 100644
--- a/src/Views/LFSFetch.axaml
+++ b/src/Views/LFSFetch.axaml
@@ -31,8 +31,8 @@
-
-
diff --git a/src/Views/LFSLocks.axaml b/src/Views/LFSLocks.axaml
index ac495bf1..0b455be0 100644
--- a/src/Views/LFSLocks.axaml
+++ b/src/Views/LFSLocks.axaml
@@ -84,7 +84,7 @@
-
+
@@ -104,7 +104,7 @@
-
+
diff --git a/src/Views/LFSTrackCustomPattern.axaml b/src/Views/LFSTrackCustomPattern.axaml
index 36eaef65..f60304d5 100644
--- a/src/Views/LFSTrackCustomPattern.axaml
+++ b/src/Views/LFSTrackCustomPattern.axaml
@@ -11,7 +11,7 @@
-
+
+ WindowStartupLocation="CenterScreen">
@@ -35,7 +35,7 @@
-
@@ -75,20 +80,20 @@
-
-
+
-
+
-
+
diff --git a/src/Views/Launcher.axaml.cs b/src/Views/Launcher.axaml.cs
index 2345958c..9ccec78c 100644
--- a/src/Views/Launcher.axaml.cs
+++ b/src/Views/Launcher.axaml.cs
@@ -34,14 +34,14 @@ namespace SourceGit.Views
get
{
if (OperatingSystem.IsLinux())
- return !ViewModels.Preference.Instance.UseSystemWindowFrame;
+ return !ViewModels.Preferences.Instance.UseSystemWindowFrame;
return OperatingSystem.IsWindows();
}
}
public Launcher()
{
- var layout = ViewModels.Preference.Instance.Layout;
+ var layout = ViewModels.Preferences.Instance.Layout;
if (layout.LauncherWindowState != WindowState.Maximized)
{
Width = layout.LauncherWidth;
@@ -81,7 +81,7 @@ namespace SourceGit.Views
{
base.OnOpened(e);
- var state = ViewModels.Preference.Instance.Layout.LauncherWindowState;
+ var state = ViewModels.Preferences.Instance.Layout.LauncherWindowState;
if (state == WindowState.Maximized || state == WindowState.FullScreen)
WindowState = WindowState.Maximized;
}
@@ -99,7 +99,7 @@ namespace SourceGit.Views
if (OperatingSystem.IsMacOS())
HasLeftCaptionButton = state != WindowState.FullScreen;
- ViewModels.Preference.Instance.Layout.LauncherWindowState = state;
+ ViewModels.Preferences.Instance.Layout.LauncherWindowState = state;
}
}
@@ -112,14 +112,32 @@ namespace SourceGit.Views
// We should clear all unhandled key modifiers.
_unhandledModifiers = KeyModifiers.None;
- // Ctrl+Shift+P opens preference dialog (macOS use hotkeys in system menu bar)
- if (!OperatingSystem.IsMacOS() && e.KeyModifiers == (KeyModifiers.Control | KeyModifiers.Shift) && e.Key == Key.P)
+ // Check for AltGr (which is detected as Ctrl+Alt)
+ bool isAltGr = e.KeyModifiers.HasFlag(KeyModifiers.Control) &&
+ e.KeyModifiers.HasFlag(KeyModifiers.Alt);
+
+ // Skip hotkey processing if AltGr is pressed
+ if (isAltGr)
{
- App.OpenDialog(new Preference());
+ base.OnKeyDown(e);
+ return;
+ }
+
+ // Ctrl+Shift+P opens preference dialog (macOS use hotkeys in system menu bar)
+ if (!OperatingSystem.IsMacOS() && e is { KeyModifiers: (KeyModifiers.Control | KeyModifiers.Shift), Key: Key.P })
+ {
+ App.OpenDialog(new Preferences());
e.Handled = true;
return;
}
+ // Ctrl+Q quits the application (macOS use hotkeys in system menu bar)
+ if (!OperatingSystem.IsMacOS() && e.KeyModifiers == KeyModifiers.Control && e.Key == Key.Q)
+ {
+ App.Quit(0);
+ return;
+ }
+
if (e.KeyModifiers.HasFlag(OperatingSystem.IsMacOS() ? KeyModifiers.Meta : KeyModifiers.Control))
{
if (e.Key == Key.W)
@@ -236,13 +254,13 @@ namespace SourceGit.Views
{
_unhandledModifiers = e.KeyModifiers;
- if (!_unhandledModifiers.HasFlag(KeyModifiers.Alt) && (e.Key == Key.LeftAlt || e.Key == Key.RightAlt))
+ if (!_unhandledModifiers.HasFlag(KeyModifiers.Alt) && e.Key is Key.LeftAlt or Key.RightAlt)
_unhandledModifiers |= KeyModifiers.Alt;
- if (!_unhandledModifiers.HasFlag(KeyModifiers.Control) && (e.Key == Key.LeftCtrl || e.Key == Key.RightCtrl))
+ if (!_unhandledModifiers.HasFlag(KeyModifiers.Control) && e.Key is Key.LeftCtrl or Key.RightCtrl)
_unhandledModifiers |= KeyModifiers.Control;
- if (!_unhandledModifiers.HasFlag(KeyModifiers.Shift) && (e.Key == Key.LeftShift || e.Key == Key.RightShift))
+ if (!_unhandledModifiers.HasFlag(KeyModifiers.Shift) && e.Key is Key.LeftShift or Key.RightShift)
_unhandledModifiers |= KeyModifiers.Shift;
}
}
@@ -255,8 +273,10 @@ namespace SourceGit.Views
protected override void OnClosing(WindowClosingEventArgs e)
{
- (DataContext as ViewModels.Launcher)?.Quit(Width, Height);
base.OnClosing(e);
+
+ if (!Design.IsDesignMode && DataContext is ViewModels.Launcher launcher)
+ launcher.Quit(Width, Height);
}
private void OnOpenWorkspaceMenu(object sender, RoutedEventArgs e)
diff --git a/src/Views/LauncherPage.axaml b/src/Views/LauncherPage.axaml
index ee4c77eb..7ce450de 100644
--- a/src/Views/LauncherPage.axaml
+++ b/src/Views/LauncherPage.axaml
@@ -17,14 +17,14 @@
-
+
-
+
@@ -32,7 +32,7 @@
-
+
@@ -53,7 +53,7 @@
PointerPressed="OnMaskClicked"
IsVisible="{Binding Popup, Converter={x:Static ObjectConverters.IsNotNull}}"/>
-
+
+
+
+
+
+
+
+
+
-
+
@@ -122,7 +138,7 @@
-
+
diff --git a/src/Views/LauncherTabBar.axaml b/src/Views/LauncherTabBar.axaml
index 40a2efe6..73b48f58 100644
--- a/src/Views/LauncherTabBar.axaml
+++ b/src/Views/LauncherTabBar.axaml
@@ -4,11 +4,17 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="using:SourceGit.ViewModels"
xmlns:c="using:SourceGit.Converters"
+ xmlns:v="using:SourceGit.Views"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="SourceGit.Views.LauncherTabBar"
- x:DataType="vm:Launcher">
+ x:DataType="vm:Launcher"
+ x:Name="ThisControl">
-
+
@@ -48,8 +54,8 @@
-
-
+
+
+ Command="{Binding AddNewTab}"
+ IsVisible="{Binding !#ThisControl.IsScrollerVisible}">
@@ -112,8 +119,30 @@
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Views/LauncherTabBar.axaml.cs b/src/Views/LauncherTabBar.axaml.cs
index f8c9107c..12bca91f 100644
--- a/src/Views/LauncherTabBar.axaml.cs
+++ b/src/Views/LauncherTabBar.axaml.cs
@@ -10,6 +10,15 @@ namespace SourceGit.Views
{
public partial class LauncherTabBar : UserControl
{
+ public static readonly StyledProperty IsScrollerVisibleProperty =
+ AvaloniaProperty.Register(nameof(IsScrollerVisible));
+
+ public bool IsScrollerVisible
+ {
+ get => GetValue(IsScrollerVisibleProperty);
+ set => SetValue(IsScrollerVisibleProperty, value);
+ }
+
public LauncherTabBar()
{
InitializeComponent();
@@ -43,6 +52,9 @@ namespace SourceGit.Views
if (containerEndX < startX || containerEndX > endX)
continue;
+ if (IsScrollerVisible && i == count - 1)
+ break;
+
var separatorX = containerEndX - startX + LauncherTabsScroller.Bounds.X;
context.DrawLine(separatorPen, new Point(separatorX, separatorY), new Point(separatorX, separatorY + 20));
}
@@ -88,7 +100,7 @@ namespace SourceGit.Views
x = drawRightX - 6;
}
- if (drawRightX < LauncherTabsScroller.Bounds.Right)
+ if (drawRightX <= LauncherTabsScroller.Bounds.Right)
{
ctx.LineTo(new Point(x, y));
x = drawRightX;
@@ -140,19 +152,7 @@ namespace SourceGit.Views
private void OnTabsLayoutUpdated(object _1, EventArgs _2)
{
- if (LauncherTabsScroller.Extent.Width > LauncherTabsScroller.Viewport.Width)
- {
- LeftScrollIndicator.IsVisible = true;
- LeftScrollIndicator.IsEnabled = LauncherTabsScroller.Offset.X > 0;
- RightScrollIndicator.IsVisible = true;
- RightScrollIndicator.IsEnabled = LauncherTabsScroller.Offset.X < LauncherTabsScroller.Extent.Width - LauncherTabsScroller.Viewport.Width;
- }
- else
- {
- LeftScrollIndicator.IsVisible = false;
- RightScrollIndicator.IsVisible = false;
- }
-
+ SetCurrentValue(IsScrollerVisibleProperty, LauncherTabsScroller.Extent.Width > LauncherTabsScroller.Viewport.Width);
InvalidateVisual();
}
@@ -248,6 +248,15 @@ namespace SourceGit.Views
e.Handled = true;
}
+ private void OnGotoSelectedPage(object sender, LauncherTabSelectedEventArgs e)
+ {
+ if (DataContext is ViewModels.Launcher vm)
+ vm.ActivePage = e.Page;
+
+ PageSelector.Flyout?.Hide();
+ e.Handled = true;
+ }
+
private bool _pressedTab = false;
private Point _pressedTabPosition = new Point();
private bool _startDragTab = false;
diff --git a/src/Views/LauncherTabsSelector.axaml b/src/Views/LauncherTabsSelector.axaml
new file mode 100644
index 00000000..109a2ce7
--- /dev/null
+++ b/src/Views/LauncherTabsSelector.axaml
@@ -0,0 +1,107 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Views/LauncherTabsSelector.axaml.cs b/src/Views/LauncherTabsSelector.axaml.cs
new file mode 100644
index 00000000..61d7a966
--- /dev/null
+++ b/src/Views/LauncherTabsSelector.axaml.cs
@@ -0,0 +1,120 @@
+using System;
+
+using Avalonia;
+using Avalonia.Collections;
+using Avalonia.Controls;
+using Avalonia.Interactivity;
+
+namespace SourceGit.Views
+{
+ public class LauncherTabSelectedEventArgs : RoutedEventArgs
+ {
+ public ViewModels.LauncherPage Page { get; }
+
+ public LauncherTabSelectedEventArgs(ViewModels.LauncherPage page)
+ {
+ RoutedEvent = LauncherTabsSelector.PageSelectedEvent;
+ Page = page;
+ }
+ }
+
+ public partial class LauncherTabsSelector : UserControl
+ {
+ public static readonly StyledProperty> PagesProperty =
+ AvaloniaProperty.Register>(nameof(Pages));
+
+ public AvaloniaList Pages
+ {
+ get => GetValue(PagesProperty);
+ set => SetValue(PagesProperty, value);
+ }
+
+ public static readonly StyledProperty SearchFilterProperty =
+ AvaloniaProperty.Register(nameof(SearchFilter));
+
+ public string SearchFilter
+ {
+ get => GetValue(SearchFilterProperty);
+ set => SetValue(SearchFilterProperty, value);
+ }
+
+ public static readonly RoutedEvent PageSelectedEvent =
+ RoutedEvent.Register(nameof(PageSelected), RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
+
+ public event EventHandler PageSelected
+ {
+ add { AddHandler(PageSelectedEvent, value); }
+ remove { RemoveHandler(PageSelectedEvent, value); }
+ }
+
+ public AvaloniaList VisiblePages
+ {
+ get;
+ private set;
+ }
+
+ public LauncherTabsSelector()
+ {
+ VisiblePages = new AvaloniaList();
+ InitializeComponent();
+ }
+
+ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
+ {
+ base.OnPropertyChanged(change);
+
+ if (change.Property == PagesProperty || change.Property == SearchFilterProperty)
+ UpdateVisiblePages();
+ }
+
+ private void OnClearSearchFilter(object sender, RoutedEventArgs e)
+ {
+ SearchFilter = string.Empty;
+ }
+
+ private void OnPageSelectionChanged(object sender, SelectionChangedEventArgs e)
+ {
+ if (sender is ListBox { SelectedItem: ViewModels.LauncherPage page })
+ {
+ _isProcessingSelection = true;
+ RaiseEvent(new LauncherTabSelectedEventArgs(page));
+ _isProcessingSelection = false;
+ }
+
+ e.Handled = true;
+ }
+
+ private void UpdateVisiblePages()
+ {
+ if (_isProcessingSelection)
+ return;
+
+ VisiblePages.Clear();
+
+ if (Pages == null)
+ return;
+
+ var filter = SearchFilter?.Trim() ?? "";
+ if (string.IsNullOrEmpty(filter))
+ {
+ foreach (var p in Pages)
+ VisiblePages.Add(p);
+
+ return;
+ }
+
+ foreach (var page in Pages)
+ {
+ if (!page.Node.IsRepository)
+ continue;
+
+ if (page.Node.Name.Contains(filter, StringComparison.OrdinalIgnoreCase) ||
+ page.Node.Id.Contains(filter, StringComparison.OrdinalIgnoreCase))
+ VisiblePages.Add(page);
+ }
+ }
+
+ private bool _isProcessingSelection = false;
+ }
+}
+
diff --git a/src/Views/MenuItemExtension.cs b/src/Views/MenuItemExtension.cs
new file mode 100644
index 00000000..1c23b2ea
--- /dev/null
+++ b/src/Views/MenuItemExtension.cs
@@ -0,0 +1,12 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Data;
+
+namespace SourceGit.Views
+{
+ public class MenuItemExtension : AvaloniaObject
+ {
+ public static readonly AttachedProperty CommandProperty =
+ AvaloniaProperty.RegisterAttached("Command", string.Empty, false, BindingMode.OneWay);
+ }
+}
diff --git a/src/Views/Merge.axaml b/src/Views/Merge.axaml
index 805ac6d0..33d07f02 100644
--- a/src/Views/Merge.axaml
+++ b/src/Views/Merge.axaml
@@ -60,15 +60,32 @@
Height="28" Padding="8,0"
VerticalAlignment="Center" HorizontalAlignment="Stretch"
ItemsSource="{Binding Source={x:Static m:MergeMode.Supported}}"
- SelectedItem="{Binding SelectedMode, Mode=TwoWay}">
+ SelectedItem="{Binding Mode, Mode=TwoWay}"
+ Grid.IsSharedSizeScope="True">
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Views/MergeMultiple.axaml b/src/Views/MergeMultiple.axaml
index bb543e16..332d9fef 100644
--- a/src/Views/MergeMultiple.axaml
+++ b/src/Views/MergeMultiple.axaml
@@ -12,7 +12,7 @@
-
+
-
+
@@ -84,7 +84,7 @@
-
+
diff --git a/src/Views/PopupRunningStatus.axaml b/src/Views/PopupRunningStatus.axaml
index 0522e46b..a8467415 100644
--- a/src/Views/PopupRunningStatus.axaml
+++ b/src/Views/PopupRunningStatus.axaml
@@ -9,19 +9,19 @@
x:Name="ThisControl">
-
+
-
+
-
+
@@ -30,7 +30,7 @@
IsVisible="{OnPlatform True, macOS=False}"/>
@@ -44,11 +44,11 @@
-
+
-
+
-
+
@@ -128,29 +128,34 @@
+ Content="{DynamicResource Text.Preferences.General.ShowAuthorTime}"
+ IsChecked="{Binding Source={x:Static vm:Preferences.Instance}, Path=ShowAuthorTimeInGraph, Mode=TwoWay}"/>
+ Content="{DynamicResource Text.Preferences.General.ShowTagsInGraph}"
+ IsChecked="{Binding Source={x:Static vm:Preferences.Instance}, Path=ShowTagsInGraph, Mode=TwoWay}"/>
+
+
+ IsChecked="{Binding Source={x:Static vm:Preferences.Instance}, Path=Check4UpdatesOnStartup, Mode=TwoWay}"/>
-
+
-
+
+ Minimum="10" Maximum="18" Increment="0.5"
+ Height="28"
+ Padding="4"
+ BorderThickness="1" BorderBrush="{DynamicResource Brush.Border1}"
+ CornerRadius="3"
+ Value="{Binding DefaultFontSize, Mode=TwoWay}">
-
+
@@ -211,17 +216,30 @@
Value="{Binding EditorFontSize, Mode=TwoWay}">
-
+
-
+
+
+
+
+
@@ -232,19 +250,19 @@
-
-
+ Content="{DynamicResource Text.Preferences.Appearance.OnlyUseMonoFontInEditor}"
+ IsChecked="{Binding OnlyUseMonoFontInEditor, Mode=TwoWay}"/>
+
+
@@ -252,12 +270,12 @@
-
+
-
+
@@ -282,34 +300,34 @@
IsVisible="{Binding #ThisControl.GitVersion, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"/>
+ Watermark="{DynamicResource Text.Preferences.Git.User.Placeholder}"/>
+ Watermark="{DynamicResource Text.Preferences.Git.Email.Placeholder}"/>
+
+
-
+
@@ -370,7 +393,7 @@
Height="28"
CornerRadius="3"
Text="{Binding #ThisControl.GPGExecutableFile, Mode=TwoWay}"
- Watermark="{DynamicResource Text.Preference.GPG.Path.Placeholder}"
+ Watermark="{DynamicResource Text.Preferences.GPG.Path.Placeholder}"
IsVisible="{Binding #ThisControl.GPGFormat.NeedFindProgram}">
@@ -380,34 +403,34 @@
+ Watermark="{DynamicResource Text.Preferences.GPG.UserKey.Placeholder}"/>
-
+
-
+
-
+
@@ -417,7 +440,7 @@
@@ -456,7 +479,7 @@
-
+
@@ -466,7 +489,7 @@
@@ -497,7 +520,7 @@
Height="28"
CornerRadius="3"
Text="{Binding ExternalMergeToolPath, Mode=TwoWay}"
- Watermark="{DynamicResource Text.Preference.DiffMerge.Path.Placeholder}"
+ Watermark="{DynamicResource Text.Preferences.DiffMerge.Path.Placeholder}"
IsVisible="{Binding ExternalMergeToolType, Converter={x:Static c:IntConverters.IsGreaterThanZero}}">
@@ -511,10 +534,124 @@
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -582,19 +719,19 @@
-
+
-
+
-
+
-
+
-
-
+
+
-
+
+
+
diff --git a/src/Views/Preference.axaml.cs b/src/Views/Preferences.axaml.cs
similarity index 75%
rename from src/Views/Preference.axaml.cs
rename to src/Views/Preferences.axaml.cs
index 05bb724c..73b2e995 100644
--- a/src/Views/Preference.axaml.cs
+++ b/src/Views/Preferences.axaml.cs
@@ -8,7 +8,7 @@ using Avalonia.Platform.Storage;
namespace SourceGit.Views
{
- public partial class Preference : ChromelessWindow
+ public partial class Preferences : ChromelessWindow
{
public string DefaultUser
{
@@ -28,8 +28,14 @@ namespace SourceGit.Views
set;
} = null;
+ public bool EnablePruneOnFetch
+ {
+ get;
+ set;
+ }
+
public static readonly StyledProperty GitVersionProperty =
- AvaloniaProperty.Register(nameof(GitVersion));
+ AvaloniaProperty.Register(nameof(GitVersion));
public string GitVersion
{
@@ -38,7 +44,7 @@ namespace SourceGit.Views
}
public static readonly StyledProperty ShowGitVersionWarningProperty =
- AvaloniaProperty.Register(nameof(ShowGitVersionWarning));
+ AvaloniaProperty.Register(nameof(ShowGitVersionWarning));
public bool ShowGitVersionWarning
{
@@ -59,7 +65,7 @@ namespace SourceGit.Views
}
public static readonly StyledProperty GPGFormatProperty =
- AvaloniaProperty.Register(nameof(GPGFormat), Models.GPGFormat.Supported[0]);
+ AvaloniaProperty.Register(nameof(GPGFormat), Models.GPGFormat.Supported[0]);
public Models.GPGFormat GPGFormat
{
@@ -68,7 +74,7 @@ namespace SourceGit.Views
}
public static readonly StyledProperty GPGExecutableFileProperty =
- AvaloniaProperty.Register(nameof(GPGExecutableFile));
+ AvaloniaProperty.Register(nameof(GPGExecutableFile));
public string GPGExecutableFile
{
@@ -89,7 +95,7 @@ namespace SourceGit.Views
} = false;
public static readonly StyledProperty SelectedOpenAIServiceProperty =
- AvaloniaProperty.Register(nameof(SelectedOpenAIService));
+ AvaloniaProperty.Register(nameof(SelectedOpenAIService));
public Models.OpenAIService SelectedOpenAIService
{
@@ -97,9 +103,18 @@ namespace SourceGit.Views
set => SetValue(SelectedOpenAIServiceProperty, value);
}
- public Preference()
+ public static readonly StyledProperty SelectedCustomActionProperty =
+ AvaloniaProperty.Register(nameof(SelectedCustomAction));
+
+ public Models.CustomAction SelectedCustomAction
{
- var pref = ViewModels.Preference.Instance;
+ get => GetValue(SelectedCustomActionProperty);
+ set => SetValue(SelectedCustomActionProperty, value);
+ }
+
+ public Preferences()
+ {
+ var pref = ViewModels.Preferences.Instance;
DataContext = pref;
if (pref.IsGitConfigured())
@@ -114,6 +129,8 @@ namespace SourceGit.Views
GPGUserKey = signingKey;
if (config.TryGetValue("core.autocrlf", out var crlf))
CRLFMode = Models.CRLFMode.Supported.Find(x => x.Value == crlf);
+ if (config.TryGetValue("fetch.prune", out var pruneOnFetch))
+ EnablePruneOnFetch = (pruneOnFetch == "true");
if (config.TryGetValue("commit.gpgsign", out var gpgCommitSign))
EnableGPGCommitSigning = (gpgCommitSign == "true");
if (config.TryGetValue("tag.gpgsign", out var gpgTagSign))
@@ -152,11 +169,17 @@ namespace SourceGit.Views
protected override void OnClosing(WindowClosingEventArgs e)
{
+ base.OnClosing(e);
+
+ if (Design.IsDesignMode)
+ return;
+
var config = new Commands.Config(null).ListAll();
SetIfChanged(config, "user.name", DefaultUser, "");
SetIfChanged(config, "user.email", DefaultEmail, "");
SetIfChanged(config, "user.signingkey", GPGUserKey, "");
SetIfChanged(config, "core.autocrlf", CRLFMode != null ? CRLFMode.Value : null, null);
+ SetIfChanged(config, "fetch.prune", EnablePruneOnFetch ? "true" : "false", "false");
SetIfChanged(config, "commit.gpgsign", EnableGPGCommitSigning ? "true" : "false", "false");
SetIfChanged(config, "tag.gpgsign", EnableGPGTagSigning ? "true" : "false", "false");
SetIfChanged(config, "http.sslverify", EnableHTTPSSLVerify ? "" : "false", "");
@@ -180,7 +203,7 @@ namespace SourceGit.Views
new Commands.Config(null).Set($"gpg.{GPGFormat.Value}.program", GPGExecutableFile);
}
- base.OnClosing(e);
+ ViewModels.Preferences.Instance.Save();
}
private async void SelectThemeOverrideFile(object _, RoutedEventArgs e)
@@ -194,7 +217,7 @@ namespace SourceGit.Views
var selected = await StorageProvider.OpenFilePickerAsync(options);
if (selected.Count == 1)
{
- ViewModels.Preference.Instance.ThemeOverrides = selected[0].Path.LocalPath;
+ ViewModels.Preferences.Instance.ThemeOverrides = selected[0].Path.LocalPath;
}
e.Handled = true;
@@ -212,7 +235,7 @@ namespace SourceGit.Views
var selected = await StorageProvider.OpenFilePickerAsync(options);
if (selected.Count == 1)
{
- ViewModels.Preference.Instance.GitInstallPath = selected[0].Path.LocalPath;
+ ViewModels.Preferences.Instance.GitInstallPath = selected[0].Path.LocalPath;
UpdateGitVersion();
}
@@ -227,7 +250,7 @@ namespace SourceGit.Views
var selected = await StorageProvider.OpenFolderPickerAsync(options);
if (selected.Count == 1)
{
- ViewModels.Preference.Instance.GitDefaultCloneDir = selected[0].Path.LocalPath;
+ ViewModels.Preferences.Instance.GitDefaultCloneDir = selected[0].Path.LocalPath;
}
}
catch (Exception ex)
@@ -263,7 +286,7 @@ namespace SourceGit.Views
private async void SelectShellOrTerminal(object _, RoutedEventArgs e)
{
- var type = ViewModels.Preference.Instance.ShellOrTerminal;
+ var type = ViewModels.Preferences.Instance.ShellOrTerminal;
if (type == -1)
return;
@@ -277,7 +300,7 @@ namespace SourceGit.Views
var selected = await StorageProvider.OpenFilePickerAsync(options);
if (selected.Count == 1)
{
- ViewModels.Preference.Instance.ShellOrTerminalPath = selected[0].Path.LocalPath;
+ ViewModels.Preferences.Instance.ShellOrTerminalPath = selected[0].Path.LocalPath;
}
e.Handled = true;
@@ -285,10 +308,10 @@ namespace SourceGit.Views
private async void SelectExternalMergeTool(object _, RoutedEventArgs e)
{
- var type = ViewModels.Preference.Instance.ExternalMergeToolType;
+ var type = ViewModels.Preferences.Instance.ExternalMergeToolType;
if (type < 0 || type >= Models.ExternalMerger.Supported.Count)
{
- ViewModels.Preference.Instance.ExternalMergeToolType = 0;
+ ViewModels.Preferences.Instance.ExternalMergeToolType = 0;
e.Handled = true;
return;
}
@@ -303,7 +326,7 @@ namespace SourceGit.Views
var selected = await StorageProvider.OpenFilePickerAsync(options);
if (selected.Count == 1)
{
- ViewModels.Preference.Instance.ExternalMergeToolPath = selected[0].Path.LocalPath;
+ ViewModels.Preferences.Instance.ExternalMergeToolPath = selected[0].Path.LocalPath;
}
e.Handled = true;
@@ -325,7 +348,7 @@ namespace SourceGit.Views
{
if (sender is CheckBox box)
{
- ViewModels.Preference.Instance.UseSystemWindowFrame = box.IsChecked == true;
+ ViewModels.Preferences.Instance.UseSystemWindowFrame = box.IsChecked == true;
var dialog = new ConfirmRestart();
App.OpenDialog(dialog);
@@ -342,7 +365,7 @@ namespace SourceGit.Views
private void OnAddOpenAIService(object sender, RoutedEventArgs e)
{
var service = new Models.OpenAIService() { Name = "Unnamed Service" };
- ViewModels.Preference.Instance.OpenAIServices.Add(service);
+ ViewModels.Preferences.Instance.OpenAIServices.Add(service);
SelectedOpenAIService = service;
e.Handled = true;
@@ -353,11 +376,45 @@ namespace SourceGit.Views
if (SelectedOpenAIService == null)
return;
- ViewModels.Preference.Instance.OpenAIServices.Remove(SelectedOpenAIService);
+ ViewModels.Preferences.Instance.OpenAIServices.Remove(SelectedOpenAIService);
SelectedOpenAIService = null;
e.Handled = true;
}
+ private void OnAddCustomAction(object sender, RoutedEventArgs e)
+ {
+ var action = new Models.CustomAction() { Name = "Unnamed Action (Global)" };
+ ViewModels.Preferences.Instance.CustomActions.Add(action);
+ SelectedCustomAction = action;
+
+ e.Handled = true;
+ }
+
+ private async void SelectExecutableForCustomAction(object sender, RoutedEventArgs e)
+ {
+ var options = new FilePickerOpenOptions()
+ {
+ FileTypeFilter = [new FilePickerFileType("Executable file(script)") { Patterns = ["*.*"] }],
+ AllowMultiple = false,
+ };
+
+ var selected = await StorageProvider.OpenFilePickerAsync(options);
+ if (selected.Count == 1 && sender is Button { DataContext: Models.CustomAction action })
+ action.Executable = selected[0].Path.LocalPath;
+
+ e.Handled = true;
+ }
+
+ private void OnRemoveSelectedCustomAction(object sender, RoutedEventArgs e)
+ {
+ if (SelectedCustomAction == null)
+ return;
+
+ ViewModels.Preferences.Instance.CustomActions.Remove(SelectedCustomAction);
+ SelectedCustomAction = null;
+ e.Handled = true;
+ }
+
private void UpdateGitVersion()
{
GitVersion = Native.OS.GitVersionString;
diff --git a/src/Views/Pull.axaml b/src/Views/Pull.axaml
index 3e1f96d9..67121826 100644
--- a/src/Views/Pull.axaml
+++ b/src/Views/Pull.axaml
@@ -22,7 +22,7 @@
-
+
-
-
-
+ Content="{DynamicResource Text.Pull.LocalChanges.StashAndReply}"
+ IsChecked="{Binding !DiscardLocalChanges, Mode=TwoWay}"/>
+
-
+
diff --git a/src/Views/Pull.axaml.cs b/src/Views/Pull.axaml.cs
index 3003f02c..c6b4923e 100644
--- a/src/Views/Pull.axaml.cs
+++ b/src/Views/Pull.axaml.cs
@@ -1,5 +1,4 @@
using Avalonia.Controls;
-using Avalonia.Interactivity;
namespace SourceGit.Views
{
@@ -9,51 +8,5 @@ namespace SourceGit.Views
{
InitializeComponent();
}
-
- protected override void OnLoaded(RoutedEventArgs e)
- {
- base.OnLoaded(e);
-
- var vm = DataContext as ViewModels.Pull;
- if (vm == null)
- return;
-
- switch (vm.PreAction)
- {
- case Models.DealWithLocalChanges.DoNothing:
- RadioDoNothing.IsChecked = true;
- break;
- case Models.DealWithLocalChanges.StashAndReaply:
- RadioStashAndReply.IsChecked = true;
- break;
- default:
- RadioDiscard.IsChecked = true;
- break;
- }
- }
-
- private void OnLocalChangeActionIsCheckedChanged(object sender, RoutedEventArgs e)
- {
- var vm = DataContext as ViewModels.Pull;
- if (vm == null)
- return;
-
- if (RadioDoNothing.IsChecked == true)
- {
- if (vm.PreAction != Models.DealWithLocalChanges.DoNothing)
- vm.PreAction = Models.DealWithLocalChanges.DoNothing;
- return;
- }
-
- if (RadioStashAndReply.IsChecked == true)
- {
- if (vm.PreAction != Models.DealWithLocalChanges.StashAndReaply)
- vm.PreAction = Models.DealWithLocalChanges.StashAndReaply;
- return;
- }
-
- if (vm.PreAction != Models.DealWithLocalChanges.Discard)
- vm.PreAction = Models.DealWithLocalChanges.Discard;
- }
}
}
diff --git a/src/Views/Push.axaml b/src/Views/Push.axaml
index e28e2afd..743606ee 100644
--- a/src/Views/Push.axaml
+++ b/src/Views/Push.axaml
@@ -76,8 +76,8 @@
diff --git a/src/Views/RemoveWorktree.axaml b/src/Views/RemoveWorktree.axaml
index 6d7ea914..736e6e40 100644
--- a/src/Views/RemoveWorktree.axaml
+++ b/src/Views/RemoveWorktree.axaml
@@ -18,8 +18,8 @@
-
-
+
+
diff --git a/src/Views/RenameBranch.axaml b/src/Views/RenameBranch.axaml
index 59a849fe..efbbf323 100644
--- a/src/Views/RenameBranch.axaml
+++ b/src/Views/RenameBranch.axaml
@@ -4,6 +4,7 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="using:SourceGit.ViewModels"
xmlns:v="using:SourceGit.Views"
+ xmlns:c="using:SourceGit.Converters"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="SourceGit.Views.RenameBranch"
x:DataType="vm:RenameBranch">
@@ -11,7 +12,7 @@
-
+
+
+
+
+
+
diff --git a/src/Views/Repository.axaml b/src/Views/Repository.axaml
index a6b86c60..b16447fa 100644
--- a/src/Views/Repository.axaml
+++ b/src/Views/Repository.axaml
@@ -11,7 +11,7 @@
x:DataType="vm:Repository">
-
+
@@ -40,7 +40,7 @@
-
+
@@ -520,18 +530,22 @@
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
@@ -548,7 +562,7 @@
-
+
-
+
@@ -597,11 +611,18 @@
-
-
+
+
-
+
@@ -628,7 +649,7 @@
-
+
-
+
-
+
-
+
+
+
+
+
-
+
@@ -694,7 +719,7 @@
diff --git a/src/Views/Repository.axaml.cs b/src/Views/Repository.axaml.cs
index def82f89..d848c000 100644
--- a/src/Views/Repository.axaml.cs
+++ b/src/Views/Repository.axaml.cs
@@ -134,7 +134,7 @@ namespace SourceGit.Views
}
else if (e.Key == Key.Down)
{
- if (repo.IsSearchCommitSuggestionOpen)
+ if (repo.MatchedFilesForSearching is { Count: > 0 })
{
SearchSuggestionBox.Focus(NavigationMethod.Tab);
SearchSuggestionBox.SelectedIndex = 0;
@@ -144,12 +144,7 @@ namespace SourceGit.Views
}
else if (e.Key == Key.Escape)
{
- if (repo.IsSearchCommitSuggestionOpen)
- {
- repo.SearchCommitFilterSuggestion.Clear();
- repo.IsSearchCommitSuggestionOpen = false;
- }
-
+ repo.ClearMatchedFilesForSearching();
e.Handled = true;
}
}
@@ -369,9 +364,7 @@ namespace SourceGit.Views
if (e.Key == Key.Escape)
{
- repo.IsSearchCommitSuggestionOpen = false;
- repo.SearchCommitFilterSuggestion.Clear();
-
+ repo.ClearMatchedFilesForSearching();
e.Handled = true;
}
else if (e.Key == Key.Enter && SearchSuggestionBox.SelectedItem is string content)
@@ -403,64 +396,8 @@ namespace SourceGit.Views
{
if (sender is Button button && DataContext is ViewModels.Repository repo)
{
- var layout = new MenuItem();
- layout.Header = App.Text("Repository.HistoriesLayout");
- layout.IsEnabled = false;
-
- var isHorizontal = ViewModels.Preference.Instance.UseTwoColumnsLayoutInHistories;
- var horizontal = new MenuItem();
- horizontal.Header = App.Text("Repository.HistoriesLayout.Horizontal");
- if (isHorizontal)
- horizontal.Icon = App.CreateMenuIcon("Icons.Check");
- horizontal.Click += (_, ev) =>
- {
- ViewModels.Preference.Instance.UseTwoColumnsLayoutInHistories = true;
- ev.Handled = true;
- };
-
- var vertical = new MenuItem();
- vertical.Header = App.Text("Repository.HistoriesLayout.Vertical");
- if (!isHorizontal)
- vertical.Icon = App.CreateMenuIcon("Icons.Check");
- vertical.Click += (_, ev) =>
- {
- ViewModels.Preference.Instance.UseTwoColumnsLayoutInHistories = false;
- ev.Handled = true;
- };
-
- var order = new MenuItem();
- order.Header = App.Text("Repository.HistoriesOrder");
- order.IsEnabled = false;
-
- var dateOrder = new MenuItem();
- dateOrder.Header = App.Text("Repository.HistoriesOrder.ByDate");
- if (!repo.EnableTopoOrderInHistories)
- dateOrder.Icon = App.CreateMenuIcon("Icons.Check");
- dateOrder.Click += (_, ev) =>
- {
- repo.EnableTopoOrderInHistories = false;
- ev.Handled = true;
- };
-
- var topoOrder = new MenuItem();
- topoOrder.Header = App.Text("Repository.HistoriesOrder.Topo");
- if (repo.EnableTopoOrderInHistories)
- topoOrder.Icon = App.CreateMenuIcon("Icons.Check");
- topoOrder.Click += (_, ev) =>
- {
- repo.EnableTopoOrderInHistories = true;
- ev.Handled = true;
- };
-
- var menu = new ContextMenu();
- menu.Items.Add(layout);
- menu.Items.Add(horizontal);
- menu.Items.Add(vertical);
- menu.Items.Add(new MenuItem() { Header = "-" });
- menu.Items.Add(order);
- menu.Items.Add(dateOrder);
- menu.Items.Add(topoOrder);
- menu.Open(button);
+ var menu = repo.CreateContextMenuForHistoriesPage();
+ menu?.Open(button);
}
e.Handled = true;
@@ -470,41 +407,8 @@ namespace SourceGit.Views
{
if (sender is Button button && DataContext is ViewModels.Repository repo)
{
- var byCreatorDate = new MenuItem();
- byCreatorDate.Header = App.Text("Repository.Tags.OrderByCreatorDate");
- if (repo.TagSortMode == Models.TagSortMode.CreatorDate)
- byCreatorDate.Icon = App.CreateMenuIcon("Icons.Check");
- byCreatorDate.Click += (_, ev) =>
- {
- repo.TagSortMode = Models.TagSortMode.CreatorDate;
- ev.Handled = true;
- };
-
- var byNameAsc = new MenuItem();
- byNameAsc.Header = App.Text("Repository.Tags.OrderByNameAsc");
- if (repo.TagSortMode == Models.TagSortMode.NameInAscending)
- byNameAsc.Icon = App.CreateMenuIcon("Icons.Check");
- byNameAsc.Click += (_, ev) =>
- {
- repo.TagSortMode = Models.TagSortMode.NameInAscending;
- ev.Handled = true;
- };
-
- var byNameDes = new MenuItem();
- byNameDes.Header = App.Text("Repository.Tags.OrderByNameDes");
- if (repo.TagSortMode == Models.TagSortMode.NameInDescending)
- byNameDes.Icon = App.CreateMenuIcon("Icons.Check");
- byNameDes.Click += (_, ev) =>
- {
- repo.TagSortMode = Models.TagSortMode.NameInDescending;
- ev.Handled = true;
- };
-
- var menu = new ContextMenu();
- menu.Items.Add(byCreatorDate);
- menu.Items.Add(byNameAsc);
- menu.Items.Add(byNameDes);
- menu.Open(button);
+ var menu = repo.CreateContextMenuForTagSortMode();
+ menu?.Open(button);
}
e.Handled = true;
@@ -517,5 +421,13 @@ namespace SourceGit.Views
e.Handled = true;
}
+
+ private void OnRemoveSelectedHistoriesFilter(object sender, RoutedEventArgs e)
+ {
+ if (DataContext is ViewModels.Repository repo && sender is Button { DataContext: Models.Filter filter })
+ repo.RemoveHistoriesFilter(filter);
+
+ e.Handled = true;
+ }
}
}
diff --git a/src/Views/RepositoryConfigure.axaml b/src/Views/RepositoryConfigure.axaml
index 5c1ce989..ee1d6fa8 100644
--- a/src/Views/RepositoryConfigure.axaml
+++ b/src/Views/RepositoryConfigure.axaml
@@ -5,7 +5,6 @@
xmlns:m="using:SourceGit.Models"
xmlns:vm="using:SourceGit.ViewModels"
xmlns:v="using:SourceGit.Views"
- xmlns:ac="using:Avalonia.Controls.Converters"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="SourceGit.Views.RepositoryConfigure"
x:DataType="vm:RepositoryConfigure"
@@ -66,7 +65,7 @@
CornerRadius="3"
Watermark="{DynamicResource Text.Configure.Email.Placeholder}"
Text="{Binding UserEmail, Mode=TwoWay}"/>
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
-
-
-
@@ -249,9 +280,9 @@
BorderThickness="1" BorderBrush="{DynamicResource Brush.Border2}"
Background="{DynamicResource Brush.Contents}">
-
@@ -261,7 +292,7 @@
-
+
@@ -288,6 +319,7 @@
+
@@ -320,7 +352,7 @@
-
+
@@ -349,7 +381,7 @@
-
+
@@ -420,20 +452,12 @@
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
@@ -447,13 +471,15 @@
+
+
-
+
diff --git a/src/Views/RepositoryConfigure.axaml.cs b/src/Views/RepositoryConfigure.axaml.cs
index 3faba5ee..455731aa 100644
--- a/src/Views/RepositoryConfigure.axaml.cs
+++ b/src/Views/RepositoryConfigure.axaml.cs
@@ -13,8 +13,10 @@ namespace SourceGit.Views
protected override void OnClosing(WindowClosingEventArgs e)
{
- (DataContext as ViewModels.RepositoryConfigure)?.Save();
base.OnClosing(e);
+
+ if (!Design.IsDesignMode && DataContext is ViewModels.RepositoryConfigure configure)
+ configure.Save();
}
private async void SelectExecutableForCustomAction(object sender, RoutedEventArgs e)
diff --git a/src/Views/RepositoryToolbar.axaml b/src/Views/RepositoryToolbar.axaml
index 2562775a..9f7f1801 100644
--- a/src/Views/RepositoryToolbar.axaml
+++ b/src/Views/RepositoryToolbar.axaml
@@ -8,128 +8,128 @@
x:Class="SourceGit.Views.RepositoryToolbar"
x:DataType="vm:Repository">
-
-
-
-
+
+
+
+
-
-
-
-
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
+
+
-
+
+
+
+
+
+
+
-
-
-
+
+
-
-
-
+
+
+
+
+
+
+
-
-
-
+
+
-
-
-
+
+
+
-
-
-
-
+
-
-
+
+
+
-
-
-
-
-
-
-
-
+
+
+
-
-
-
-
-
-
-
-
+
+
+
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Views/RepositoryToolbar.axaml.cs b/src/Views/RepositoryToolbar.axaml.cs
index aa78c4d3..66b49fc2 100644
--- a/src/Views/RepositoryToolbar.axaml.cs
+++ b/src/Views/RepositoryToolbar.axaml.cs
@@ -59,6 +59,12 @@ namespace SourceGit.Views
var launcher = this.FindAncestorOfType();
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);
diff --git a/src/Views/RevisionCompare.axaml b/src/Views/RevisionCompare.axaml
index 912fde39..f0498fbf 100644
--- a/src/Views/RevisionCompare.axaml
+++ b/src/Views/RevisionCompare.axaml
@@ -15,7 +15,7 @@
-
+
@@ -32,7 +32,7 @@
-
+
@@ -91,14 +91,15 @@
+ ViewMode="{Binding Source={x:Static vm:Preferences.Instance}, Path=CommitChangeViewMode, Mode=TwoWay}"/>
-
diff --git a/src/Views/RevisionFileContentViewer.axaml b/src/Views/RevisionFileContentViewer.axaml
index 5c2501e9..86393316 100644
--- a/src/Views/RevisionFileContentViewer.axaml
+++ b/src/Views/RevisionFileContentViewer.axaml
@@ -21,7 +21,8 @@
@@ -34,12 +35,12 @@
-
+
-
+
@@ -63,7 +64,7 @@
-
+
diff --git a/src/Views/RevisionFileContentViewer.axaml.cs b/src/Views/RevisionFileContentViewer.axaml.cs
index bca6a082..16f4fc83 100644
--- a/src/Views/RevisionFileContentViewer.axaml.cs
+++ b/src/Views/RevisionFileContentViewer.axaml.cs
@@ -1,7 +1,139 @@
+using System;
+
+using Avalonia;
using Avalonia.Controls;
+using Avalonia.Controls.Primitives;
+using Avalonia.Interactivity;
+using Avalonia.Media;
+
+using AvaloniaEdit;
+using AvaloniaEdit.Document;
+using AvaloniaEdit.Editing;
+using AvaloniaEdit.TextMate;
namespace SourceGit.Views
{
+ public class RevisionTextFileView : TextEditor
+ {
+ public static readonly StyledProperty TabWidthProperty =
+ AvaloniaProperty.Register(nameof(TabWidth), 4);
+
+ public int TabWidth
+ {
+ get => GetValue(TabWidthProperty);
+ set => SetValue(TabWidthProperty, value);
+ }
+
+ protected override Type StyleKeyOverride => typeof(TextEditor);
+
+ public RevisionTextFileView() : base(new TextArea(), new TextDocument())
+ {
+ IsReadOnly = true;
+ ShowLineNumbers = true;
+ WordWrap = false;
+
+ Options.IndentationSize = TabWidth;
+ Options.EnableHyperlinks = false;
+ Options.EnableEmailHyperlinks = false;
+
+ HorizontalScrollBarVisibility = ScrollBarVisibility.Auto;
+ VerticalScrollBarVisibility = ScrollBarVisibility.Auto;
+
+ TextArea.LeftMargins[0].Margin = new Thickness(8, 0);
+ TextArea.TextView.Margin = new Thickness(4, 0);
+ }
+
+ protected override void OnLoaded(RoutedEventArgs e)
+ {
+ base.OnLoaded(e);
+
+ TextArea.TextView.ContextRequested += OnTextViewContextRequested;
+ UpdateTextMate();
+ }
+
+ protected override void OnUnloaded(RoutedEventArgs e)
+ {
+ base.OnUnloaded(e);
+
+ TextArea.TextView.ContextRequested -= OnTextViewContextRequested;
+
+ if (_textMate != null)
+ {
+ _textMate.Dispose();
+ _textMate = null;
+ }
+
+ GC.Collect();
+ }
+
+ protected override void OnDataContextChanged(EventArgs e)
+ {
+ base.OnDataContextChanged(e);
+
+ if (DataContext is Models.RevisionTextFile source)
+ {
+ UpdateTextMate();
+ Text = source.Content;
+ }
+ else
+ {
+ Text = string.Empty;
+ }
+ }
+
+ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
+ {
+ base.OnPropertyChanged(change);
+
+ if (change.Property == TabWidthProperty)
+ {
+ Options.IndentationSize = TabWidth;
+ }
+ }
+
+ private void OnTextViewContextRequested(object sender, ContextRequestedEventArgs e)
+ {
+ var selected = SelectedText;
+ if (string.IsNullOrEmpty(selected))
+ return;
+
+ var copy = new MenuItem() { Header = App.Text("Copy") };
+ copy.Click += (_, ev) =>
+ {
+ App.CopyText(selected);
+ ev.Handled = true;
+ };
+
+ if (this.FindResource("Icons.Copy") is Geometry geo)
+ {
+ copy.Icon = new Avalonia.Controls.Shapes.Path()
+ {
+ Width = 10,
+ Height = 10,
+ Stretch = Stretch.Uniform,
+ Data = geo,
+ };
+ }
+
+ var menu = new ContextMenu();
+ menu.Items.Add(copy);
+ menu.Open(TextArea.TextView);
+
+ e.Handled = true;
+ }
+
+ private void UpdateTextMate()
+ {
+ if (_textMate == null)
+ _textMate = Models.TextMateHelper.CreateForEditor(this);
+
+ if (DataContext is Models.RevisionTextFile file)
+ Models.TextMateHelper.SetGrammarByFileName(_textMate, file.FileName);
+ }
+
+ private TextMate.Installation _textMate = null;
+ }
+
public partial class RevisionFileContentViewer : UserControl
{
public RevisionFileContentViewer()
diff --git a/src/Views/RevisionFiles.axaml b/src/Views/RevisionFiles.axaml
index fdb15807..6575dc66 100644
--- a/src/Views/RevisionFiles.axaml
+++ b/src/Views/RevisionFiles.axaml
@@ -10,7 +10,7 @@
x:DataType="vm:CommitDetail">
-
+
@@ -43,8 +43,14 @@
+ HorizontalOffset="-8" VerticalAlignment="-8">
+
+
+
+
+
+
+
typeof(TextEditor);
-
- public RevisionTextFileView() : base(new TextArea(), new TextDocument())
- {
- IsReadOnly = true;
- ShowLineNumbers = true;
- WordWrap = false;
- HorizontalScrollBarVisibility = ScrollBarVisibility.Auto;
- VerticalScrollBarVisibility = ScrollBarVisibility.Auto;
-
- TextArea.LeftMargins[0].Margin = new Thickness(8, 0);
- TextArea.TextView.Margin = new Thickness(4, 0);
- TextArea.TextView.Options.EnableHyperlinks = false;
- TextArea.TextView.Options.EnableEmailHyperlinks = false;
- }
-
- protected override void OnLoaded(RoutedEventArgs e)
- {
- base.OnLoaded(e);
-
- TextArea.TextView.ContextRequested += OnTextViewContextRequested;
- UpdateTextMate();
- }
-
- protected override void OnUnloaded(RoutedEventArgs e)
- {
- base.OnUnloaded(e);
-
- TextArea.TextView.ContextRequested -= OnTextViewContextRequested;
-
- if (_textMate != null)
- {
- _textMate.Dispose();
- _textMate = null;
- }
-
- GC.Collect();
- }
-
- protected override void OnDataContextChanged(EventArgs e)
- {
- base.OnDataContextChanged(e);
-
- if (DataContext is Models.RevisionTextFile source)
- {
- UpdateTextMate();
- Text = source.Content;
- }
- else
- {
- Text = string.Empty;
- }
- }
-
- private void OnTextViewContextRequested(object sender, ContextRequestedEventArgs e)
- {
- var selected = SelectedText;
- if (string.IsNullOrEmpty(selected))
- return;
-
- var copy = new MenuItem() { Header = App.Text("Copy") };
- copy.Click += (_, ev) =>
- {
- App.CopyText(selected);
- ev.Handled = true;
- };
-
- if (this.FindResource("Icons.Copy") is Geometry geo)
- {
- copy.Icon = new Avalonia.Controls.Shapes.Path()
- {
- Width = 10,
- Height = 10,
- Stretch = Stretch.Uniform,
- Data = geo,
- };
- }
-
- var menu = new ContextMenu();
- menu.Items.Add(copy);
- menu.Open(TextArea.TextView);
-
- e.Handled = true;
- }
-
- private void UpdateTextMate()
- {
- if (_textMate == null)
- _textMate = Models.TextMateHelper.CreateForEditor(this);
-
- if (DataContext is Models.RevisionTextFile file)
- Models.TextMateHelper.SetGrammarByFileName(_textMate, file.FileName);
- }
-
- private TextMate.Installation _textMate = null;
- }
-
public partial class RevisionFiles : UserControl
{
public RevisionFiles()
@@ -133,7 +23,7 @@ namespace SourceGit.Views
}
else if (e.Key == Key.Down || e.Key == Key.Up)
{
- if (vm.IsRevisionFileSearchSuggestionOpen)
+ if (vm.RevisionFileSearchSuggestion.Count > 0)
{
SearchSuggestionBox.Focus(NavigationMethod.Tab);
SearchSuggestionBox.SelectedIndex = 0;
@@ -143,12 +33,7 @@ namespace SourceGit.Views
}
else if (e.Key == Key.Escape)
{
- if (vm.IsRevisionFileSearchSuggestionOpen)
- {
- vm.RevisionFileSearchSuggestion.Clear();
- vm.IsRevisionFileSearchSuggestionOpen = false;
- }
-
+ vm.CancelRevisionFileSuggestions();
e.Handled = true;
}
}
@@ -167,7 +52,7 @@ namespace SourceGit.Views
if (e.Key == Key.Escape)
{
- vm.RevisionFileSearchSuggestion.Clear();
+ vm.CancelRevisionFileSuggestions();
e.Handled = true;
}
else if (e.Key == Key.Enter && SearchSuggestionBox.SelectedItem is string content)
diff --git a/src/Views/Reword.axaml b/src/Views/Reword.axaml
index f5de4ee7..3ea1ad98 100644
--- a/src/Views/Reword.axaml
+++ b/src/Views/Reword.axaml
@@ -17,9 +17,9 @@
-
+
-
+
-
+
-
-
-
+
+
+
-
-
-
+
-
-
-
-
+
+
+
+
+
+
-
-
+
-
@@ -43,7 +43,13 @@
IsChecked="{Binding KeepIndex, Mode=TwoWay}"
ToolTip.Tip="--keep-index"/>
-
+
+
-
+
@@ -92,7 +92,7 @@
-
+
diff --git a/src/Views/StashesPage.axaml.cs b/src/Views/StashesPage.axaml.cs
index af32cb2c..461f9d5d 100644
--- a/src/Views/StashesPage.axaml.cs
+++ b/src/Views/StashesPage.axaml.cs
@@ -15,7 +15,7 @@ namespace SourceGit.Views
if (grid == null)
return;
- var layout = ViewModels.Preference.Instance.Layout;
+ var layout = ViewModels.Preferences.Instance.Layout;
var width = grid.Bounds.Width;
var maxLeft = width - 304;
diff --git a/src/Views/Statistics.axaml b/src/Views/Statistics.axaml
index 0c002407..3bbdafbe 100644
--- a/src/Views/Statistics.axaml
+++ b/src/Views/Statistics.axaml
@@ -136,7 +136,7 @@
-
+
-
-
-
+
+
+
+
-
+
@@ -177,7 +181,7 @@
-
+
diff --git a/src/Views/TagsView.axaml b/src/Views/TagsView.axaml
index 9832bb0a..b5384c8f 100644
--- a/src/Views/TagsView.axaml
+++ b/src/Views/TagsView.axaml
@@ -17,7 +17,7 @@
-
+
-
+
-
@@ -65,7 +65,7 @@
@@ -73,17 +73,17 @@
Background="Transparent"
ContextRequested="OnRowContextRequested"
ToolTip.Tip="{Binding Message}">
-
-
+
diff --git a/src/Views/TextDiffView.axaml b/src/Views/TextDiffView.axaml
index 1dc26bb3..ec3475fa 100644
--- a/src/Views/TextDiffView.axaml
+++ b/src/Views/TextDiffView.axaml
@@ -14,7 +14,7 @@
-
-
+
@@ -80,14 +82,15 @@
DeletedHighlightBrush="{DynamicResource Brush.Diff.DeletedHighlight}"
IndicatorForeground="{DynamicResource Brush.FG2}"
FontFamily="{DynamicResource Fonts.Monospace}"
- FontSize="{Binding Source={x:Static vm:Preference.Instance}, Path=EditorFontSize}"
- UseSyntaxHighlighting="{Binding Source={x:Static vm:Preference.Instance}, Path=UseSyntaxHighlighting}"
+ FontSize="{Binding Source={x:Static vm:Preferences.Instance}, Path=EditorFontSize}"
+ TabWidth="{Binding Source={x:Static vm:Preferences.Instance}, Path=EditorTabWidth}"
+ UseSyntaxHighlighting="{Binding Source={x:Static vm:Preferences.Instance}, Path=UseSyntaxHighlighting}"
WordWrap="False"
- ShowHiddenSymbols="{Binding Source={x:Static vm:Preference.Instance}, Path=ShowHiddenSymbolsInDiffView}"
+ ShowHiddenSymbols="{Binding Source={x:Static vm:Preferences.Instance}, Path=ShowHiddenSymbolsInDiffView}"
EnableChunkSelection="{Binding #ThisControl.EnableChunkSelection}"
SelectedChunk="{Binding #ThisControl.SelectedChunk, Mode=TwoWay}"
BlockNavigation="{Binding #ThisControl.BlockNavigation, Mode=TwoWay}"/>
-
+
-
+
@@ -115,7 +118,7 @@
-
+
diff --git a/src/Views/TextDiffView.axaml.cs b/src/Views/TextDiffView.axaml.cs
index cca3751d..7ce9f288 100644
--- a/src/Views/TextDiffView.axaml.cs
+++ b/src/Views/TextDiffView.axaml.cs
@@ -60,7 +60,7 @@ namespace SourceGit.Views
public class ThemedTextDiffPresenter : TextEditor
{
- public class VerticalSeperatorMargin : AbstractMargin
+ public class VerticalSeparatorMargin : AbstractMargin
{
public override void Render(DrawingContext context)
{
@@ -475,6 +475,15 @@ namespace SourceGit.Views
set => SetValue(ShowHiddenSymbolsProperty, value);
}
+ public static readonly StyledProperty TabWidthProperty =
+ AvaloniaProperty.Register(nameof(TabWidth), 4);
+
+ public int TabWidth
+ {
+ get => GetValue(TabWidthProperty);
+ set => SetValue(TabWidthProperty, value);
+ }
+
public static readonly StyledProperty EnableChunkSelectionProperty =
AvaloniaProperty.Register(nameof(EnableChunkSelection));
@@ -519,12 +528,13 @@ namespace SourceGit.Views
ShowLineNumbers = false;
BorderThickness = new Thickness(0);
+ Options.IndentationSize = TabWidth;
+ Options.EnableHyperlinks = false;
+ Options.EnableEmailHyperlinks = false;
+
_lineStyleTransformer = new LineStyleTransformer(this);
TextArea.TextView.Margin = new Thickness(2, 0);
- TextArea.TextView.Options.EnableHyperlinks = false;
- TextArea.TextView.Options.EnableEmailHyperlinks = false;
-
TextArea.TextView.BackgroundRenderers.Add(new LineBackgroundRenderer(this));
TextArea.TextView.LineTransformers.Add(_lineStyleTransformer);
}
@@ -543,7 +553,21 @@ namespace SourceGit.Views
{
}
- public void GotoPrevChange()
+ public virtual void GotoFirstChange()
+ {
+ var blockNavigation = BlockNavigation;
+ if (blockNavigation != null)
+ {
+ var prev = blockNavigation.GotoFirst();
+ if (prev != null)
+ {
+ TextArea.Caret.Line = prev.Start;
+ ScrollToLine(prev.Start);
+ }
+ }
+ }
+
+ public virtual void GotoPrevChange()
{
var blockNavigation = BlockNavigation;
if (blockNavigation != null)
@@ -599,7 +623,7 @@ namespace SourceGit.Views
}
}
- public void GotoNextChange()
+ public virtual void GotoNextChange()
{
var blockNavigation = BlockNavigation;
if (blockNavigation != null)
@@ -641,6 +665,20 @@ namespace SourceGit.Views
}
}
+ public virtual void GotoLastChange()
+ {
+ var blockNavigation = BlockNavigation;
+ if (blockNavigation != null)
+ {
+ var next = blockNavigation.GotoLast();
+ if (next != null)
+ {
+ TextArea.Caret.Line = next.Start;
+ ScrollToLine(next.Start);
+ }
+ }
+ }
+
public override void Render(DrawingContext context)
{
base.Render(context);
@@ -669,6 +707,8 @@ namespace SourceGit.Views
TextArea.TextView.PointerWheelChanged += OnTextViewPointerWheelChanged;
TextArea.TextView.VisualLinesChanged += OnTextViewVisualLinesChanged;
+ TextArea.AddHandler(KeyDownEvent, OnTextAreaKeyDown, RoutingStrategies.Tunnel);
+
UpdateTextMate();
OnTextViewVisualLinesChanged(null, null);
}
@@ -677,6 +717,8 @@ namespace SourceGit.Views
{
base.OnUnloaded(e);
+ TextArea.RemoveHandler(KeyDownEvent, OnTextAreaKeyDown);
+
TextArea.TextView.ContextRequested -= OnTextViewContextRequested;
TextArea.TextView.PointerEntered -= OnTextViewPointerChanged;
TextArea.TextView.PointerMoved -= OnTextViewPointerChanged;
@@ -700,10 +742,14 @@ namespace SourceGit.Views
}
else if (change.Property == ShowHiddenSymbolsProperty)
{
- var val = change.NewValue is true;
+ var val = ShowHiddenSymbols;
Options.ShowTabs = val;
Options.ShowSpaces = val;
}
+ else if (change.Property == TabWidthProperty)
+ {
+ Options.IndentationSize = TabWidth;
+ }
else if (change.Property == FileNameProperty)
{
Models.TextMateHelper.SetGrammarByFileName(_textMate, FileName);
@@ -720,21 +766,35 @@ namespace SourceGit.Views
{
var oldValue = change.OldValue as ViewModels.BlockNavigation;
if (oldValue != null)
- {
oldValue.PropertyChanged -= OnBlockNavigationPropertyChanged;
- if (oldValue.Current != -1)
- TextArea?.TextView?.Redraw();
- }
var newValue = change.NewValue as ViewModels.BlockNavigation;
if (newValue != null)
newValue.PropertyChanged += OnBlockNavigationPropertyChanged;
+
+ TextArea?.TextView?.Redraw();
}
}
- private void OnBlockNavigationPropertyChanged(object _1, PropertyChangedEventArgs _2)
+ private void OnTextAreaKeyDown(object sender, KeyEventArgs e)
{
- TextArea?.TextView?.Redraw();
+ if (e.KeyModifiers.Equals(OperatingSystem.IsMacOS() ? KeyModifiers.Meta : KeyModifiers.Control))
+ {
+ if (e.Key == Key.C)
+ {
+ CopyWithoutIndicators();
+ e.Handled = true;
+ }
+ }
+
+ if (!e.Handled)
+ base.OnKeyDown(e);
+ }
+
+ private void OnBlockNavigationPropertyChanged(object _1, PropertyChangedEventArgs e)
+ {
+ if (e.PropertyName == "Current")
+ TextArea?.TextView?.Redraw();
}
private void OnTextViewContextRequested(object sender, ContextRequestedEventArgs e)
@@ -748,7 +808,7 @@ namespace SourceGit.Views
copy.Icon = App.CreateMenuIcon("Icons.Copy");
copy.Click += (_, ev) =>
{
- App.CopyText(SelectedText);
+ CopyWithoutIndicators();
ev.Handled = true;
};
@@ -941,6 +1001,76 @@ namespace SourceGit.Views
}
}
+ private void CopyWithoutIndicators()
+ {
+ var selection = TextArea.Selection;
+ if (selection.IsEmpty)
+ {
+ App.CopyText(string.Empty);
+ return;
+ }
+
+ var lines = GetLines();
+
+ var startPosition = selection.StartPosition;
+ var endPosition = selection.EndPosition;
+
+ if (startPosition.Location > endPosition.Location)
+ (startPosition, endPosition) = (endPosition, startPosition);
+
+ var startIdx = startPosition.Line - 1;
+ var endIdx = endPosition.Line - 1;
+
+ if (startIdx == endIdx)
+ {
+ var line = lines[startIdx];
+ if (line.Type == Models.TextDiffLineType.Indicator ||
+ line.Type == Models.TextDiffLineType.None)
+ {
+ App.CopyText(string.Empty);
+ return;
+ }
+
+ App.CopyText(SelectedText);
+ return;
+ }
+
+ var builder = new StringBuilder();
+ for (var i = startIdx; i <= endIdx && i <= lines.Count - 1; i++)
+ {
+ var line = lines[i];
+ if (line.Type == Models.TextDiffLineType.Indicator ||
+ line.Type == Models.TextDiffLineType.None)
+ continue;
+
+ // The first selected line (partial selection)
+ if (i == startIdx && startPosition.Column > 1)
+ {
+ builder.AppendLine(line.Content.Substring(startPosition.Column - 1));
+ continue;
+ }
+
+ // The selection range is larger than original source.
+ if (i == lines.Count - 1 && i < endIdx)
+ {
+ builder.Append(line.Content);
+ break;
+ }
+
+ // For the last line (selection range is within original source)
+ if (i == endIdx)
+ {
+ builder.Append(endPosition.Column - 1 < line.Content.Length ? line.Content.Substring(0, endPosition.Column - 1) : line.Content);
+ break;
+ }
+
+ // Other lines.
+ builder.AppendLine(line.Content);
+ }
+
+ App.CopyText(builder.ToString());
+ }
+
private TextMate.Installation _textMate = null;
private TextLocation _lastSelectStart = TextLocation.Empty;
private TextLocation _lastSelectEnd = TextLocation.Empty;
@@ -952,9 +1082,9 @@ namespace SourceGit.Views
public CombinedTextDiffPresenter() : base(new TextArea(), new TextDocument())
{
TextArea.LeftMargins.Add(new LineNumberMargin(false, true));
- TextArea.LeftMargins.Add(new VerticalSeperatorMargin());
+ TextArea.LeftMargins.Add(new VerticalSeparatorMargin());
TextArea.LeftMargins.Add(new LineNumberMargin(false, false));
- TextArea.LeftMargins.Add(new VerticalSeperatorMargin());
+ TextArea.LeftMargins.Add(new VerticalSeparatorMargin());
TextArea.LeftMargins.Add(new LineModifyTypeMargin());
}
@@ -1092,19 +1222,18 @@ namespace SourceGit.Views
{
base.OnLoaded(e);
- var scroller = this.FindDescendantOfType();
- if (scroller != null)
+ _scrollViewer = this.FindDescendantOfType();
+ if (_scrollViewer != null)
{
- scroller.Bind(ScrollViewer.OffsetProperty, new Binding("ScrollOffset", BindingMode.TwoWay));
- scroller.GotFocus += OnTextViewScrollGotFocus;
+ _scrollViewer.Bind(ScrollViewer.OffsetProperty, new Binding("ScrollOffset", BindingMode.TwoWay));
+ _scrollViewer.ScrollChanged += OnTextViewScrollChanged;
}
}
protected override void OnUnloaded(RoutedEventArgs e)
{
- var scroller = this.FindDescendantOfType();
- if (scroller != null)
- scroller.GotFocus -= OnTextViewScrollGotFocus;
+ if (_scrollViewer != null)
+ _scrollViewer.ScrollChanged -= OnTextViewScrollChanged;
base.OnUnloaded(e);
}
@@ -1141,11 +1270,13 @@ namespace SourceGit.Views
GC.Collect();
}
- private void OnTextViewScrollGotFocus(object sender, GotFocusEventArgs e)
+ private void OnTextViewScrollChanged(object sender, ScrollChangedEventArgs e)
{
- if (EnableChunkSelection && !TextArea.IsPointerOver)
+ if (!TextArea.TextView.IsPointerOver)
TrySetChunk(null);
}
+
+ private ScrollViewer _scrollViewer = null;
}
public class SingleSideTextDiffPresenter : ThemedTextDiffPresenter
@@ -1153,18 +1284,10 @@ namespace SourceGit.Views
public SingleSideTextDiffPresenter() : base(new TextArea(), new TextDocument())
{
TextArea.LeftMargins.Add(new LineNumberMargin(true, false));
- TextArea.LeftMargins.Add(new VerticalSeperatorMargin());
+ TextArea.LeftMargins.Add(new VerticalSeparatorMargin());
TextArea.LeftMargins.Add(new LineModifyTypeMargin());
}
- public void ForceSyncScrollOffset()
- {
- if (_scrollViewer == null)
- return;
- if (DataContext is ViewModels.TwoSideTextDiff diff)
- diff.SyncScrollOffset = _scrollViewer?.Offset ?? Vector.Zero;
- }
-
public override List GetLines()
{
if (DataContext is ViewModels.TwoSideTextDiff diff)
@@ -1179,6 +1302,30 @@ namespace SourceGit.Views
return 0;
}
+ public override void GotoFirstChange()
+ {
+ base.GotoFirstChange();
+ DirectSyncScrollOffset();
+ }
+
+ public override void GotoPrevChange()
+ {
+ base.GotoPrevChange();
+ DirectSyncScrollOffset();
+ }
+
+ public override void GotoNextChange()
+ {
+ base.GotoNextChange();
+ DirectSyncScrollOffset();
+ }
+
+ public override void GotoLastChange()
+ {
+ base.GotoLastChange();
+ DirectSyncScrollOffset();
+ }
+
public override void UpdateSelectedChunk(double y)
{
var diff = DataContext as ViewModels.TwoSideTextDiff;
@@ -1313,12 +1460,9 @@ namespace SourceGit.Views
_scrollViewer = this.FindDescendantOfType();
if (_scrollViewer != null)
{
- _scrollViewer.GotFocus += OnTextViewScrollGotFocus;
_scrollViewer.ScrollChanged += OnTextViewScrollChanged;
_scrollViewer.Bind(ScrollViewer.OffsetProperty, new Binding("SyncScrollOffset", BindingMode.OneWay));
}
-
- TextArea.PointerWheelChanged += OnTextAreaPointerWheelChanged;
}
protected override void OnUnloaded(RoutedEventArgs e)
@@ -1326,12 +1470,9 @@ namespace SourceGit.Views
if (_scrollViewer != null)
{
_scrollViewer.ScrollChanged -= OnTextViewScrollChanged;
- _scrollViewer.GotFocus -= OnTextViewScrollGotFocus;
_scrollViewer = null;
}
- TextArea.PointerWheelChanged -= OnTextAreaPointerWheelChanged;
-
base.OnUnloaded(e);
GC.Collect();
}
@@ -1366,22 +1507,21 @@ namespace SourceGit.Views
}
}
- private void OnTextViewScrollGotFocus(object sender, GotFocusEventArgs e)
- {
- if (EnableChunkSelection && !TextArea.IsPointerOver)
- TrySetChunk(null);
- }
-
private void OnTextViewScrollChanged(object sender, ScrollChangedEventArgs e)
{
- if (TextArea.IsFocused && DataContext is ViewModels.TwoSideTextDiff diff)
+ if (IsPointerOver && DataContext is ViewModels.TwoSideTextDiff diff)
+ {
diff.SyncScrollOffset = _scrollViewer?.Offset ?? Vector.Zero;
+
+ if (!TextArea.TextView.IsPointerOver)
+ TrySetChunk(null);
+ }
}
- private void OnTextAreaPointerWheelChanged(object sender, PointerWheelEventArgs e)
+ private void DirectSyncScrollOffset()
{
- if (!TextArea.IsFocused)
- Focus();
+ if (_scrollViewer is { } && DataContext is ViewModels.TwoSideTextDiff diff)
+ diff.SyncScrollOffset = _scrollViewer?.Offset ?? Vector.Zero;
}
private ScrollViewer _scrollViewer = null;
@@ -1561,13 +1701,13 @@ namespace SourceGit.Views
set => SetValue(BlockNavigationProperty, value);
}
- public static readonly StyledProperty BlockNavigationIndicatorProperty =
- AvaloniaProperty.Register(nameof(BlockNavigationIndicator));
+ public static readonly RoutedEvent BlockNavigationChangedEvent =
+ RoutedEvent.Register(nameof(BlockNavigationChanged), RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
- public string BlockNavigationIndicator
+ public event EventHandler BlockNavigationChanged
{
- get => GetValue(BlockNavigationIndicatorProperty);
- set => SetValue(BlockNavigationIndicatorProperty, value);
+ add { AddHandler(BlockNavigationChangedEvent, value); }
+ remove { RemoveHandler(BlockNavigationChangedEvent, value); }
}
static TextDiffView()
@@ -1603,30 +1743,28 @@ namespace SourceGit.Views
InitializeComponent();
}
+ public void GotoFirstChange()
+ {
+ this.FindDescendantOfType()?.GotoFirstChange();
+ TryRaiseBlockNavigationChanged();
+ }
+
public void GotoPrevChange()
{
- var presenter = this.FindDescendantOfType();
- if (presenter == null)
- return;
-
- presenter.GotoPrevChange();
- if (presenter is SingleSideTextDiffPresenter singleSide)
- singleSide.ForceSyncScrollOffset();
-
- BlockNavigationIndicator = BlockNavigation?.Indicator ?? string.Empty;
+ this.FindDescendantOfType()?.GotoPrevChange();
+ TryRaiseBlockNavigationChanged();
}
public void GotoNextChange()
{
- var presenter = this.FindDescendantOfType();
- if (presenter == null)
- return;
+ this.FindDescendantOfType()?.GotoNextChange();
+ TryRaiseBlockNavigationChanged();
+ }
- presenter.GotoNextChange();
- if (presenter is SingleSideTextDiffPresenter singleSide)
- singleSide.ForceSyncScrollOffset();
-
- BlockNavigationIndicator = BlockNavigation?.Indicator ?? string.Empty;
+ public void GotoLastChange()
+ {
+ this.FindDescendantOfType()?.GotoLastChange();
+ TryRaiseBlockNavigationChanged();
}
protected override void OnDataContextChanged(EventArgs e)
@@ -1676,15 +1814,11 @@ namespace SourceGit.Views
private void RefreshBlockNavigation()
{
if (UseBlockNavigation)
- {
BlockNavigation = new ViewModels.BlockNavigation(Editor.Content);
- BlockNavigationIndicator = BlockNavigation.Indicator;
- }
else
- {
BlockNavigation = null;
- BlockNavigationIndicator = "-/-";
- }
+
+ TryRaiseBlockNavigationChanged();
}
private void OnStageChunk(object _1, RoutedEventArgs _2)
@@ -1717,7 +1851,7 @@ namespace SourceGit.Views
if (!selection.HasLeftChanges)
{
- new Commands.Add(repo.FullPath, [change]).Exec();
+ new Commands.Add(repo.FullPath, [change.Path]).Exec();
}
else
{
@@ -1856,5 +1990,11 @@ namespace SourceGit.Views
repo.MarkWorkingCopyDirtyManually();
repo.SetWatcherEnabled(true);
}
+
+ private void TryRaiseBlockNavigationChanged()
+ {
+ if (UseBlockNavigation)
+ RaiseEvent(new RoutedEventArgs(BlockNavigationChangedEvent));
+ }
}
}
diff --git a/src/Views/Welcome.axaml b/src/Views/Welcome.axaml
index cdc892f4..265c2cd4 100644
--- a/src/Views/Welcome.axaml
+++ b/src/Views/Welcome.axaml
@@ -158,7 +158,7 @@
Classes="italic"
Margin="0,0,8,0"
HorizontalAlignment="Center" VerticalAlignment="Center"
- FontSize="{Binding Source={x:Static vm:Preference.Instance}, Path=DefaultFontSize, Converter={x:Static c:DoubleConverters.Decrease}}"
+ FontSize="{Binding Source={x:Static vm:Preferences.Instance}, Path=DefaultFontSize, Converter={x:Static c:DoubleConverters.Decrease}}"
Text="{DynamicResource Text.Welcome.DragDropTip}"
Foreground="{DynamicResource Brush.FG2}"/>
diff --git a/src/Views/Welcome.axaml.cs b/src/Views/Welcome.axaml.cs
index 500bc571..3ab11782 100644
--- a/src/Views/Welcome.axaml.cs
+++ b/src/Views/Welcome.axaml.cs
@@ -1,5 +1,4 @@
using System;
-using System.IO;
using Avalonia;
using Avalonia.Controls;
@@ -197,7 +196,7 @@ namespace SourceGit.Views
{
foreach (var item in items)
{
- OpenOrInitRepository(item.Path.LocalPath);
+ ViewModels.Welcome.Instance.OpenOrInitRepository(item.Path.LocalPath, null, true);
break;
}
}
@@ -261,7 +260,7 @@ namespace SourceGit.Views
{
foreach (var item in items)
{
- OpenOrInitRepository(item.Path.LocalPath, to);
+ ViewModels.Welcome.Instance.OpenOrInitRepository(item.Path.LocalPath, to, true);
break;
}
}
@@ -290,30 +289,6 @@ namespace SourceGit.Views
}
}
- private void OpenOrInitRepository(string path, ViewModels.RepositoryNode parent = null)
- {
- if (!Directory.Exists(path))
- {
- if (File.Exists(path))
- path = Path.GetDirectoryName(path);
- else
- return;
- }
-
- var test = new Commands.QueryRepositoryRootPath(path).ReadToEnd();
- if (!test.IsSuccess || string.IsNullOrEmpty(test.StdOut))
- {
- ViewModels.Welcome.Instance.InitRepository(path, parent, test.StdErr);
- return;
- }
-
- var node = ViewModels.Preference.Instance.FindOrAddNodeByRepositoryPath(test.StdOut.Trim(), parent, true);
- ViewModels.Welcome.Instance.Refresh();
-
- var launcher = this.FindAncestorOfType()?.DataContext as ViewModels.Launcher;
- launcher?.OpenRepositoryInTab(node, launcher.ActivePage);
- }
-
private bool _pressedTreeNode = false;
private Point _pressedTreeNodePosition = new Point();
private bool _startDragTreeNode = false;
diff --git a/src/Views/WelcomeToolbar.axaml b/src/Views/WelcomeToolbar.axaml
index 59802241..5245a130 100644
--- a/src/Views/WelcomeToolbar.axaml
+++ b/src/Views/WelcomeToolbar.axaml
@@ -18,14 +18,14 @@
-
+
-
+
diff --git a/src/Views/WelcomeToolbar.axaml.cs b/src/Views/WelcomeToolbar.axaml.cs
index 19be5500..9e170c1a 100644
--- a/src/Views/WelcomeToolbar.axaml.cs
+++ b/src/Views/WelcomeToolbar.axaml.cs
@@ -4,7 +4,6 @@ using System.IO;
using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.Platform.Storage;
-using Avalonia.VisualTree;
namespace SourceGit.Views
{
@@ -26,9 +25,9 @@ namespace SourceGit.Views
return;
var options = new FolderPickerOpenOptions() { AllowMultiple = false };
- if (Directory.Exists(ViewModels.Preference.Instance.GitDefaultCloneDir))
+ if (Directory.Exists(ViewModels.Preferences.Instance.GitDefaultCloneDir))
{
- var folder = await topLevel.StorageProvider.TryGetFolderFromPathAsync(ViewModels.Preference.Instance.GitDefaultCloneDir);
+ var folder = await topLevel.StorageProvider.TryGetFolderFromPathAsync(ViewModels.Preferences.Instance.GitDefaultCloneDir);
options.SuggestedStartLocation = folder;
}
@@ -36,7 +35,7 @@ namespace SourceGit.Views
{
var selected = await topLevel.StorageProvider.OpenFolderPickerAsync(options);
if (selected.Count == 1)
- OpenOrInitRepository(selected[0].Path.LocalPath);
+ ViewModels.Welcome.Instance.OpenOrInitRepository(selected[0].Path.LocalPath, null, false);
}
catch (Exception exception)
{
@@ -45,30 +44,6 @@ namespace SourceGit.Views
e.Handled = true;
}
-
- private void OpenOrInitRepository(string path, ViewModels.RepositoryNode parent = null)
- {
- if (!Directory.Exists(path))
- {
- if (File.Exists(path))
- path = Path.GetDirectoryName(path);
- else
- return;
- }
-
- var test = new Commands.QueryRepositoryRootPath(path).ReadToEnd();
- if (!test.IsSuccess || string.IsNullOrEmpty(test.StdOut))
- {
- ViewModels.Welcome.Instance.InitRepository(path, parent, test.StdErr);
- return;
- }
-
- var node = ViewModels.Preference.Instance.FindOrAddNodeByRepositoryPath(test.StdOut.Trim(), parent, false);
- ViewModels.Welcome.Instance.Refresh();
-
- var launcher = this.FindAncestorOfType()?.DataContext as ViewModels.Launcher;
- launcher?.OpenRepositoryInTab(node, launcher.ActivePage);
- }
}
}
diff --git a/src/Views/WorkingCopy.axaml b/src/Views/WorkingCopy.axaml
index 342ea4e0..41d80b04 100644
--- a/src/Views/WorkingCopy.axaml
+++ b/src/Views/WorkingCopy.axaml
@@ -11,7 +11,7 @@
x:DataType="vm:WorkingCopy">
-
+
@@ -19,16 +19,49 @@
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
@@ -48,6 +81,15 @@
ToolTip.Tip="{DynamicResource Text.WorkingCopy.IncludeUntracked}"
IsChecked="{Binding IncludeUntracked, Mode=TwoWay}"/>
+
+
+
-
-
+ ViewMode="{Binding Source={x:Static vm:Preferences.Instance}, Path=UnstagedChangeViewMode, Mode=TwoWay}"/>
@@ -82,22 +124,22 @@
IsUnstagedChange="True"
SelectionMode="Multiple"
Background="{DynamicResource Brush.Contents}"
- ViewMode="{Binding Source={x:Static vm:Preference.Instance}, Path=UnstagedChangeViewMode}"
- Changes="{Binding Unstaged}"
+ ViewMode="{Binding Source={x:Static vm:Preferences.Instance}, Path=UnstagedChangeViewMode}"
+ Changes="{Binding VisibleUnstaged}"
SelectedChanges="{Binding SelectedUnstaged, Mode=TwoWay}"
ContextRequested="OnUnstagedContextRequested"
ChangeDoubleTapped="OnUnstagedChangeDoubleTapped"
KeyDown="OnUnstagedKeyDown"/>
-
+
-
-
+
@@ -120,18 +162,19 @@
+ ViewMode="{Binding Source={x:Static vm:Preferences.Instance}, Path=StagedChangeViewMode, Mode=TwoWay}"/>
-
+
-
+
@@ -171,75 +214,7 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
@@ -258,7 +233,7 @@
-
+
+ IsChecked="{Binding EnableSignOff, Mode=TwoWay}"
+ Content="{DynamicResource Text.WorkingCopy.SignOff}"
+ ToolTip.Tip="--signoff"
+ ToolTip.Placement="Top"
+ ToolTip.VerticalOffset="0"/>
+
+
+
+
-
-
+ IsVisible="{Binding InProgressContext, Converter={x:Static ObjectConverters.IsNotNull}}">
+
+
+
+
+
+
-
+
@@ -336,14 +334,28 @@
+
+
+
+
+
+
+
-
+
+ HotKey="{OnPlatform Ctrl+Shift+Enter, macOS=⌘+Shift+Enter}">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
diff --git a/src/Views/WorkingCopy.axaml.cs b/src/Views/WorkingCopy.axaml.cs
index df45a7f1..4ae4d779 100644
--- a/src/Views/WorkingCopy.axaml.cs
+++ b/src/Views/WorkingCopy.axaml.cs
@@ -17,7 +17,7 @@ namespace SourceGit.Views
if (grid == null)
return;
- var layout = ViewModels.Preference.Instance.Layout;
+ var layout = ViewModels.Preferences.Instance.Layout;
var width = grid.Bounds.Width;
var maxLeft = width - 304;