diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 369a122a5..48859b540 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,7 +13,7 @@ jobs:
os: windows-2022
runtime: win-arm64
- name: macOS (Intel)
- os: macos-13
+ os: macos-15-intel
runtime: osx-x64
- name: macOS (Apple Silicon)
os: macos-latest
@@ -43,7 +43,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
- dotnet-version: 9.0.x
+ dotnet-version: 10.0.x
- name: Configure arm64 packages
if: matrix.runtime == 'linux-arm64'
run: |
diff --git a/.github/workflows/format-check.yml b/.github/workflows/format-check.yml
index 5e75fb2a3..59720f15a 100644
--- a/.github/workflows/format-check.yml
+++ b/.github/workflows/format-check.yml
@@ -18,7 +18,7 @@ jobs:
- name: Set up .NET
uses: actions/setup-dotnet@v4
with:
- dotnet-version: 9.0.x
+ dotnet-version: 10.0.x
- name: Run formatting check
run: dotnet format --verify-no-changes
diff --git a/.github/workflows/homebrew-notify.yml b/.github/workflows/homebrew-notify.yml
new file mode 100644
index 000000000..d0538b37a
--- /dev/null
+++ b/.github/workflows/homebrew-notify.yml
@@ -0,0 +1,22 @@
+name: Notify Homebrew Tap
+
+on:
+ release:
+ types: [published]
+
+jobs:
+ notify-homebrew:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Notify Homebrew tap
+ env:
+ TAG: ${{ github.event.release.tag_name }}
+ HOMEBREW_TAP_REPO_TOKEN: ${{ secrets.HOMEBREW_TAP_REPO_TOKEN }}
+ run: |
+ echo "📢 Notifying Homebrew tap of new release $TAG..."
+ curl -X POST \
+ -H "Authorization: token $HOMEBREW_TAP_REPO_TOKEN" \
+ -H "Accept: application/vnd.github.v3+json" \
+ https://api.github.com/repos/ybeapps/homebrew-sourcegit/dispatches \
+ -d "{\"event_type\":\"new-sourcegit-release\",\"client_payload\":{\"version\":\"$TAG\"}}"
+ echo "✅ Homebrew tap notified successfully"
diff --git a/.github/workflows/package.yml b/.github/workflows/package.yml
index 37d8afbab..d203dd2e2 100644
--- a/.github/workflows/package.yml
+++ b/.github/workflows/package.yml
@@ -22,11 +22,11 @@ jobs:
name: sourcegit.${{ matrix.runtime }}
path: build/SourceGit
- name: Package
- shell: bash
+ shell: pwsh
env:
VERSION: ${{ inputs.version }}
RUNTIME: ${{ matrix.runtime }}
- run: ./build/scripts/package.windows.sh
+ run: ./build/scripts/package.win.ps1
- name: Upload package artifact
uses: actions/upload-artifact@v4
with:
diff --git a/README.md b/README.md
index e84f438fa..c4ac40081 100644
--- a/README.md
+++ b/README.md
@@ -6,12 +6,26 @@
[](https://github.com/sourcegit-scm/sourcegit/releases/latest)
[](https://github.com/sourcegit-scm/sourcegit/releases)
+## Screenshots
+
+* Dark Theme
+
+ 
+
+* Light Theme
+
+ 
+
+* Custom
+
+ You can find custom themes from [sourcegit-theme](https://github.com/sourcegit-scm/sourcegit-theme.git). And welcome to share your own themes.
+
## Highlights
* Supports Windows/macOS/Linux
* Opensource/Free
* Fast
-* Deutsch/English/Español/Français/Italiano/Português/Русский/Українська/简体中文/繁體中文/日本語/தமிழ் (Tamil)
+* Deutsch/English/Español/Bahasa Indonesia/Français/Italiano/Português/Русский/Українська/简体中文/繁體中文/日本語/தமிழ் (Tamil)/한국어
* Built-in light/dark themes
* Customize theme
* Visual commit graph
@@ -43,7 +57,9 @@
* Issue Link
* Workspace
* Custom Action
+* Create PR on GitHub/Gitlab/Gitea/Gitee/Bitbucket...
* Using AI to generate commit message (C# port of [anjerodev/commitollama](https://github.com/anjerodev/commitollama))
+* Built-in conventional commit message helper.
> [!WARNING]
> **Linux** only tested on **Debian 12** on both **X11** & **Wayland**.
@@ -73,12 +89,6 @@ This software creates a folder `$"{System.Environment.SpecialFolder.ApplicationD
For **Windows** users:
* **MSYS Git is NOT supported**. Please use official [Git for Windows](https://git-scm.com/download/win) instead.
-* You can install the latest stable from `winget` with follow commands:
- ```shell
- winget install SourceGit
- ```
-> [!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 `scoop` with follow commands:
```shell
scoop bucket add extras
@@ -86,17 +96,25 @@ For **Windows** users:
```
* Pre-built binaries can be found in [Releases](https://github.com/sourcegit-scm/sourcegit/releases/latest)
+> [!NOTE]
+> `git-flow` is no longer shipped with **Git for Windows** since `2.51.1`. You can use it by following these steps:
+> * Download [git-flow-next](https://github.com/gittower/git-flow-next/releases)
+> * Unzip & Rename the `git-flow-next` to `git-flow`
+> * Copy to `$GIT_INSTALL_DIR/cmd` or just add its path to you `PATH` directly
+
For **macOS** users:
-* Thanks [@ybeapps](https://github.com/ybeapps) for making `SourceGit` available on `Homebrew`. You can simply install it with following command:
+* Thanks [@ybeapps](https://github.com/ybeapps) for making `SourceGit` available on `Homebrew`:
```shell
- brew tap ybeapps/homebrew-sourcegit
- brew install --cask --no-quarantine sourcegit
+ brew install --cask sourcegit
```
* If you want to install `SourceGit.app` from GitHub Release manually, you need run following command to make sure it works:
```shell
sudo xattr -cr /Applications/SourceGit.app
```
+> [!NOTE]
+> macOS packages in the `Release` page of this project are all unsigned. If you are worried about potential security issues with the above command, you can download the signed package from the [distribution repository](https://github.com/ybeapps/homebrew-sourcegit/releases) provided by [@ybeapps](https://github.com/ybeapps) (there is no need to execute the above command while installing `SourceGit`).
+
* Make sure [git-credential-manager](https://github.com/git-ecosystem/git-credential-manager/releases) is installed on your mac.
* You can run `echo $PATH > ~/Library/Application\ Support/SourceGit/PATH` to generate a custom PATH env file to introduce `PATH` env to SourceGit.
@@ -155,7 +173,7 @@ This app supports open repository in external tools listed in the table below.
| Cursor | YES | YES | YES |
| Fleet | YES | YES | YES |
| Sublime Text | YES | YES | YES |
-| Zed | NO | YES | YES |
+| Zed | YES | YES | YES |
| Visual Studio | YES | NO | NO |
> [!NOTE]
@@ -172,19 +190,26 @@ This app supports open repository in external tools listed in the table below.
> [!NOTE]
> This app also supports a lot of `JetBrains` IDEs, installing `JetBrains Toolbox` will help this app to find them.
-## Screenshots
+## Conventional Commit Helper
-* Dark Theme
-
- 
+You can define your own conventional commit types (per-repository) by following steps:
-* Light Theme
-
- 
-
-* Custom
-
- You can find custom themes from [sourcegit-theme](https://github.com/sourcegit-scm/sourcegit-theme.git). And welcome to share your own themes.
+1. Create a json file with your own conventional commit type definitions. For example:
+```json
+[
+ {
+ "Name": "New Feature",
+ "Type": "Feature",
+ "Description": "Adding a new feature"
+ },
+ {
+ "Name": "Bug Fixes",
+ "Type": "Fix",
+ "Description": "Fixing a bug"
+ }
+]
+```
+2. Configure the `Conventional Commit Types` in repository configuration window.
## Contributing
diff --git a/SourceGit.sln b/SourceGit.sln
deleted file mode 100644
index dad5a4757..000000000
--- a/SourceGit.sln
+++ /dev/null
@@ -1,123 +0,0 @@
-
-Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio Version 17
-VisualStudioVersion = 17.9.34714.143
-MinimumVisualStudioVersion = 10.0.40219.1
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SourceGit", "src\SourceGit.csproj", "{2091C34D-4A17-4375-BEF3-4D60BE8113E4}"
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{773082AC-D9C8-4186-8521-4B6A7BEE6158}"
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "resources", "resources", "{FD384607-ED99-47B7-AF31-FB245841BC92}"
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".github", ".github", "{F45A9D95-AF25-42D8-BBAC-8259C9EEE820}"
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{67B6D05F-A000-40BA-ADB4-C9065F880D7B}"
- ProjectSection(SolutionItems) = preProject
- .github\workflows\build.yml = .github\workflows\build.yml
- .github\workflows\ci.yml = .github\workflows\ci.yml
- .github\workflows\package.yml = .github\workflows\package.yml
- .github\workflows\release.yml = .github\workflows\release.yml
- .github\workflows\localization-check.yml = .github\workflows\localization-check.yml
- .github\workflows\format-check.yml = .github\workflows\format-check.yml
- EndProjectSection
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{49A7C2D6-558C-4FAA-8F5D-EEE81497AED7}"
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "files", "files", "{3AB707DB-A02C-4AFC-BF12-D7DF2B333BAC}"
- ProjectSection(SolutionItems) = preProject
- .editorconfig = .editorconfig
- .gitattributes = .gitattributes
- .gitignore = .gitignore
- global.json = global.json
- LICENSE = LICENSE
- README.md = README.md
- VERSION = VERSION
- EndProjectSection
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "app", "app", "{ABC98884-F023-4EF4-A9C9-5DE9452BE955}"
- ProjectSection(SolutionItems) = preProject
- build\resources\app\App.icns = build\resources\app\App.icns
- build\resources\app\App.plist = build\resources\app\App.plist
- EndProjectSection
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "_common", "_common", "{04FD74B1-FBDB-496E-A48F-3D59D71FF952}"
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "usr", "usr", "{76639799-54BC-45E8-BD90-F45F63ACD11D}"
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "share", "share", "{A3ABAA7C-EE14-4448-B466-6E69C1347E7D}"
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "applications", "applications", "{2AF28D3B-14A8-46A8-B828-157FAAB1B06F}"
- ProjectSection(SolutionItems) = preProject
- build\resources\_common\usr\share\applications\sourcegit.desktop = build\resources\_common\usr\share\applications\sourcegit.desktop
- EndProjectSection
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "icons", "icons", "{7166EC6C-17F5-4B5E-B38E-1E53C81EACF6}"
- ProjectSection(SolutionItems) = preProject
- build\resources\_common\usr\share\icons\sourcegit.png = build\resources\_common\usr\share\icons\sourcegit.png
- EndProjectSection
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "deb", "deb", "{9C2F0CDA-B56E-44A5-94B6-F3EA7AC20CDC}"
-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}"
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SPECS", "SPECS", "{7802CD7A-591B-4EDD-96F8-9BF3F61692E4}"
- ProjectSection(SolutionItems) = preProject
- build\resources\rpm\SPECS\build.spec = build\resources\rpm\SPECS\build.spec
- EndProjectSection
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "appimage", "appimage", "{5D125DD9-B48A-491F-B2FB-D7830D74C4DC}"
- ProjectSection(SolutionItems) = preProject
- build\resources\appimage\sourcegit.appdata.xml = build\resources\appimage\sourcegit.appdata.xml
- build\resources\appimage\sourcegit.png = build\resources\appimage\sourcegit.png
- EndProjectSection
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "scripts", "scripts", "{C54D4001-9940-477C-A0B6-E795ED0A3209}"
- ProjectSection(SolutionItems) = preProject
- build\scripts\localization-check.js = build\scripts\localization-check.js
- build\scripts\package.linux.sh = build\scripts\package.linux.sh
- build\scripts\package.osx-app.sh = build\scripts\package.osx-app.sh
- build\scripts\package.windows.sh = build\scripts\package.windows.sh
- EndProjectSection
-EndProject
-Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|Any CPU = Debug|Any CPU
- Release|Any CPU = Release|Any CPU
- EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {2091C34D-4A17-4375-BEF3-4D60BE8113E4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {2091C34D-4A17-4375-BEF3-4D60BE8113E4}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {2091C34D-4A17-4375-BEF3-4D60BE8113E4}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {2091C34D-4A17-4375-BEF3-4D60BE8113E4}.Release|Any CPU.Build.0 = Release|Any CPU
- EndGlobalSection
- GlobalSection(SolutionProperties) = preSolution
- HideSolutionNode = FALSE
- EndGlobalSection
- GlobalSection(NestedProjects) = preSolution
- {2091C34D-4A17-4375-BEF3-4D60BE8113E4} = {49A7C2D6-558C-4FAA-8F5D-EEE81497AED7}
- {FD384607-ED99-47B7-AF31-FB245841BC92} = {773082AC-D9C8-4186-8521-4B6A7BEE6158}
- {67B6D05F-A000-40BA-ADB4-C9065F880D7B} = {F45A9D95-AF25-42D8-BBAC-8259C9EEE820}
- {ABC98884-F023-4EF4-A9C9-5DE9452BE955} = {FD384607-ED99-47B7-AF31-FB245841BC92}
- {04FD74B1-FBDB-496E-A48F-3D59D71FF952} = {FD384607-ED99-47B7-AF31-FB245841BC92}
- {76639799-54BC-45E8-BD90-F45F63ACD11D} = {04FD74B1-FBDB-496E-A48F-3D59D71FF952}
- {A3ABAA7C-EE14-4448-B466-6E69C1347E7D} = {76639799-54BC-45E8-BD90-F45F63ACD11D}
- {2AF28D3B-14A8-46A8-B828-157FAAB1B06F} = {A3ABAA7C-EE14-4448-B466-6E69C1347E7D}
- {7166EC6C-17F5-4B5E-B38E-1E53C81EACF6} = {A3ABAA7C-EE14-4448-B466-6E69C1347E7D}
- {9C2F0CDA-B56E-44A5-94B6-F3EA7AC20CDC} = {FD384607-ED99-47B7-AF31-FB245841BC92}
- {F101849D-BDB7-40D4-A516-751150C3CCFC} = {9C2F0CDA-B56E-44A5-94B6-F3EA7AC20CDC}
- {9BA0B044-0CC9-46F8-B551-204F149BF45D} = {FD384607-ED99-47B7-AF31-FB245841BC92}
- {7802CD7A-591B-4EDD-96F8-9BF3F61692E4} = {9BA0B044-0CC9-46F8-B551-204F149BF45D}
- {5D125DD9-B48A-491F-B2FB-D7830D74C4DC} = {FD384607-ED99-47B7-AF31-FB245841BC92}
- {C54D4001-9940-477C-A0B6-E795ED0A3209} = {773082AC-D9C8-4186-8521-4B6A7BEE6158}
- EndGlobalSection
- GlobalSection(ExtensibilityGlobals) = postSolution
- SolutionGuid = {7FF1B9C6-B5BF-4A50-949F-4B407A0E31C9}
- EndGlobalSection
-EndGlobal
diff --git a/SourceGit.slnx b/SourceGit.slnx
new file mode 100644
index 000000000..080f2e63e
--- /dev/null
+++ b/SourceGit.slnx
@@ -0,0 +1,69 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/THIRD-PARTY-LICENSES.md b/THIRD-PARTY-LICENSES.md
index efc5676f9..5c696b1ba 100644
--- a/THIRD-PARTY-LICENSES.md
+++ b/THIRD-PARTY-LICENSES.md
@@ -7,42 +7,42 @@ The project uses the following third-party libraries or assets
### AvaloniaUI
- **Source**: https://github.com/AvaloniaUI/Avalonia
-- **Version**: 11.2.8
+- **Version**: 11.3.9
- **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
+- **Version**: 11.3.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
+- **Version**: 2.0.0-rc6.1
- **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
+- **Version**: 1.0.70
- **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-beta.4
+- **Version**: 2.8.0
- **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-beta.4
+- **Version**: 2.8.0-beta.1
- **License**: MIT License
- **License Link**: https://github.com/Azure/azure-sdk-for-net/blob/main/LICENSE.txt
@@ -56,7 +56,7 @@ The project uses the following third-party libraries or assets
### Pfim
- **Source**: https://github.com/nickbabcock/Pfim
-- **Version**: 0.11.3
+- **Version**: 0.11.4
- **License**: MIT License
- **License Link**: https://github.com/nickbabcock/Pfim/blob/master/LICENSE.txt
@@ -98,3 +98,10 @@ The project uses the following third-party libraries or assets
- **Commit**: 0e89ecdb13650dbbe5a1e85b47b2e1530bf2f355
- **License**: MIT License
- **License Link**: https://github.com/samuel-weinhardt/vscode-jsp-lang/blob/0e89ecdb13650dbbe5a1e85b47b2e1530bf2f355/LICENSE
+
+### vuejs-language-tools
+
+- **Source**: https://github.com/vuejs/language-tools
+- **Commit**: 68d98dc57f8486c2946ae28dc86bf8e91d45da4d
+- **License**: MIT License
+- **License Link**: https://github.com/vuejs/language-tools/blob/68d98dc57f8486c2946ae28dc86bf8e91d45da4d/LICENSE
diff --git a/TRANSLATION.md b/TRANSLATION.md
index 65f1b5142..4014aadf9 100644
--- a/TRANSLATION.md
+++ b/TRANSLATION.md
@@ -6,293 +6,180 @@ This document shows the translation status of each locale file in the repository
### 
-### 
+### 
+
+
+Missing keys in de_DE.axaml
+
+- Text.Hotkeys.Global.ShowWorkspaceDropdownMenu
+- Text.PageTabBar.Tab.MoveToWorkspace
+- Text.Preferences.DiffMerge.DiffArgs
+- Text.Preferences.DiffMerge.DiffArgs.Tip
+- Text.Preferences.DiffMerge.MergeArgs
+- Text.Preferences.DiffMerge.MergeArgs.Tip
+- Text.Preferences.Shell.Args
+- Text.Preferences.Shell.Args.Tip
+- Text.SquashOrFixup.Squash
+- Text.SquashOrFixup.Fixup
+- Text.SquashOrFixup.Into
+
+
### 
-### 
+### 
Missing keys in fr_FR.axaml
-- Text.AddToIgnore
-- Text.AddToIgnore.Pattern
-- Text.AddToIgnore.Storage
-- Text.Askpass.Passphrase
-- Text.Avatar.Load
-- Text.Bisect
-- Text.Bisect.Abort
-- Text.Bisect.Bad
-- Text.Bisect.Detecting
-- Text.Bisect.Good
-- Text.Bisect.Skip
-- Text.Bisect.WaitingForRange
-- Text.BranchCM.ResetToSelectedCommit
-- Text.BranchTree.Local
-- Text.BranchTree.Remote
-- Text.BranchTree.Tracking
-- Text.BranchTree.URL
-- Text.ChangeSubmoduleUrl
-- Text.ChangeSubmoduleUrl.Submodule
-- Text.ChangeSubmoduleUrl.URL
-- Text.Checkout.RecurseSubmodules
-- Text.Checkout.WarnLostCommits
-- Text.Checkout.WithFastForward
-- Text.Checkout.WithFastForward.Upstream
-- Text.CommitCM.CopyAuthor
-- Text.CommitCM.CopyCommitMessage
-- Text.CommitCM.CopyCommitter
-- Text.CommitCM.CopySubject
-- Text.CommitCM.InteractiveRebase
-- Text.CommitCM.InteractiveRebase.Drop
-- Text.CommitCM.InteractiveRebase.Edit
-- Text.CommitCM.InteractiveRebase.Fixup
-- Text.CommitCM.InteractiveRebase.Manually
-- Text.CommitCM.InteractiveRebase.Reword
-- Text.CommitCM.InteractiveRebase.Squash
-- Text.CommitCM.PushRevision
-- Text.CommitCM.Rebase
-- Text.CommitCM.Reset
-- Text.CommitDetail.Changes.Count
-- Text.CommitDetail.Info.Key
-- Text.CommitDetail.Info.Signer
-- Text.CommitMessageTextBox.SubjectCount
+- Text.BranchCM.EditDescription
+- Text.CommitMessageTextBox.Placeholder
+- Text.EditBranchDescription
+- Text.EditBranchDescription.Target
+- Text.FileCM.CustomAction
+- Text.Hotkeys.Global.ShowWorkspaceDropdownMenu
+- Text.OpenFile
+- Text.PageTabBar.Tab.MoveToWorkspace
+- Text.PageTabBar.Tab.Refresh
+- Text.Preferences.DiffMerge.DiffArgs
+- Text.Preferences.DiffMerge.DiffArgs.Tip
+- Text.Preferences.DiffMerge.MergeArgs
+- Text.Preferences.DiffMerge.MergeArgs.Tip
+- Text.Preferences.Shell.Args
+- Text.Preferences.Shell.Args.Tip
+- Text.SquashOrFixup.Squash
+- Text.SquashOrFixup.Fixup
+- Text.SquashOrFixup.Into
+
+
+
+### 
+
+
+Missing keys in id_ID.axaml
+
+- Text.About.ReleaseNotes
+- Text.Blame.BlameOnPreviousRevision
+- Text.BranchCM.CreatePR
+- Text.BranchCM.CreatePRForUpstream
+- Text.BranchCM.EditDescription
+- Text.CommitCM.Drop
+- Text.CommitMessageTextBox.Placeholder
- Text.Configure.CommitMessageTemplate.BuiltinVars
-- Text.Configure.CustomAction.Arguments.Tip
-- Text.Configure.CustomAction.InputControls
-- Text.Configure.CustomAction.InputControls.Edit
-- Text.Configure.CustomAction.InputControls.Tip
-- Text.Configure.CustomAction.Scope.Tag
-- Text.Configure.Git.PreferredMergeMode
-- Text.Configure.IssueTracker.Share
-- Text.ConfigureCustomActionControls
-- Text.ConfigureCustomActionControls.CheckedValue
-- Text.ConfigureCustomActionControls.CheckedValue.Tip
-- Text.ConfigureCustomActionControls.Description
-- Text.ConfigureCustomActionControls.DefaultValue
-- Text.ConfigureCustomActionControls.IsFolder
-- Text.ConfigureCustomActionControls.Label
-- Text.ConfigureCustomActionControls.Options
-- Text.ConfigureCustomActionControls.Options.Tip
-- Text.ConfigureCustomActionControls.Type
-- Text.ConfirmEmptyCommit.Continue
-- Text.ConfirmEmptyCommit.NoLocalChanges
-- Text.ConfirmEmptyCommit.StageAllThenCommit
-- Text.ConfirmEmptyCommit.WithLocalChanges
-- Text.ConfirmRestart.Title
-- Text.ConfirmRestart.Message
-- Text.CreateBranch.OverwriteExisting
-- Text.DeinitSubmodule
-- Text.DeinitSubmodule.Force
-- Text.DeinitSubmodule.Path
-- Text.Diff.Image.Blend
-- Text.Diff.Image.SideBySide
-- Text.Diff.Image.Swipe
-- Text.Diff.New
-- Text.Diff.Old
-- Text.Diff.Submodule.Deleted
-- Text.DirHistories
-- Text.Discard.IncludeUntracked
-- Text.ExecuteCustomAction.Target
-- Text.ExecuteCustomAction.Repository
-- Text.GitFlow.FinishWithPush
-- Text.GitFlow.FinishWithSquash
-- Text.Hotkeys.Global.SwitchWorkspace
-- Text.Hotkeys.Global.SwitchTab
-- Text.Hotkeys.TextEditor.OpenExternalMergeTool
-- Text.InteractiveRebase.ReorderTip
-- Text.Launcher.Workspaces
-- Text.Launcher.Pages
-- Text.Merge.Edit
-- Text.MoveSubmodule
-- Text.MoveSubmodule.MoveTo
-- Text.MoveSubmodule.Submodule
-- Text.Preferences.Git.IgnoreCRAtEOLInDiff
-- Text.Preferences.Git.UseLibsecret
-- Text.Pull.RecurseSubmodules
-- Text.Push.New
-- Text.Push.Revision
-- Text.Push.Revision.Title
-- Text.Repository.BranchSort
-- Text.Repository.BranchSort.ByCommitterDate
-- Text.Repository.BranchSort.ByName
-- Text.Repository.ClearStashes
-- Text.Repository.OnlyHighlightCurrentBranchInGraph
-- Text.Repository.Search.ByContent
-- Text.Repository.Search.ByPath
-- Text.Repository.ShowDecoratedCommitsOnly
-- Text.Repository.ShowFirstParentOnly
-- Text.Repository.ShowFlags
-- Text.Repository.ShowLostCommits
-- Text.Repository.ShowSubmodulesAsTree
-- Text.Repository.UseRelativeTimeInGraph
-- Text.Repository.ViewLogs
-- Text.Repository.Visit
-- Text.ResetWithoutCheckout
-- Text.ResetWithoutCheckout.MoveTo
-- Text.ResetWithoutCheckout.Target
-- Text.SetSubmoduleBranch
-- Text.SetSubmoduleBranch.Submodule
-- Text.SetSubmoduleBranch.Current
-- Text.SetSubmoduleBranch.New
-- Text.SetSubmoduleBranch.New.Tip
-- Text.Stash.Mode
-- Text.StashCM.CopyMessage
-- Text.Submodule.Branch
-- Text.Submodule.Deinit
-- Text.Submodule.Histories
-- Text.Submodule.Move
-- Text.Submodule.RelativePath
-- Text.Submodule.RelativePath.Placeholder
-- Text.Submodule.SetBranch
-- Text.Submodule.SetURL
-- Text.Submodule.Status
-- Text.Submodule.Status.Modified
-- Text.Submodule.Status.NotInited
-- Text.Submodule.Status.RevisionChanged
-- Text.Submodule.Status.Unmerged
-- Text.Submodule.Update
-- Text.Submodule.URL
-- Text.TagCM.CustomAction
-- Text.UpdateSubmodules.UpdateToRemoteTrackingBranch
-- Text.ViewLogs
-- Text.ViewLogs.Clear
-- Text.ViewLogs.CopyLog
-- Text.ViewLogs.Delete
-- Text.WorkingCopy.AddToGitIgnore.InFolder
-- Text.WorkingCopy.ConfirmCommitWithDetachedHead
-- Text.WorkingCopy.ConfirmCommitWithFilter
-- Text.WorkingCopy.Conflicts.OpenExternalMergeTool
-- Text.WorkingCopy.Conflicts.OpenExternalMergeToolAllConflicts
-- Text.WorkingCopy.Conflicts.UseMine
-- Text.WorkingCopy.Conflicts.UseTheirs
-- Text.WorkingCopy.ResetAuthor
+- Text.Configure.Git.ConventionalTypesOverride
+- Text.ConfigureCustomActionControls.StringValue.Tip
+- Text.DropHead
+- Text.DropHead.Commit
+- Text.DropHead.NewHead
+- Text.EditBranchDescription
+- Text.EditBranchDescription.Target
+- Text.FileCM.CustomAction
+- Text.GitLFS.Locks.UnlockAllMyLocks
+- Text.GitLFS.Locks.UnlockAllMyLocks.Confirm
+- Text.Hotkeys.Global.ShowWorkspaceDropdownMenu
+- Text.Hotkeys.Repo.OpenCommandPalette
+- Text.Launcher.Commands
+- Text.Launcher.OpenRepository
+- Text.Open
+- Text.Open.SystemDefaultEditor
+- Text.OpenFile
+- Text.PageTabBar.Tab.MoveToWorkspace
+- Text.PageTabBar.Tab.Refresh
+- Text.Preferences.DiffMerge.DiffArgs
+- Text.Preferences.DiffMerge.DiffArgs.Tip
+- Text.Preferences.DiffMerge.MergeArgs
+- Text.Preferences.DiffMerge.MergeArgs.Tip
+- Text.Preferences.Shell.Args
+- Text.Preferences.Shell.Args.Tip
+- Text.PushToNewBranch
+- Text.PushToNewBranch.Title
+- Text.SquashOrFixup.Squash
+- Text.SquashOrFixup.Fixup
+- Text.SquashOrFixup.Into
-### 
+### 
Missing keys in it_IT.axaml
-- Text.AddToIgnore
-- Text.AddToIgnore.Pattern
-- Text.AddToIgnore.Storage
-- Text.Askpass.Passphrase
-- Text.Avatar.Load
-- Text.BranchCM.ResetToSelectedCommit
-- Text.BranchTree.Local
-- Text.BranchTree.Remote
-- Text.BranchTree.Tracking
-- Text.BranchTree.URL
-- Text.ChangeSubmoduleUrl
-- Text.ChangeSubmoduleUrl.Submodule
-- Text.ChangeSubmoduleUrl.URL
-- Text.Checkout.WarnLostCommits
-- Text.Checkout.WithFastForward
-- Text.Checkout.WithFastForward.Upstream
-- Text.CommitCM.CopyCommitMessage
-- Text.CommitCM.InteractiveRebase
-- Text.CommitCM.InteractiveRebase.Drop
-- Text.CommitCM.InteractiveRebase.Edit
-- Text.CommitCM.InteractiveRebase.Fixup
-- Text.CommitCM.InteractiveRebase.Manually
-- Text.CommitCM.InteractiveRebase.Reword
-- Text.CommitCM.InteractiveRebase.Squash
-- Text.CommitCM.PushRevision
-- Text.CommitCM.Rebase
-- Text.CommitCM.Reset
-- Text.CommitDetail.Changes.Count
-- Text.CommitDetail.Info.Key
-- Text.CommitDetail.Info.Signer
+- Text.About.ReleaseNotes
+- Text.Blame.BlameOnPreviousRevision
+- Text.BranchCM.CreatePR
+- Text.BranchCM.CreatePRForUpstream
+- Text.BranchCM.EditDescription
+- Text.BranchCM.SwitchToWorktree
+- Text.BranchTree.Ahead
+- Text.BranchTree.AheadBehind
+- Text.BranchTree.Behind
+- Text.BranchTree.Status
+- Text.BranchTree.Worktree
+- Text.CommitCM.Drop
+- Text.CommitDetail.Info.CopyEmail
+- Text.CommitDetail.Info.CopyName
+- Text.CommitDetail.Info.CopyNameAndEmail
+- Text.CommitMessageTextBox.Placeholder
- Text.Configure.CommitMessageTemplate.BuiltinVars
-- Text.Configure.CustomAction.Arguments.Tip
-- Text.Configure.CustomAction.InputControls
-- Text.Configure.CustomAction.InputControls.Edit
-- Text.Configure.CustomAction.InputControls.Tip
-- Text.Configure.CustomAction.Scope.Tag
-- Text.Configure.IssueTracker.Share
-- Text.ConfigureCustomActionControls
-- Text.ConfigureCustomActionControls.CheckedValue
-- Text.ConfigureCustomActionControls.CheckedValue.Tip
-- Text.ConfigureCustomActionControls.Description
-- Text.ConfigureCustomActionControls.DefaultValue
-- Text.ConfigureCustomActionControls.IsFolder
-- Text.ConfigureCustomActionControls.Label
-- Text.ConfigureCustomActionControls.Options
-- Text.ConfigureCustomActionControls.Options.Tip
-- Text.ConfigureCustomActionControls.Type
-- Text.ConfirmRestart.Title
-- Text.ConfirmRestart.Message
-- Text.CreateBranch.OverwriteExisting
-- Text.DeinitSubmodule
-- Text.DeinitSubmodule.Force
-- Text.DeinitSubmodule.Path
-- Text.Diff.Image.Blend
-- Text.Diff.Image.SideBySide
-- Text.Diff.Image.Swipe
-- Text.Diff.New
-- Text.Diff.Old
-- Text.Diff.Submodule.Deleted
-- Text.DirHistories
-- Text.Discard.IncludeUntracked
-- Text.ExecuteCustomAction.Target
-- Text.ExecuteCustomAction.Repository
-- Text.Hotkeys.Global.SwitchWorkspace
-- Text.Hotkeys.Global.SwitchTab
-- Text.InteractiveRebase.ReorderTip
-- Text.Launcher.Workspaces
-- Text.Launcher.Pages
-- Text.Merge.Edit
-- Text.MoveSubmodule
-- Text.MoveSubmodule.MoveTo
-- Text.MoveSubmodule.Submodule
-- Text.Preferences.Git.UseLibsecret
-- Text.Pull.RecurseSubmodules
-- Text.Push.New
-- Text.Push.Revision
-- Text.Push.Revision.Title
-- Text.Repository.ClearStashes
-- Text.Repository.OnlyHighlightCurrentBranchInGraph
-- Text.Repository.Search.ByPath
-- Text.Repository.ShowDecoratedCommitsOnly
-- Text.Repository.ShowFirstParentOnly
-- Text.Repository.ShowFlags
-- Text.Repository.ShowLostCommits
-- Text.Repository.UseRelativeTimeInGraph
-- Text.ResetWithoutCheckout
-- Text.ResetWithoutCheckout.MoveTo
-- Text.ResetWithoutCheckout.Target
-- Text.SetSubmoduleBranch
-- Text.SetSubmoduleBranch.Submodule
-- Text.SetSubmoduleBranch.Current
-- Text.SetSubmoduleBranch.New
-- Text.SetSubmoduleBranch.New.Tip
-- Text.Stash.Mode
-- Text.StashCM.CopyMessage
-- Text.Submodule.Branch
-- Text.Submodule.Deinit
-- Text.Submodule.Histories
-- Text.Submodule.Move
-- Text.Submodule.SetBranch
-- Text.Submodule.SetURL
-- Text.Submodule.Update
-- Text.TagCM.CustomAction
-- Text.UpdateSubmodules.UpdateToRemoteTrackingBranch
-- Text.WorkingCopy.AddToGitIgnore.InFolder
-- Text.WorkingCopy.ConfirmCommitWithDetachedHead
-- Text.WorkingCopy.ResetAuthor
+- Text.Configure.Git.ConventionalTypesOverride
+- Text.ConfigureCustomActionControls.StringValue.Tip
+- Text.Diff.Image.Difference
+- Text.DirtyState.HasLocalChanges
+- Text.DirtyState.HasPendingPullOrPush
+- Text.DirtyState.UpToDate
+- Text.DropHead
+- Text.DropHead.Commit
+- Text.DropHead.NewHead
+- Text.EditBranchDescription
+- Text.EditBranchDescription.Target
+- Text.FileCM.CustomAction
+- Text.GitLFS.Locks.UnlockAllMyLocks
+- Text.GitLFS.Locks.UnlockAllMyLocks.Confirm
+- Text.Hotkeys.Global.ShowWorkspaceDropdownMenu
+- Text.Hotkeys.Repo.OpenCommandPalette
+- Text.Launcher.Commands
+- Text.Launcher.OpenRepository
+- Text.Open
+- Text.Open.SystemDefaultEditor
+- Text.OpenFile
+- Text.PageTabBar.Tab.MoveToWorkspace
+- Text.PageTabBar.Tab.Refresh
+- Text.Preferences.AI.ReadApiKeyFromEnv
+- Text.Preferences.Appearance.UseAutoHideScrollBars
+- Text.Preferences.DiffMerge.DiffArgs
+- Text.Preferences.DiffMerge.DiffArgs.Tip
+- Text.Preferences.DiffMerge.MergeArgs
+- Text.Preferences.DiffMerge.MergeArgs.Tip
+- Text.Preferences.General.EnableCompactFolders
+- Text.Preferences.General.ShowChangesPageByDefault
+- Text.Preferences.General.ShowChangesTabInCommitDetailByDefault
+- Text.Preferences.General.UseGitHubStyleAvatar
+- Text.Preferences.Shell.Args
+- Text.Preferences.Shell.Args.Tip
+- Text.PushToNewBranch
+- Text.PushToNewBranch.Title
+- Text.ScanRepositories.UseCustomDir
+- Text.SquashOrFixup.Squash
+- Text.SquashOrFixup.Fixup
+- Text.SquashOrFixup.Into
+- Text.WorkingCopy.ClearCommitHistories
+- Text.WorkingCopy.ClearCommitHistories.Confirm
+- Text.WorkingCopy.NoVerify
+- Text.Worktree.Open
-### 
+### 
Missing keys in ja_JP.axaml
+- Text.About.ReleaseNotes
- Text.AddToIgnore
- Text.AddToIgnore.Pattern
- Text.AddToIgnore.Storage
+- Text.App.Hide
+- Text.App.ShowAll
- Text.Askpass.Passphrase
- Text.Avatar.Load
- Text.Bisect
@@ -302,16 +189,25 @@ This document shows the translation status of each locale file in the repository
- Text.Bisect.Good
- Text.Bisect.Skip
- Text.Bisect.WaitingForRange
+- Text.Blame.BlameOnPreviousRevision
- Text.BranchCM.CompareWithCurrent
+- Text.BranchCM.CreatePR
+- Text.BranchCM.CreatePRForUpstream
+- Text.BranchCM.EditDescription
- Text.BranchCM.ResetToSelectedCommit
-- Text.BranchTree.Local
+- Text.BranchCM.SwitchToWorktree
+- Text.BranchTree.Ahead
+- Text.BranchTree.AheadBehind
+- Text.BranchTree.Behind
+- Text.BranchTree.InvalidUpstream
- Text.BranchTree.Remote
+- Text.BranchTree.Status
- Text.BranchTree.Tracking
- Text.BranchTree.URL
+- Text.BranchTree.Worktree
- Text.ChangeSubmoduleUrl
- Text.ChangeSubmoduleUrl.Submodule
- Text.ChangeSubmoduleUrl.URL
-- Text.Checkout.RecurseSubmodules
- Text.Checkout.WarnLostCommits
- Text.Checkout.WithFastForward
- Text.Checkout.WithFastForward.Upstream
@@ -319,6 +215,7 @@ This document shows the translation status of each locale file in the repository
- Text.CommitCM.CopyCommitMessage
- Text.CommitCM.CopyCommitter
- Text.CommitCM.CopySubject
+- Text.CommitCM.Drop
- Text.CommitCM.InteractiveRebase
- Text.CommitCM.InteractiveRebase.Drop
- Text.CommitCM.InteractiveRebase.Edit
@@ -329,17 +226,25 @@ This document shows the translation status of each locale file in the repository
- Text.CommitCM.PushRevision
- Text.CommitCM.Rebase
- Text.CommitCM.Reset
+- Text.CommitCM.Fixup
- Text.CommitDetail.Changes.Count
+- Text.CommitDetail.Info.CopyEmail
+- Text.CommitDetail.Info.CopyName
+- Text.CommitDetail.Info.CopyNameAndEmail
- Text.CommitDetail.Info.Key
- Text.CommitDetail.Info.Signer
+- Text.CommitMessageTextBox.Placeholder
- Text.CommitMessageTextBox.SubjectCount
- Text.Configure.CommitMessageTemplate.BuiltinVars
- Text.Configure.CustomAction.Arguments.Tip
- Text.Configure.CustomAction.InputControls
- Text.Configure.CustomAction.InputControls.Edit
-- Text.Configure.CustomAction.InputControls.Tip
+- Text.Configure.CustomAction.Scope.File
+- Text.Configure.CustomAction.Scope.Remote
- Text.Configure.CustomAction.Scope.Tag
+- Text.Configure.Git.ConventionalTypesOverride
- Text.Configure.Git.PreferredMergeMode
+- Text.Configure.IssueTracker.AddSampleGerritChangeIdCommit
- Text.Configure.IssueTracker.Share
- Text.ConfigureCustomActionControls
- Text.ConfigureCustomActionControls.CheckedValue
@@ -350,6 +255,7 @@ This document shows the translation status of each locale file in the repository
- Text.ConfigureCustomActionControls.Label
- Text.ConfigureCustomActionControls.Options
- Text.ConfigureCustomActionControls.Options.Tip
+- Text.ConfigureCustomActionControls.StringValue.Tip
- Text.ConfigureCustomActionControls.Type
- Text.ConfirmEmptyCommit.Continue
- Text.ConfirmEmptyCommit.NoLocalChanges
@@ -361,39 +267,78 @@ This document shows the translation status of each locale file in the repository
- Text.DeinitSubmodule
- Text.DeinitSubmodule.Force
- Text.DeinitSubmodule.Path
+- Text.DeleteMultiTags
+- Text.DeleteMultiTags.DeleteFromRemotes
+- Text.DeleteMultiTags.Tip
- Text.Diff.Image.Blend
+- Text.Diff.Image.Difference
- Text.Diff.Image.SideBySide
- Text.Diff.Image.Swipe
- Text.Diff.New
- Text.Diff.Old
- Text.Diff.Submodule.Deleted
- Text.DirHistories
+- Text.DirtyState.HasLocalChanges
+- Text.DirtyState.HasPendingPullOrPush
+- Text.DirtyState.UpToDate
- Text.Discard.IncludeUntracked
+- Text.DropHead
+- Text.DropHead.Commit
+- Text.DropHead.NewHead
+- Text.EditBranchDescription
+- Text.EditBranchDescription.Target
- Text.ExecuteCustomAction.Target
- Text.ExecuteCustomAction.Repository
+- Text.FileCM.CustomAction
- Text.GitFlow.FinishWithPush
- Text.GitFlow.FinishWithSquash
-- Text.Hotkeys.Global.SwitchWorkspace
+- Text.GitLFS.Locks.UnlockAllMyLocks
+- Text.GitLFS.Locks.UnlockAllMyLocks.Confirm
+- Text.Hotkeys.Global.ShowWorkspaceDropdownMenu
- Text.Hotkeys.Global.SwitchTab
+- Text.Hotkeys.Repo.OpenCommandPalette
- Text.Hotkeys.TextEditor.OpenExternalMergeTool
- Text.InteractiveRebase.ReorderTip
-- Text.Launcher.Workspaces
+- Text.Launcher.Commands
+- Text.Launcher.OpenRepository
- Text.Launcher.Pages
+- Text.Launcher.Workspaces
- Text.Merge.Edit
- Text.MoveSubmodule
- Text.MoveSubmodule.MoveTo
- Text.MoveSubmodule.Submodule
+- Text.Open
+- Text.Open.SystemDefaultEditor
+- Text.OpenFile
+- Text.PageTabBar.Tab.MoveToWorkspace
+- Text.PageTabBar.Tab.Refresh
+- Text.Preferences.AI.ReadApiKeyFromEnv
+- Text.Preferences.Appearance.UseAutoHideScrollBars
+- Text.Preferences.DiffMerge.DiffArgs
+- Text.Preferences.DiffMerge.DiffArgs.Tip
+- Text.Preferences.DiffMerge.MergeArgs
+- Text.Preferences.DiffMerge.MergeArgs.Tip
+- Text.Preferences.General.EnableCompactFolders
+- Text.Preferences.General.ShowChangesPageByDefault
+- Text.Preferences.General.ShowChangesTabInCommitDetailByDefault
+- Text.Preferences.General.UseGitHubStyleAvatar
- Text.Preferences.Git.IgnoreCRAtEOLInDiff
- Text.Preferences.Git.UseLibsecret
-- Text.Pull.RecurseSubmodules
+- Text.Preferences.Shell.Args
+- Text.Preferences.Shell.Args.Tip
- Text.Push.New
- Text.Push.Revision
- Text.Push.Revision.Title
+- Text.PushToNewBranch
+- Text.PushToNewBranch.Title
+- Text.RemoteCM.CustomAction
- Text.Repository.BranchSort
- Text.Repository.BranchSort.ByCommitterDate
- Text.Repository.BranchSort.ByName
- Text.Repository.ClearStashes
+- Text.Repository.Dashboard
- Text.Repository.FilterCommits
+- Text.Repository.MoreOptions
- Text.Repository.OnlyHighlightCurrentBranchInGraph
- Text.Repository.Search.ByContent
- Text.Repository.Search.ByPath
@@ -408,14 +353,19 @@ This document shows the translation status of each locale file in the repository
- Text.ResetWithoutCheckout
- Text.ResetWithoutCheckout.MoveTo
- Text.ResetWithoutCheckout.Target
+- Text.ScanRepositories.UseCustomDir
- Text.SetSubmoduleBranch
- Text.SetSubmoduleBranch.Submodule
- Text.SetSubmoduleBranch.Current
- Text.SetSubmoduleBranch.New
- Text.SetSubmoduleBranch.New.Tip
+- Text.SquashOrFixup.Squash
+- Text.SquashOrFixup.Fixup
+- Text.SquashOrFixup.Into
- Text.Stash.Mode
- Text.StashCM.CopyMessage
- Text.Submodule.Branch
+- Text.Submodule.CopyBranch
- Text.Submodule.Deinit
- Text.Submodule.Histories
- Text.Submodule.Move
@@ -428,33 +378,90 @@ This document shows the translation status of each locale file in the repository
- Text.Submodule.Status.Unmerged
- Text.Submodule.Update
- Text.Submodule.URL
+- Text.Tag.Tagger
+- Text.Tag.Time
+- Text.TagCM.Copy.Message
+- Text.TagCM.Copy.Name
+- Text.TagCM.Copy.Tagger
+- Text.TagCM.CopyName
- Text.TagCM.CustomAction
+- Text.TagCM.DeleteMultiple
- Text.UpdateSubmodules.UpdateToRemoteTrackingBranch
- Text.ViewLogs
- Text.ViewLogs.Clear
- Text.ViewLogs.CopyLog
- Text.ViewLogs.Delete
- Text.WorkingCopy.AddToGitIgnore.InFolder
+- Text.WorkingCopy.ClearCommitHistories
+- Text.WorkingCopy.ClearCommitHistories.Confirm
- Text.WorkingCopy.ConfirmCommitWithDetachedHead
- Text.WorkingCopy.ConfirmCommitWithFilter
- Text.WorkingCopy.Conflicts.OpenExternalMergeTool
- Text.WorkingCopy.Conflicts.OpenExternalMergeToolAllConflicts
- Text.WorkingCopy.Conflicts.UseMine
- Text.WorkingCopy.Conflicts.UseTheirs
+- Text.WorkingCopy.NoVerify
- Text.WorkingCopy.ResetAuthor
+- Text.Worktree.Open
-### 
+### 
+
+
+Missing keys in ko_KR.axaml
+
+- Text.Blame.BlameOnPreviousRevision
+- Text.Blame.TypeNotSupported
+- Text.BranchCM.CreatePR
+- Text.BranchCM.CreatePRForUpstream
+- Text.BranchCM.EditDescription
+- Text.CommitMessageTextBox.Placeholder
+- Text.Configure.Git.ConventionalTypesOverride
+- Text.ConfigureCustomActionControls.StringValue.Tip
+- Text.EditBranchDescription
+- Text.EditBranchDescription.Target
+- Text.FileCM.CustomAction
+- Text.GitLFS.Locks.UnlockAllMyLocks
+- Text.GitLFS.Locks.UnlockAllMyLocks.Confirm
+- Text.Hotkeys.Global.ShowWorkspaceDropdownMenu
+- Text.Hotkeys.Repo.OpenCommandPalette
+- Text.Launcher.Commands
+- Text.Launcher.OpenRepository
+- Text.Open
+- Text.Open.SystemDefaultEditor
+- Text.OpenFile
+- Text.PageTabBar.Tab.MoveToWorkspace
+- Text.PageTabBar.Tab.Refresh
+- Text.Preferences.Appearance.UseFixedTabWidth
+- Text.Preferences.DiffMerge.DiffArgs
+- Text.Preferences.DiffMerge.DiffArgs.Tip
+- Text.Preferences.DiffMerge.MergeArgs
+- Text.Preferences.DiffMerge.MergeArgs.Tip
+- Text.Preferences.Shell.Args
+- Text.Preferences.Shell.Args.Tip
+- Text.PushToNewBranch
+- Text.PushToNewBranch.Title
+- Text.SquashOrFixup.Squash
+- Text.SquashOrFixup.Fixup
+- Text.SquashOrFixup.Into
+- Text.Submodule.Status.Unmerged
+
+
+
+### 
Missing keys in pt_BR.axaml
+- Text.About.ReleaseNotes
- Text.AddToIgnore
- Text.AddToIgnore.Pattern
- Text.AddToIgnore.Storage
- Text.AIAssistant.Regen
- Text.AIAssistant.Use
+- Text.App.Hide
+- Text.App.ShowAll
- Text.ApplyStash
- Text.ApplyStash.DropAfterApply
- Text.ApplyStash.RestoreIndex
@@ -468,18 +475,26 @@ This document shows the translation status of each locale file in the repository
- Text.Bisect.Good
- Text.Bisect.Skip
- Text.Bisect.WaitingForRange
+- Text.Blame.BlameOnPreviousRevision
+- Text.BranchCM.CreatePR
+- Text.BranchCM.CreatePRForUpstream
- Text.BranchCM.CustomAction
+- Text.BranchCM.EditDescription
- Text.BranchCM.MergeMultiBranches
- Text.BranchCM.ResetToSelectedCommit
-- Text.BranchTree.Local
+- Text.BranchCM.SwitchToWorktree
+- Text.BranchTree.Ahead
+- Text.BranchTree.AheadBehind
+- Text.BranchTree.Behind
+- Text.BranchTree.InvalidUpstream
- Text.BranchTree.Remote
+- Text.BranchTree.Status
- Text.BranchTree.Tracking
- Text.BranchTree.URL
-- Text.BranchUpstreamInvalid
+- Text.BranchTree.Worktree
- Text.ChangeSubmoduleUrl
- Text.ChangeSubmoduleUrl.Submodule
- Text.ChangeSubmoduleUrl.URL
-- Text.Checkout.RecurseSubmodules
- Text.Checkout.WarnLostCommits
- Text.Checkout.WithFastForward
- Text.Checkout.WithFastForward.Upstream
@@ -488,6 +503,7 @@ This document shows the translation status of each locale file in the repository
- Text.CommitCM.CopyCommitMessage
- Text.CommitCM.CopyCommitter
- Text.CommitCM.CopySubject
+- Text.CommitCM.Drop
- Text.CommitCM.InteractiveRebase
- Text.CommitCM.InteractiveRebase.Drop
- Text.CommitCM.InteractiveRebase.Edit
@@ -500,21 +516,29 @@ This document shows the translation status of each locale file in the repository
- Text.CommitCM.PushRevision
- Text.CommitCM.Rebase
- Text.CommitCM.Reset
+- Text.CommitCM.Fixup
- Text.CommitDetail.Changes.Count
- Text.CommitDetail.Files.Search
- Text.CommitDetail.Info.Children
+- Text.CommitDetail.Info.CopyEmail
+- Text.CommitDetail.Info.CopyName
+- Text.CommitDetail.Info.CopyNameAndEmail
- Text.CommitDetail.Info.Key
- Text.CommitDetail.Info.Signer
+- Text.CommitMessageTextBox.Placeholder
- Text.CommitMessageTextBox.SubjectCount
- Text.Configure.CommitMessageTemplate.BuiltinVars
- Text.Configure.CustomAction.Arguments.Tip
- Text.Configure.CustomAction.InputControls
- Text.Configure.CustomAction.InputControls.Edit
-- Text.Configure.CustomAction.InputControls.Tip
- Text.Configure.CustomAction.Scope.Branch
+- Text.Configure.CustomAction.Scope.File
+- Text.Configure.CustomAction.Scope.Remote
- Text.Configure.CustomAction.Scope.Tag
- Text.Configure.CustomAction.WaitForExit
+- Text.Configure.Git.ConventionalTypesOverride
- Text.Configure.Git.PreferredMergeMode
+- Text.Configure.IssueTracker.AddSampleGerritChangeIdCommit
- Text.Configure.IssueTracker.AddSampleGiteeIssue
- Text.Configure.IssueTracker.AddSampleGiteePullRequest
- Text.Configure.IssueTracker.Share
@@ -527,6 +551,7 @@ This document shows the translation status of each locale file in the repository
- Text.ConfigureCustomActionControls.Label
- Text.ConfigureCustomActionControls.Options
- Text.ConfigureCustomActionControls.Options.Tip
+- Text.ConfigureCustomActionControls.StringValue.Tip
- Text.ConfigureCustomActionControls.Type
- Text.ConfirmEmptyCommit.Continue
- Text.ConfirmEmptyCommit.NoLocalChanges
@@ -535,42 +560,58 @@ This document shows the translation status of each locale file in the repository
- Text.ConfirmRestart.Title
- Text.ConfirmRestart.Message
- Text.CopyFullPath
-- Text.CreateBranch.Name.WarnSpace
- Text.CreateBranch.OverwriteExisting
- Text.DeinitSubmodule
- Text.DeinitSubmodule.Force
- Text.DeinitSubmodule.Path
+- Text.DeleteMultiTags
+- Text.DeleteMultiTags.DeleteFromRemotes
+- Text.DeleteMultiTags.Tip
- Text.DeleteRepositoryNode.Path
- Text.DeleteRepositoryNode.TipForGroup
- Text.DeleteRepositoryNode.TipForRepository
- Text.Diff.First
- Text.Diff.Image.Blend
+- Text.Diff.Image.Difference
- Text.Diff.Image.SideBySide
- Text.Diff.Image.Swipe
- Text.Diff.Last
- Text.Diff.New
- Text.Diff.Old
- Text.Diff.Submodule.Deleted
-- Text.Diff.UseBlockNavigation
- Text.DirHistories
+- Text.DirtyState.HasLocalChanges
+- Text.DirtyState.HasPendingPullOrPush
+- Text.DirtyState.UpToDate
- Text.Discard.IncludeUntracked
+- Text.DropHead
+- Text.DropHead.Commit
+- Text.DropHead.NewHead
+- Text.EditBranchDescription
+- Text.EditBranchDescription.Target
- Text.ExecuteCustomAction.Target
- Text.ExecuteCustomAction.Repository
- Text.Fetch.Force
+- Text.FileCM.CustomAction
- Text.FileCM.ResolveUsing
- Text.GitFlow.FinishWithPush
- Text.GitFlow.FinishWithSquash
+- Text.GitLFS.Locks.UnlockAllMyLocks
+- Text.GitLFS.Locks.UnlockAllMyLocks.Confirm
- Text.Hotkeys.Global.Clone
-- Text.Hotkeys.Global.SwitchWorkspace
+- Text.Hotkeys.Global.ShowWorkspaceDropdownMenu
- Text.Hotkeys.Global.SwitchTab
+- Text.Hotkeys.Repo.OpenCommandPalette
- Text.Hotkeys.TextEditor.OpenExternalMergeTool
- Text.InProgress.CherryPick.Head
- Text.InProgress.Merge.Operating
- Text.InProgress.Rebase.StoppedAt
- Text.InProgress.Revert.Head
- Text.InteractiveRebase.ReorderTip
-- Text.Launcher.Workspaces
+- Text.Launcher.Commands
+- Text.Launcher.OpenRepository
- Text.Launcher.Pages
+- Text.Launcher.Workspaces
- Text.Merge.Edit
- Text.Merge.Source
- Text.MergeMultiple
@@ -580,27 +621,48 @@ This document shows the translation status of each locale file in the repository
- Text.MoveSubmodule
- Text.MoveSubmodule.MoveTo
- Text.MoveSubmodule.Submodule
+- Text.Open
+- Text.Open.SystemDefaultEditor
+- Text.OpenFile
+- Text.PageTabBar.Tab.MoveToWorkspace
+- Text.PageTabBar.Tab.Refresh
+- Text.Preferences.AI.ReadApiKeyFromEnv
- Text.Preferences.AI.Streaming
- Text.Preferences.Appearance.EditorTabWidth
+- Text.Preferences.Appearance.UseAutoHideScrollBars
+- Text.Preferences.DiffMerge.DiffArgs
+- Text.Preferences.DiffMerge.DiffArgs.Tip
+- Text.Preferences.DiffMerge.MergeArgs
+- Text.Preferences.DiffMerge.MergeArgs.Tip
- Text.Preferences.General.DateFormat
+- Text.Preferences.General.EnableCompactFolders
+- Text.Preferences.General.ShowChangesPageByDefault
+- Text.Preferences.General.ShowChangesTabInCommitDetailByDefault
- Text.Preferences.General.ShowChildren
- Text.Preferences.General.ShowTagsInGraph
+- Text.Preferences.General.UseGitHubStyleAvatar
- Text.Preferences.Git.IgnoreCRAtEOLInDiff
- Text.Preferences.Git.SSLVerify
- Text.Preferences.Git.UseLibsecret
-- Text.Pull.RecurseSubmodules
+- Text.Preferences.Shell.Args
+- Text.Preferences.Shell.Args.Tip
- Text.Push.New
- Text.Push.Revision
- Text.Push.Revision.Title
+- Text.PushToNewBranch
+- Text.PushToNewBranch.Title
+- Text.RemoteCM.CustomAction
- Text.Repository.BranchSort
- Text.Repository.BranchSort.ByCommitterDate
- Text.Repository.BranchSort.ByName
- Text.Repository.ClearStashes
+- Text.Repository.Dashboard
- Text.Repository.FilterCommits
- Text.Repository.HistoriesLayout
- Text.Repository.HistoriesLayout.Horizontal
- Text.Repository.HistoriesLayout.Vertical
- Text.Repository.HistoriesOrder
+- Text.Repository.MoreOptions
- Text.Repository.Notifications.Clear
- Text.Repository.OnlyHighlightCurrentBranchInGraph
- Text.Repository.Search.ByContent
@@ -620,6 +682,7 @@ This document shows the translation status of each locale file in the repository
- Text.ResetWithoutCheckout
- Text.ResetWithoutCheckout.MoveTo
- Text.ResetWithoutCheckout.Target
+- Text.ScanRepositories.UseCustomDir
- Text.SetSubmoduleBranch
- Text.SetSubmoduleBranch.Submodule
- Text.SetSubmoduleBranch.Current
@@ -630,10 +693,14 @@ This document shows the translation status of each locale file in the repository
- Text.SetUpstream.Unset
- Text.SetUpstream.Upstream
- Text.SHALinkCM.NavigateTo
+- Text.SquashOrFixup.Squash
+- Text.SquashOrFixup.Fixup
+- Text.SquashOrFixup.Into
- Text.Stash.Mode
- Text.StashCM.CopyMessage
- Text.StashCM.SaveAsPatch
- Text.Submodule.Branch
+- Text.Submodule.CopyBranch
- Text.Submodule.Deinit
- Text.Submodule.Histories
- Text.Submodule.Move
@@ -646,13 +713,22 @@ This document shows the translation status of each locale file in the repository
- Text.Submodule.Status.Unmerged
- Text.Submodule.Update
- Text.Submodule.URL
+- Text.Tag.Tagger
+- Text.Tag.Time
+- Text.TagCM.Copy.Message
+- Text.TagCM.Copy.Name
+- Text.TagCM.Copy.Tagger
+- Text.TagCM.CopyName
- Text.TagCM.CustomAction
+- Text.TagCM.DeleteMultiple
- Text.UpdateSubmodules.UpdateToRemoteTrackingBranch
- Text.ViewLogs
- Text.ViewLogs.Clear
- Text.ViewLogs.CopyLog
- Text.ViewLogs.Delete
- Text.WorkingCopy.AddToGitIgnore.InFolder
+- Text.WorkingCopy.ClearCommitHistories
+- Text.WorkingCopy.ClearCommitHistories.Confirm
- Text.WorkingCopy.CommitToEdit
- Text.WorkingCopy.ConfirmCommitWithDetachedHead
- Text.WorkingCopy.ConfirmCommitWithFilter
@@ -660,21 +736,26 @@ This document shows the translation status of each locale file in the repository
- Text.WorkingCopy.Conflicts.OpenExternalMergeToolAllConflicts
- Text.WorkingCopy.Conflicts.UseMine
- Text.WorkingCopy.Conflicts.UseTheirs
+- Text.WorkingCopy.NoVerify
- Text.WorkingCopy.ResetAuthor
- Text.WorkingCopy.SignOff
+- Text.Worktree.Open
### 
-### 
+### 
Missing keys in ta_IN.axaml
+- Text.About.ReleaseNotes
- Text.AddToIgnore
- Text.AddToIgnore.Pattern
- Text.AddToIgnore.Storage
+- Text.App.Hide
+- Text.App.ShowAll
- Text.Askpass.Passphrase
- Text.Avatar.Load
- Text.Bisect
@@ -684,16 +765,25 @@ This document shows the translation status of each locale file in the repository
- Text.Bisect.Good
- Text.Bisect.Skip
- Text.Bisect.WaitingForRange
+- Text.Blame.BlameOnPreviousRevision
- Text.BranchCM.CompareWithCurrent
+- Text.BranchCM.CreatePR
+- Text.BranchCM.CreatePRForUpstream
+- Text.BranchCM.EditDescription
- Text.BranchCM.ResetToSelectedCommit
-- Text.BranchTree.Local
+- Text.BranchCM.SwitchToWorktree
+- Text.BranchTree.Ahead
+- Text.BranchTree.AheadBehind
+- Text.BranchTree.Behind
+- Text.BranchTree.InvalidUpstream
- Text.BranchTree.Remote
+- Text.BranchTree.Status
- Text.BranchTree.Tracking
- Text.BranchTree.URL
+- Text.BranchTree.Worktree
- Text.ChangeSubmoduleUrl
- Text.ChangeSubmoduleUrl.Submodule
- Text.ChangeSubmoduleUrl.URL
-- Text.Checkout.RecurseSubmodules
- Text.Checkout.WarnLostCommits
- Text.Checkout.WithFastForward
- Text.Checkout.WithFastForward.Upstream
@@ -701,6 +791,7 @@ This document shows the translation status of each locale file in the repository
- Text.CommitCM.CopyCommitMessage
- Text.CommitCM.CopyCommitter
- Text.CommitCM.CopySubject
+- Text.CommitCM.Drop
- Text.CommitCM.InteractiveRebase
- Text.CommitCM.InteractiveRebase.Drop
- Text.CommitCM.InteractiveRebase.Edit
@@ -711,17 +802,25 @@ This document shows the translation status of each locale file in the repository
- Text.CommitCM.PushRevision
- Text.CommitCM.Rebase
- Text.CommitCM.Reset
+- Text.CommitCM.Fixup
- Text.CommitDetail.Changes.Count
+- Text.CommitDetail.Info.CopyEmail
+- Text.CommitDetail.Info.CopyName
+- Text.CommitDetail.Info.CopyNameAndEmail
- Text.CommitDetail.Info.Key
- Text.CommitDetail.Info.Signer
+- Text.CommitMessageTextBox.Placeholder
- Text.CommitMessageTextBox.SubjectCount
- Text.Configure.CommitMessageTemplate.BuiltinVars
- Text.Configure.CustomAction.Arguments.Tip
- Text.Configure.CustomAction.InputControls
- Text.Configure.CustomAction.InputControls.Edit
-- Text.Configure.CustomAction.InputControls.Tip
+- Text.Configure.CustomAction.Scope.File
+- Text.Configure.CustomAction.Scope.Remote
- Text.Configure.CustomAction.Scope.Tag
+- Text.Configure.Git.ConventionalTypesOverride
- Text.Configure.Git.PreferredMergeMode
+- Text.Configure.IssueTracker.AddSampleGerritChangeIdCommit
- Text.Configure.IssueTracker.Share
- Text.ConfigureCustomActionControls
- Text.ConfigureCustomActionControls.CheckedValue
@@ -732,6 +831,7 @@ This document shows the translation status of each locale file in the repository
- Text.ConfigureCustomActionControls.Label
- Text.ConfigureCustomActionControls.Options
- Text.ConfigureCustomActionControls.Options.Tip
+- Text.ConfigureCustomActionControls.StringValue.Tip
- Text.ConfigureCustomActionControls.Type
- Text.ConfirmEmptyCommit.Continue
- Text.ConfirmEmptyCommit.NoLocalChanges
@@ -743,38 +843,77 @@ This document shows the translation status of each locale file in the repository
- Text.DeinitSubmodule
- Text.DeinitSubmodule.Force
- Text.DeinitSubmodule.Path
+- Text.DeleteMultiTags
+- Text.DeleteMultiTags.DeleteFromRemotes
+- Text.DeleteMultiTags.Tip
- Text.Diff.Image.Blend
+- Text.Diff.Image.Difference
- Text.Diff.Image.SideBySide
- Text.Diff.Image.Swipe
- Text.Diff.New
- Text.Diff.Old
- Text.Diff.Submodule.Deleted
- Text.DirHistories
+- Text.DirtyState.HasLocalChanges
+- Text.DirtyState.HasPendingPullOrPush
+- Text.DirtyState.UpToDate
- Text.Discard.IncludeUntracked
+- Text.DropHead
+- Text.DropHead.Commit
+- Text.DropHead.NewHead
+- Text.EditBranchDescription
+- Text.EditBranchDescription.Target
- Text.ExecuteCustomAction.Target
- Text.ExecuteCustomAction.Repository
+- Text.FileCM.CustomAction
- Text.GitFlow.FinishWithPush
- Text.GitFlow.FinishWithSquash
-- Text.Hotkeys.Global.SwitchWorkspace
+- Text.GitLFS.Locks.UnlockAllMyLocks
+- Text.GitLFS.Locks.UnlockAllMyLocks.Confirm
+- Text.Hotkeys.Global.ShowWorkspaceDropdownMenu
- Text.Hotkeys.Global.SwitchTab
+- Text.Hotkeys.Repo.OpenCommandPalette
- Text.Hotkeys.TextEditor.OpenExternalMergeTool
- Text.InteractiveRebase.ReorderTip
-- Text.Launcher.Workspaces
+- Text.Launcher.Commands
+- Text.Launcher.OpenRepository
- Text.Launcher.Pages
+- Text.Launcher.Workspaces
- Text.Merge.Edit
- Text.MoveSubmodule
- Text.MoveSubmodule.MoveTo
- Text.MoveSubmodule.Submodule
+- Text.Open
+- Text.Open.SystemDefaultEditor
+- Text.OpenFile
+- Text.PageTabBar.Tab.MoveToWorkspace
+- Text.PageTabBar.Tab.Refresh
+- Text.Preferences.AI.ReadApiKeyFromEnv
+- Text.Preferences.Appearance.UseAutoHideScrollBars
+- Text.Preferences.DiffMerge.DiffArgs
+- Text.Preferences.DiffMerge.DiffArgs.Tip
+- Text.Preferences.DiffMerge.MergeArgs
+- Text.Preferences.DiffMerge.MergeArgs.Tip
+- Text.Preferences.General.EnableCompactFolders
+- Text.Preferences.General.ShowChangesPageByDefault
+- Text.Preferences.General.ShowChangesTabInCommitDetailByDefault
+- Text.Preferences.General.UseGitHubStyleAvatar
- Text.Preferences.Git.IgnoreCRAtEOLInDiff
- Text.Preferences.Git.UseLibsecret
-- Text.Pull.RecurseSubmodules
+- Text.Preferences.Shell.Args
+- Text.Preferences.Shell.Args.Tip
- Text.Push.New
- Text.Push.Revision
- Text.Push.Revision.Title
+- Text.PushToNewBranch
+- Text.PushToNewBranch.Title
+- Text.RemoteCM.CustomAction
- Text.Repository.BranchSort
- Text.Repository.BranchSort.ByCommitterDate
- Text.Repository.BranchSort.ByName
- Text.Repository.ClearStashes
+- Text.Repository.Dashboard
+- Text.Repository.MoreOptions
- Text.Repository.OnlyHighlightCurrentBranchInGraph
- Text.Repository.Search.ByContent
- Text.Repository.Search.ByPath
@@ -789,14 +928,19 @@ This document shows the translation status of each locale file in the repository
- Text.ResetWithoutCheckout
- Text.ResetWithoutCheckout.MoveTo
- Text.ResetWithoutCheckout.Target
+- Text.ScanRepositories.UseCustomDir
- Text.SetSubmoduleBranch
- Text.SetSubmoduleBranch.Submodule
- Text.SetSubmoduleBranch.Current
- Text.SetSubmoduleBranch.New
- Text.SetSubmoduleBranch.New.Tip
+- Text.SquashOrFixup.Squash
+- Text.SquashOrFixup.Fixup
+- Text.SquashOrFixup.Into
- Text.Stash.Mode
- Text.StashCM.CopyMessage
- Text.Submodule.Branch
+- Text.Submodule.CopyBranch
- Text.Submodule.Deinit
- Text.Submodule.Histories
- Text.Submodule.Move
@@ -809,7 +953,14 @@ This document shows the translation status of each locale file in the repository
- Text.Submodule.Status.Unmerged
- Text.Submodule.Update
- Text.Submodule.URL
+- Text.Tag.Tagger
+- Text.Tag.Time
+- Text.TagCM.Copy.Message
+- Text.TagCM.Copy.Name
+- Text.TagCM.Copy.Tagger
+- Text.TagCM.CopyName
- Text.TagCM.CustomAction
+- Text.TagCM.DeleteMultiple
- Text.UpdateSubmodules.Target
- Text.UpdateSubmodules.UpdateToRemoteTrackingBranch
- Text.ViewLogs
@@ -817,23 +968,30 @@ This document shows the translation status of each locale file in the repository
- Text.ViewLogs.CopyLog
- Text.ViewLogs.Delete
- Text.WorkingCopy.AddToGitIgnore.InFolder
+- Text.WorkingCopy.ClearCommitHistories
+- Text.WorkingCopy.ClearCommitHistories.Confirm
- Text.WorkingCopy.ConfirmCommitWithDetachedHead
- Text.WorkingCopy.Conflicts.OpenExternalMergeTool
- Text.WorkingCopy.Conflicts.OpenExternalMergeToolAllConflicts
- Text.WorkingCopy.Conflicts.UseMine
- Text.WorkingCopy.Conflicts.UseTheirs
+- Text.WorkingCopy.NoVerify
- Text.WorkingCopy.ResetAuthor
+- Text.Worktree.Open
-### 
+### 
Missing keys in uk_UA.axaml
+- Text.About.ReleaseNotes
- Text.AddToIgnore
- Text.AddToIgnore.Pattern
- Text.AddToIgnore.Storage
+- Text.App.Hide
+- Text.App.ShowAll
- Text.Askpass.Passphrase
- Text.Avatar.Load
- Text.Bisect
@@ -843,15 +1001,24 @@ This document shows the translation status of each locale file in the repository
- Text.Bisect.Good
- Text.Bisect.Skip
- Text.Bisect.WaitingForRange
+- Text.Blame.BlameOnPreviousRevision
+- Text.BranchCM.CreatePR
+- Text.BranchCM.CreatePRForUpstream
+- Text.BranchCM.EditDescription
- Text.BranchCM.ResetToSelectedCommit
-- Text.BranchTree.Local
+- Text.BranchCM.SwitchToWorktree
+- Text.BranchTree.Ahead
+- Text.BranchTree.AheadBehind
+- Text.BranchTree.Behind
+- Text.BranchTree.InvalidUpstream
- Text.BranchTree.Remote
+- Text.BranchTree.Status
- Text.BranchTree.Tracking
- Text.BranchTree.URL
+- Text.BranchTree.Worktree
- Text.ChangeSubmoduleUrl
- Text.ChangeSubmoduleUrl.Submodule
- Text.ChangeSubmoduleUrl.URL
-- Text.Checkout.RecurseSubmodules
- Text.Checkout.WarnLostCommits
- Text.Checkout.WithFastForward
- Text.Checkout.WithFastForward.Upstream
@@ -859,6 +1026,7 @@ This document shows the translation status of each locale file in the repository
- Text.CommitCM.CopyCommitMessage
- Text.CommitCM.CopyCommitter
- Text.CommitCM.CopySubject
+- Text.CommitCM.Drop
- Text.CommitCM.InteractiveRebase
- Text.CommitCM.InteractiveRebase.Drop
- Text.CommitCM.InteractiveRebase.Edit
@@ -869,16 +1037,24 @@ This document shows the translation status of each locale file in the repository
- Text.CommitCM.PushRevision
- Text.CommitCM.Rebase
- Text.CommitCM.Reset
+- Text.CommitCM.Fixup
- Text.CommitDetail.Changes.Count
+- Text.CommitDetail.Info.CopyEmail
+- Text.CommitDetail.Info.CopyName
+- Text.CommitDetail.Info.CopyNameAndEmail
- Text.CommitDetail.Info.Key
- Text.CommitDetail.Info.Signer
+- Text.CommitMessageTextBox.Placeholder
- Text.CommitMessageTextBox.SubjectCount
- Text.Configure.CommitMessageTemplate.BuiltinVars
- Text.Configure.CustomAction.Arguments.Tip
- Text.Configure.CustomAction.InputControls
- Text.Configure.CustomAction.InputControls.Edit
-- Text.Configure.CustomAction.InputControls.Tip
+- Text.Configure.CustomAction.Scope.File
+- Text.Configure.CustomAction.Scope.Remote
- Text.Configure.CustomAction.Scope.Tag
+- Text.Configure.Git.ConventionalTypesOverride
+- Text.Configure.IssueTracker.AddSampleGerritChangeIdCommit
- Text.Configure.IssueTracker.Share
- Text.ConfigureCustomActionControls
- Text.ConfigureCustomActionControls.CheckedValue
@@ -889,6 +1065,7 @@ This document shows the translation status of each locale file in the repository
- Text.ConfigureCustomActionControls.Label
- Text.ConfigureCustomActionControls.Options
- Text.ConfigureCustomActionControls.Options.Tip
+- Text.ConfigureCustomActionControls.StringValue.Tip
- Text.ConfigureCustomActionControls.Type
- Text.ConfigureWorkspace.Name
- Text.ConfirmRestart.Title
@@ -897,38 +1074,77 @@ This document shows the translation status of each locale file in the repository
- Text.DeinitSubmodule
- Text.DeinitSubmodule.Force
- Text.DeinitSubmodule.Path
+- Text.DeleteMultiTags
+- Text.DeleteMultiTags.DeleteFromRemotes
+- Text.DeleteMultiTags.Tip
- Text.Diff.Image.Blend
+- Text.Diff.Image.Difference
- Text.Diff.Image.SideBySide
- Text.Diff.Image.Swipe
- Text.Diff.New
- Text.Diff.Old
- Text.Diff.Submodule.Deleted
- Text.DirHistories
+- Text.DirtyState.HasLocalChanges
+- Text.DirtyState.HasPendingPullOrPush
+- Text.DirtyState.UpToDate
- Text.Discard.IncludeUntracked
+- Text.DropHead
+- Text.DropHead.Commit
+- Text.DropHead.NewHead
+- Text.EditBranchDescription
+- Text.EditBranchDescription.Target
- Text.ExecuteCustomAction.Target
- Text.ExecuteCustomAction.Repository
+- Text.FileCM.CustomAction
- Text.GitFlow.FinishWithPush
- Text.GitFlow.FinishWithSquash
-- Text.Hotkeys.Global.SwitchWorkspace
+- Text.GitLFS.Locks.UnlockAllMyLocks
+- Text.GitLFS.Locks.UnlockAllMyLocks.Confirm
+- Text.Hotkeys.Global.ShowWorkspaceDropdownMenu
- Text.Hotkeys.Global.SwitchTab
+- Text.Hotkeys.Repo.OpenCommandPalette
- Text.Hotkeys.TextEditor.OpenExternalMergeTool
- Text.InteractiveRebase.ReorderTip
-- Text.Launcher.Workspaces
+- Text.Launcher.Commands
+- Text.Launcher.OpenRepository
- Text.Launcher.Pages
+- Text.Launcher.Workspaces
- Text.Merge.Edit
- Text.MoveSubmodule
- Text.MoveSubmodule.MoveTo
- Text.MoveSubmodule.Submodule
+- Text.Open
+- Text.Open.SystemDefaultEditor
+- Text.OpenFile
+- Text.PageTabBar.Tab.MoveToWorkspace
+- Text.PageTabBar.Tab.Refresh
+- Text.Preferences.AI.ReadApiKeyFromEnv
+- Text.Preferences.Appearance.UseAutoHideScrollBars
+- Text.Preferences.DiffMerge.DiffArgs
+- Text.Preferences.DiffMerge.DiffArgs.Tip
+- Text.Preferences.DiffMerge.MergeArgs
+- Text.Preferences.DiffMerge.MergeArgs.Tip
+- Text.Preferences.General.EnableCompactFolders
+- Text.Preferences.General.ShowChangesPageByDefault
+- Text.Preferences.General.ShowChangesTabInCommitDetailByDefault
+- Text.Preferences.General.UseGitHubStyleAvatar
- Text.Preferences.Git.IgnoreCRAtEOLInDiff
- Text.Preferences.Git.UseLibsecret
-- Text.Pull.RecurseSubmodules
+- Text.Preferences.Shell.Args
+- Text.Preferences.Shell.Args.Tip
- Text.Push.New
- Text.Push.Revision
- Text.Push.Revision.Title
+- Text.PushToNewBranch
+- Text.PushToNewBranch.Title
+- Text.RemoteCM.CustomAction
- Text.Repository.BranchSort
- Text.Repository.BranchSort.ByCommitterDate
- Text.Repository.BranchSort.ByName
- Text.Repository.ClearStashes
+- Text.Repository.Dashboard
+- Text.Repository.MoreOptions
- Text.Repository.OnlyHighlightCurrentBranchInGraph
- Text.Repository.Search.ByContent
- Text.Repository.Search.ByPath
@@ -943,14 +1159,19 @@ This document shows the translation status of each locale file in the repository
- Text.ResetWithoutCheckout
- Text.ResetWithoutCheckout.MoveTo
- Text.ResetWithoutCheckout.Target
+- Text.ScanRepositories.UseCustomDir
- Text.SetSubmoduleBranch
- Text.SetSubmoduleBranch.Submodule
- Text.SetSubmoduleBranch.Current
- Text.SetSubmoduleBranch.New
- Text.SetSubmoduleBranch.New.Tip
+- Text.SquashOrFixup.Squash
+- Text.SquashOrFixup.Fixup
+- Text.SquashOrFixup.Into
- Text.Stash.Mode
- Text.StashCM.CopyMessage
- Text.Submodule.Branch
+- Text.Submodule.CopyBranch
- Text.Submodule.Deinit
- Text.Submodule.Histories
- Text.Submodule.Move
@@ -963,15 +1184,26 @@ This document shows the translation status of each locale file in the repository
- Text.Submodule.Status.Unmerged
- Text.Submodule.Update
- Text.Submodule.URL
+- Text.Tag.Tagger
+- Text.Tag.Time
+- Text.TagCM.Copy.Message
+- Text.TagCM.Copy.Name
+- Text.TagCM.Copy.Tagger
+- Text.TagCM.CopyName
- Text.TagCM.CustomAction
+- Text.TagCM.DeleteMultiple
- Text.UpdateSubmodules.UpdateToRemoteTrackingBranch
- Text.ViewLogs
- Text.ViewLogs.Clear
- Text.ViewLogs.CopyLog
- Text.ViewLogs.Delete
- Text.WorkingCopy.AddToGitIgnore.InFolder
+- Text.WorkingCopy.ClearCommitHistories
+- Text.WorkingCopy.ClearCommitHistories.Confirm
- Text.WorkingCopy.ConfirmCommitWithDetachedHead
+- Text.WorkingCopy.NoVerify
- Text.WorkingCopy.ResetAuthor
+- Text.Worktree.Open
diff --git a/VERSION b/VERSION
index 67b05cfc5..dff1fb957 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-2025.27
\ No newline at end of file
+2025.41
\ No newline at end of file
diff --git a/build/README.md b/build/README.md
index 17305edf6..0698a8fbc 100644
--- a/build/README.md
+++ b/build/README.md
@@ -5,7 +5,7 @@
## How to build this project manually
-1. Make sure [.NET SDK 9](https://dotnet.microsoft.com/en-us/download) is installed on your machine.
+1. Make sure [.NET SDK 10](https://dotnet.microsoft.com/en-us/download) is installed on your machine.
2. Clone this project
3. Run the follow command under the project root dir
```sh
diff --git a/build/resources/appimage/sourcegit.png b/build/resources/appimage/sourcegit.png
deleted file mode 100644
index 8cdcd3a87..000000000
Binary files a/build/resources/appimage/sourcegit.png and /dev/null differ
diff --git a/build/resources/rpm/SPECS/build.spec b/build/resources/rpm/SPECS/build.spec
index 2a684837a..669fdf846 100644
--- a/build/resources/rpm/SPECS/build.spec
+++ b/build/resources/rpm/SPECS/build.spec
@@ -20,10 +20,10 @@ mkdir -p %{buildroot}/opt/sourcegit
mkdir -p %{buildroot}/%{_bindir}
mkdir -p %{buildroot}/usr/share/applications
mkdir -p %{buildroot}/usr/share/icons
-cp -f ../../../SourceGit/* %{buildroot}/opt/sourcegit/
+cp -f %{_topdir}/../../SourceGit/* %{buildroot}/opt/sourcegit/
ln -rsf %{buildroot}/opt/sourcegit/sourcegit %{buildroot}/%{_bindir}
-cp -r ../../_common/applications %{buildroot}/%{_datadir}
-cp -r ../../_common/icons %{buildroot}/%{_datadir}
+cp -r %{_topdir}/../_common/applications %{buildroot}/%{_datadir}
+cp -r %{_topdir}/../_common/icons %{buildroot}/%{_datadir}
chmod 755 -R %{buildroot}/opt/sourcegit
chmod 755 %{buildroot}/%{_datadir}/applications/sourcegit.desktop
diff --git a/build/scripts/package.linux.sh b/build/scripts/package.linux.sh
index 1b4adbdcb..d9900cc48 100755
--- a/build/scripts/package.linux.sh
+++ b/build/scripts/package.linux.sh
@@ -41,7 +41,7 @@ cp -r SourceGit SourceGit.AppDir/opt/sourcegit
desktop-file-install resources/_common/applications/sourcegit.desktop --dir SourceGit.AppDir/usr/share/applications \
--set-icon com.sourcegit_scm.SourceGit --set-key=Exec --set-value=AppRun
mv SourceGit.AppDir/usr/share/applications/{sourcegit,com.sourcegit_scm.SourceGit}.desktop
-cp resources/appimage/sourcegit.png SourceGit.AppDir/com.sourcegit_scm.SourceGit.png
+cp resources/_common/icons/sourcegit.png SourceGit.AppDir/com.sourcegit_scm.SourceGit.png
ln -rsf SourceGit.AppDir/opt/sourcegit/sourcegit SourceGit.AppDir/AppRun
ln -rsf SourceGit.AppDir/usr/share/applications/com.sourcegit_scm.SourceGit.desktop SourceGit.AppDir
cp resources/appimage/sourcegit.appdata.xml SourceGit.AppDir/usr/share/metainfo/com.sourcegit_scm.SourceGit.appdata.xml
diff --git a/build/scripts/package.win.ps1 b/build/scripts/package.win.ps1
new file mode 100644
index 000000000..04cd07134
--- /dev/null
+++ b/build/scripts/package.win.ps1
@@ -0,0 +1,2 @@
+Remove-Item -Path build\SourceGit\*.pdb -Force
+Compress-Archive -Path build\SourceGit -DestinationPath "build\sourcegit_${env:VERSION}.${env:RUNTIME}.zip" -Force
\ No newline at end of file
diff --git a/build/scripts/package.windows.sh b/build/scripts/package.windows.sh
deleted file mode 100755
index c22a9d354..000000000
--- a/build/scripts/package.windows.sh
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/usr/bin/env bash
-
-set -e
-set -o
-set -u
-set pipefail
-
-cd build
-
-rm -rf SourceGit/*.pdb
-
-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/global.json b/global.json
index a27a2b823..32035c656 100644
--- a/global.json
+++ b/global.json
@@ -1,7 +1,7 @@
{
"sdk": {
- "version": "9.0.0",
+ "version": "10.0.0",
"rollForward": "latestMajor",
"allowPrerelease": false
}
-}
\ No newline at end of file
+}
diff --git a/src/App.Commands.cs b/src/App.Commands.cs
index f26919c73..194adc07c 100644
--- a/src/App.Commands.cs
+++ b/src/App.Commands.cs
@@ -1,6 +1,8 @@
using System;
using System.Windows.Input;
+
using Avalonia.Controls;
+using Avalonia.Controls.ApplicationLifetimes;
namespace SourceGit
{
@@ -53,5 +55,17 @@ public static bool IsCheckForUpdateCommandVisible
else if (!string.IsNullOrEmpty(textBlock.Text))
await CopyTextAsync(textBlock.Text);
});
+
+ public static readonly Command HideAppCommand = new Command(_ =>
+ {
+ if (Current is App app && app.TryGetFeature(typeof(IActivatableLifetime)) is IActivatableLifetime lifetime)
+ lifetime.TryEnterBackground();
+ });
+
+ public static readonly Command ShowAppCommand = new Command(_ =>
+ {
+ if (Current is App app && app.TryGetFeature(typeof(IActivatableLifetime)) is IActivatableLifetime lifetime)
+ lifetime.TryLeaveBackground();
+ });
}
}
diff --git a/src/App.JsonCodeGen.cs b/src/App.JsonCodeGen.cs
index d60b76515..f19480a39 100644
--- a/src/App.JsonCodeGen.cs
+++ b/src/App.JsonCodeGen.cs
@@ -60,11 +60,14 @@ public override void Write(Utf8JsonWriter writer, DataGridLength value, JsonSeri
]
)]
[JsonSerializable(typeof(Models.ExternalToolPaths))]
+ [JsonSerializable(typeof(Models.HistoryFilterCollection))]
[JsonSerializable(typeof(Models.InteractiveRebaseJobCollection))]
[JsonSerializable(typeof(Models.JetBrainsState))]
[JsonSerializable(typeof(Models.ThemeOverrides))]
[JsonSerializable(typeof(Models.Version))]
[JsonSerializable(typeof(Models.RepositorySettings))]
+ [JsonSerializable(typeof(List))]
+ [JsonSerializable(typeof(List))]
[JsonSerializable(typeof(List))]
[JsonSerializable(typeof(ViewModels.Preferences))]
internal partial class JsonCodeGen : JsonSerializerContext { }
diff --git a/src/App.axaml b/src/App.axaml
index f4dc3d893..a7a0c17f2 100644
--- a/src/App.axaml
+++ b/src/App.axaml
@@ -14,6 +14,7 @@
+
@@ -23,6 +24,7 @@
+
@@ -42,6 +44,9 @@
+
+
+
diff --git a/src/App.axaml.cs b/src/App.axaml.cs
index f5c0559a1..a247062da 100644
--- a/src/App.axaml.cs
+++ b/src/App.axaml.cs
@@ -14,10 +14,10 @@
using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Data.Core.Plugins;
+using Avalonia.Input.Platform;
using Avalonia.Markup.Xaml;
using Avalonia.Media;
using Avalonia.Media.Fonts;
-using Avalonia.Platform.Storage;
using Avalonia.Styling;
using Avalonia.Threading;
@@ -106,7 +106,7 @@ public static void LogException(Exception ex)
#endregion
#region Utility Functions
- public static object CreateViewForViewModel(object data)
+ public static Control CreateViewForViewModel(object data)
{
var dataTypeName = data.GetType().FullName;
if (string.IsNullOrEmpty(dataTypeName) || !dataTypeName.Contains(".ViewModels.", StringComparison.Ordinal))
@@ -115,7 +115,7 @@ public static object CreateViewForViewModel(object data)
var viewTypeName = dataTypeName.Replace(".ViewModels.", ".Views.");
var viewType = Type.GetType(viewTypeName);
if (viewType != null)
- return Activator.CreateInstance(viewType);
+ return Activator.CreateInstance(viewType) as Control;
return null;
}
@@ -159,19 +159,31 @@ public static void ShowWindow(object data)
}
}
- public static async Task AskConfirmAsync(string message, Action onSure)
+ public static async Task AskConfirmAsync(string message)
{
if (Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime { MainWindow: { } owner })
{
var confirm = new Views.Confirm();
confirm.Message.Text = message;
- confirm.OnSure = onSure;
return await confirm.ShowDialog(owner);
}
return false;
}
+ public static async Task AskConfirmEmptyCommitAsync(bool hasLocalChanges)
+ {
+ if (Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime { MainWindow: { } owner })
+ {
+ var confirm = new Views.ConfirmEmptyCommit();
+ confirm.TxtMessage.Text = Text(hasLocalChanges ? "ConfirmEmptyCommit.WithLocalChanges" : "ConfirmEmptyCommit.NoLocalChanges");
+ confirm.BtnStageAllAndCommit.IsVisible = hasLocalChanges;
+ return await confirm.ShowDialog(owner);
+ }
+
+ return Models.ConfirmEmptyCommitResult.Cancel;
+ }
+
public static void RaiseException(string context, string message)
{
if (Current is App { _launcher: not null } app)
@@ -236,8 +248,6 @@ public static void SetTheme(string theme, string themeOverridesFile)
else
Models.CommitGraph.SetDefaultPens(overrides.GraphPenThickness);
- Models.Commit.OpacityForNotMerged = overrides.OpacityForNotMergedCommits;
-
app.Resources.MergedDictionaries.Add(resDic);
app._themeOverrides = resDic;
}
@@ -252,7 +262,7 @@ public static void SetTheme(string theme, string themeOverridesFile)
}
}
- public static void SetFonts(string defaultFont, string monospaceFont, bool onlyUseMonospaceFontInEditor)
+ public static void SetFonts(string defaultFont, string monospaceFont)
{
if (Current is not App app)
return;
@@ -275,7 +285,7 @@ public static void SetFonts(string defaultFont, string monospaceFont, bool onlyU
if (!string.IsNullOrEmpty(defaultFont))
{
monospaceFont = $"fonts:SourceGit#JetBrains Mono,{defaultFont}";
- resDic.Add("Fonts.Monospace", new FontFamily(monospaceFont));
+ resDic.Add("Fonts.Monospace", FontFamily.Parse(monospaceFont));
}
}
else
@@ -283,20 +293,7 @@ public static void SetFonts(string defaultFont, string monospaceFont, bool onlyU
if (!string.IsNullOrEmpty(defaultFont) && !monospaceFont.Contains(defaultFont, StringComparison.Ordinal))
monospaceFont = $"{monospaceFont},{defaultFont}";
- resDic.Add("Fonts.Monospace", new FontFamily(monospaceFont));
- }
-
- if (onlyUseMonospaceFontInEditor)
- {
- if (string.IsNullOrEmpty(defaultFont))
- resDic.Add("Fonts.Primary", new FontFamily("fonts:Inter#Inter"));
- else
- resDic.Add("Fonts.Primary", new FontFamily(defaultFont));
- }
- else
- {
- if (!string.IsNullOrEmpty(monospaceFont))
- resDic.Add("Fonts.Primary", new FontFamily(monospaceFont));
+ resDic.Add("Fonts.Monospace", FontFamily.Parse(monospaceFont));
}
if (resDic.Count > 0)
@@ -315,7 +312,7 @@ public static async Task CopyTextAsync(string data)
public static async Task GetClipboardTextAsync()
{
if (Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime { MainWindow.Clipboard: { } clipboard })
- return await clipboard.GetTextAsync();
+ return await clipboard.TryGetTextAsync();
return null;
}
@@ -344,14 +341,6 @@ public static Avalonia.Controls.Shapes.Path CreateMenuIcon(string key)
return icon;
}
- public static IStorageProvider GetStorageProvider()
- {
- if (Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
- return desktop.MainWindow?.StorageProvider;
-
- return null;
- }
-
public static ViewModels.Launcher GetLauncher()
{
return Current is App app ? app._launcher : null;
@@ -381,7 +370,7 @@ public override void Initialize()
SetLocale(pref.Locale);
SetTheme(pref.Theme, pref.ThemeOverrides);
- SetFonts(pref.DefaultFontFamily, pref.MonospaceFontFamily, pref.OnlyUseMonoFontInEditor);
+ SetFonts(pref.DefaultFontFamily, pref.MonospaceFontFamily);
}
public override void OnFrameworkInitializationCompleted()
@@ -398,6 +387,9 @@ public override void OnFrameworkInitializationCompleted()
e.Cancel = true;
});
+ if (TryLaunchAsFileHistoryViewer(desktop))
+ return;
+
if (TryLaunchAsCoreEditor(desktop))
return;
@@ -446,7 +438,7 @@ private static bool TryLaunchAsRebaseTodoEditor(string[] args, out int exitCode)
if (!dirInfo.Exists || !dirInfo.Name.Equals("rebase-merge", StringComparison.Ordinal))
return true;
- var jobsFile = Path.Combine(dirInfo.Parent!.FullName, "sourcegit_rebase_jobs.json");
+ var jobsFile = Path.Combine(dirInfo.Parent!.FullName, "sourcegit.interactive_rebase");
if (!File.Exists(jobsFile))
return true;
@@ -491,7 +483,7 @@ private static bool TryLaunchAsRebaseMessageEditor(string[] args, out int exitCo
var origHeadFile = Path.Combine(gitDir, "rebase-merge", "orig-head");
var ontoFile = Path.Combine(gitDir, "rebase-merge", "onto");
var doneFile = Path.Combine(gitDir, "rebase-merge", "done");
- var jobsFile = Path.Combine(gitDir, "sourcegit_rebase_jobs.json");
+ var jobsFile = Path.Combine(gitDir, "sourcegit.interactive_rebase");
if (!File.Exists(ontoFile) || !File.Exists(origHeadFile) || !File.Exists(doneFile) || !File.Exists(jobsFile))
return true;
@@ -524,6 +516,33 @@ private static bool TryLaunchAsRebaseMessageEditor(string[] args, out int exitCo
return true;
}
+ private bool TryLaunchAsFileHistoryViewer(IClassicDesktopStyleApplicationLifetime desktop)
+ {
+ var args = desktop.Args;
+ if (args is not { Length: > 1 } || !args[0].Equals("--file-history", StringComparison.Ordinal))
+ return false;
+
+ var file = Path.GetFullPath(args[1]);
+ var dir = Path.GetDirectoryName(file);
+
+ var test = new Commands.QueryRepositoryRootPath(dir).GetResult();
+ if (!test.IsSuccess || string.IsNullOrEmpty(test.StdOut))
+ {
+ Console.Out.WriteLine($"'{args[1]}' is not in a valid git repository");
+ desktop.Shutdown(-1);
+ return true;
+ }
+
+ var repo = test.StdOut.Trim();
+ var relFile = Path.GetRelativePath(repo, file);
+ var viewer = new Views.FileHistories()
+ {
+ DataContext = new ViewModels.FileHistories(repo, relFile)
+ };
+ desktop.MainWindow = viewer;
+ return true;
+ }
+
private bool TryLaunchAsCoreEditor(IClassicDesktopStyleApplicationLifetime desktop)
{
var args = desktop.Args;
@@ -587,7 +606,7 @@ private void TryOpenRepository(string repo)
{
if (!string.IsNullOrEmpty(repo) && Directory.Exists(repo))
{
- var test = new Commands.QueryRepositoryRootPath(repo).GetResultAsync().Result;
+ var test = new Commands.QueryRepositoryRootPath(repo).GetResult();
if (test.IsSuccess && !string.IsNullOrEmpty(test.StdOut))
{
Dispatcher.UIThread.Invoke(() =>
@@ -618,10 +637,10 @@ private void Check4Update(bool manually = false)
try
{
// Fetch latest release information.
- using var client = new HttpClient() { Timeout = TimeSpan.FromSeconds(5) };
- var data = await client.GetStringAsync("https://sourcegit-scm.github.io/data/version.json");
+ using var client = new HttpClient();
+ client.Timeout = TimeSpan.FromSeconds(5);
- // Parse JSON into Models.Version.
+ var data = await client.GetStringAsync("https://sourcegit-scm.github.io/data/version.json");
var ver = JsonSerializer.Deserialize(data, JsonCodeGen.Default.Version);
if (ver == null)
return;
@@ -674,9 +693,8 @@ private string FixFontFamilyName(string input)
if (string.IsNullOrEmpty(t))
continue;
- // Collapse multiple spaces into single space
- var prevChar = '\0';
var sb = new StringBuilder();
+ var prevChar = '\0';
foreach (var c in t)
{
@@ -687,14 +705,16 @@ private string FixFontFamilyName(string input)
}
var name = sb.ToString();
- if (name.Contains('#'))
+ try
{
- if (!name.Equals("fonts:Inter#Inter", StringComparison.Ordinal) &&
- !name.Equals("fonts:SourceGit#JetBrains Mono", StringComparison.Ordinal))
- continue;
+ var fontFamily = FontFamily.Parse(name);
+ if (fontFamily.FamilyTypefaces.Count > 0)
+ trimmed.Add(name);
+ }
+ catch
+ {
+ // Ignore exceptions.
}
-
- trimmed.Add(name);
}
return trimmed.Count > 0 ? string.Join(',', trimmed) : string.Empty;
diff --git a/src/Commands/Add.cs b/src/Commands/Add.cs
index 9bd576359..916063d82 100644
--- a/src/Commands/Add.cs
+++ b/src/Commands/Add.cs
@@ -2,25 +2,11 @@
{
public class Add : Command
{
- public Add(string repo, bool includeUntracked)
- {
- WorkingDirectory = repo;
- Context = repo;
- Args = includeUntracked ? "add ." : "add -u .";
- }
-
- public Add(string repo, Models.Change change)
- {
- WorkingDirectory = repo;
- Context = repo;
- Args = $"add -- {change.Path.Quoted()}";
- }
-
public Add(string repo, string pathspecFromFile)
{
WorkingDirectory = repo;
Context = repo;
- Args = $"add --pathspec-from-file={pathspecFromFile.Quoted()}";
+ Args = $"add --force --verbose --pathspec-from-file={pathspecFromFile.Quoted()}";
}
}
}
diff --git a/src/Commands/Apply.cs b/src/Commands/Apply.cs
index 189d43359..ca6ffe8d9 100644
--- a/src/Commands/Apply.cs
+++ b/src/Commands/Apply.cs
@@ -1,4 +1,6 @@
-namespace SourceGit.Commands
+using System.Text;
+
+namespace SourceGit.Commands
{
public class Apply : Command
{
@@ -6,14 +8,19 @@ public Apply(string repo, string file, bool ignoreWhitespace, string whitespaceM
{
WorkingDirectory = repo;
Context = repo;
- Args = "apply ";
+
+ var builder = new StringBuilder(1024);
+ builder.Append("apply ");
+
if (ignoreWhitespace)
- Args += "--ignore-whitespace ";
+ builder.Append("--ignore-whitespace ");
else
- Args += $"--whitespace={whitespaceMode} ";
+ builder.Append("--whitespace=").Append(whitespaceMode).Append(' ');
+
if (!string.IsNullOrEmpty(extra))
- Args += $"{extra} ";
- Args += $"{file.Quoted()}";
+ builder.Append(extra).Append(' ');
+
+ Args = builder.Append(file.Quoted()).ToString();
}
}
}
diff --git a/src/Commands/Branch.cs b/src/Commands/Branch.cs
index 1928154e9..efb325d06 100644
--- a/src/Commands/Branch.cs
+++ b/src/Commands/Branch.cs
@@ -32,12 +32,12 @@ public async Task RenameAsync(string to)
return await ExecAsync().ConfigureAwait(false);
}
- public async Task SetUpstreamAsync(string upstream)
+ public async Task SetUpstreamAsync(Models.Branch tracking)
{
- if (string.IsNullOrEmpty(upstream))
+ if (tracking == null)
Args = $"branch {_name} --unset-upstream";
else
- Args = $"branch {_name} -u {upstream}";
+ Args = $"branch {_name} -u {tracking.FriendlyName}";
return await ExecAsync().ConfigureAwait(false);
}
diff --git a/src/Commands/Checkout.cs b/src/Commands/Checkout.cs
index 23cbd413b..024636bf9 100644
--- a/src/Commands/Checkout.cs
+++ b/src/Commands/Checkout.cs
@@ -72,5 +72,20 @@ public async Task FileWithRevisionAsync(string file, string revision)
Args = $"checkout --no-overlay {revision} -- {file.Quoted()}";
return await ExecAsync().ConfigureAwait(false);
}
+
+ public async Task MultipleFilesWithRevisionAsync(List files, string revision)
+ {
+ var builder = new StringBuilder();
+ builder
+ .Append("checkout --no-overlay ")
+ .Append(revision)
+ .Append(" --");
+
+ foreach (var f in files)
+ builder.Append(' ').Append(f.Quoted());
+
+ Args = builder.ToString();
+ return await ExecAsync().ConfigureAwait(false);
+ }
}
}
diff --git a/src/Commands/CherryPick.cs b/src/Commands/CherryPick.cs
index 0c82b9fda..d9d4faea2 100644
--- a/src/Commands/CherryPick.cs
+++ b/src/Commands/CherryPick.cs
@@ -1,4 +1,6 @@
-namespace SourceGit.Commands
+using System.Text;
+
+namespace SourceGit.Commands
{
public class CherryPick : Command
{
@@ -7,14 +9,16 @@ public CherryPick(string repo, string commits, bool noCommit, bool appendSourceT
WorkingDirectory = repo;
Context = repo;
- Args = "cherry-pick ";
+ var builder = new StringBuilder(1024);
+ builder.Append("cherry-pick ");
if (noCommit)
- Args += "-n ";
+ builder.Append("-n ");
if (appendSourceToMessage)
- Args += "-x ";
+ builder.Append("-x ");
if (!string.IsNullOrEmpty(extraParams))
- Args += $"{extraParams} ";
- Args += commits;
+ builder.Append(extraParams).Append(' ');
+
+ Args = builder.Append(commits).ToString();
}
}
}
diff --git a/src/Commands/Clone.cs b/src/Commands/Clone.cs
index efec264b8..ec3c4594c 100644
--- a/src/Commands/Clone.cs
+++ b/src/Commands/Clone.cs
@@ -1,4 +1,6 @@
-namespace SourceGit.Commands
+using System.Text;
+
+namespace SourceGit.Commands
{
public class Clone : Command
{
@@ -7,15 +9,16 @@ public Clone(string ctx, string path, string url, string localName, string sshKe
Context = ctx;
WorkingDirectory = path;
SSHKey = sshKey;
- Args = "clone --progress --verbose ";
+ var builder = new StringBuilder(1024);
+ builder.Append("clone --progress --verbose ");
if (!string.IsNullOrEmpty(extraArgs))
- Args += $"{extraArgs} ";
-
- Args += $"{url} ";
-
+ builder.Append(extraArgs).Append(' ');
+ builder.Append(url).Append(' ');
if (!string.IsNullOrEmpty(localName))
- Args += localName;
+ builder.Append(localName);
+
+ Args = builder.ToString();
}
}
}
diff --git a/src/Commands/Command.cs b/src/Commands/Command.cs
index 11a25b369..e6e64f054 100644
--- a/src/Commands/Command.cs
+++ b/src/Commands/Command.cs
@@ -37,19 +37,6 @@ public enum EditorType
public bool RaiseError { get; set; } = true;
public Models.ICommandLog Log { get; set; } = null;
- public void Exec()
- {
- try
- {
- var start = CreateGitStartInfo(false);
- Process.Start(start);
- }
- catch (Exception ex)
- {
- App.RaiseException(Context, ex.Message);
- }
- }
-
public async Task ExecAsync()
{
Log?.AppendLine($"$ git {Args}\n");
@@ -61,8 +48,8 @@ public async Task ExecAsync()
proc.OutputDataReceived += (_, e) => HandleOutput(e.Data, errs);
proc.ErrorDataReceived += (_, e) => HandleOutput(e.Data, errs);
- Process dummy = null;
- var dummyProcLock = new object();
+ var captured = new CapturedProcess() { Process = proc };
+ var capturedLock = new object();
try
{
proc.Start();
@@ -70,13 +57,12 @@ public async Task ExecAsync()
// Not safe, please only use `CancellationToken` in readonly commands.
if (CancellationToken.CanBeCanceled)
{
- dummy = proc;
CancellationToken.Register(() =>
{
- lock (dummyProcLock)
+ lock (capturedLock)
{
- if (dummy is { HasExited: false })
- dummy.Kill();
+ if (captured is { Process: { HasExited: false } })
+ captured.Process.Kill();
}
});
}
@@ -102,12 +88,9 @@ public async Task ExecAsync()
HandleOutput(e.Message, errs);
}
- if (dummy != null)
+ lock (capturedLock)
{
- lock (dummyProcLock)
- {
- dummy = null;
- }
+ captured.Process = null;
}
Log?.AppendLine(string.Empty);
@@ -127,9 +110,33 @@ public async Task ExecAsync()
return true;
}
+ protected Result ReadToEnd()
+ {
+ using var proc = new Process();
+ proc.StartInfo = CreateGitStartInfo(true);
+
+ try
+ {
+ proc.Start();
+ }
+ catch (Exception e)
+ {
+ return Result.Failed(e.Message);
+ }
+
+ var rs = new Result() { IsSuccess = true };
+ rs.StdOut = proc.StandardOutput.ReadToEnd();
+ rs.StdErr = proc.StandardError.ReadToEnd();
+ proc.WaitForExit();
+
+ rs.IsSuccess = proc.ExitCode == 0;
+ return rs;
+ }
+
protected async Task ReadToEndAsync()
{
- using var proc = new Process() { StartInfo = CreateGitStartInfo(true) };
+ using var proc = new Process();
+ proc.StartInfo = CreateGitStartInfo(true);
try
{
@@ -149,7 +156,7 @@ protected async Task ReadToEndAsync()
return rs;
}
- private ProcessStartInfo CreateGitStartInfo(bool redirect)
+ protected ProcessStartInfo CreateGitStartInfo(bool redirect)
{
var start = new ProcessStartInfo();
start.FileName = Native.OS.GitExecutable;
@@ -167,12 +174,14 @@ private ProcessStartInfo CreateGitStartInfo(bool redirect)
// Force using this app as SSH askpass program
var selfExecFile = Process.GetCurrentProcess().MainModule!.FileName;
start.Environment.Add("SSH_ASKPASS", selfExecFile); // Can not use parameter here, because it invoked by SSH with `exec`
- start.Environment.Add("SSH_ASKPASS_REQUIRE", "force");
+ start.Environment.Add("SSH_ASKPASS_REQUIRE", "prefer");
start.Environment.Add("SOURCEGIT_LAUNCH_AS_ASKPASS", "TRUE");
+ if (!OperatingSystem.IsLinux())
+ start.Environment.Add("DISPLAY", "required");
// If an SSH private key was provided, sets the environment.
if (!start.Environment.ContainsKey("GIT_SSH_COMMAND") && !string.IsNullOrEmpty(SSHKey))
- start.Environment.Add("GIT_SSH_COMMAND", $"ssh -i '{SSHKey}'");
+ start.Environment.Add("GIT_SSH_COMMAND", $"ssh -i '{SSHKey}' -F '/dev/null'");
// Force using en_US.UTF-8 locale
if (OperatingSystem.IsLinux())
@@ -181,7 +190,7 @@ private ProcessStartInfo CreateGitStartInfo(bool redirect)
start.Environment.Add("LC_ALL", "C");
}
- var builder = new StringBuilder();
+ var builder = new StringBuilder(2048);
builder
.Append("--no-pager -c core.quotepath=off -c credential.helper=")
.Append(Native.OS.CredentialHelper)
@@ -234,6 +243,11 @@ private void HandleOutput(string line, List errs)
errs.Add(line);
}
+ private class CapturedProcess
+ {
+ public Process Process { get; set; } = null;
+ }
+
[GeneratedRegex(@"\d+%")]
private static partial Regex REG_PROGRESS();
}
diff --git a/src/Commands/Commit.cs b/src/Commands/Commit.cs
index 41d650f76..b756c4ab4 100644
--- a/src/Commands/Commit.cs
+++ b/src/Commands/Commit.cs
@@ -1,22 +1,39 @@
using System.IO;
+using System.Text;
using System.Threading.Tasks;
namespace SourceGit.Commands
{
public class Commit : Command
{
- public Commit(string repo, string message, bool signOff, bool amend, bool resetAuthor)
+ public Commit(string repo, string message, bool signOff, bool noVerify, bool amend, bool resetAuthor)
{
_tmpFile = Path.GetTempFileName();
_message = message;
WorkingDirectory = repo;
Context = repo;
- Args = $"commit --allow-empty --file={_tmpFile.Quoted()}";
+
+ var builder = new StringBuilder();
+ builder.Append("commit --allow-empty --file=");
+ builder.Append(_tmpFile.Quoted());
+ builder.Append(' ');
+
if (signOff)
- Args += " --signoff";
+ builder.Append("--signoff ");
+
+ if (noVerify)
+ builder.Append("--no-verify ");
+
if (amend)
- Args += resetAuthor ? " --amend --reset-author --no-edit" : " --amend --no-edit";
+ {
+ builder.Append("--amend ");
+ if (resetAuthor)
+ builder.Append("--reset-author ");
+ builder.Append("--no-edit");
+ }
+
+ Args = builder.ToString();
}
public async Task RunAsync()
@@ -34,7 +51,7 @@ public async Task RunAsync()
}
}
- private readonly string _tmpFile = string.Empty;
- private readonly string _message = string.Empty;
+ private readonly string _tmpFile;
+ private readonly string _message;
}
}
diff --git a/src/Commands/CompareRevisions.cs b/src/Commands/CompareRevisions.cs
index 7951e6adf..a4ed972d6 100644
--- a/src/Commands/CompareRevisions.cs
+++ b/src/Commands/CompareRevisions.cs
@@ -1,5 +1,5 @@
-using System;
-using System.Collections.Generic;
+using System.Collections.Generic;
+using System.Diagnostics;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
@@ -33,56 +33,62 @@ public CompareRevisions(string repo, string start, string end, string path)
public async Task> ReadAsync()
{
var changes = new List();
- var rs = await ReadToEndAsync().ConfigureAwait(false);
- if (!rs.IsSuccess)
- return changes;
+ try
+ {
+ using var proc = new Process();
+ proc.StartInfo = CreateGitStartInfo(true);
+ proc.Start();
- var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
- foreach (var line in lines)
- ParseLine(changes, line);
+ while (await proc.StandardOutput.ReadLineAsync().ConfigureAwait(false) is { } line)
+ {
+ 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);
+ }
- changes.Sort((l, r) => Models.NumericSort.Compare(l.Path, r.Path));
- return changes;
- }
+ continue;
+ }
- private void ParseLine(List outs, string line)
- {
- 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);
- }
+ var change = new Models.Change() { Path = match.Groups[2].Value };
+ var status = match.Groups[1].Value;
- return;
- }
+ switch (status[0])
+ {
+ 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 'C':
+ change.Set(Models.ChangeState.Copied);
+ changes.Add(change);
+ break;
+ }
+ }
- var change = new Models.Change() { Path = match.Groups[2].Value };
- var status = match.Groups[1].Value;
+ await proc.WaitForExitAsync().ConfigureAwait(false);
- switch (status[0])
+ changes.Sort((l, r) => Models.NumericSort.Compare(l.Path, r.Path));
+ }
+ catch
{
- 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;
+ //ignore changes;
}
+
+ return changes;
}
}
}
diff --git a/src/Commands/Config.cs b/src/Commands/Config.cs
index 0348c5109..52fc021cb 100644
--- a/src/Commands/Config.cs
+++ b/src/Commands/Config.cs
@@ -20,6 +20,26 @@ public Config(string repository)
}
}
+ public Dictionary ReadAll()
+ {
+ Args = "config -l";
+
+ var output = ReadToEnd();
+ var rs = new Dictionary();
+ if (output.IsSuccess)
+ {
+ var lines = output.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
+ foreach (var line in lines)
+ {
+ var parts = line.Split('=', 2);
+ if (parts.Length == 2)
+ rs[parts[0]] = parts[1];
+ }
+ }
+
+ return rs;
+ }
+
public async Task> ReadAllAsync()
{
Args = "config -l";
@@ -40,6 +60,12 @@ public async Task> ReadAllAsync()
return rs;
}
+ public string Get(string key)
+ {
+ Args = $"config {key}";
+ return ReadToEnd().StdOut.Trim();
+ }
+
public async Task GetAsync(string key)
{
Args = $"config {key}";
diff --git a/src/Commands/CountLocalChangesWithoutUntracked.cs b/src/Commands/CountLocalChanges.cs
similarity index 66%
rename from src/Commands/CountLocalChangesWithoutUntracked.cs
rename to src/Commands/CountLocalChanges.cs
index 769d732e9..17916926d 100644
--- a/src/Commands/CountLocalChangesWithoutUntracked.cs
+++ b/src/Commands/CountLocalChanges.cs
@@ -3,13 +3,14 @@
namespace SourceGit.Commands
{
- public class CountLocalChangesWithoutUntracked : Command
+ public class CountLocalChanges : Command
{
- public CountLocalChangesWithoutUntracked(string repo)
+ public CountLocalChanges(string repo, bool includeUntracked)
{
+ var option = includeUntracked ? "-uall" : "-uno";
WorkingDirectory = repo;
Context = repo;
- Args = "--no-optional-locks status -uno --ignore-submodules=all --porcelain";
+ Args = $"--no-optional-locks status {option} --ignore-submodules=all --porcelain";
}
public async Task GetResultAsync()
diff --git a/src/Commands/Diff.cs b/src/Commands/Diff.cs
index 3eae1b54b..680aff63d 100644
--- a/src/Commands/Diff.cs
+++ b/src/Commands/Diff.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
-using System.IO;
+using System.Diagnostics;
+using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
@@ -20,29 +21,53 @@ public partial class Diff : Command
public Diff(string repo, Models.DiffOption opt, int unified, bool ignoreWhitespace)
{
- _result.TextDiff = new Models.TextDiff()
- {
- Repo = repo,
- Option = opt,
- };
+ _result.TextDiff = new Models.TextDiff();
WorkingDirectory = repo;
Context = repo;
+ var builder = new StringBuilder(256);
+ builder.Append("diff --no-color --no-ext-diff --patch ");
+ if (Models.DiffOption.IgnoreCRAtEOL)
+ builder.Append("--ignore-cr-at-eol ");
if (ignoreWhitespace)
- Args = $"diff --no-ext-diff --patch --ignore-all-space --unified={unified} {opt}";
- else if (Models.DiffOption.IgnoreCRAtEOL)
- Args = $"diff --no-ext-diff --patch --ignore-cr-at-eol --unified={unified} {opt}";
- else
- Args = $"diff --no-ext-diff --patch --unified={unified} {opt}";
+ builder.Append("--ignore-space-change ");
+ builder.Append("--unified=").Append(unified).Append(' ');
+ builder.Append(opt.ToString());
+
+ Args = builder.ToString();
}
public async Task ReadAsync()
{
- var rs = await ReadToEndAsync().ConfigureAwait(false);
- var sr = new StringReader(rs.StdOut);
- while (sr.ReadLine() is { } line)
- ParseLine(line);
+ try
+ {
+ using var proc = new Process();
+ proc.StartInfo = CreateGitStartInfo(true);
+ proc.Start();
+
+ var text = await proc.StandardOutput.ReadToEndAsync().ConfigureAwait(false);
+
+ var start = 0;
+ var end = text.IndexOf('\n', start);
+ while (end > 0)
+ {
+ var line = text[start..end];
+ ParseLine(line);
+
+ start = end + 1;
+ end = text.IndexOf('\n', start);
+ }
+
+ if (start < text.Length)
+ ParseLine(text[start..]);
+
+ await proc.WaitForExitAsync().ConfigureAwait(false);
+ }
+ catch
+ {
+ // Ignore exceptions.
+ }
if (_result.IsBinary || _result.IsLFS || _result.TextDiff.Lines.Count == 0)
{
@@ -240,10 +265,10 @@ private void ProcessInlineHighlights()
foreach (var chunk in chunks)
{
if (chunk.DeletedCount > 0)
- left.Highlights.Add(new Models.TextInlineRange(chunk.DeletedStart, chunk.DeletedCount));
+ left.Highlights.Add(new Models.TextRange(chunk.DeletedStart, chunk.DeletedCount));
if (chunk.AddedCount > 0)
- right.Highlights.Add(new Models.TextInlineRange(chunk.AddedStart, chunk.AddedCount));
+ right.Highlights.Add(new Models.TextRange(chunk.AddedStart, chunk.AddedCount));
}
}
}
diff --git a/src/Commands/DiffTool.cs b/src/Commands/DiffTool.cs
index b80f55959..5bc23db36 100644
--- a/src/Commands/DiffTool.cs
+++ b/src/Commands/DiffTool.cs
@@ -1,47 +1,77 @@
-using System.IO;
+using System;
+using System.Diagnostics;
namespace SourceGit.Commands
{
public class DiffTool : Command
{
- public DiffTool(string repo, int type, string exec, Models.DiffOption option)
+ public DiffTool(string repo, Models.DiffOption option)
{
WorkingDirectory = repo;
Context = repo;
-
- _merger = Models.ExternalMerger.Supported.Find(x => x.Type == type);
- _exec = exec;
_option = option;
}
public void Open()
{
- if (_merger == null)
+ var tool = Native.OS.GetDiffMergeTool(true);
+ if (tool == null)
{
- App.RaiseException(Context, "Invalid merge tool in preference setting!");
+ App.RaiseException(Context, "Invalid diff/merge tool in preference setting!");
return;
}
- if (_merger.Type == 0)
+ if (string.IsNullOrEmpty(tool.Cmd))
{
+ if (!CheckGitConfiguration())
+ return;
+
Args = $"difftool -g --no-prompt {_option}";
}
- else if (File.Exists(_exec))
+ else
{
- var cmd = $"{_exec.Quoted()} {_merger.DiffCmd}";
+ var cmd = $"{tool.Exec.Quoted()} {tool.Cmd}";
Args = $"-c difftool.sourcegit.cmd={cmd.Quoted()} difftool --tool=sourcegit --no-prompt {_option}";
}
- else
+
+ try
{
- App.RaiseException(Context, $"Can NOT find external diff tool in '{_exec}'!");
- return;
+ Process.Start(CreateGitStartInfo(false));
+ }
+ catch (Exception ex)
+ {
+ App.RaiseException(Context, ex.Message);
+ }
+ }
+
+ private bool CheckGitConfiguration()
+ {
+ var config = new Config(WorkingDirectory).ReadAll();
+ if (config.TryGetValue("diff.guitool", out var guiTool))
+ return CheckCLIBasedTool(guiTool);
+ if (config.TryGetValue("merge.guitool", out var mergeGuiTool))
+ return CheckCLIBasedTool(mergeGuiTool);
+ if (config.TryGetValue("diff.tool", out var diffTool))
+ return CheckCLIBasedTool(diffTool);
+ if (config.TryGetValue("merge.tool", out var mergeTool))
+ return CheckCLIBasedTool(mergeTool);
+
+ App.RaiseException(Context, "Missing git configuration: diff.guitool");
+ return false;
+ }
+
+ private bool CheckCLIBasedTool(string tool)
+ {
+ if (tool.StartsWith("vimdiff", StringComparison.Ordinal) ||
+ tool.StartsWith("nvimdiff", StringComparison.Ordinal))
+ {
+ App.RaiseException(Context, $"CLI based diff tool \"{tool}\" is not supported by this app!");
+ return false;
}
- Exec();
+ return true;
}
- private Models.ExternalMerger _merger;
- private string _exec;
private Models.DiffOption _option;
}
}
diff --git a/src/Commands/Discard.cs b/src/Commands/Discard.cs
index cbf38bd49..aad589112 100644
--- a/src/Commands/Discard.cs
+++ b/src/Commands/Discard.cs
@@ -86,7 +86,7 @@ public static async Task ChangesAsync(string repo, List changes,
{
var pathSpecFile = Path.GetTempFileName();
await File.WriteAllLinesAsync(pathSpecFile, restores).ConfigureAwait(false);
- await new Restore(repo, pathSpecFile, false).Use(log).ExecAsync().ConfigureAwait(false);
+ await new Restore(repo, pathSpecFile).Use(log).ExecAsync().ConfigureAwait(false);
File.Delete(pathSpecFile);
}
}
diff --git a/src/Commands/Fetch.cs b/src/Commands/Fetch.cs
index d25cc80c8..914361257 100644
--- a/src/Commands/Fetch.cs
+++ b/src/Commands/Fetch.cs
@@ -1,4 +1,5 @@
-using System.Threading.Tasks;
+using System.Text;
+using System.Threading.Tasks;
namespace SourceGit.Commands
{
@@ -6,27 +7,35 @@ public class Fetch : Command
{
public Fetch(string repo, string remote, bool noTags, bool force)
{
- _remoteKey = $"remote.{remote}.sshkey";
+ _remote = remote;
WorkingDirectory = repo;
Context = repo;
- Args = "fetch --progress --verbose ";
-
- if (noTags)
- Args += "--no-tags ";
- else
- Args += "--tags ";
+ var builder = new StringBuilder(512);
+ builder.Append("fetch --progress --verbose ");
+ builder.Append(noTags ? "--no-tags " : "--tags ");
if (force)
- Args += "--force ";
+ builder.Append("--force ");
+ builder.Append(remote);
+
+ Args = builder.ToString();
+ }
- Args += remote;
+ public Fetch(string repo, string remote)
+ {
+ _remote = remote;
+
+ WorkingDirectory = repo;
+ Context = repo;
+ RaiseError = false;
+ Args = $"fetch --progress --verbose {remote}";
}
public Fetch(string repo, Models.Branch local, Models.Branch remote)
{
- _remoteKey = $"remote.{remote.Remote}.sshkey";
+ _remote = remote.Remote;
WorkingDirectory = repo;
Context = repo;
@@ -35,10 +44,10 @@ public Fetch(string repo, Models.Branch local, Models.Branch remote)
public async Task RunAsync()
{
- SSHKey = await new Config(WorkingDirectory).GetAsync(_remoteKey).ConfigureAwait(false);
+ SSHKey = await new Config(WorkingDirectory).GetAsync($"remote.{_remote}.sshkey").ConfigureAwait(false);
return await ExecAsync().ConfigureAwait(false);
}
- private readonly string _remoteKey;
+ private readonly string _remote;
}
}
diff --git a/src/Commands/GenerateCommitMessage.cs b/src/Commands/GenerateCommitMessage.cs
index 4889881bf..bbefa34e5 100644
--- a/src/Commands/GenerateCommitMessage.cs
+++ b/src/Commands/GenerateCommitMessage.cs
@@ -17,7 +17,7 @@ public GetDiffContent(string repo, Models.DiffOption opt)
{
WorkingDirectory = repo;
Context = repo;
- Args = $"diff --diff-algorithm=minimal {opt}";
+ Args = $"diff --no-color --no-ext-diff --diff-algorithm=minimal {opt}";
}
public async Task ReadAsync()
diff --git a/src/Commands/InteractiveRebase.cs b/src/Commands/InteractiveRebase.cs
index ebcadec13..7e4ca86b2 100644
--- a/src/Commands/InteractiveRebase.cs
+++ b/src/Commands/InteractiveRebase.cs
@@ -1,4 +1,6 @@
-namespace SourceGit.Commands
+using System.Text;
+
+namespace SourceGit.Commands
{
public class InteractiveRebase : Command
{
@@ -7,10 +9,13 @@ public InteractiveRebase(string repo, string basedOn, bool autoStash)
WorkingDirectory = repo;
Context = repo;
Editor = EditorType.RebaseEditor;
- Args = "rebase -i --autosquash ";
+
+ var builder = new StringBuilder(512);
+ builder.Append("rebase -i --autosquash ");
if (autoStash)
- Args += "--autostash ";
- Args += basedOn;
+ builder.Append("--autostash ");
+
+ Args = builder.Append(basedOn).ToString();
}
}
}
diff --git a/src/Commands/IsAncestor.cs b/src/Commands/IsAncestor.cs
new file mode 100644
index 000000000..e40793e2d
--- /dev/null
+++ b/src/Commands/IsAncestor.cs
@@ -0,0 +1,20 @@
+using System.Threading.Tasks;
+
+namespace SourceGit.Commands
+{
+ public class IsAncestor : Command
+ {
+ public IsAncestor(string repo, string checkPoint, string endPoint)
+ {
+ WorkingDirectory = repo;
+ Context = repo;
+ Args = $"merge-base --is-ancestor {checkPoint} {endPoint}";
+ }
+
+ public async Task GetResultAsync()
+ {
+ var rs = await ReadToEndAsync().ConfigureAwait(false);
+ return rs.IsSuccess;
+ }
+ }
+}
diff --git a/src/Commands/IsBareRepository.cs b/src/Commands/IsBareRepository.cs
index 98b127ce6..03520131c 100644
--- a/src/Commands/IsBareRepository.cs
+++ b/src/Commands/IsBareRepository.cs
@@ -11,6 +11,17 @@ public IsBareRepository(string path)
Args = "rev-parse --is-bare-repository";
}
+ public bool GetResult()
+ {
+ 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";
+ }
+
public async Task GetResultAsync()
{
if (!Directory.Exists(Path.Combine(WorkingDirectory, "refs")) ||
diff --git a/src/Commands/IsBinary.cs b/src/Commands/IsBinary.cs
index 0e60f38c6..087e71c7b 100644
--- a/src/Commands/IsBinary.cs
+++ b/src/Commands/IsBinary.cs
@@ -12,7 +12,7 @@ public IsBinary(string repo, string commit, string path)
{
WorkingDirectory = repo;
Context = repo;
- Args = $"diff {Models.Commit.EmptyTreeSHA1} {commit} --numstat -- {path.Quoted()}";
+ Args = $"diff --no-color --no-ext-diff --numstat {Models.Commit.EmptyTreeSHA1} {commit} -- {path.Quoted()}";
RaiseError = false;
}
diff --git a/src/Commands/IsConflictResolved.cs b/src/Commands/IsConflictResolved.cs
index 2d53766a2..e5b752d35 100644
--- a/src/Commands/IsConflictResolved.cs
+++ b/src/Commands/IsConflictResolved.cs
@@ -10,7 +10,12 @@ public IsConflictResolved(string repo, Models.Change change)
WorkingDirectory = repo;
Context = repo;
- Args = $"diff -a --ignore-cr-at-eol --check {opt}";
+ Args = $"diff --no-color --no-ext-diff -a --ignore-cr-at-eol --check {opt}";
+ }
+
+ public bool GetResult()
+ {
+ return ReadToEnd().IsSuccess;
}
public async Task GetResultAsync()
diff --git a/src/Commands/IsLFSFiltered.cs b/src/Commands/IsLFSFiltered.cs
index e8e5513ca..5c45f8bc6 100644
--- a/src/Commands/IsLFSFiltered.cs
+++ b/src/Commands/IsLFSFiltered.cs
@@ -20,9 +20,19 @@ public IsLFSFiltered(string repo, string sha, string path)
RaiseError = false;
}
+ public bool GetResult()
+ {
+ return Parse(ReadToEnd());
+ }
+
public async Task GetResultAsync()
{
var rs = await ReadToEndAsync().ConfigureAwait(false);
+ return Parse(rs);
+ }
+
+ private bool Parse(Result rs)
+ {
return rs.IsSuccess && rs.StdOut.Contains("filter\0lfs");
}
}
diff --git a/src/Commands/IssueTracker.cs b/src/Commands/IssueTracker.cs
new file mode 100644
index 000000000..e4c156417
--- /dev/null
+++ b/src/Commands/IssueTracker.cs
@@ -0,0 +1,118 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Threading.Tasks;
+
+namespace SourceGit.Commands
+{
+ public class IssueTracker : Command
+ {
+ public IssueTracker(string repo, bool isShared)
+ {
+ WorkingDirectory = repo;
+ Context = repo;
+
+ if (isShared)
+ {
+ var storage = $"{repo}/.issuetracker";
+ _isStorageFileExists = File.Exists(storage);
+ _baseArg = $"config -f {storage.Quoted()}";
+ }
+ else
+ {
+ _isStorageFileExists = true;
+ _baseArg = "config --local";
+ }
+ }
+
+ public async Task ReadAllAsync(List outs, bool isShared)
+ {
+ if (!_isStorageFileExists)
+ return;
+
+ Args = $"{_baseArg} -l";
+
+ var rs = await ReadToEndAsync().ConfigureAwait(false);
+ if (rs.IsSuccess)
+ {
+ var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
+ foreach (var line in lines)
+ {
+ var parts = line.Split('=', 2);
+ if (parts.Length < 2)
+ continue;
+
+ var key = parts[0];
+ var value = parts[1];
+
+ if (!key.StartsWith("issuetracker.", StringComparison.Ordinal))
+ continue;
+
+ if (key.EndsWith(".regex", StringComparison.Ordinal))
+ {
+ var prefixLen = "issuetracker.".Length;
+ var suffixLen = ".regex".Length;
+ var ruleName = key.Substring(prefixLen, key.Length - prefixLen - suffixLen);
+ FindOrAdd(outs, ruleName, isShared).RegexString = value;
+ }
+ else if (key.EndsWith(".url", StringComparison.Ordinal))
+ {
+ var prefixLen = "issuetracker.".Length;
+ var suffixLen = ".url".Length;
+ var ruleName = key.Substring(prefixLen, key.Length - prefixLen - suffixLen);
+ FindOrAdd(outs, ruleName, isShared).URLTemplate = value;
+ }
+ }
+ }
+ }
+
+ public async Task AddAsync(Models.IssueTracker rule)
+ {
+ Args = $"{_baseArg} issuetracker.{rule.Name.Quoted()}.regex {rule.RegexString.Quoted()}";
+
+ var succ = await ExecAsync().ConfigureAwait(false);
+ if (succ)
+ {
+ Args = $"{_baseArg} issuetracker.{rule.Name.Quoted()}.url {rule.URLTemplate.Quoted()}";
+ return await ExecAsync().ConfigureAwait(false);
+ }
+
+ return false;
+ }
+
+ public async Task UpdateRegexAsync(Models.IssueTracker rule)
+ {
+ Args = $"{_baseArg} issuetracker.{rule.Name.Quoted()}.regex {rule.RegexString.Quoted()}";
+ return await ExecAsync().ConfigureAwait(false);
+ }
+
+ public async Task UpdateURLTemplateAsync(Models.IssueTracker rule)
+ {
+ Args = $"{_baseArg} issuetracker.{rule.Name.Quoted()}.url {rule.URLTemplate.Quoted()}";
+ return await ExecAsync().ConfigureAwait(false);
+ }
+
+ public async Task RemoveAsync(string name)
+ {
+ if (!_isStorageFileExists)
+ return true;
+
+ Args = $"{_baseArg} --remove-section issuetracker.{name.Quoted()}";
+ return await ExecAsync().ConfigureAwait(false);
+ }
+
+ private Models.IssueTracker FindOrAdd(List rules, string ruleName, bool isShared)
+ {
+ var rule = rules.Find(x => x.Name.Equals(ruleName, StringComparison.Ordinal));
+ if (rule != null)
+ return rule;
+
+ rule = new Models.IssueTracker() { IsShared = isShared, Name = ruleName };
+ rules.Add(rule);
+ return rule;
+ }
+
+ private readonly bool _isStorageFileExists;
+ private readonly string _baseArg;
+ }
+}
diff --git a/src/Commands/LFS.cs b/src/Commands/LFS.cs
index 001002d1d..6e4283359 100644
--- a/src/Commands/LFS.cs
+++ b/src/Commands/LFS.cs
@@ -1,16 +1,12 @@
-using System;
-using System.Collections.Generic;
+using System.Collections.Generic;
using System.Text;
-using System.Text.RegularExpressions;
+using System.Text.Json;
using System.Threading.Tasks;
namespace SourceGit.Commands
{
- public partial class LFS : Command
+ public class LFS : Command
{
- [GeneratedRegex(@"^(.+)\s+([\w.]+)\s+\w+:(\d+)$")]
- private static partial Regex REG_LOCK();
-
public LFS(string repo)
{
WorkingDirectory = repo;
@@ -60,30 +56,23 @@ public async Task PruneAsync()
public async Task> GetLocksAsync(string remote)
{
- Args = $"lfs locks --remote={remote}";
+ Args = $"lfs locks --json --remote={remote}";
var rs = await ReadToEndAsync().ConfigureAwait(false);
- var locks = new List();
-
if (rs.IsSuccess)
{
- var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
- foreach (var line in lines)
+ try
+ {
+ var locks = JsonSerializer.Deserialize(rs.StdOut, JsonCodeGen.Default.ListLFSLock);
+ return locks;
+ }
+ catch
{
- var match = REG_LOCK().Match(line);
- if (match.Success)
- {
- locks.Add(new Models.LFSLock()
- {
- File = match.Groups[1].Value,
- User = match.Groups[2].Value,
- ID = long.Parse(match.Groups[3].Value),
- });
- }
+ // Ignore exceptions.
}
}
- return locks;
+ return [];
}
public async Task LockAsync(string remote, string file)
@@ -104,5 +93,20 @@ public async Task UnlockAsync(string remote, string file, bool force)
Args = builder.ToString();
return await ExecAsync().ConfigureAwait(false);
}
+
+ public async Task UnlockMultipleAsync(string remote, List files, bool force)
+ {
+ var builder = new StringBuilder();
+ builder
+ .Append("lfs unlock --remote=")
+ .Append(remote)
+ .Append(force ? " -f" : " ");
+
+ foreach (string file in files)
+ builder.Append(' ').Append(file.Quoted());
+
+ Args = builder.ToString();
+ return await ExecAsync().ConfigureAwait(false);
+ }
}
}
diff --git a/src/Commands/MergeTool.cs b/src/Commands/MergeTool.cs
index c2262c69f..0f15fb617 100644
--- a/src/Commands/MergeTool.cs
+++ b/src/Commands/MergeTool.cs
@@ -1,48 +1,65 @@
-using System.IO;
+using System;
using System.Threading.Tasks;
namespace SourceGit.Commands
{
public class MergeTool : Command
{
- public MergeTool(string repo, int type, string exec, string file)
+ public MergeTool(string repo, string file)
{
WorkingDirectory = repo;
- Context = exec;
-
- _merger = Models.ExternalMerger.Supported.Find(x => x.Type == type);
- _exec = exec;
+ Context = repo;
_file = string.IsNullOrEmpty(file) ? string.Empty : file.Quoted();
}
public async Task OpenAsync()
{
- if (_merger == null)
+ var tool = Native.OS.GetDiffMergeTool(false);
+ if (tool == null)
{
- App.RaiseException(Context, "Invalid merge tool in preference setting!");
+ App.RaiseException(Context, "Invalid diff/merge tool in preference setting!");
return false;
}
- if (_merger.Type == 0)
+ if (string.IsNullOrEmpty(tool.Cmd))
{
- Args = $"mergetool {_file}";
+ var ok = await CheckGitConfigurationAsync();
+ if (!ok)
+ return false;
+
+ Args = $"mergetool -g --no-prompt {_file}";
}
- else if (File.Exists(_exec))
+ else
{
- var cmd = $"{_exec.Quoted()} {_merger.Cmd}";
+ var cmd = $"{tool.Exec.Quoted()} {tool.Cmd}";
Args = $"-c mergetool.sourcegit.cmd={cmd.Quoted()} -c mergetool.writeToTemp=true -c mergetool.keepBackup=false -c mergetool.trustExitCode=true mergetool --tool=sourcegit {_file}";
}
- else
+
+ return await ExecAsync().ConfigureAwait(false);
+ }
+
+ private async Task CheckGitConfigurationAsync()
+ {
+ var tool = await new Config(WorkingDirectory).GetAsync("merge.guitool");
+ if (string.IsNullOrEmpty(tool))
+ tool = await new Config(WorkingDirectory).GetAsync("merge.tool");
+
+ if (string.IsNullOrEmpty(tool))
{
- App.RaiseException(Context, $"Can NOT find external merge tool in '{_exec}'!");
+ App.RaiseException(Context, "Missing git configuration: merge.guitool");
return false;
}
- return await ExecAsync().ConfigureAwait(false);
+ if (tool.StartsWith("vimdiff", StringComparison.Ordinal) ||
+ tool.StartsWith("nvimdiff", StringComparison.Ordinal))
+ {
+ App.RaiseException(Context, $"CLI based merge tool \"{tool}\" is not supported by this app!");
+ return false;
+ }
+
+ return true;
}
- private Models.ExternalMerger _merger;
- private string _exec;
private string _file;
}
}
diff --git a/src/Commands/Pull.cs b/src/Commands/Pull.cs
index 93896c754..e121445ba 100644
--- a/src/Commands/Pull.cs
+++ b/src/Commands/Pull.cs
@@ -1,4 +1,5 @@
-using System.Threading.Tasks;
+using System.Text;
+using System.Threading.Tasks;
namespace SourceGit.Commands
{
@@ -10,12 +11,14 @@ public Pull(string repo, string remote, string branch, bool useRebase)
WorkingDirectory = repo;
Context = repo;
- Args = "pull --verbose --progress ";
+ var builder = new StringBuilder(512);
+ builder.Append("pull --verbose --progress ");
if (useRebase)
- Args += "--rebase=true ";
+ builder.Append("--rebase=true ");
+ builder.Append(remote).Append(' ').Append(branch);
- Args += $"{remote} {branch}";
+ Args = builder.ToString();
}
public async Task RunAsync()
diff --git a/src/Commands/Push.cs b/src/Commands/Push.cs
index b822af46d..44394dc41 100644
--- a/src/Commands/Push.cs
+++ b/src/Commands/Push.cs
@@ -1,4 +1,5 @@
-using System.Threading.Tasks;
+using System.Text;
+using System.Threading.Tasks;
namespace SourceGit.Commands
{
@@ -10,18 +11,20 @@ public Push(string repo, string local, string remote, string remoteBranch, bool
WorkingDirectory = repo;
Context = repo;
- Args = "push --progress --verbose ";
+ var builder = new StringBuilder(1024);
+ builder.Append("push --progress --verbose ");
if (withTags)
- Args += "--tags ";
+ builder.Append("--tags ");
if (checkSubmodules)
- Args += "--recurse-submodules=check ";
+ builder.Append("--recurse-submodules=check ");
if (track)
- Args += "-u ";
+ builder.Append("-u ");
if (force)
- Args += "--force-with-lease ";
+ builder.Append("--force-with-lease ");
- Args += $"{remote} {local}:{remoteBranch}";
+ builder.Append(remote).Append(' ').Append(local).Append(':').Append(remoteBranch);
+ Args = builder.ToString();
}
public Push(string repo, string remote, string refname, bool isDelete)
@@ -30,12 +33,14 @@ public Push(string repo, string remote, string refname, bool isDelete)
WorkingDirectory = repo;
Context = repo;
- Args = "push ";
+ var builder = new StringBuilder(512);
+ builder.Append("push ");
if (isDelete)
- Args += "--delete ";
+ builder.Append("--delete ");
+ builder.Append(remote).Append(' ').Append(refname);
- Args += $"{remote} {refname}";
+ Args = builder.ToString();
}
public async Task RunAsync()
diff --git a/src/Commands/QueryBranches.cs b/src/Commands/QueryBranches.cs
index 0eaf2837f..b741fb5c0 100644
--- a/src/Commands/QueryBranches.cs
+++ b/src/Commands/QueryBranches.cs
@@ -15,7 +15,7 @@ public QueryBranches(string repo)
{
WorkingDirectory = repo;
Context = repo;
- Args = "branch -l --all -v --format=\"%(refname)%00%(committerdate:unix)%00%(objectname)%00%(HEAD)%00%(upstream)%00%(upstream:trackshort)\"";
+ Args = "branch -l --all -v --format=\"%(refname)%00%(committerdate:unix)%00%(objectname)%00%(HEAD)%00%(upstream)%00%(upstream:trackshort)%00%(worktreepath)\"";
}
public async Task> GetResultAsync()
@@ -26,15 +26,16 @@ public QueryBranches(string repo)
return branches;
var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
- var remoteHeads = new Dictionary();
+ var mismatched = new HashSet();
+ var remotes = new Dictionary();
foreach (var line in lines)
{
- var b = ParseLine(line);
+ var b = ParseLine(line, mismatched);
if (b != null)
{
branches.Add(b);
if (!b.IsLocal)
- remoteHeads.Add(b.FullName, b.Head);
+ remotes.Add(b.FullName, b);
}
}
@@ -42,15 +43,16 @@ public QueryBranches(string repo)
{
if (b.IsLocal && !string.IsNullOrEmpty(b.Upstream))
{
- if (remoteHeads.TryGetValue(b.Upstream, out var upstreamHead))
+ if (remotes.TryGetValue(b.Upstream, out var upstream))
{
b.IsUpstreamGone = false;
- b.TrackStatus ??= await new QueryTrackStatus(WorkingDirectory, b.Head, upstreamHead).GetResultAsync().ConfigureAwait(false);
+
+ if (mismatched.Contains(b.FullName))
+ await new QueryTrackStatus(WorkingDirectory).GetResultAsync(b, upstream).ConfigureAwait(false);
}
else
{
b.IsUpstreamGone = true;
- b.TrackStatus ??= new Models.BranchTrackStatus();
}
}
}
@@ -58,10 +60,10 @@ public QueryBranches(string repo)
return branches;
}
- private Models.Branch ParseLine(string line)
+ private Models.Branch ParseLine(string line, HashSet mismatched)
{
var parts = line.Split('\0');
- if (parts.Length != 6)
+ if (parts.Length != 7)
return null;
var branch = new Models.Branch();
@@ -94,19 +96,22 @@ private Models.Branch ParseLine(string line)
branch.IsLocal = true;
}
+ ulong.TryParse(parts[1], out var committerDate);
+
branch.FullName = refName;
- branch.CommitterDate = ulong.Parse(parts[1]);
+ branch.CommitterDate = committerDate;
branch.Head = parts[2];
branch.IsCurrent = parts[3] == "*";
branch.Upstream = parts[4];
branch.IsUpstreamGone = false;
- if (!branch.IsLocal ||
- string.IsNullOrEmpty(branch.Upstream) ||
- string.IsNullOrEmpty(parts[5]) ||
- parts[5].Equals("=", StringComparison.Ordinal))
- branch.TrackStatus = new Models.BranchTrackStatus();
+ if (branch.IsLocal &&
+ !string.IsNullOrEmpty(branch.Upstream) &&
+ !string.IsNullOrEmpty(parts[5]) &&
+ !parts[5].Equals("=", StringComparison.Ordinal))
+ mismatched.Add(branch.FullName);
+ branch.WorktreePath = parts[6];
return branch;
}
}
diff --git a/src/Commands/QueryCommitFullMessage.cs b/src/Commands/QueryCommitFullMessage.cs
index 07b77f2e3..2e9db9298 100644
--- a/src/Commands/QueryCommitFullMessage.cs
+++ b/src/Commands/QueryCommitFullMessage.cs
@@ -11,6 +11,12 @@ public QueryCommitFullMessage(string repo, string sha)
Args = $"show --no-show-signature --format=%B -s {sha}";
}
+ public string GetResult()
+ {
+ var rs = ReadToEnd();
+ return rs.IsSuccess ? rs.StdOut.TrimEnd() : string.Empty;
+ }
+
public async Task GetResultAsync()
{
var rs = await ReadToEndAsync().ConfigureAwait(false);
diff --git a/src/Commands/QueryCommits.cs b/src/Commands/QueryCommits.cs
index 311406bdc..0e46ead81 100644
--- a/src/Commands/QueryCommits.cs
+++ b/src/Commands/QueryCommits.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics;
using System.Text;
using System.Threading.Tasks;
@@ -7,144 +8,107 @@ namespace SourceGit.Commands
{
public class QueryCommits : Command
{
- public QueryCommits(string repo, string limits, bool needFindHead = true)
+ public QueryCommits(string repo, string limits, bool markMerged = true)
{
WorkingDirectory = repo;
Context = repo;
- 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;
+ Args = $"log --no-show-signature --decorate=full --format=%H%x00%P%x00%D%x00%aN±%aE%x00%at%x00%cN±%cE%x00%ct%x00%s {limits}";
+ _markMerged = markMerged;
}
public QueryCommits(string repo, string filter, Models.CommitSearchMethod method, bool onlyCurrentBranch)
{
- string search = onlyCurrentBranch ? string.Empty : "--branches --remotes ";
+ var builder = new StringBuilder();
+ builder.Append("log -1000 --date-order --no-show-signature --decorate=full --format=%H%x00%P%x00%D%x00%aN±%aE%x00%at%x00%cN±%cE%x00%ct%x00%s ");
+
+ if (!onlyCurrentBranch)
+ builder.Append("--branches --remotes ");
if (method == Models.CommitSearchMethod.ByAuthor)
{
- search += $"-i --author={filter.Quoted()}";
+ builder.Append("-i --author=").Append(filter.Quoted());
}
else if (method == Models.CommitSearchMethod.ByCommitter)
{
- search += $"-i --committer={filter.Quoted()}";
+ builder.Append("-i --committer=").Append(filter.Quoted());
}
else if (method == Models.CommitSearchMethod.ByMessage)
{
- var argsBuilder = new StringBuilder();
- argsBuilder.Append(search);
-
var words = filter.Split([' ', '\t', '\r'], StringSplitOptions.RemoveEmptyEntries);
foreach (var word in words)
- argsBuilder.Append("--grep=").Append(word.Trim().Quoted()).Append(' ');
- argsBuilder.Append("--all-match -i");
-
- search = argsBuilder.ToString();
+ builder.Append("--grep=").Append(word.Trim().Quoted()).Append(' ');
+ builder.Append("--all-match -i");
}
else if (method == Models.CommitSearchMethod.ByPath)
{
- search += $"-- {filter.Quoted()}";
+ builder.Append("-- ").Append(filter.Quoted());
}
else
{
- search = $"-G{filter.Quoted()}";
+ builder.Append("-G").Append(filter.Quoted());
}
WorkingDirectory = repo;
Context = repo;
- 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;
+ Args = builder.ToString();
+ _markMerged = false;
}
public async Task> GetResultAsync()
{
- var rs = await ReadToEndAsync().ConfigureAwait(false);
- if (!rs.IsSuccess)
- return _commits;
-
- var nextPartIdx = 0;
- var start = 0;
- var end = rs.StdOut.IndexOf('\n', start);
- while (end > 0)
+ var commits = new List();
+ try
{
- var line = rs.StdOut.Substring(start, end - start);
- switch (nextPartIdx)
+ using var proc = new Process();
+ proc.StartInfo = CreateGitStartInfo(true);
+ proc.Start();
+
+ var findHead = false;
+ while (await proc.StandardOutput.ReadLineAsync().ConfigureAwait(false) is { } line)
{
- case 0:
- _current = new Models.Commit() { SHA = line };
- _commits.Add(_current);
- break;
- case 1:
- ParseParent(line);
- break;
- case 2:
- _current.ParseDecorators(line);
- if (_current.IsMerged && !_isHeadFound)
- _isHeadFound = true;
- break;
- case 3:
- _current.Author = Models.User.FindOrAdd(line);
- break;
- case 4:
- _current.AuthorTime = ulong.Parse(line);
- break;
- case 5:
- _current.Committer = Models.User.FindOrAdd(line);
- break;
- case 6:
- _current.CommitterTime = ulong.Parse(line);
- break;
- case 7:
- _current.Subject = line;
- nextPartIdx = -1;
- break;
+ var parts = line.Split('\0');
+ if (parts.Length != 8)
+ continue;
+
+ var commit = new Models.Commit() { SHA = parts[0] };
+ commit.ParseParents(parts[1]);
+ commit.ParseDecorators(parts[2]);
+ commit.Author = Models.User.FindOrAdd(parts[3]);
+ commit.AuthorTime = ulong.Parse(parts[4]);
+ commit.Committer = Models.User.FindOrAdd(parts[5]);
+ commit.CommitterTime = ulong.Parse(parts[6]);
+ commit.Subject = parts[7];
+ commits.Add(commit);
+
+ findHead |= commit.IsMerged;
}
- nextPartIdx++;
-
- start = end + 1;
- end = rs.StdOut.IndexOf('\n', start);
- }
-
- if (start < rs.StdOut.Length)
- _current.Subject = rs.StdOut.Substring(start);
-
- if (_findFirstMerged && !_isHeadFound && _commits.Count > 0)
- await MarkFirstMergedAsync().ConfigureAwait(false);
+ await proc.WaitForExitAsync().ConfigureAwait(false);
- return _commits;
- }
-
- private void ParseParent(string data)
- {
- if (data.Length < 8)
- return;
-
- _current.Parents.AddRange(data.Split(' ', StringSplitOptions.RemoveEmptyEntries));
- }
-
- private async Task MarkFirstMergedAsync()
- {
- Args = $"log --since={_commits[^1].CommitterTimeStr.Quoted()} --format=\"%H\"";
-
- var rs = await ReadToEndAsync().ConfigureAwait(false);
- var shas = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
- if (shas.Length == 0)
- return;
-
- var set = new HashSet(shas);
-
- foreach (var c in _commits)
- {
- if (set.Contains(c.SHA))
+ if (_markMerged && !findHead && commits.Count > 0)
{
- c.IsMerged = true;
- break;
+ var set = await new QueryCurrentBranchCommitHashes(WorkingDirectory, commits[^1].CommitterTime)
+ .GetResultAsync()
+ .ConfigureAwait(false);
+
+ foreach (var c in commits)
+ {
+ if (set.Contains(c.SHA))
+ {
+ c.IsMerged = true;
+ break;
+ }
+ }
}
}
+ catch (Exception e)
+ {
+ App.RaiseException(Context, $"Failed to query commits. Reason: {e.Message}");
+ }
+
+ return commits;
}
- private List _commits = new List();
- private Models.Commit _current = null;
- private bool _findFirstMerged = false;
- private bool _isHeadFound = false;
+ private bool _markMerged = false;
}
}
diff --git a/src/Commands/QueryCommitsForInteractiveRebase.cs b/src/Commands/QueryCommitsForInteractiveRebase.cs
index 81e28d4fc..e1f964881 100644
--- a/src/Commands/QueryCommitsForInteractiveRebase.cs
+++ b/src/Commands/QueryCommitsForInteractiveRebase.cs
@@ -12,14 +12,20 @@ public QueryCommitsForInteractiveRebase(string repo, string on)
WorkingDirectory = repo;
Context = repo;
- 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";
+ Args = $"log --topo-order --cherry-pick --right-only --no-merges --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 async Task> GetResultAsync()
{
+ var commits = new List();
var rs = await ReadToEndAsync().ConfigureAwait(false);
if (!rs.IsSuccess)
- return _commits;
+ {
+ App.RaiseException(Context, $"Failed to query commits for interactive-rebase. Reason: {rs.StdErr}");
+ return commits;
+ }
+
+ Models.InteractiveCommit current = null;
var nextPartIdx = 0;
var start = 0;
@@ -30,38 +36,38 @@ public QueryCommitsForInteractiveRebase(string repo, string on)
switch (nextPartIdx)
{
case 0:
- _current = new Models.InteractiveCommit();
- _current.Commit.SHA = line;
- _commits.Add(_current);
+ current = new Models.InteractiveCommit();
+ current.Commit.SHA = line;
+ commits.Add(current);
break;
case 1:
- ParseParent(line);
+ current.Commit.ParseParents(line);
break;
case 2:
- _current.Commit.ParseDecorators(line);
+ current.Commit.ParseDecorators(line);
break;
case 3:
- _current.Commit.Author = Models.User.FindOrAdd(line);
+ current.Commit.Author = Models.User.FindOrAdd(line);
break;
case 4:
- _current.Commit.AuthorTime = ulong.Parse(line);
+ current.Commit.AuthorTime = ulong.Parse(line);
break;
case 5:
- _current.Commit.Committer = Models.User.FindOrAdd(line);
+ current.Commit.Committer = Models.User.FindOrAdd(line);
break;
case 6:
- _current.Commit.CommitterTime = ulong.Parse(line);
+ current.Commit.CommitterTime = ulong.Parse(line);
break;
default:
var boundary = rs.StdOut.IndexOf(_boundary, end + 1, StringComparison.Ordinal);
if (boundary > end)
{
- _current.Message = rs.StdOut.Substring(start, boundary - start - 1);
+ current.Message = rs.StdOut.Substring(start, boundary - start - 1);
end = boundary + _boundary.Length;
}
else
{
- _current.Message = rs.StdOut.Substring(start);
+ current.Message = rs.StdOut.Substring(start);
end = rs.StdOut.Length - 2;
}
@@ -78,19 +84,9 @@ public QueryCommitsForInteractiveRebase(string repo, string on)
end = rs.StdOut.IndexOf('\n', start);
}
- return _commits;
- }
-
- private void ParseParent(string data)
- {
- if (data.Length < 8)
- return;
-
- _current.Commit.Parents.AddRange(data.Split(' ', StringSplitOptions.RemoveEmptyEntries));
+ return commits;
}
- private List _commits = [];
- private Models.InteractiveCommit _current = null;
private readonly string _boundary;
}
}
diff --git a/src/Commands/QueryCurrentBranch.cs b/src/Commands/QueryCurrentBranch.cs
index c721d13b0..8b698d1e5 100644
--- a/src/Commands/QueryCurrentBranch.cs
+++ b/src/Commands/QueryCurrentBranch.cs
@@ -11,6 +11,11 @@ public QueryCurrentBranch(string repo)
Args = "branch --show-current";
}
+ public string GetResult()
+ {
+ return ReadToEnd().StdOut.Trim();
+ }
+
public async Task GetResultAsync()
{
var rs = await ReadToEndAsync().ConfigureAwait(false);
diff --git a/src/Commands/QueryCurrentBranchCommitHashes.cs b/src/Commands/QueryCurrentBranchCommitHashes.cs
new file mode 100644
index 000000000..a795e1f54
--- /dev/null
+++ b/src/Commands/QueryCurrentBranchCommitHashes.cs
@@ -0,0 +1,41 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Threading.Tasks;
+
+namespace SourceGit.Commands
+{
+ public class QueryCurrentBranchCommitHashes : Command
+ {
+ public QueryCurrentBranchCommitHashes(string repo, ulong sinceTimestamp)
+ {
+ var since = DateTime.UnixEpoch.AddSeconds(sinceTimestamp).ToLocalTime().ToString("yyyy/MM/dd HH:mm:ss");
+ WorkingDirectory = repo;
+ Context = repo;
+ Args = $"log --since={since.Quoted()} --format=%H";
+ }
+
+ public async Task> GetResultAsync()
+ {
+ var outs = new HashSet();
+
+ try
+ {
+ using var proc = new Process();
+ proc.StartInfo = CreateGitStartInfo(true);
+ proc.Start();
+
+ while (await proc.StandardOutput.ReadLineAsync().ConfigureAwait(false) is { Length: > 8 } line)
+ outs.Add(line);
+
+ await proc.WaitForExitAsync().ConfigureAwait(false);
+ }
+ catch
+ {
+ // Ignore exceptions;
+ }
+
+ return outs;
+ }
+ }
+}
diff --git a/src/Commands/QueryFileContent.cs b/src/Commands/QueryFileContent.cs
index 41cf63836..66f964600 100644
--- a/src/Commands/QueryFileContent.cs
+++ b/src/Commands/QueryFileContent.cs
@@ -21,7 +21,7 @@ public static async Task RunAsync(string repo, string revision, string f
var stream = new MemoryStream();
try
{
- using var proc = Process.Start(starter);
+ using var proc = Process.Start(starter)!;
await proc.StandardOutput.BaseStream.CopyToAsync(stream).ConfigureAwait(false);
await proc.WaitForExitAsync().ConfigureAwait(false);
}
@@ -49,7 +49,7 @@ public static async Task FromLFSAsync(string repo, string oid, long size
var stream = new MemoryStream();
try
{
- using var proc = Process.Start(starter);
+ using var proc = Process.Start(starter)!;
await proc.StandardInput.WriteLineAsync("version https://git-lfs.github.com/spec/v1").ConfigureAwait(false);
await proc.StandardInput.WriteLineAsync($"oid sha256:{oid}").ConfigureAwait(false);
await proc.StandardInput.WriteLineAsync($"size {size}").ConfigureAwait(false);
diff --git a/src/Commands/QueryGitCommonDir.cs b/src/Commands/QueryGitCommonDir.cs
index c5b9339d5..e71cf2b07 100644
--- a/src/Commands/QueryGitCommonDir.cs
+++ b/src/Commands/QueryGitCommonDir.cs
@@ -9,19 +9,19 @@ public QueryGitCommonDir(string workDir)
{
WorkingDirectory = workDir;
Args = "rev-parse --git-common-dir";
+ RaiseError = false;
}
public async Task GetResultAsync()
{
var rs = await ReadToEndAsync().ConfigureAwait(false);
- if (!rs.IsSuccess)
- return null;
+ if (!rs.IsSuccess || string.IsNullOrEmpty(rs.StdOut))
+ return string.Empty;
- var stdout = rs.StdOut.Trim();
- if (string.IsNullOrEmpty(stdout))
- return null;
-
- return Path.IsPathRooted(stdout) ? stdout : Path.GetFullPath(Path.Combine(WorkingDirectory, stdout));
+ var dir = rs.StdOut.Trim();
+ if (Path.IsPathRooted(dir))
+ return dir;
+ return Path.GetFullPath(Path.Combine(WorkingDirectory, dir));
}
}
}
diff --git a/src/Commands/QueryGitDir.cs b/src/Commands/QueryGitDir.cs
index ce8bfee60..5a91b2173 100644
--- a/src/Commands/QueryGitDir.cs
+++ b/src/Commands/QueryGitDir.cs
@@ -1,5 +1,4 @@
using System.IO;
-using System.Threading.Tasks;
namespace SourceGit.Commands
{
@@ -11,9 +10,13 @@ public QueryGitDir(string workDir)
Args = "rev-parse --git-dir";
}
- public async Task GetResultAsync()
+ public string GetResult()
+ {
+ return Parse(ReadToEnd());
+ }
+
+ private string Parse(Result rs)
{
- var rs = await ReadToEndAsync().ConfigureAwait(false);
if (!rs.IsSuccess)
return null;
diff --git a/src/Commands/QueryLocalChanges.cs b/src/Commands/QueryLocalChanges.cs
index 9605014da..385a95f27 100644
--- a/src/Commands/QueryLocalChanges.cs
+++ b/src/Commands/QueryLocalChanges.cs
@@ -1,5 +1,5 @@
-using System;
-using System.Collections.Generic;
+using System.Collections.Generic;
+using System.Diagnostics;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
@@ -21,141 +21,145 @@ public QueryLocalChanges(string repo, bool includeUntracked = true)
public async Task> GetResultAsync()
{
var outs = new List();
- var rs = await ReadToEndAsync().ConfigureAwait(false);
- if (!rs.IsSuccess)
- {
- App.RaiseException(Context, rs.StdErr);
- return outs;
- }
- var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
- foreach (var line in lines)
+ try
{
- var match = REG_FORMAT().Match(line);
- if (!match.Success)
- continue;
-
- var change = new Models.Change() { Path = match.Groups[2].Value };
- var status = match.Groups[1].Value;
+ using var proc = new Process();
+ proc.StartInfo = CreateGitStartInfo(true);
+ proc.Start();
- switch (status)
+ while (await proc.StandardOutput.ReadLineAsync().ConfigureAwait(false) is { } line)
{
- case " M":
- change.Set(Models.ChangeState.None, Models.ChangeState.Modified);
- break;
- case " T":
- change.Set(Models.ChangeState.None, Models.ChangeState.TypeChanged);
- break;
- case " A":
- change.Set(Models.ChangeState.None, Models.ChangeState.Added);
- break;
- case " D":
- change.Set(Models.ChangeState.None, Models.ChangeState.Deleted);
- break;
- case " R":
- change.Set(Models.ChangeState.None, Models.ChangeState.Renamed);
- break;
- case " C":
- change.Set(Models.ChangeState.None, Models.ChangeState.Copied);
- break;
- case "M":
- change.Set(Models.ChangeState.Modified);
- break;
- case "MM":
- change.Set(Models.ChangeState.Modified, Models.ChangeState.Modified);
- break;
- case "MT":
- change.Set(Models.ChangeState.Modified, Models.ChangeState.TypeChanged);
- break;
- case "MD":
- change.Set(Models.ChangeState.Modified, Models.ChangeState.Deleted);
- break;
- case "T":
- change.Set(Models.ChangeState.TypeChanged);
- break;
- case "TM":
- change.Set(Models.ChangeState.TypeChanged, Models.ChangeState.Modified);
- break;
- case "TT":
- change.Set(Models.ChangeState.TypeChanged, Models.ChangeState.TypeChanged);
- break;
- case "TD":
- change.Set(Models.ChangeState.TypeChanged, Models.ChangeState.Deleted);
- break;
- case "A":
- change.Set(Models.ChangeState.Added);
- break;
- case "AM":
- change.Set(Models.ChangeState.Added, Models.ChangeState.Modified);
- break;
- case "AT":
- change.Set(Models.ChangeState.Added, Models.ChangeState.TypeChanged);
- break;
- case "AD":
- change.Set(Models.ChangeState.Added, Models.ChangeState.Deleted);
- break;
- case "D":
- change.Set(Models.ChangeState.Deleted);
- break;
- case "R":
- change.Set(Models.ChangeState.Renamed);
- break;
- case "RM":
- change.Set(Models.ChangeState.Renamed, Models.ChangeState.Modified);
- break;
- case "RT":
- change.Set(Models.ChangeState.Renamed, Models.ChangeState.TypeChanged);
- break;
- case "RD":
- change.Set(Models.ChangeState.Renamed, Models.ChangeState.Deleted);
- break;
- case "C":
- change.Set(Models.ChangeState.Copied);
- break;
- case "CM":
- change.Set(Models.ChangeState.Copied, Models.ChangeState.Modified);
- break;
- case "CT":
- change.Set(Models.ChangeState.Copied, Models.ChangeState.TypeChanged);
- break;
- case "CD":
- change.Set(Models.ChangeState.Copied, Models.ChangeState.Deleted);
- break;
- case "DD":
- change.ConflictReason = Models.ConflictReason.BothDeleted;
- change.Set(Models.ChangeState.None, Models.ChangeState.Conflicted);
- break;
- case "AU":
- change.ConflictReason = Models.ConflictReason.AddedByUs;
- change.Set(Models.ChangeState.None, Models.ChangeState.Conflicted);
- break;
- case "UD":
- change.ConflictReason = Models.ConflictReason.DeletedByThem;
- change.Set(Models.ChangeState.None, Models.ChangeState.Conflicted);
- break;
- case "UA":
- change.ConflictReason = Models.ConflictReason.AddedByThem;
- change.Set(Models.ChangeState.None, Models.ChangeState.Conflicted);
- break;
- case "DU":
- change.ConflictReason = Models.ConflictReason.DeletedByUs;
- change.Set(Models.ChangeState.None, Models.ChangeState.Conflicted);
- break;
- case "AA":
- change.ConflictReason = Models.ConflictReason.BothAdded;
- change.Set(Models.ChangeState.None, Models.ChangeState.Conflicted);
- break;
- case "UU":
- change.ConflictReason = Models.ConflictReason.BothModified;
- change.Set(Models.ChangeState.None, Models.ChangeState.Conflicted);
- break;
- case "??":
- change.Set(Models.ChangeState.None, Models.ChangeState.Untracked);
- break;
- }
+ var match = REG_FORMAT().Match(line);
+ if (!match.Success)
+ continue;
+
+ var change = new Models.Change() { Path = match.Groups[2].Value };
+ var status = match.Groups[1].Value;
- if (change.Index != Models.ChangeState.None || change.WorkTree != Models.ChangeState.None)
- outs.Add(change);
+ switch (status)
+ {
+ case " M":
+ change.Set(Models.ChangeState.None, Models.ChangeState.Modified);
+ break;
+ case " T":
+ change.Set(Models.ChangeState.None, Models.ChangeState.TypeChanged);
+ break;
+ case " A":
+ change.Set(Models.ChangeState.None, Models.ChangeState.Added);
+ break;
+ case " D":
+ change.Set(Models.ChangeState.None, Models.ChangeState.Deleted);
+ break;
+ case " R":
+ change.Set(Models.ChangeState.None, Models.ChangeState.Renamed);
+ break;
+ case " C":
+ change.Set(Models.ChangeState.None, Models.ChangeState.Copied);
+ break;
+ case "M":
+ change.Set(Models.ChangeState.Modified);
+ break;
+ case "MM":
+ change.Set(Models.ChangeState.Modified, Models.ChangeState.Modified);
+ break;
+ case "MT":
+ change.Set(Models.ChangeState.Modified, Models.ChangeState.TypeChanged);
+ break;
+ case "MD":
+ change.Set(Models.ChangeState.Modified, Models.ChangeState.Deleted);
+ break;
+ case "T":
+ change.Set(Models.ChangeState.TypeChanged);
+ break;
+ case "TM":
+ change.Set(Models.ChangeState.TypeChanged, Models.ChangeState.Modified);
+ break;
+ case "TT":
+ change.Set(Models.ChangeState.TypeChanged, Models.ChangeState.TypeChanged);
+ break;
+ case "TD":
+ change.Set(Models.ChangeState.TypeChanged, Models.ChangeState.Deleted);
+ break;
+ case "A":
+ change.Set(Models.ChangeState.Added);
+ break;
+ case "AM":
+ change.Set(Models.ChangeState.Added, Models.ChangeState.Modified);
+ break;
+ case "AT":
+ change.Set(Models.ChangeState.Added, Models.ChangeState.TypeChanged);
+ break;
+ case "AD":
+ change.Set(Models.ChangeState.Added, Models.ChangeState.Deleted);
+ break;
+ case "D":
+ change.Set(Models.ChangeState.Deleted);
+ break;
+ case "R":
+ change.Set(Models.ChangeState.Renamed);
+ break;
+ case "RM":
+ change.Set(Models.ChangeState.Renamed, Models.ChangeState.Modified);
+ break;
+ case "RT":
+ change.Set(Models.ChangeState.Renamed, Models.ChangeState.TypeChanged);
+ break;
+ case "RD":
+ change.Set(Models.ChangeState.Renamed, Models.ChangeState.Deleted);
+ break;
+ case "C":
+ change.Set(Models.ChangeState.Copied);
+ break;
+ case "CM":
+ change.Set(Models.ChangeState.Copied, Models.ChangeState.Modified);
+ break;
+ case "CT":
+ change.Set(Models.ChangeState.Copied, Models.ChangeState.TypeChanged);
+ break;
+ case "CD":
+ change.Set(Models.ChangeState.Copied, Models.ChangeState.Deleted);
+ break;
+ case "DD":
+ change.ConflictReason = Models.ConflictReason.BothDeleted;
+ change.Set(Models.ChangeState.None, Models.ChangeState.Conflicted);
+ break;
+ case "AU":
+ change.ConflictReason = Models.ConflictReason.AddedByUs;
+ change.Set(Models.ChangeState.None, Models.ChangeState.Conflicted);
+ break;
+ case "UD":
+ change.ConflictReason = Models.ConflictReason.DeletedByThem;
+ change.Set(Models.ChangeState.None, Models.ChangeState.Conflicted);
+ break;
+ case "UA":
+ change.ConflictReason = Models.ConflictReason.AddedByThem;
+ change.Set(Models.ChangeState.None, Models.ChangeState.Conflicted);
+ break;
+ case "DU":
+ change.ConflictReason = Models.ConflictReason.DeletedByUs;
+ change.Set(Models.ChangeState.None, Models.ChangeState.Conflicted);
+ break;
+ case "AA":
+ change.ConflictReason = Models.ConflictReason.BothAdded;
+ change.Set(Models.ChangeState.None, Models.ChangeState.Conflicted);
+ break;
+ case "UU":
+ change.ConflictReason = Models.ConflictReason.BothModified;
+ change.Set(Models.ChangeState.None, Models.ChangeState.Conflicted);
+ break;
+ case "??":
+ change.Set(Models.ChangeState.None, Models.ChangeState.Untracked);
+ break;
+ }
+
+ if (change.Index != Models.ChangeState.None || change.WorkTree != Models.ChangeState.None)
+ outs.Add(change);
+ }
+ }
+ catch
+ {
+ // Ignore exceptions.
}
return outs;
diff --git a/src/Commands/QueryRemotes.cs b/src/Commands/QueryRemotes.cs
index bd42aabf1..48d7040a0 100644
--- a/src/Commands/QueryRemotes.cs
+++ b/src/Commands/QueryRemotes.cs
@@ -40,6 +40,16 @@ public QueryRemotes(string repo)
if (outs.Find(x => x.Name == remote.Name) != null)
continue;
+ if (remote.URL.StartsWith("git@", StringComparison.Ordinal))
+ {
+ var hostEnd = remote.URL.IndexOf(':', 4);
+ if (hostEnd > 4)
+ {
+ var host = remote.URL.Substring(4, hostEnd - 4);
+ Models.HTTPSValidator.Add(host);
+ }
+ }
+
outs.Add(remote);
}
diff --git a/src/Commands/QueryRepositoryRootPath.cs b/src/Commands/QueryRepositoryRootPath.cs
index f7e1eb637..89d259296 100644
--- a/src/Commands/QueryRepositoryRootPath.cs
+++ b/src/Commands/QueryRepositoryRootPath.cs
@@ -10,6 +10,11 @@ public QueryRepositoryRootPath(string path)
Args = "rev-parse --show-toplevel";
}
+ public Result GetResult()
+ {
+ return ReadToEnd();
+ }
+
public async Task GetResultAsync()
{
return await ReadToEndAsync().ConfigureAwait(false);
diff --git a/src/Commands/QueryRepositoryStatus.cs b/src/Commands/QueryRepositoryStatus.cs
new file mode 100644
index 000000000..32c2489a6
--- /dev/null
+++ b/src/Commands/QueryRepositoryStatus.cs
@@ -0,0 +1,59 @@
+using System;
+using System.Text.RegularExpressions;
+using System.Threading.Tasks;
+
+namespace SourceGit.Commands
+{
+ public partial class QueryRepositoryStatus : Command
+ {
+ [GeneratedRegex(@"ahead\s(\d+)")]
+ private static partial Regex REG_AHEAD();
+
+ [GeneratedRegex(@"behind\s(\d+)")]
+ private static partial Regex REG_BEHIND();
+
+ public QueryRepositoryStatus(string repo)
+ {
+ WorkingDirectory = repo;
+ RaiseError = false;
+ }
+
+ public async Task GetResultAsync()
+ {
+ Args = "branch -l -v --format=\"%(refname:short)%00%(HEAD)%00%(upstream:track,nobracket)\"";
+ var rs = await ReadToEndAsync().ConfigureAwait(false);
+ if (!rs.IsSuccess)
+ return null;
+
+ var status = new Models.RepositoryStatus();
+ var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
+ foreach (var line in lines)
+ {
+ var parts = line.Split('\0');
+ if (parts.Length != 3 || !parts[1].Equals("*", StringComparison.Ordinal))
+ continue;
+
+ status.CurrentBranch = parts[0];
+ if (!string.IsNullOrEmpty(parts[2]))
+ ParseTrackStatus(status, parts[2]);
+ }
+
+ status.LocalChanges = await new CountLocalChanges(WorkingDirectory, true) { RaiseError = false }
+ .GetResultAsync()
+ .ConfigureAwait(false);
+
+ return status;
+ }
+
+ private void ParseTrackStatus(Models.RepositoryStatus status, string input)
+ {
+ var aheadMatch = REG_AHEAD().Match(input);
+ if (aheadMatch.Success)
+ status.Ahead = int.Parse(aheadMatch.Groups[1].Value);
+
+ var behindMatch = REG_BEHIND().Match(input);
+ if (behindMatch.Success)
+ status.Behind = int.Parse(behindMatch.Groups[1].Value);
+ }
+ }
+}
diff --git a/src/Commands/QueryRevisionByRefName.cs b/src/Commands/QueryRevisionByRefName.cs
index 64a03e9df..78104523a 100644
--- a/src/Commands/QueryRevisionByRefName.cs
+++ b/src/Commands/QueryRevisionByRefName.cs
@@ -11,9 +11,19 @@ public QueryRevisionByRefName(string repo, string refname)
Args = $"rev-parse {refname}";
}
+ public string GetResult()
+ {
+ return Parse(ReadToEnd());
+ }
+
public async Task GetResultAsync()
{
var rs = await ReadToEndAsync().ConfigureAwait(false);
+ return Parse(rs);
+ }
+
+ private string Parse(Result rs)
+ {
if (rs.IsSuccess && !string.IsNullOrEmpty(rs.StdOut))
return rs.StdOut.Trim();
diff --git a/src/Commands/QueryRevisionFileNames.cs b/src/Commands/QueryRevisionFileNames.cs
index 747534124..e4dcc25c5 100644
--- a/src/Commands/QueryRevisionFileNames.cs
+++ b/src/Commands/QueryRevisionFileNames.cs
@@ -1,4 +1,5 @@
using System.Collections.Generic;
+using System.Diagnostics;
using System.Threading.Tasks;
namespace SourceGit.Commands
@@ -9,17 +10,30 @@ public QueryRevisionFileNames(string repo, string revision)
{
WorkingDirectory = repo;
Context = repo;
- Args = $"ls-tree -r -z --name-only {revision}";
+ Args = $"ls-tree -r --name-only {revision}";
}
public async Task> GetResultAsync()
{
- var rs = await ReadToEndAsync().ConfigureAwait(false);
- if (!rs.IsSuccess)
- return [];
+ var outs = new List();
- var lines = rs.StdOut.Split('\0', System.StringSplitOptions.RemoveEmptyEntries);
- return [.. lines];
+ try
+ {
+ using var proc = new Process();
+ proc.StartInfo = CreateGitStartInfo(true);
+ proc.Start();
+
+ while (await proc.StandardOutput.ReadLineAsync().ConfigureAwait(false) is { Length: > 0 } line)
+ outs.Add(line);
+
+ await proc.WaitForExitAsync().ConfigureAwait(false);
+ }
+ catch
+ {
+ // Ignore exceptions.
+ }
+
+ return outs;
}
}
}
diff --git a/src/Commands/QueryRevisionObjects.cs b/src/Commands/QueryRevisionObjects.cs
index 9657c7c7e..a7eaaa9e7 100644
--- a/src/Commands/QueryRevisionObjects.cs
+++ b/src/Commands/QueryRevisionObjects.cs
@@ -1,5 +1,6 @@
using System.Collections.Generic;
-using System.IO;
+using System.Diagnostics;
+using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
@@ -14,47 +15,56 @@ public QueryRevisionObjects(string repo, string sha, string parentFolder)
{
WorkingDirectory = repo;
Context = repo;
- Args = $"ls-tree {sha}";
+ var builder = new StringBuilder(1024);
+ builder.Append("ls-tree ").Append(sha);
if (!string.IsNullOrEmpty(parentFolder))
- Args += $" -- {parentFolder.Quoted()}";
+ builder.Append(" -- ").Append(parentFolder.Quoted());
+
+ Args = builder.ToString();
}
public async Task> GetResultAsync()
{
var outs = new List();
- var rs = await ReadToEndAsync().ConfigureAwait(false);
- if (rs.IsSuccess)
+
+ try
{
- var sr = new StringReader(rs.StdOut);
- while (sr.ReadLine() is { } line)
- Parse(outs, line);
- }
+ using var proc = new Process();
+ proc.StartInfo = CreateGitStartInfo(true);
+ proc.Start();
- return outs;
- }
+ while (await proc.StandardOutput.ReadLineAsync().ConfigureAwait(false) is { } line)
+ {
+ var match = REG_FORMAT().Match(line);
+ if (!match.Success)
+ continue;
- private void Parse(List outs, string line)
- {
- var match = REG_FORMAT().Match(line);
- if (!match.Success)
- return;
+ var obj = new Models.Object();
+ obj.SHA = match.Groups[2].Value;
+ obj.Type = Models.ObjectType.Blob;
+ obj.Path = match.Groups[3].Value;
- var obj = new Models.Object();
- obj.SHA = match.Groups[2].Value;
- obj.Type = Models.ObjectType.Blob;
- obj.Path = match.Groups[3].Value;
+ obj.Type = match.Groups[1].Value switch
+ {
+ "blob" => Models.ObjectType.Blob,
+ "tree" => Models.ObjectType.Tree,
+ "tag" => Models.ObjectType.Tag,
+ "commit" => Models.ObjectType.Commit,
+ _ => obj.Type,
+ };
- obj.Type = match.Groups[1].Value switch
+ outs.Add(obj);
+ }
+
+ await proc.WaitForExitAsync().ConfigureAwait(false);
+ }
+ catch
{
- "blob" => Models.ObjectType.Blob,
- "tree" => Models.ObjectType.Tree,
- "tag" => Models.ObjectType.Tag,
- "commit" => Models.ObjectType.Commit,
- _ => obj.Type,
- };
-
- outs.Add(obj);
+ // Ignore exceptions.
+ }
+
+ return outs;
}
}
}
diff --git a/src/Commands/QuerySingleCommit.cs b/src/Commands/QuerySingleCommit.cs
index 897459f0d..822f5c4a5 100644
--- a/src/Commands/QuerySingleCommit.cs
+++ b/src/Commands/QuerySingleCommit.cs
@@ -12,31 +12,40 @@ public QuerySingleCommit(string repo, string 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 GetResult()
+ {
+ var rs = ReadToEnd();
+ return Parse(rs);
+ }
+
public async Task GetResultAsync()
{
var rs = await ReadToEndAsync().ConfigureAwait(false);
- if (rs.IsSuccess && !string.IsNullOrEmpty(rs.StdOut))
- {
- var commit = new Models.Commit();
- var lines = rs.StdOut.Split('\n');
- if (lines.Length < 8)
- return null;
+ return Parse(rs);
+ }
+
+ private Models.Commit Parse(Result rs)
+ {
+ if (!rs.IsSuccess || string.IsNullOrEmpty(rs.StdOut))
+ return null;
- commit.SHA = lines[0];
- if (!string.IsNullOrEmpty(lines[1]))
- commit.Parents.AddRange(lines[1].Split(' ', StringSplitOptions.RemoveEmptyEntries));
- if (!string.IsNullOrEmpty(lines[2]))
- commit.ParseDecorators(lines[2]);
- commit.Author = Models.User.FindOrAdd(lines[3]);
- commit.AuthorTime = ulong.Parse(lines[4]);
- commit.Committer = Models.User.FindOrAdd(lines[5]);
- commit.CommitterTime = ulong.Parse(lines[6]);
- commit.Subject = lines[7];
+ var commit = new Models.Commit();
+ var lines = rs.StdOut.Split('\n');
+ if (lines.Length < 8)
+ return null;
- return commit;
- }
+ commit.SHA = lines[0];
+ if (!string.IsNullOrEmpty(lines[1]))
+ commit.Parents.AddRange(lines[1].Split(' ', StringSplitOptions.RemoveEmptyEntries));
+ if (!string.IsNullOrEmpty(lines[2]))
+ commit.ParseDecorators(lines[2]);
+ commit.Author = Models.User.FindOrAdd(lines[3]);
+ commit.AuthorTime = ulong.Parse(lines[4]);
+ commit.Committer = Models.User.FindOrAdd(lines[5]);
+ commit.CommitterTime = ulong.Parse(lines[6]);
+ commit.Subject = lines[7];
- return null;
+ return commit;
}
}
}
diff --git a/src/Commands/QueryStagedChangesWithAmend.cs b/src/Commands/QueryStagedChangesWithAmend.cs
index bec033ff7..229d9e65e 100644
--- a/src/Commands/QueryStagedChangesWithAmend.cs
+++ b/src/Commands/QueryStagedChangesWithAmend.cs
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
-using System.Threading.Tasks;
namespace SourceGit.Commands
{
@@ -20,9 +19,9 @@ public QueryStagedChangesWithAmend(string repo, string parent)
_parent = parent;
}
- public async Task> GetResultAsync()
+ public List GetResult()
{
- var rs = await ReadToEndAsync().ConfigureAwait(false);
+ var rs = ReadToEnd();
if (!rs.IsSuccess)
return [];
diff --git a/src/Commands/QueryTags.cs b/src/Commands/QueryTags.cs
index ba83cb182..8718542eb 100644
--- a/src/Commands/QueryTags.cs
+++ b/src/Commands/QueryTags.cs
@@ -12,7 +12,7 @@ public QueryTags(string repo)
Context = repo;
WorkingDirectory = repo;
- Args = $"tag -l --format=\"{_boundary}%(refname)%00%(objecttype)%00%(objectname)%00%(*objectname)%00%(creatordate:unix)%00%(contents:subject)%0a%0a%(contents:body)\"";
+ Args = $"tag -l --format=\"{_boundary}%(refname)%00%(objecttype)%00%(objectname)%00%(*objectname)%00%(taggername)±%(taggeremail)%00%(creatordate:unix)%00%(contents:subject)%0a%0a%(contents:body)\"";
}
public async Task> GetResultAsync()
@@ -26,20 +26,23 @@ public QueryTags(string repo)
foreach (var record in records)
{
var subs = record.Split('\0');
- if (subs.Length != 6)
+ if (subs.Length != 7)
continue;
var name = subs[0].Substring(10);
- var message = subs[5].Trim();
+ var message = subs[6].Trim();
if (!string.IsNullOrEmpty(message) && message.Equals(name, StringComparison.Ordinal))
message = null;
+ ulong.TryParse(subs[5], out var creatorDate);
+
tags.Add(new Models.Tag()
{
Name = name,
IsAnnotated = subs[1].Equals("tag", StringComparison.Ordinal),
SHA = string.IsNullOrEmpty(subs[3]) ? subs[2] : subs[3],
- CreatorDate = ulong.Parse(subs[4]),
+ Creator = Models.User.FindOrAdd(subs[4]),
+ CreatorDate = creatorDate,
Message = message,
});
}
@@ -47,6 +50,6 @@ public QueryTags(string repo)
return tags;
}
- private string _boundary = string.Empty;
+ private readonly string _boundary;
}
}
diff --git a/src/Commands/QueryTrackStatus.cs b/src/Commands/QueryTrackStatus.cs
index d687d2745..f00074f82 100644
--- a/src/Commands/QueryTrackStatus.cs
+++ b/src/Commands/QueryTrackStatus.cs
@@ -5,31 +5,28 @@ namespace SourceGit.Commands
{
public class QueryTrackStatus : Command
{
- public QueryTrackStatus(string repo, string local, string upstream)
+ public QueryTrackStatus(string repo)
{
WorkingDirectory = repo;
Context = repo;
- Args = $"rev-list --left-right {local}...{upstream}";
}
- public async Task GetResultAsync()
+ public async Task GetResultAsync(Models.Branch local, Models.Branch remote)
{
- var status = new Models.BranchTrackStatus();
+ Args = $"rev-list --left-right {local.Head}...{remote.Head}";
var rs = await ReadToEndAsync().ConfigureAwait(false);
if (!rs.IsSuccess)
- return status;
+ return;
var lines = rs.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
foreach (var line in lines)
{
if (line[0] == '>')
- status.Behind.Add(line.Substring(1));
+ local.Behind.Add(line.Substring(1));
else
- status.Ahead.Add(line.Substring(1));
+ local.Ahead.Add(line.Substring(1));
}
-
- return status;
}
}
}
diff --git a/src/Commands/QueryUpdatableSubmodules.cs b/src/Commands/QueryUpdatableSubmodules.cs
index 05fcc0538..55f429905 100644
--- a/src/Commands/QueryUpdatableSubmodules.cs
+++ b/src/Commands/QueryUpdatableSubmodules.cs
@@ -7,14 +7,16 @@ namespace SourceGit.Commands
{
public partial class QueryUpdatableSubmodules : Command
{
- [GeneratedRegex(@"^([U\-\+ ])([0-9a-f]+)\s(.*?)(\s\(.*\))?$")]
+ [GeneratedRegex(@"^([\-\+])([0-9a-f]+)\s(.*?)(\s\(.*\))?$")]
private static partial Regex REG_FORMAT_STATUS();
- public QueryUpdatableSubmodules(string repo)
+ public QueryUpdatableSubmodules(string repo, bool includeUninited)
{
WorkingDirectory = repo;
Context = repo;
Args = "submodule status";
+
+ _includeUninited = includeUninited;
}
public async Task> GetResultAsync()
@@ -30,12 +32,16 @@ public async Task> GetResultAsync()
{
var stat = match.Groups[1].Value;
var path = match.Groups[3].Value;
- if (!stat.StartsWith(' '))
- submodules.Add(path);
+ if (!_includeUninited && stat.StartsWith('-'))
+ continue;
+
+ submodules.Add(path);
}
}
return submodules;
}
+
+ private bool _includeUninited = false;
}
}
diff --git a/src/Commands/Rebase.cs b/src/Commands/Rebase.cs
index d08d55ad8..f7f33ac5c 100644
--- a/src/Commands/Rebase.cs
+++ b/src/Commands/Rebase.cs
@@ -1,4 +1,6 @@
-namespace SourceGit.Commands
+using System.Text;
+
+namespace SourceGit.Commands
{
public class Rebase : Command
{
@@ -6,10 +8,13 @@ public Rebase(string repo, string basedOn, bool autoStash)
{
WorkingDirectory = repo;
Context = repo;
- Args = "rebase ";
+
+ var builder = new StringBuilder(512);
+ builder.Append("rebase ");
if (autoStash)
- Args += "--autostash ";
- Args += basedOn;
+ builder.Append("--autostash ");
+
+ Args = builder.Append(basedOn).ToString();
}
}
}
diff --git a/src/Commands/Reset.cs b/src/Commands/Reset.cs
index 6a54533b1..cfcd337af 100644
--- a/src/Commands/Reset.cs
+++ b/src/Commands/Reset.cs
@@ -8,5 +8,12 @@ public Reset(string repo, string revision, string mode)
Context = repo;
Args = $"reset {mode} {revision}";
}
+
+ public Reset(string repo, string pathspec)
+ {
+ WorkingDirectory = repo;
+ Context = repo;
+ Args = $"reset HEAD --pathspec-from-file={pathspec.Quoted()}";
+ }
}
}
diff --git a/src/Commands/Restore.cs b/src/Commands/Restore.cs
index e2f9aa09a..bf3bd0a55 100644
--- a/src/Commands/Restore.cs
+++ b/src/Commands/Restore.cs
@@ -1,45 +1,12 @@
-using System.Text;
-
-namespace SourceGit.Commands
+namespace SourceGit.Commands
{
public class Restore : Command
{
- ///
- /// Only used for single staged change.
- ///
- ///
- ///
- public Restore(string repo, Models.Change stagedChange)
+ public Restore(string repo, string pathspecFile)
{
WorkingDirectory = repo;
Context = repo;
-
- var builder = new StringBuilder();
- builder.Append("restore --staged -- ").Append(stagedChange.Path.Quoted());
-
- if (stagedChange.Index == Models.ChangeState.Renamed)
- builder.Append(' ').Append(stagedChange.OriginalPath.Quoted());
-
- Args = builder.ToString();
- }
-
- ///
- /// Restore changes given in a path-spec file.
- ///
- ///
- ///
- ///
- public Restore(string repo, string pathspecFile, bool isStaged)
- {
- WorkingDirectory = repo;
- Context = repo;
-
- var builder = new StringBuilder();
- builder.Append("restore ");
- builder.Append(isStaged ? "--staged " : "--worktree --recurse-submodules ");
- builder.Append("--pathspec-from-file=").Append(pathspecFile.Quoted());
-
- Args = builder.ToString();
+ Args = $"restore --progress --worktree --recurse-submodules --pathspec-from-file={pathspecFile.Quoted()}";
}
}
}
diff --git a/src/Commands/Revert.cs b/src/Commands/Revert.cs
index 2e7afd11d..f42a62d05 100644
--- a/src/Commands/Revert.cs
+++ b/src/Commands/Revert.cs
@@ -1,4 +1,6 @@
-namespace SourceGit.Commands
+using System.Text;
+
+namespace SourceGit.Commands
{
public class Revert : Command
{
@@ -6,9 +8,16 @@ public Revert(string repo, string commit, bool autoCommit)
{
WorkingDirectory = repo;
Context = repo;
- Args = $"revert -m 1 {commit} --no-edit";
+
+ var builder = new StringBuilder(512);
+ builder
+ .Append("revert -m 1 ")
+ .Append(commit)
+ .Append(" --no-edit");
if (!autoCommit)
- Args += " --no-commit";
+ builder.Append(" --no-commit");
+
+ Args = builder.ToString();
}
}
}
diff --git a/src/Commands/SaveChangesAsPatch.cs b/src/Commands/SaveChangesAsPatch.cs
index c86fc0e06..51bc1319b 100644
--- a/src/Commands/SaveChangesAsPatch.cs
+++ b/src/Commands/SaveChangesAsPatch.cs
@@ -54,7 +54,7 @@ private static async Task ProcessSingleChangeAsync(string repo, Models.Dif
var starter = new ProcessStartInfo();
starter.WorkingDirectory = repo;
starter.FileName = Native.OS.GitExecutable;
- starter.Arguments = $"diff --ignore-cr-at-eol --unified=4 {opt}";
+ starter.Arguments = $"diff --no-color --no-ext-diff --ignore-cr-at-eol --unified=4 {opt}";
starter.UseShellExecute = false;
starter.CreateNoWindow = true;
starter.WindowStyle = ProcessWindowStyle.Hidden;
@@ -62,7 +62,7 @@ private static async Task ProcessSingleChangeAsync(string repo, Models.Dif
try
{
- using var proc = Process.Start(starter);
+ using var proc = Process.Start(starter)!;
await proc.StandardOutput.BaseStream.CopyToAsync(writer).ConfigureAwait(false);
await proc.WaitForExitAsync().ConfigureAwait(false);
return proc.ExitCode == 0;
diff --git a/src/Commands/SaveRevisionFile.cs b/src/Commands/SaveRevisionFile.cs
index a3ca373f8..e05d6d358 100644
--- a/src/Commands/SaveRevisionFile.cs
+++ b/src/Commands/SaveRevisionFile.cs
@@ -9,7 +9,7 @@ public static class SaveRevisionFile
{
public static async Task RunAsync(string repo, string revision, string file, string saveTo)
{
- var dir = Path.GetDirectoryName(saveTo);
+ var dir = Path.GetDirectoryName(saveTo) ?? string.Empty;
if (!Directory.Exists(dir))
Directory.CreateDirectory(dir);
@@ -42,7 +42,7 @@ private static async Task ExecCmdAsync(string repo, string args, string outputFi
{
try
{
- using var proc = Process.Start(starter);
+ using var proc = Process.Start(starter)!;
if (input != null)
{
diff --git a/src/Commands/SharedIssueTracker.cs b/src/Commands/SharedIssueTracker.cs
deleted file mode 100644
index 3e96fbeb7..000000000
--- a/src/Commands/SharedIssueTracker.cs
+++ /dev/null
@@ -1,94 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Threading.Tasks;
-
-namespace SourceGit.Commands
-{
- public class SharedIssueTracker : Command
- {
- public SharedIssueTracker(string repo)
- {
- WorkingDirectory = repo;
- Context = repo;
- _file = $"{repo}/.issuetracker";
- }
-
- public async Task> ReadAllAsync()
- {
- if (!File.Exists(_file))
- return [];
-
- Args = $"config -f {_file.Quoted()} -l";
-
- var output = await ReadToEndAsync().ConfigureAwait(false);
- var rs = new List();
- if (output.IsSuccess)
- {
- var lines = output.StdOut.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries);
- foreach (var line in lines)
- {
- var parts = line.Split('=', 2);
- if (parts.Length < 2)
- continue;
-
- var key = parts[0];
- var value = parts[1];
-
- if (!key.StartsWith("issuetracker.", StringComparison.Ordinal))
- continue;
-
- if (key.EndsWith(".regex", StringComparison.Ordinal))
- {
- var prefixLen = "issuetracker.".Length;
- var suffixLen = ".regex".Length;
- var ruleName = key.Substring(prefixLen, key.Length - prefixLen - suffixLen);
- FindOrAdd(rs, ruleName).RegexString = value;
- }
- else if (key.EndsWith(".url", StringComparison.Ordinal))
- {
- var prefixLen = "issuetracker.".Length;
- var suffixLen = ".url".Length;
- var ruleName = key.Substring(prefixLen, key.Length - prefixLen - suffixLen);
- FindOrAdd(rs, ruleName).URLTemplate = value;
- }
- }
- }
-
- return rs;
- }
-
- public async Task AddAsync(Models.IssueTrackerRule rule)
- {
- Args = $"config -f {_file.Quoted()} issuetracker.{rule.Name.Quoted()}.regex {rule.RegexString.Quoted()}";
-
- var succ = await ExecAsync().ConfigureAwait(false);
- if (succ)
- {
- Args = $"config -f {_file.Quoted()} issuetracker.{rule.Name.Quoted()}.url {rule.URLTemplate.Quoted()}";
- return await ExecAsync().ConfigureAwait(false);
- }
-
- return false;
- }
-
- public async Task RemoveAsync(Models.IssueTrackerRule rule)
- {
- Args = $"config -f {_file.Quoted()} --remove-section issuetracker.{rule.Name.Quoted()}";
- return await ExecAsync().ConfigureAwait(false);
- }
-
- private Models.IssueTrackerRule FindOrAdd(List rules, string ruleName)
- {
- var rule = rules.Find(x => x.Name.Equals(ruleName, StringComparison.Ordinal));
- if (rule != null)
- return rule;
-
- rule = new Models.IssueTrackerRule() { IsShared = true, Name = ruleName };
- rules.Add(rule);
- return rule;
- }
-
- private readonly string _file;
- }
-}
diff --git a/src/Commands/UnstageChangesForAmend.cs b/src/Commands/UpdateIndexInfo.cs
similarity index 84%
rename from src/Commands/UnstageChangesForAmend.cs
rename to src/Commands/UpdateIndexInfo.cs
index 0b2b7e478..3633a2823 100644
--- a/src/Commands/UnstageChangesForAmend.cs
+++ b/src/Commands/UpdateIndexInfo.cs
@@ -6,9 +6,9 @@
namespace SourceGit.Commands
{
- public class UnstageChangesForAmend
+ public class UpdateIndexInfo
{
- public UnstageChangesForAmend(string repo, List changes)
+ public UpdateIndexInfo(string repo, List changes)
{
_repo = repo;
@@ -18,7 +18,7 @@ public UnstageChangesForAmend(string repo, List changes)
{
_patchBuilder.Append("0 0000000000000000000000000000000000000000\t");
_patchBuilder.Append(c.Path);
- _patchBuilder.Append("\0100644 ");
+ _patchBuilder.Append("\n100644 ");
_patchBuilder.Append(c.DataForAmend.ObjectHash);
_patchBuilder.Append("\t");
_patchBuilder.Append(c.OriginalPath);
@@ -60,10 +60,12 @@ public async Task ExecAsync()
starter.RedirectStandardInput = true;
starter.RedirectStandardOutput = false;
starter.RedirectStandardError = true;
+ starter.StandardInputEncoding = new UTF8Encoding(false);
+ starter.StandardErrorEncoding = Encoding.UTF8;
try
{
- using var proc = Process.Start(starter);
+ using var proc = Process.Start(starter)!;
await proc.StandardInput.WriteAsync(_patchBuilder.ToString());
proc.StandardInput.Close();
@@ -78,12 +80,12 @@ public async Task ExecAsync()
}
catch (Exception e)
{
- App.RaiseException(_repo, "Failed to unstage changes: " + e.Message);
+ App.RaiseException(_repo, "Failed to update index: " + e.Message);
return false;
}
}
- private string _repo = "";
- private StringBuilder _patchBuilder = new StringBuilder();
+ private readonly string _repo;
+ private readonly StringBuilder _patchBuilder = new();
}
}
diff --git a/src/Commands/Worktree.cs b/src/Commands/Worktree.cs
index af03029f6..50ee97242 100644
--- a/src/Commands/Worktree.cs
+++ b/src/Commands/Worktree.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
+using System.Text;
using System.Threading.Tasks;
namespace SourceGit.Commands
@@ -30,26 +31,32 @@ public Worktree(string repo)
last = new Models.Worktree() { FullPath = line.Substring(9).Trim() };
last.RelativePath = Path.GetRelativePath(WorkingDirectory, last.FullPath);
worktrees.Add(last);
+ continue;
}
- else if (line.StartsWith("bare", StringComparison.Ordinal))
+
+ if (last == null)
+ continue;
+
+ if (line.StartsWith("bare", StringComparison.Ordinal))
{
- last!.IsBare = true;
+ worktrees.Remove(last);
+ last = null;
}
else if (line.StartsWith("HEAD ", StringComparison.Ordinal))
{
- last!.Head = line.Substring(5).Trim();
+ last.Head = line.Substring(5).Trim();
}
else if (line.StartsWith("branch ", StringComparison.Ordinal))
{
- last!.Branch = line.Substring(7).Trim();
+ last.Branch = line.Substring(7).Trim();
}
else if (line.StartsWith("detached", StringComparison.Ordinal))
{
- last!.IsDetached = true;
+ last.IsDetached = true;
}
else if (line.StartsWith("locked", StringComparison.Ordinal))
{
- last!.IsLocked = true;
+ last.IsLocked = true;
}
}
}
@@ -59,26 +66,20 @@ public Worktree(string repo)
public async Task AddAsync(string fullpath, string name, bool createNew, string tracking)
{
- Args = "worktree add ";
-
+ var builder = new StringBuilder(1024);
+ builder.Append("worktree add ");
if (!string.IsNullOrEmpty(tracking))
- Args += "--track ";
-
+ builder.Append("--track ");
if (!string.IsNullOrEmpty(name))
- {
- if (createNew)
- Args += $"-b {name} ";
- else
- Args += $"-B {name} ";
- }
-
- Args += $"{fullpath.Quoted()} ";
+ builder.Append(createNew ? "-b " : "-B ").Append(name).Append(' ');
+ builder.Append(fullpath.Quoted()).Append(' ');
if (!string.IsNullOrEmpty(tracking))
- Args += tracking;
+ builder.Append(tracking);
else if (!string.IsNullOrEmpty(name) && !createNew)
- Args += name;
+ builder.Append(name);
+ Args = builder.ToString();
return await ExecAsync().ConfigureAwait(false);
}
diff --git a/src/Converters/BoolConverters.cs b/src/Converters/BoolConverters.cs
index 3563fb37c..8a2f31416 100644
--- a/src/Converters/BoolConverters.cs
+++ b/src/Converters/BoolConverters.cs
@@ -5,10 +5,10 @@ namespace SourceGit.Converters
{
public static class BoolConverters
{
- 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);
+ new FuncValueConverter(x => x ? FontWeight.Bold : FontWeight.Regular);
+
+ public static readonly FuncValueConverter IsMergedToOpacity =
+ new FuncValueConverter(x => x ? 1 : 0.65);
}
}
diff --git a/src/Converters/DirtyStateConverters.cs b/src/Converters/DirtyStateConverters.cs
new file mode 100644
index 000000000..f140f7d3c
--- /dev/null
+++ b/src/Converters/DirtyStateConverters.cs
@@ -0,0 +1,28 @@
+using Avalonia.Data.Converters;
+using Avalonia.Media;
+
+namespace SourceGit.Converters
+{
+ public static class DirtyStateConverters
+ {
+ public static readonly FuncValueConverter ToBrush =
+ new FuncValueConverter(v =>
+ {
+ if (v.HasFlag(Models.DirtyState.HasLocalChanges))
+ return Brushes.Gray;
+ if (v.HasFlag(Models.DirtyState.HasPendingPullOrPush))
+ return Brushes.RoyalBlue;
+ return Brushes.Transparent;
+ });
+
+ public static readonly FuncValueConverter ToDesc =
+ new FuncValueConverter(v =>
+ {
+ if (v.HasFlag(Models.DirtyState.HasLocalChanges))
+ return " • " + App.Text("DirtyState.HasLocalChanges");
+ if (v.HasFlag(Models.DirtyState.HasPendingPullOrPush))
+ return " • " + App.Text("DirtyState.HasPendingPullOrPush");
+ return " • " + App.Text("DirtyState.UpToDate");
+ });
+ }
+}
diff --git a/src/Converters/DoubleConverters.cs b/src/Converters/DoubleConverters.cs
index 5b7c0a03d..871a80b3e 100644
--- a/src/Converters/DoubleConverters.cs
+++ b/src/Converters/DoubleConverters.cs
@@ -1,4 +1,5 @@
-using Avalonia.Data.Converters;
+using Avalonia;
+using Avalonia.Data.Converters;
namespace SourceGit.Converters
{
@@ -11,9 +12,12 @@ public static class DoubleConverters
new FuncValueConverter(v => v - 1.0);
public static readonly FuncValueConverter ToPercentage =
- new FuncValueConverter(v => (v * 100).ToString("F3") + "%");
+ new FuncValueConverter(v => (v * 100).ToString("F0") + "%");
public static readonly FuncValueConverter OneMinusToPercentage =
- new FuncValueConverter(v => ((1.0 - v) * 100).ToString("F3") + "%");
+ new FuncValueConverter(v => ((1.0 - v) * 100).ToString("F0") + "%");
+
+ public static readonly FuncValueConverter ToLeftMargin =
+ new FuncValueConverter(v => new Thickness(v, 0, 0, 0));
}
}
diff --git a/src/Converters/IntConverters.cs b/src/Converters/IntConverters.cs
index f21c5d240..7d2dabe25 100644
--- a/src/Converters/IntConverters.cs
+++ b/src/Converters/IntConverters.cs
@@ -32,12 +32,6 @@ public static class IntConverters
new FuncValueConverter(v => new Thickness(v * 16, 0, 0, 0));
public static readonly FuncValueConverter ToBookmarkBrush =
- new FuncValueConverter(bookmark =>
- {
- if (bookmark == 0)
- return Application.Current?.FindResource("Brush.FG1") as IBrush;
- else
- return Models.Bookmarks.Brushes[bookmark];
- });
+ new FuncValueConverter(v => Models.Bookmarks.Get(v) ?? App.Current?.FindResource("Brush.FG1") as IBrush);
}
}
diff --git a/src/Converters/InteractiveRebaseActionConverters.cs b/src/Converters/InteractiveRebaseActionConverters.cs
index 3534c809f..76967ce3e 100644
--- a/src/Converters/InteractiveRebaseActionConverters.cs
+++ b/src/Converters/InteractiveRebaseActionConverters.cs
@@ -21,8 +21,5 @@ public static class InteractiveRebaseActionConverters
public static readonly FuncValueConverter ToName =
new FuncValueConverter(v => v.ToString());
-
- public static readonly FuncValueConverter CanEditMessage =
- new FuncValueConverter(v => v == Models.InteractiveRebaseAction.Reword || v == Models.InteractiveRebaseAction.Squash);
}
}
diff --git a/src/Converters/ListConverters.cs b/src/Converters/ListConverters.cs
index 6f3ae98b0..e0c5967e8 100644
--- a/src/Converters/ListConverters.cs
+++ b/src/Converters/ListConverters.cs
@@ -7,9 +7,6 @@ namespace SourceGit.Converters
{
public static class ListConverters
{
- public static readonly FuncValueConverter Count =
- new FuncValueConverter(v => v == null ? "0" : $"{v.Count}");
-
public static readonly FuncValueConverter ToCount =
new FuncValueConverter(v => v == null ? "(0)" : $"({v.Count})");
diff --git a/src/Converters/PathConverters.cs b/src/Converters/PathConverters.cs
index ac1e61e52..23dae2ab3 100644
--- a/src/Converters/PathConverters.cs
+++ b/src/Converters/PathConverters.cs
@@ -1,6 +1,4 @@
-using System;
using System.IO;
-
using Avalonia.Data.Converters;
namespace SourceGit.Converters
@@ -14,17 +12,6 @@ public static class PathConverters
new(v => Path.GetDirectoryName(v) ?? "");
public static readonly FuncValueConverter RelativeToHome =
- new(v =>
- {
- if (OperatingSystem.IsWindows())
- return v;
-
- var home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
- var prefixLen = home.EndsWith('/') ? home.Length - 1 : home.Length;
- if (v.StartsWith(home, StringComparison.Ordinal))
- return $"~{v.AsSpan(prefixLen)}";
-
- return v;
- });
+ new(Native.OS.GetRelativePathToHome);
}
}
diff --git a/src/Converters/StringConverters.cs b/src/Converters/StringConverters.cs
index 56c00fb4d..7d2821914 100644
--- a/src/Converters/StringConverters.cs
+++ b/src/Converters/StringConverters.cs
@@ -86,6 +86,6 @@ public object ConvertBack(object value, Type targetType, object parameter, Cultu
new FuncValueConverter(v => v != null && v.Trim().Length > 0);
public static readonly FuncValueConverter ToFriendlyUpstream =
- new FuncValueConverter(v => v != null ? v.Substring(13) : string.Empty);
+ new FuncValueConverter(v => v is { Length: > 13 } ? v.Substring(13) : string.Empty);
}
}
diff --git a/src/Models/AvatarManager.cs b/src/Models/AvatarManager.cs
index 69e12819b..cf4eb3e38 100644
--- a/src/Models/AvatarManager.cs
+++ b/src/Models/AvatarManager.cs
@@ -51,7 +51,7 @@ public void Start()
LoadDefaultAvatar("noreply@github.com", "github.png");
LoadDefaultAvatar("unrealbot@epicgames.com", "unreal.png");
- Task.Run(() =>
+ Task.Run(async () =>
{
while (true)
{
@@ -84,7 +84,7 @@ public void Start()
{
using var client = new HttpClient();
client.Timeout = TimeSpan.FromSeconds(2);
- var rsp = client.GetAsync(url).Result;
+ var rsp = await client.GetAsync(url);
if (rsp.IsSuccessStatusCode)
{
using (var stream = rsp.Content.ReadAsStream())
@@ -190,9 +190,6 @@ public void SetFromLocal(string email, string file)
image = Bitmap.DecodeToWidth(stream, 128);
}
- if (image == null)
- return;
-
_resources[email] = image;
lock (_synclock)
diff --git a/src/Models/Bookmarks.cs b/src/Models/Bookmarks.cs
index 37cf689b7..ae3b2abd3 100644
--- a/src/Models/Bookmarks.cs
+++ b/src/Models/Bookmarks.cs
@@ -1,11 +1,9 @@
-using System.Collections.Generic;
-
-namespace SourceGit.Models
+namespace SourceGit.Models
{
public static class Bookmarks
{
public static readonly Avalonia.Media.IBrush[] Brushes = [
- Avalonia.Media.Brushes.Transparent,
+ null,
Avalonia.Media.Brushes.Red,
Avalonia.Media.Brushes.Orange,
Avalonia.Media.Brushes.Gold,
@@ -15,12 +13,9 @@ public static class Bookmarks
Avalonia.Media.Brushes.Purple,
];
- public static readonly List Supported = new List();
-
- static Bookmarks()
+ public static Avalonia.Media.IBrush Get(int i)
{
- for (int i = 0; i < Brushes.Length; i++)
- Supported.Add(i);
+ return (i >= 0 && i < Brushes.Length) ? Brushes[i] : null;
}
}
}
diff --git a/src/Models/Branch.cs b/src/Models/Branch.cs
index 350bc5b5a..47aa2153a 100644
--- a/src/Models/Branch.cs
+++ b/src/Models/Branch.cs
@@ -1,36 +1,14 @@
using System.Collections.Generic;
-using System.Text.RegularExpressions;
namespace SourceGit.Models
{
- public class BranchTrackStatus
- {
- public List Ahead { get; set; } = new List();
- public List Behind { get; set; } = new List();
-
- public bool IsVisible => Ahead.Count > 0 || Behind.Count > 0;
-
- public override string ToString()
- {
- if (Ahead.Count == 0 && Behind.Count == 0)
- return string.Empty;
-
- var track = "";
- if (Ahead.Count > 0)
- track += $"{Ahead.Count}↑";
- if (Behind.Count > 0)
- track += $" {Behind.Count}↓";
- return track.Trim();
- }
- }
-
public enum BranchSortMode
{
Name = 0,
CommitterDate,
}
- public partial class Branch
+ public class Branch
{
public string Name { get; set; }
public string FullName { get; set; }
@@ -40,18 +18,27 @@ public partial class Branch
public bool IsCurrent { get; set; }
public bool IsDetachedHead { get; set; }
public string Upstream { get; set; }
- public BranchTrackStatus TrackStatus { get; set; }
+ public List Ahead { get; set; } = [];
+ public List Behind { get; set; } = [];
public string Remote { get; set; }
public bool IsUpstreamGone { get; set; }
+ public string WorktreePath { get; set; }
+ public bool HasWorktree => !IsCurrent && !string.IsNullOrEmpty(WorktreePath);
public string FriendlyName => IsLocal ? Name : $"{Remote}/{Name}";
+ public bool IsTrackStatusVisible => Ahead.Count > 0 || Behind.Count > 0;
- [GeneratedRegex(@"\s+")]
- private static partial Regex REG_FIX_NAME();
-
- public static string FixName(string name)
+ public string TrackStatusDescription
{
- return REG_FIX_NAME().Replace(name, "-");
+ get
+ {
+ var ahead = Ahead.Count;
+ var behind = Behind.Count;
+ if (ahead > 0)
+ return behind > 0 ? $"{ahead}↑ {behind}↓" : $"{ahead}↑";
+
+ return behind > 0 ? $"{behind}↓" : string.Empty;
+ }
}
}
}
diff --git a/src/Models/Commit.cs b/src/Models/Commit.cs
index 61438424a..4a98b985a 100644
--- a/src/Models/Commit.cs
+++ b/src/Models/Commit.cs
@@ -1,9 +1,6 @@
using System;
using System.Collections.Generic;
-using Avalonia;
-using Avalonia.Media;
-
namespace SourceGit.Models
{
public enum CommitSearchMethod
@@ -18,15 +15,8 @@ public enum CommitSearchMethod
public class Commit
{
- // As retrieved by: git mktree Parents { get; set; } = new();
public List Decorators { get; set; } = new();
- public bool HasDecorators => Decorators.Count > 0;
+
+ public bool IsMerged { get; set; } = false;
+ public int Color { get; set; } = 0;
+ public double LeftMargin { get; set; } = 0;
public string AuthorTimeStr => DateTime.UnixEpoch.AddSeconds(AuthorTime).ToLocalTime().ToString(DateTimeFormat.Active.DateTime);
public string CommitterTimeStr => DateTime.UnixEpoch.AddSeconds(CommitterTime).ToLocalTime().ToString(DateTimeFormat.Active.DateTime);
public string AuthorTimeShortStr => DateTime.UnixEpoch.AddSeconds(AuthorTime).ToLocalTime().ToString(DateTimeFormat.Active.DateOnly);
public string CommitterTimeShortStr => DateTime.UnixEpoch.AddSeconds(CommitterTime).ToLocalTime().ToString(DateTimeFormat.Active.DateOnly);
- public bool IsMerged { get; set; } = false;
public bool IsCommitterVisible => !Author.Equals(Committer) || AuthorTime != CommitterTime;
public bool IsCurrentHead => Decorators.Find(x => x.Type is DecoratorType.CurrentBranchHead or DecoratorType.CurrentCommitHead) != null;
-
- public int Color { get; set; } = 0;
- public double Opacity => IsMerged ? 1 : OpacityForNotMerged;
- public FontWeight FontWeight => IsCurrentHead ? FontWeight.Bold : FontWeight.Regular;
- public Thickness Margin { get; set; } = new(0);
- public IBrush Brush => CommitGraph.Pens[Color].Brush;
+ public bool HasDecorators => Decorators.Count > 0;
public string GetFriendlyName()
{
@@ -65,6 +52,14 @@ public string GetFriendlyName()
return SHA[..10];
}
+ public void ParseParents(string data)
+ {
+ if (data.Length < 8)
+ return;
+
+ Parents.AddRange(data.Split(' ', StringSplitOptions.RemoveEmptyEntries));
+ }
+
public void ParseDecorators(string data)
{
if (data.Length < 3)
diff --git a/src/Models/CommitGraph.cs b/src/Models/CommitGraph.cs
index cb5696101..82505c351 100644
--- a/src/Models/CommitGraph.cs
+++ b/src/Models/CommitGraph.cs
@@ -6,12 +6,7 @@
namespace SourceGit.Models
{
- public record CommitGraphLayout(double startY, double clipWidth, double rowHeight)
- {
- public double StartY { get; set; } = startY;
- public double ClipWidth { get; set; } = clipWidth;
- public double RowHeight { get; set; } = rowHeight;
- }
+ public record CommitGraphLayout(double StartY, double ClipWidth, double RowHeight);
public class CommitGraph
{
@@ -204,8 +199,8 @@ public static CommitGraph Parse(List commits, bool firstParentOnlyEnable
// Margins & merge state (used by Views.Histories).
commit.IsMerged = isMerged;
- commit.Margin = new Thickness(Math.Max(offsetX, maxOffsetOld) + halfWidth + 2, 0, 0, 0);
commit.Color = dotColor;
+ commit.LeftMargin = Math.Max(offsetX, maxOffsetOld) + halfWidth + 2;
}
// Deal with curves haven't ended yet.
diff --git a/src/Models/CommitLink.cs b/src/Models/CommitLink.cs
index 08caad8d1..fa78f206c 100644
--- a/src/Models/CommitLink.cs
+++ b/src/Models/CommitLink.cs
@@ -5,8 +5,8 @@ namespace SourceGit.Models
{
public class CommitLink
{
- public string Name { get; set; } = null;
- public string URLPrefix { get; set; } = null;
+ public string Name { get; } = null;
+ public string URLPrefix { get; } = null;
public CommitLink(string name, string prefix)
{
@@ -20,26 +20,28 @@ public static List Get(List remotes)
foreach (var remote in remotes)
{
- if (remote.TryGetVisitURL(out var url))
+ if (remote.TryGetVisitURL(out var link))
{
- var trimmedUrl = url.AsSpan();
- if (url.EndsWith(".git"))
- trimmedUrl = url.AsSpan(0, url.Length - 4);
+ var uri = new Uri(link, UriKind.Absolute);
+ var host = uri.Host;
+ var route = uri.AbsolutePath.TrimStart('/');
- if (url.StartsWith("https://github.com/", StringComparison.Ordinal))
- outs.Add(new($"GitHub ({trimmedUrl[19..]})", $"{url}/commit/"));
- else if (url.StartsWith("https://gitlab.", StringComparison.Ordinal))
- outs.Add(new($"GitLab ({trimmedUrl[(trimmedUrl[15..].IndexOf('/') + 16)..]})", $"{url}/-/commit/"));
- else if (url.StartsWith("https://gitee.com/", StringComparison.Ordinal))
- outs.Add(new($"Gitee ({trimmedUrl[18..]})", $"{url}/commit/"));
- else if (url.StartsWith("https://bitbucket.org/", StringComparison.Ordinal))
- outs.Add(new($"BitBucket ({trimmedUrl[22..]})", $"{url}/commits/"));
- else if (url.StartsWith("https://codeberg.org/", StringComparison.Ordinal))
- outs.Add(new($"Codeberg ({trimmedUrl[21..]})", $"{url}/commit/"));
- else if (url.StartsWith("https://gitea.org/", StringComparison.Ordinal))
- outs.Add(new($"Gitea ({trimmedUrl[18..]})", $"{url}/commit/"));
- else if (url.StartsWith("https://git.sr.ht/", StringComparison.Ordinal))
- outs.Add(new($"sourcehut ({trimmedUrl[18..]})", $"{url}/commit/"));
+ if (host.Equals("github.com", StringComparison.Ordinal))
+ outs.Add(new($"GitHub ({route})", $"{link}/commit/"));
+ else if (host.Contains("gitlab", StringComparison.Ordinal))
+ outs.Add(new($"GitLab ({route})", $"{link}/-/commit/"));
+ else if (host.Equals("gitee.com", StringComparison.Ordinal))
+ outs.Add(new($"Gitee ({route})", $"{link}/commit/"));
+ else if (host.Equals("bitbucket.org", StringComparison.Ordinal))
+ outs.Add(new($"BitBucket ({route})", $"{link}/commits/"));
+ else if (host.Equals("codeberg.org", StringComparison.Ordinal))
+ outs.Add(new($"Codeberg ({route})", $"{link}/commit/"));
+ else if (host.Equals("gitea.org", StringComparison.Ordinal))
+ outs.Add(new($"Gitea ({route})", $"{link}/commit/"));
+ else if (host.Equals("git.sr.ht", StringComparison.Ordinal))
+ outs.Add(new($"sourcehut ({route})", $"{link}/commit/"));
+ else if (host.Equals("gitcode.com", StringComparison.Ordinal))
+ outs.Add(new($"GitCode ({route})", $"{link}/commit/"));
}
}
diff --git a/src/Models/ConfirmEmptyCommitResult.cs b/src/Models/ConfirmEmptyCommitResult.cs
new file mode 100644
index 000000000..176845b9a
--- /dev/null
+++ b/src/Models/ConfirmEmptyCommitResult.cs
@@ -0,0 +1,9 @@
+namespace SourceGit.Models
+{
+ public enum ConfirmEmptyCommitResult
+ {
+ Cancel = 0,
+ StageAllAndCommit,
+ CreateEmptyCommit,
+ }
+}
diff --git a/src/Models/ConventionalCommitType.cs b/src/Models/ConventionalCommitType.cs
index 531a16c07..9275ff116 100644
--- a/src/Models/ConventionalCommitType.cs
+++ b/src/Models/ConventionalCommitType.cs
@@ -1,4 +1,6 @@
using System.Collections.Generic;
+using System.IO;
+using System.Text.Json;
namespace SourceGit.Models
{
@@ -8,26 +10,39 @@ public class ConventionalCommitType
public string Type { get; set; }
public string Description { get; set; }
- public static readonly List Supported = [
- new("Features", "feat", "Adding a new feature"),
- new("Bug Fixes", "fix", "Fixing a bug"),
- new("Work In Progress", "wip", "Still being developed and not yet complete"),
- new("Reverts", "revert", "Undoing a previous commit"),
- new("Code Refactoring", "refactor", "Restructuring code without changing its external behavior"),
- new("Performance Improvements", "perf", "Improves performance"),
- new("Builds", "build", "Changes that affect the build system or external dependencies"),
- new("Continuous Integrations", "ci", "Changes to CI configuration files and scripts"),
- new("Documentations", "docs", "Updating documentation"),
- new("Styles", "style", "Elements or code styles without changing the code logic"),
- new("Tests", "test", "Adding or updating tests"),
- new("Chores", "chore", "Other changes that don't modify src or test files"),
- ];
-
public ConventionalCommitType(string name, string type, string description)
{
Name = name;
Type = type;
Description = description;
}
+
+ public static List Load(string storageFile)
+ {
+ try
+ {
+ if (!string.IsNullOrEmpty(storageFile) && File.Exists(storageFile))
+ return JsonSerializer.Deserialize(File.ReadAllText(storageFile), JsonCodeGen.Default.ListConventionalCommitType) ?? [];
+ }
+ catch
+ {
+ // Ignore errors.
+ }
+
+ return new List {
+ new("Features", "feat", "Adding a new feature"),
+ new("Bug Fixes", "fix", "Fixing a bug"),
+ new("Work In Progress", "wip", "Still being developed and not yet complete"),
+ new("Reverts", "revert", "Undoing a previous commit"),
+ new("Code Refactoring", "refactor", "Restructuring code without changing its external behavior"),
+ new("Performance Improvements", "perf", "Improves performance"),
+ new("Builds", "build", "Changes that affect the build system or external dependencies"),
+ new("Continuous Integrations", "ci", "Changes to CI configuration files and scripts"),
+ new("Documentations", "docs", "Updating documentation"),
+ new("Styles", "style", "Elements or code styles without changing the code logic"),
+ new("Tests", "test", "Adding or updating tests"),
+ new("Chores", "chore", "Other changes that don't modify src or test files"),
+ };
+ }
}
}
diff --git a/src/Models/CustomAction.cs b/src/Models/CustomAction.cs
index 1ed65b8b3..ec500d3c0 100644
--- a/src/Models/CustomAction.cs
+++ b/src/Models/CustomAction.cs
@@ -9,6 +9,8 @@ public enum CustomActionScope
Commit,
Branch,
Tag,
+ Remote,
+ File,
}
public enum CustomActionControlType
@@ -19,6 +21,8 @@ public enum CustomActionControlType
ComboBox,
}
+ public record CustomActionTargetFile(string File, Commit Revision);
+
public class CustomActionControl : ObservableObject
{
public CustomActionControlType Type
diff --git a/src/Models/DiffResult.cs b/src/Models/DiffResult.cs
index 95ffa99f1..6c381df35 100644
--- a/src/Models/DiffResult.cs
+++ b/src/Models/DiffResult.cs
@@ -1,8 +1,6 @@
using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
-
-using Avalonia;
using Avalonia.Media.Imaging;
namespace SourceGit.Models
@@ -16,7 +14,7 @@ public enum TextDiffLineType
Deleted,
}
- public class TextInlineRange(int p, int n)
+ public class TextRange(int p, int n)
{
public int Start { get; set; } = p;
public int End { get; set; } = p + n - 1;
@@ -28,7 +26,7 @@ public class TextDiffLine
public string Content { get; set; } = "";
public int OldLineNumber { get; set; } = 0;
public int NewLineNumber { get; set; } = 0;
- public List Highlights { get; set; } = new List();
+ public List Highlights { get; set; } = new List();
public bool NoNewLineEndOfFile { get; set; } = false;
public string OldLine => OldLineNumber == 0 ? string.Empty : OldLineNumber.ToString();
@@ -49,26 +47,15 @@ public class TextDiffSelection
public int StartLine { get; set; } = 0;
public int EndLine { get; set; } = 0;
public bool HasChanges { get; set; } = false;
- public bool HasLeftChanges { get; set; } = false;
public int IgnoredAdds { get; set; } = 0;
public int IgnoredDeletes { get; set; } = 0;
-
- public bool IsInRange(int idx)
- {
- return idx >= StartLine - 1 && idx < EndLine;
- }
}
public partial class TextDiff
{
- public string File { get; set; } = string.Empty;
public List Lines { get; set; } = new List();
- public Vector ScrollOffset { get; set; } = Vector.Zero;
public int MaxLineNumber = 0;
- public string Repo { get; set; } = null;
- public DiffOption Option { get; set; } = null;
-
public TextDiffSelection MakeSelection(int startLine, int endLine, bool isCombined, bool isOldSide)
{
var rs = new TextDiffSelection();
@@ -79,15 +66,9 @@ public TextDiffSelection MakeSelection(int startLine, int endLine, bool isCombin
{
var line = Lines[i];
if (line.Type == TextDiffLineType.Added)
- {
- rs.HasLeftChanges = true;
rs.IgnoredAdds++;
- }
else if (line.Type == TextDiffLineType.Deleted)
- {
- rs.HasLeftChanges = true;
rs.IgnoredDeletes++;
- }
}
for (int i = startLine - 1; i < endLine; i++)
@@ -95,48 +76,19 @@ public TextDiffSelection MakeSelection(int startLine, int endLine, bool isCombin
var line = Lines[i];
if (line.Type == TextDiffLineType.Added)
{
- if (isCombined)
+ if (isCombined || !isOldSide)
{
rs.HasChanges = true;
break;
}
- if (isOldSide)
- {
- rs.HasLeftChanges = true;
- }
- else
- {
- rs.HasChanges = true;
- }
}
else if (line.Type == TextDiffLineType.Deleted)
{
- if (isCombined)
+ if (isCombined || isOldSide)
{
rs.HasChanges = true;
break;
}
- if (isOldSide)
- {
- rs.HasChanges = true;
- }
- else
- {
- rs.HasLeftChanges = true;
- }
- }
- }
-
- if (!rs.HasLeftChanges)
- {
- for (int i = endLine; i < Lines.Count; i++)
- {
- var line = Lines[i];
- if (line.Type == TextDiffLineType.Added || line.Type == TextDiffLineType.Deleted)
- {
- rs.HasLeftChanges = true;
- break;
- }
}
}
@@ -149,6 +101,7 @@ public void GenerateNewPatchFromSelection(Change change, string fileBlobGuid, Te
var fileGuid = isTracked ? fileBlobGuid : "00000000";
using var writer = new StreamWriter(output);
+ writer.NewLine = "\n";
writer.WriteLine($"diff --git a/{change.Path} b/{change.Path}");
if (!revert && !isTracked)
writer.WriteLine("new file mode 100644");
@@ -169,7 +122,11 @@ public void GenerateNewPatchFromSelection(Change change, string fileBlobGuid, Te
var line = Lines[i];
if (line.Type != TextDiffLineType.Added)
continue;
- writer.WriteLine($"{(selection.IsInRange(i) ? "+" : " ")}{line.Content}");
+
+ if (i >= selection.StartLine - 1 && i < selection.EndLine)
+ writer.WriteLine($"+{line.Content}");
+ else
+ writer.WriteLine($" {line.Content}");
}
}
else
@@ -193,6 +150,7 @@ public void GeneratePatchFromSelection(Change change, string fileTreeGuid, TextD
var orgFile = !string.IsNullOrEmpty(change.OriginalPath) ? change.OriginalPath : change.Path;
using var writer = new StreamWriter(output);
+ writer.NewLine = "\n";
writer.WriteLine($"diff --git a/{change.Path} b/{change.Path}");
writer.WriteLine($"index 00000000...{fileTreeGuid} 100644");
writer.WriteLine($"--- a/{orgFile}");
@@ -260,16 +218,16 @@ public void GeneratePatchFromSelection(Change change, string fileTreeGuid, TextD
else if (line.Type == TextDiffLineType.Added)
{
if (revert)
- writer.WriteLine($" {line.Content}");
+ WriteLine(writer, ' ', line);
}
else if (line.Type == TextDiffLineType.Deleted)
{
if (!revert)
- writer.WriteLine($" {line.Content}");
+ WriteLine(writer, ' ', line);
}
else if (line.Type == TextDiffLineType.Normal)
{
- writer.WriteLine($" {line.Content}");
+ WriteLine(writer, ' ', line);
}
}
}
@@ -285,15 +243,15 @@ public void GeneratePatchFromSelection(Change change, string fileTreeGuid, TextD
}
else if (line.Type == TextDiffLineType.Normal)
{
- writer.WriteLine($" {line.Content}");
+ WriteLine(writer, ' ', line);
}
else if (line.Type == TextDiffLineType.Added)
{
- writer.WriteLine($"+{line.Content}");
+ WriteLine(writer, '+', line);
}
else if (line.Type == TextDiffLineType.Deleted)
{
- writer.WriteLine($"-{line.Content}");
+ WriteLine(writer, '-', line);
}
}
@@ -306,6 +264,7 @@ public void GeneratePatchFromSelectionSingleSide(Change change, string fileTreeG
var orgFile = !string.IsNullOrEmpty(change.OriginalPath) ? change.OriginalPath : change.Path;
using var writer = new StreamWriter(output);
+ writer.NewLine = "\n";
writer.WriteLine($"diff --git a/{change.Path} b/{change.Path}");
writer.WriteLine($"index 00000000...{fileTreeGuid} 100644");
writer.WriteLine($"--- a/{orgFile}");
@@ -382,16 +341,16 @@ public void GeneratePatchFromSelectionSingleSide(Change change, string fileTreeG
else if (line.Type == TextDiffLineType.Added)
{
if (revert)
- writer.WriteLine($" {line.Content}");
+ WriteLine(writer, ' ', line);
}
else if (line.Type == TextDiffLineType.Deleted)
{
if (!revert)
- writer.WriteLine($" {line.Content}");
+ WriteLine(writer, ' ', line);
}
else if (line.Type == TextDiffLineType.Normal)
{
- writer.WriteLine($" {line.Content}");
+ WriteLine(writer, ' ', line);
}
}
}
@@ -407,7 +366,7 @@ public void GeneratePatchFromSelectionSingleSide(Change change, string fileTreeG
}
else if (line.Type == TextDiffLineType.Normal)
{
- writer.WriteLine($" {line.Content}");
+ WriteLine(writer, ' ', line);
}
else if (line.Type == TextDiffLineType.Added)
{
@@ -415,7 +374,7 @@ public void GeneratePatchFromSelectionSingleSide(Change change, string fileTreeG
{
if (revert)
{
- writer.WriteLine($" {line.Content}");
+ WriteLine(writer, ' ', line);
}
else
{
@@ -424,20 +383,20 @@ public void GeneratePatchFromSelectionSingleSide(Change change, string fileTreeG
}
else
{
- writer.WriteLine($"+{line.Content}");
+ WriteLine(writer, '+', line);
}
}
else if (line.Type == TextDiffLineType.Deleted)
{
if (isOldSide)
{
- writer.WriteLine($"-{line.Content}");
+ WriteLine(writer, '-', line);
}
else
{
if (!revert)
{
- writer.WriteLine($" {line.Content}");
+ WriteLine(writer, ' ', line);
}
else
{
@@ -600,6 +559,14 @@ private bool ProcessIndicatorForPatchSingleSide(StreamWriter writer, TextDiffLin
return true;
}
+ private static void WriteLine(StreamWriter writer, char prefix, TextDiffLine line)
+ {
+ writer.WriteLine($"{prefix}{line.Content}");
+
+ if (line.NoNewLineEndOfFile)
+ writer.WriteLine("\\ No newline at end of file");
+ }
+
[GeneratedRegex(@"^@@ \-(\d+),?\d* \+(\d+),?\d* @@")]
private static partial Regex REG_INDICATOR();
}
diff --git a/src/Models/ExternalMerger.cs b/src/Models/ExternalMerger.cs
index ed9b9b08a..655a1d58a 100644
--- a/src/Models/ExternalMerger.cs
+++ b/src/Models/ExternalMerger.cs
@@ -7,14 +7,13 @@
namespace SourceGit.Models
{
- public class ExternalMerger
+ public class ExternalMerger(string icon, string name, string finder, string mergeCmd, string diffCmd)
{
- public int Type { get; set; }
- public string Icon { get; set; }
- public string Name { get; set; }
- public string Exec { get; set; }
- public string Cmd { get; set; }
- public string DiffCmd { get; set; }
+ public string Icon { get; } = icon;
+ public string Name { get; } = name;
+ public string Finder { get; } = finder;
+ public string MergeCmd { get; } = mergeCmd;
+ public string DiffCmd { get; } = diffCmd;
public Bitmap IconImage
{
@@ -32,74 +31,69 @@ static ExternalMerger()
if (OperatingSystem.IsWindows())
{
Supported = new List() {
- new ExternalMerger(0, "git", "Use Git Settings", "", "", ""),
- new ExternalMerger(1, "vscode", "Visual Studio Code", "Code.exe", "-n --wait \"$MERGED\"", "-n --wait --diff \"$LOCAL\" \"$REMOTE\""),
- new ExternalMerger(2, "vscode_insiders", "Visual Studio Code - Insiders", "Code - Insiders.exe", "-n --wait \"$MERGED\"", "-n --wait --diff \"$LOCAL\" \"$REMOTE\""),
- new ExternalMerger(3, "vs", "Visual Studio", "vsDiffMerge.exe", "\"$REMOTE\" \"$LOCAL\" \"$BASE\" \"$MERGED\" /m", "\"$LOCAL\" \"$REMOTE\""),
- new ExternalMerger(4, "tortoise_merge", "Tortoise Merge", "TortoiseMerge.exe;TortoiseGitMerge.exe", "-base:\"$BASE\" -theirs:\"$REMOTE\" -mine:\"$LOCAL\" -merged:\"$MERGED\"", "-base:\"$LOCAL\" -theirs:\"$REMOTE\""),
- new ExternalMerger(5, "kdiff3", "KDiff3", "kdiff3.exe", "\"$REMOTE\" -b \"$BASE\" \"$LOCAL\" -o \"$MERGED\"", "\"$LOCAL\" \"$REMOTE\""),
- new ExternalMerger(6, "beyond_compare", "Beyond Compare", "BComp.exe", "\"$REMOTE\" \"$LOCAL\" \"$BASE\" \"$MERGED\"", "\"$LOCAL\" \"$REMOTE\""),
- 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\""),
- new ExternalMerger(11, "meld", "Meld", "Meld.exe", "\"$LOCAL\" \"$BASE\" \"$REMOTE\" --output \"$MERGED\"", "\"$LOCAL\" \"$REMOTE\""),
- new ExternalMerger(12, "cursor", "Cursor", "Cursor.exe", "-n --wait \"$MERGED\"", "-n --wait --diff \"$LOCAL\" \"$REMOTE\""),
+ new ExternalMerger("git", "Use Git Settings", "", "", ""),
+ new ExternalMerger("vscode", "Visual Studio Code", "Code.exe", "-n --wait \"$MERGED\"", "-n --wait --diff \"$LOCAL\" \"$REMOTE\""),
+ new ExternalMerger("vscode_insiders", "Visual Studio Code - Insiders", "Code - Insiders.exe", "-n --wait \"$MERGED\"", "-n --wait --diff \"$LOCAL\" \"$REMOTE\""),
+ new ExternalMerger("vs", "Visual Studio", "vsDiffMerge.exe", "\"$REMOTE\" \"$LOCAL\" \"$BASE\" \"$MERGED\" /m", "\"$LOCAL\" \"$REMOTE\""),
+ new ExternalMerger("tortoise_merge", "Tortoise Merge", "TortoiseMerge.exe;TortoiseGitMerge.exe", "-base:\"$BASE\" -theirs:\"$REMOTE\" -mine:\"$LOCAL\" -merged:\"$MERGED\"", "-base:\"$LOCAL\" -theirs:\"$REMOTE\""),
+ new ExternalMerger("kdiff3", "KDiff3", "kdiff3.exe", "\"$REMOTE\" -b \"$BASE\" \"$LOCAL\" -o \"$MERGED\"", "\"$LOCAL\" \"$REMOTE\""),
+ new ExternalMerger("beyond_compare", "Beyond Compare", "BComp.exe", "\"$REMOTE\" \"$LOCAL\" \"$BASE\" \"$MERGED\"", "\"$LOCAL\" \"$REMOTE\""),
+ new ExternalMerger("win_merge", "WinMerge", "WinMergeU.exe", "\"$MERGED\"", "-u -e -sw \"$LOCAL\" \"$REMOTE\""),
+ new ExternalMerger("codium", "VSCodium", "VSCodium.exe", "-n --wait \"$MERGED\"", "-n --wait --diff \"$LOCAL\" \"$REMOTE\""),
+ new ExternalMerger("p4merge", "P4Merge", "p4merge.exe", "-tw 4 \"$BASE\" \"$LOCAL\" \"$REMOTE\" \"$MERGED\"", "-tw 4 \"$LOCAL\" \"$REMOTE\""),
+ new ExternalMerger("plastic_merge", "Plastic SCM", "mergetool.exe", "-s=\"$REMOTE\" -b=\"$BASE\" -d=\"$LOCAL\" -r=\"$MERGED\" --automatic", "-s=\"$LOCAL\" -d=\"$REMOTE\""),
+ new ExternalMerger("meld", "Meld", "Meld.exe", "\"$LOCAL\" \"$BASE\" \"$REMOTE\" --output \"$MERGED\"", "\"$LOCAL\" \"$REMOTE\""),
+ new ExternalMerger("cursor", "Cursor", "Cursor.exe", "-n --wait \"$MERGED\"", "-n --wait --diff \"$LOCAL\" \"$REMOTE\""),
};
}
else if (OperatingSystem.IsMacOS())
{
Supported = new List() {
- new ExternalMerger(0, "git", "Use Git Settings", "", "", ""),
- new ExternalMerger(1, "xcode", "FileMerge", "/usr/bin/opendiff", "\"$BASE\" \"$LOCAL\" \"$REMOTE\" -ancestor \"$MERGED\"", "\"$LOCAL\" \"$REMOTE\""),
- new ExternalMerger(2, "vscode", "Visual Studio Code", "/Applications/Visual Studio Code.app/Contents/Resources/app/bin/code", "-n --wait \"$MERGED\"", "-n --wait --diff \"$LOCAL\" \"$REMOTE\""),
- new ExternalMerger(3, "vscode_insiders", "Visual Studio Code - Insiders", "/Applications/Visual Studio Code - Insiders.app/Contents/Resources/app/bin/code", "-n --wait \"$MERGED\"", "-n --wait --diff \"$LOCAL\" \"$REMOTE\""),
- new ExternalMerger(4, "kdiff3", "KDiff3", "/Applications/kdiff3.app/Contents/MacOS/kdiff3", "\"$REMOTE\" -b \"$BASE\" \"$LOCAL\" -o \"$MERGED\"", "\"$LOCAL\" \"$REMOTE\""),
- new ExternalMerger(5, "beyond_compare", "Beyond Compare", "/Applications/Beyond Compare.app/Contents/MacOS/bcomp", "\"$REMOTE\" \"$LOCAL\" \"$BASE\" \"$MERGED\"", "\"$LOCAL\" \"$REMOTE\""),
- new ExternalMerger(6, "codium", "VSCodium", "/Applications/VSCodium.app/Contents/Resources/app/bin/codium", "-n --wait \"$MERGED\"", "-n --wait --diff \"$LOCAL\" \"$REMOTE\""),
- new ExternalMerger(7, "p4merge", "P4Merge", "/Applications/p4merge.app/Contents/Resources/launchp4merge", "-tw 4 \"$BASE\" \"$LOCAL\" \"$REMOTE\" \"$MERGED\"", "-tw 4 \"$LOCAL\" \"$REMOTE\""),
- new ExternalMerger(8, "cursor", "Cursor", "/Applications/Cursor.app/Contents/Resources/app/bin/cursor", "-n --wait \"$MERGED\"", "-n --wait --diff \"$LOCAL\" \"$REMOTE\""),
+ new ExternalMerger("git", "Use Git Settings", "", "", ""),
+ new ExternalMerger("xcode", "FileMerge", "/usr/bin/opendiff", "\"$LOCAL\" \"$REMOTE\" -ancestor \"$BASE\" -merge \"$MERGED\"", "\"$LOCAL\" \"$REMOTE\""),
+ new ExternalMerger("vscode", "Visual Studio Code", "/Applications/Visual Studio Code.app/Contents/Resources/app/bin/code", "-n --wait \"$MERGED\"", "-n --wait --diff \"$LOCAL\" \"$REMOTE\""),
+ new ExternalMerger("vscode_insiders", "Visual Studio Code - Insiders", "/Applications/Visual Studio Code - Insiders.app/Contents/Resources/app/bin/code", "-n --wait \"$MERGED\"", "-n --wait --diff \"$LOCAL\" \"$REMOTE\""),
+ new ExternalMerger("kdiff3", "KDiff3", "/Applications/kdiff3.app/Contents/MacOS/kdiff3", "\"$REMOTE\" -b \"$BASE\" \"$LOCAL\" -o \"$MERGED\"", "\"$LOCAL\" \"$REMOTE\""),
+ new ExternalMerger("beyond_compare", "Beyond Compare", "/Applications/Beyond Compare.app/Contents/MacOS/bcomp", "\"$REMOTE\" \"$LOCAL\" \"$BASE\" \"$MERGED\"", "\"$LOCAL\" \"$REMOTE\""),
+ new ExternalMerger("codium", "VSCodium", "/Applications/VSCodium.app/Contents/Resources/app/bin/codium", "-n --wait \"$MERGED\"", "-n --wait --diff \"$LOCAL\" \"$REMOTE\""),
+ new ExternalMerger("p4merge", "P4Merge", "/Applications/p4merge.app/Contents/Resources/launchp4merge", "-tw 4 \"$BASE\" \"$LOCAL\" \"$REMOTE\" \"$MERGED\"", "-tw 4 \"$LOCAL\" \"$REMOTE\""),
+ new ExternalMerger("cursor", "Cursor", "/Applications/Cursor.app/Contents/Resources/app/bin/cursor", "-n --wait \"$MERGED\"", "-n --wait --diff \"$LOCAL\" \"$REMOTE\""),
};
}
else if (OperatingSystem.IsLinux())
{
Supported = new List() {
- new ExternalMerger(0, "git", "Use Git Settings", "", "", ""),
- new ExternalMerger(1, "vscode", "Visual Studio Code", "/usr/share/code/code", "-n --wait \"$MERGED\"", "-n --wait --diff \"$LOCAL\" \"$REMOTE\""),
- new ExternalMerger(2, "vscode_insiders", "Visual Studio Code - Insiders", "/usr/share/code-insiders/code-insiders", "-n --wait \"$MERGED\"", "-n --wait --diff \"$LOCAL\" \"$REMOTE\""),
- new ExternalMerger(3, "kdiff3", "KDiff3", "/usr/bin/kdiff3", "\"$REMOTE\" -b \"$BASE\" \"$LOCAL\" -o \"$MERGED\"", "\"$LOCAL\" \"$REMOTE\""),
- new ExternalMerger(4, "beyond_compare", "Beyond Compare", "/usr/bin/bcomp", "\"$REMOTE\" \"$LOCAL\" \"$BASE\" \"$MERGED\"", "\"$LOCAL\" \"$REMOTE\""),
- new ExternalMerger(5, "meld", "Meld", "/usr/bin/meld", "\"$LOCAL\" \"$BASE\" \"$REMOTE\" --output \"$MERGED\"", "\"$LOCAL\" \"$REMOTE\""),
- new ExternalMerger(6, "codium", "VSCodium", "/usr/share/codium/bin/codium", "-n --wait \"$MERGED\"", "-n --wait --diff \"$LOCAL\" \"$REMOTE\""),
- new ExternalMerger(7, "p4merge", "P4Merge", "/usr/local/bin/p4merge", "-tw 4 \"$BASE\" \"$LOCAL\" \"$REMOTE\" \"$MERGED\"", "-tw 4 \"$LOCAL\" \"$REMOTE\""),
- new ExternalMerger(8, "cursor", "Cursor", "cursor", "-n --wait \"$MERGED\"", "-n --wait --diff \"$LOCAL\" \"$REMOTE\""),
+ new ExternalMerger("git", "Use Git Settings", "", "", ""),
+ new ExternalMerger("vscode", "Visual Studio Code", "/usr/share/code/code", "-n --wait \"$MERGED\"", "-n --wait --diff \"$LOCAL\" \"$REMOTE\""),
+ new ExternalMerger("vscode_insiders", "Visual Studio Code - Insiders", "/usr/share/code-insiders/code-insiders", "-n --wait \"$MERGED\"", "-n --wait --diff \"$LOCAL\" \"$REMOTE\""),
+ new ExternalMerger("kdiff3", "KDiff3", "/usr/bin/kdiff3", "\"$REMOTE\" -b \"$BASE\" \"$LOCAL\" -o \"$MERGED\"", "\"$LOCAL\" \"$REMOTE\""),
+ new ExternalMerger("beyond_compare", "Beyond Compare", "/usr/bin/bcomp", "\"$REMOTE\" \"$LOCAL\" \"$BASE\" \"$MERGED\"", "\"$LOCAL\" \"$REMOTE\""),
+ new ExternalMerger("meld", "Meld", "/usr/bin/meld", "\"$LOCAL\" \"$BASE\" \"$REMOTE\" --output \"$MERGED\"", "\"$LOCAL\" \"$REMOTE\""),
+ new ExternalMerger("codium", "VSCodium", "/usr/share/codium/bin/codium", "-n --wait \"$MERGED\"", "-n --wait --diff \"$LOCAL\" \"$REMOTE\""),
+ new ExternalMerger("p4merge", "P4Merge", "/usr/local/bin/p4merge", "-tw 4 \"$BASE\" \"$LOCAL\" \"$REMOTE\" \"$MERGED\"", "-tw 4 \"$LOCAL\" \"$REMOTE\""),
+ new ExternalMerger("cursor", "Cursor", "cursor", "-n --wait \"$MERGED\"", "-n --wait --diff \"$LOCAL\" \"$REMOTE\""),
};
}
else
{
Supported = new List() {
- new ExternalMerger(0, "git", "Use Git Settings", "", "", ""),
+ new ExternalMerger("git", "Use Git Settings", "", "", ""),
};
}
}
- public ExternalMerger(int type, string icon, string name, string exec, string cmd, string diffCmd)
- {
- Type = type;
- Icon = icon;
- Name = name;
- Exec = exec;
- Cmd = cmd;
- DiffCmd = diffCmd;
- }
-
- public string[] GetPatterns()
+ public string[] GetPatternsToFindExecFile()
{
if (OperatingSystem.IsWindows())
- return Exec.Split(';');
+ return Finder.Split(';', StringSplitOptions.RemoveEmptyEntries);
- var choices = Exec.Split(';', StringSplitOptions.RemoveEmptyEntries);
- return Array.ConvertAll(choices, Path.GetFileName);
+ return [Path.GetFileName(Finder)];
}
}
+
+ public class DiffMergeTool(string exec, string cmd)
+ {
+ public string Exec { get; } = exec;
+ public string Cmd { get; } = cmd;
+ }
}
diff --git a/src/Models/ExternalTool.cs b/src/Models/ExternalTool.cs
index 377eba2f2..0f272ab35 100644
--- a/src/Models/ExternalTool.cs
+++ b/src/Models/ExternalTool.cs
@@ -12,14 +12,15 @@ namespace SourceGit.Models
{
public class ExternalTool
{
- public string Name { get; private set; }
- public Bitmap IconImage { get; private set; } = null;
+ public string Name { get; }
+ public string ExecFile { get; }
+ public Bitmap IconImage { get; }
public ExternalTool(string name, string icon, string execFile, Func execArgsGenerator = null)
{
Name = name;
- _execFile = execFile;
- _execArgsGenerator = execArgsGenerator ?? (repo => repo.Quoted());
+ ExecFile = execFile;
+ _execArgsGenerator = execArgsGenerator ?? (path => path.Quoted());
try
{
@@ -33,18 +34,16 @@ public ExternalTool(string name, string icon, string execFile, Func _execArgsGenerator = null;
}
@@ -181,17 +180,24 @@ public void FindJetBrainsFromToolbox(Func platformFinder)
var state = Path.Combine(platformFinder(), "state.json");
if (File.Exists(state))
{
- using var stream = File.OpenRead(state);
- var stateData = JsonSerializer.Deserialize(stream, JsonCodeGen.Default.JetBrainsState);
- foreach (var tool in stateData.Tools)
+ try
{
- if (exclude.Contains(tool.ToolId.ToLowerInvariant()))
- continue;
-
- Tools.Add(new ExternalTool(
- $"{tool.DisplayName} {tool.DisplayVersion}",
- supportedIcons.Contains(tool.ProductCode) ? $"JetBrains/{tool.ProductCode}" : "JetBrains/JB",
- Path.Combine(tool.InstallLocation, tool.LaunchCommand)));
+ using var stream = File.OpenRead(state);
+ var stateData = JsonSerializer.Deserialize(stream, JsonCodeGen.Default.JetBrainsState);
+ foreach (var tool in stateData.Tools)
+ {
+ if (exclude.Contains(tool.ToolId.ToLowerInvariant()))
+ continue;
+
+ Tools.Add(new ExternalTool(
+ $"{tool.DisplayName} {tool.DisplayVersion}",
+ supportedIcons.Contains(tool.ProductCode) ? $"JetBrains/{tool.ProductCode}" : "JetBrains/JB",
+ Path.Combine(tool.InstallLocation, tool.LaunchCommand)));
+ }
+ }
+ catch
+ {
+ // Ignore exceptions.
}
}
}
diff --git a/src/Models/Filter.cs b/src/Models/Filter.cs
deleted file mode 100644
index af4569fad..000000000
--- a/src/Models/Filter.cs
+++ /dev/null
@@ -1,60 +0,0 @@
-using CommunityToolkit.Mvvm.ComponentModel;
-
-namespace SourceGit.Models
-{
- public enum FilterType
- {
- LocalBranch = 0,
- LocalBranchFolder,
- RemoteBranch,
- RemoteBranchFolder,
- Tag,
- }
-
- public enum FilterMode
- {
- None = 0,
- Included,
- Excluded,
- }
-
- public class Filter : ObservableObject
- {
- public string Pattern
- {
- get => _pattern;
- set => SetProperty(ref _pattern, value);
- }
-
- public FilterType Type
- {
- get;
- set;
- } = FilterType.LocalBranch;
-
- public FilterMode Mode
- {
- get => _mode;
- set => SetProperty(ref _mode, value);
- }
-
- public bool IsBranch
- {
- get => Type != FilterType.Tag;
- }
-
- public Filter()
- {
- }
-
- public Filter(string pattern, FilterType type, FilterMode mode)
- {
- _pattern = pattern;
- _mode = mode;
- Type = type;
- }
-
- private string _pattern = string.Empty;
- private FilterMode _mode = FilterMode.None;
- }
-}
diff --git a/src/Models/HTTPSValidator.cs b/src/Models/HTTPSValidator.cs
new file mode 100644
index 000000000..014207c21
--- /dev/null
+++ b/src/Models/HTTPSValidator.cs
@@ -0,0 +1,84 @@
+using System;
+using System.Collections.Generic;
+using System.Net.Security;
+using System.Net.Sockets;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace SourceGit.Models
+{
+ public static class HTTPSValidator
+ {
+ public static void Add(string host)
+ {
+ lock (_syncLock)
+ {
+ // Already checked
+ if (_hosts.ContainsKey(host))
+ return;
+
+ // Temporarily mark as supported to avoid duplicate checks
+ _hosts.Add(host, true);
+
+ // Well-known hosts always support HTTPS
+ if (host.Contains("github.com", StringComparison.Ordinal) ||
+ host.Contains("gitlab", StringComparison.Ordinal) ||
+ host.Contains("azure.com", StringComparison.Ordinal) ||
+ host.Equals("gitee.com", StringComparison.Ordinal) ||
+ host.Equals("bitbucket.org", StringComparison.Ordinal) ||
+ host.Equals("gitea.org", StringComparison.Ordinal) ||
+ host.Equals("gitcode.com", StringComparison.Ordinal))
+ return;
+ }
+
+ Task.Run(() =>
+ {
+ var supported = false;
+
+ try
+ {
+ using (var client = new TcpClient())
+ {
+ client.ConnectAsync(host, 443).Wait(3000);
+ if (!client.Connected)
+ {
+ client.ConnectAsync(host, 80).Wait(3000);
+ supported = !client.Connected; // If the network is not available, assume HTTPS is supported
+ }
+ else
+ {
+ using (var ssl = new SslStream(client.GetStream(), false, (s, cert, chain, errs) => true))
+ {
+ ssl.AuthenticateAsClient(host);
+ supported = ssl.IsAuthenticated; // Hand-shake succeeded
+ }
+ }
+ }
+ }
+ catch
+ {
+ // Ignore exceptions
+ }
+
+ lock (_syncLock)
+ {
+ _hosts[host] = supported;
+ }
+ });
+ }
+
+ public static bool IsSupported(string host)
+ {
+ lock (_syncLock)
+ {
+ if (_hosts.TryGetValue(host, out var supported))
+ return supported;
+
+ return false;
+ }
+ }
+
+ private static Lock _syncLock = new();
+ private static Dictionary _hosts = new();
+ }
+}
diff --git a/src/Models/HistoryFilterCollection.cs b/src/Models/HistoryFilterCollection.cs
new file mode 100644
index 000000000..e2aeb56b1
--- /dev/null
+++ b/src/Models/HistoryFilterCollection.cs
@@ -0,0 +1,258 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Avalonia.Collections;
+using CommunityToolkit.Mvvm.ComponentModel;
+
+namespace SourceGit.Models
+{
+ public enum FilterType
+ {
+ LocalBranch = 0,
+ LocalBranchFolder,
+ RemoteBranch,
+ RemoteBranchFolder,
+ Tag,
+ }
+
+ public enum FilterMode
+ {
+ None = 0,
+ Included,
+ Excluded,
+ }
+
+ public class HistoryFilter : ObservableObject
+ {
+ public string Pattern
+ {
+ get => _pattern;
+ set => SetProperty(ref _pattern, value);
+ }
+
+ public FilterType Type
+ {
+ get;
+ set;
+ } = FilterType.LocalBranch;
+
+ public FilterMode Mode
+ {
+ get => _mode;
+ set => SetProperty(ref _mode, value);
+ }
+
+ public bool IsBranch
+ {
+ get => Type != FilterType.Tag;
+ }
+
+ public HistoryFilter()
+ {
+ }
+
+ public HistoryFilter(string pattern, FilterType type, FilterMode mode)
+ {
+ _pattern = pattern;
+ _mode = mode;
+ Type = type;
+ }
+
+ private string _pattern = string.Empty;
+ private FilterMode _mode = FilterMode.None;
+ }
+
+ public class HistoryFilterCollection
+ {
+ public AvaloniaList Filters
+ {
+ get;
+ set;
+ } = [];
+
+ public FilterMode Mode => Filters.Count > 0 ? Filters[0].Mode : FilterMode.None;
+
+ public Dictionary ToMap()
+ {
+ var map = new Dictionary();
+ foreach (var filter in Filters)
+ map.Add(filter.Pattern, filter.Mode);
+ return map;
+ }
+
+ public bool Update(string pattern, FilterType type, FilterMode mode)
+ {
+ // Clear all filters when there's a filter that has different mode.
+ if (mode != FilterMode.None)
+ {
+ var clear = false;
+ foreach (var filter in Filters)
+ {
+ if (filter.Mode != mode)
+ {
+ clear = true;
+ break;
+ }
+ }
+
+ if (clear)
+ {
+ Filters.Clear();
+ Filters.Add(new HistoryFilter(pattern, type, mode));
+ return true;
+ }
+ }
+ else
+ {
+ for (int i = 0; i < Filters.Count; i++)
+ {
+ var filter = Filters[i];
+ if (filter.Type == type && filter.Pattern.Equals(pattern, StringComparison.Ordinal))
+ {
+ Filters.RemoveAt(i);
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ foreach (var filter in Filters)
+ {
+ if (filter.Type != type)
+ continue;
+
+ if (filter.Pattern.Equals(pattern, StringComparison.Ordinal))
+ return false;
+ }
+
+ Filters.Add(new HistoryFilter(pattern, type, mode));
+ return true;
+ }
+
+ public FilterMode GetFilterMode(string pattern)
+ {
+ foreach (var filter in Filters)
+ {
+ if (filter.Pattern.Equals(pattern, StringComparison.Ordinal))
+ return filter.Mode;
+ }
+
+ return FilterMode.None;
+ }
+
+ public void RemoveFilter(string pattern, FilterType type)
+ {
+ foreach (var filter in Filters)
+ {
+ if (filter.Type == type && filter.Pattern.Equals(pattern, StringComparison.Ordinal))
+ {
+ Filters.Remove(filter);
+ break;
+ }
+ }
+ }
+
+ public void RemoveBranchFiltersByPrefix(string pattern)
+ {
+ var dirty = new List();
+ var prefix = $"{pattern}/";
+
+ foreach (var filter in Filters)
+ {
+ if (filter.Type != FilterType.Tag)
+ continue;
+
+ if (filter.Pattern.StartsWith(prefix, StringComparison.Ordinal))
+ dirty.Add(filter);
+ }
+
+ foreach (var filter in dirty)
+ Filters.Remove(filter);
+ }
+
+ public string Build()
+ {
+ var includedRefs = new List();
+ var excludedBranches = new List();
+ var excludedRemotes = new List();
+ var excludedTags = new List();
+ foreach (var filter in Filters)
+ {
+ if (filter.Type == FilterType.LocalBranch)
+ {
+ if (filter.Mode == FilterMode.Included)
+ includedRefs.Add(filter.Pattern);
+ else if (filter.Mode == FilterMode.Excluded)
+ excludedBranches.Add($"--exclude=\"{filter.Pattern.AsSpan(11)}\" --decorate-refs-exclude=\"{filter.Pattern}\"");
+ }
+ else if (filter.Type == FilterType.LocalBranchFolder)
+ {
+ if (filter.Mode == FilterMode.Included)
+ includedRefs.Add($"--branches={filter.Pattern.AsSpan(11)}/*");
+ else if (filter.Mode == FilterMode.Excluded)
+ excludedBranches.Add($"--exclude=\"{filter.Pattern.AsSpan(11)}/*\" --decorate-refs-exclude=\"{filter.Pattern}/*\"");
+ }
+ else if (filter.Type == FilterType.RemoteBranch)
+ {
+ if (filter.Mode == FilterMode.Included)
+ includedRefs.Add(filter.Pattern);
+ else if (filter.Mode == FilterMode.Excluded)
+ excludedRemotes.Add($"--exclude=\"{filter.Pattern.AsSpan(13)}\" --decorate-refs-exclude=\"{filter.Pattern}\"");
+ }
+ else if (filter.Type == FilterType.RemoteBranchFolder)
+ {
+ if (filter.Mode == FilterMode.Included)
+ includedRefs.Add($"--remotes={filter.Pattern.AsSpan(13)}/*");
+ else if (filter.Mode == FilterMode.Excluded)
+ excludedRemotes.Add($"--exclude=\"{filter.Pattern.AsSpan(13)}/*\" --decorate-refs-exclude=\"{filter.Pattern}/*\"");
+ }
+ else if (filter.Type == FilterType.Tag)
+ {
+ if (filter.Mode == FilterMode.Included)
+ includedRefs.Add($"refs/tags/{filter.Pattern}");
+ else if (filter.Mode == FilterMode.Excluded)
+ excludedTags.Add($"--exclude=\"{filter.Pattern}\" --decorate-refs-exclude=\"refs/tags/{filter.Pattern}\"");
+ }
+ }
+
+ var builder = new StringBuilder();
+ if (includedRefs.Count > 0)
+ {
+ 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(b);
+ builder.Append(' ');
+ }
+
+ builder.Append("--exclude=HEAD --branches ");
+
+ foreach (var r in excludedRemotes)
+ {
+ builder.Append(r);
+ builder.Append(' ');
+ }
+
+ builder.Append("--exclude=origin/HEAD --remotes ");
+
+ foreach (var t in excludedTags)
+ {
+ builder.Append(t);
+ builder.Append(' ');
+ }
+
+ builder.Append("--tags ");
+ }
+
+ return builder.ToString();
+ }
+ }
+}
diff --git a/src/Models/ICommandLog.cs b/src/Models/ICommandLog.cs
index 34ec70316..28e1fcb39 100644
--- a/src/Models/ICommandLog.cs
+++ b/src/Models/ICommandLog.cs
@@ -1,5 +1,10 @@
namespace SourceGit.Models
{
+ public interface ICommandLogReceiver
+ {
+ void OnReceiveCommandLog(string line);
+ }
+
public interface ICommandLog
{
void AppendLine(string line);
diff --git a/src/Models/InteractiveRebase.cs b/src/Models/InteractiveRebase.cs
index d1710d4a9..bae99ac52 100644
--- a/src/Models/InteractiveRebase.cs
+++ b/src/Models/InteractiveRebase.cs
@@ -12,6 +12,15 @@ public enum InteractiveRebaseAction
Drop,
}
+ public enum InteractiveRebasePendingType
+ {
+ None = 0,
+ Target,
+ Pending,
+ Ignore,
+ Last,
+ }
+
public class InteractiveCommit
{
public Commit Commit { get; set; } = new Commit();
diff --git a/src/Models/IpcChannel.cs b/src/Models/IpcChannel.cs
index 001c65a65..702f0630b 100644
--- a/src/Models/IpcChannel.cs
+++ b/src/Models/IpcChannel.cs
@@ -80,7 +80,7 @@ private async void StartServer()
if (!_cancellationTokenSource.IsCancellationRequested)
{
var line = await reader.ReadToEndAsync(_cancellationTokenSource.Token);
- MessageReceived?.Invoke(line?.Trim());
+ MessageReceived?.Invoke(line.Trim());
}
_server.Disconnect();
diff --git a/src/Models/IssueTrackerRule.cs b/src/Models/IssueTracker.cs
similarity index 95%
rename from src/Models/IssueTrackerRule.cs
rename to src/Models/IssueTracker.cs
index 7adaa1763..b424707f6 100644
--- a/src/Models/IssueTrackerRule.cs
+++ b/src/Models/IssueTracker.cs
@@ -1,10 +1,9 @@
using System.Text.RegularExpressions;
-
using CommunityToolkit.Mvvm.ComponentModel;
namespace SourceGit.Models
{
- public class IssueTrackerRule : ObservableObject
+ public class IssueTracker : ObservableObject
{
public bool IsShared
{
@@ -27,12 +26,11 @@ public string RegexString
{
try
{
- _regex = null;
_regex = new Regex(_regexString, RegexOptions.Multiline);
}
catch
{
- // Ignore errors.
+ _regex = null;
}
}
diff --git a/src/Models/LFSLock.cs b/src/Models/LFSLock.cs
index 0a328cfb2..8d9a4acff 100644
--- a/src/Models/LFSLock.cs
+++ b/src/Models/LFSLock.cs
@@ -1,9 +1,22 @@
-namespace SourceGit.Models
+using System.Text.Json.Serialization;
+
+namespace SourceGit.Models
{
+ public class LFSLockOwner
+ {
+ [JsonPropertyName("name")]
+ public string Name { get; set; } = string.Empty;
+ }
+
public class LFSLock
{
- public string File { get; set; } = string.Empty;
- public string User { get; set; } = string.Empty;
- public long ID { get; set; } = 0;
+ [JsonPropertyName("id")]
+ public string ID { get; set; } = string.Empty;
+
+ [JsonPropertyName("path")]
+ public string Path { get; set; } = string.Empty;
+
+ [JsonPropertyName("owner")]
+ public LFSLockOwner Owner { get; set; } = null;
}
}
diff --git a/src/Models/Locales.cs b/src/Models/Locales.cs
index 1788a9b22..027433336 100644
--- a/src/Models/Locales.cs
+++ b/src/Models/Locales.cs
@@ -1,4 +1,4 @@
-using System.Collections.Generic;
+using System.Collections.Generic;
namespace SourceGit.Models
{
@@ -12,6 +12,7 @@ public class Locale
new Locale("English", "en_US"),
new Locale("Español", "es_ES"),
new Locale("Français", "fr_FR"),
+ new Locale("Bahasa Indonesia", "id_ID"),
new Locale("Italiano", "it_IT"),
new Locale("Português (Brasil)", "pt_BR"),
new Locale("Українська", "uk_UA"),
@@ -20,6 +21,7 @@ public class Locale
new Locale("繁體中文", "zh_TW"),
new Locale("日本語", "ja_JP"),
new Locale("தமிழ் (Tamil)", "ta_IN"),
+ new Locale("한국어", "ko_KR"),
};
public Locale(string name, string key)
diff --git a/src/Models/NumericSort.cs b/src/Models/NumericSort.cs
index baaf3da4f..433a921bd 100644
--- a/src/Models/NumericSort.cs
+++ b/src/Models/NumericSort.cs
@@ -6,6 +6,8 @@ public static class NumericSort
{
public static int Compare(string s1, string s2)
{
+ var comparer = StringComparer.InvariantCultureIgnoreCase;
+
int len1 = s1.Length;
int len2 = s2.Length;
@@ -20,7 +22,7 @@ public static int Compare(string s1, string s2)
bool isDigit1 = char.IsDigit(c1);
bool isDigit2 = char.IsDigit(c2);
if (isDigit1 != isDigit2)
- return c1.CompareTo(c2);
+ return comparer.Compare(c1.ToString(), c2.ToString());
int subLen1 = 1;
while (marker1 + subLen1 < len1 && char.IsDigit(s1[marker1 + subLen1]) == isDigit1)
@@ -40,7 +42,7 @@ public static int Compare(string s1, string s2)
if (isDigit1)
result = (subLen1 == subLen2) ? string.CompareOrdinal(sub1, sub2) : (subLen1 - subLen2);
else
- result = string.Compare(sub1, sub2, StringComparison.OrdinalIgnoreCase);
+ result = comparer.Compare(sub1, sub2);
if (result != 0)
return result;
diff --git a/src/Models/OpenAI.cs b/src/Models/OpenAI.cs
index f8d76328d..c38eb674e 100644
--- a/src/Models/OpenAI.cs
+++ b/src/Models/OpenAI.cs
@@ -117,6 +117,12 @@ public string ApiKey
set => SetProperty(ref _apiKey, value);
}
+ public bool ReadApiKeyFromEnv
+ {
+ get => _readApiKeyFromEnv;
+ set => SetProperty(ref _readApiKeyFromEnv, value);
+ }
+
public string Model
{
get => _model;
@@ -176,15 +182,19 @@ Your only goal is to retrieve a single commit message.
public async Task ChatAsync(string prompt, string question, CancellationToken cancellation, Action onUpdate)
{
- var server = new Uri(_server);
- var key = new ApiKeyCredential(_apiKey);
- var oaiClient = _server.Contains("openai.azure.com/", StringComparison.Ordinal)
- ? new AzureOpenAIClient(server, key)
- : new OpenAIClient(key, new() { Endpoint = server });
- var client = oaiClient.GetChatClient(_model);
- var messages = new List();
- messages.Add(_model.Equals("o1-mini", StringComparison.Ordinal) ? new UserChatMessage(prompt) : new SystemChatMessage(prompt));
- messages.Add(new UserChatMessage(question));
+ var key = _readApiKeyFromEnv ? Environment.GetEnvironmentVariable(_apiKey) : _apiKey;
+ var endPoint = new Uri(_server);
+ var credential = new ApiKeyCredential(key);
+ var client = _server.Contains("openai.azure.com/", StringComparison.Ordinal)
+ ? new AzureOpenAIClient(endPoint, credential)
+ : new OpenAIClient(credential, new() { Endpoint = endPoint });
+
+ var chatClient = client.GetChatClient(_model);
+ var messages = new List()
+ {
+ _model.Equals("o1-mini", StringComparison.Ordinal) ? new UserChatMessage(prompt) : new SystemChatMessage(prompt),
+ new UserChatMessage(question),
+ };
try
{
@@ -192,7 +202,7 @@ public async Task ChatAsync(string prompt, string question, CancellationToken ca
if (_streaming)
{
- var updates = client.CompleteChatStreamingAsync(messages, null, cancellation);
+ var updates = chatClient.CompleteChatStreamingAsync(messages, null, cancellation);
await foreach (var update in updates)
{
@@ -202,7 +212,7 @@ public async Task ChatAsync(string prompt, string question, CancellationToken ca
}
else
{
- var completion = await client.CompleteChatAsync(messages, null, cancellation);
+ var completion = await chatClient.CompleteChatAsync(messages, null, cancellation);
if (completion.Value.Content.Count > 0)
rsp.Append(completion.Value.Content[0].Text);
@@ -220,6 +230,7 @@ public async Task ChatAsync(string prompt, string question, CancellationToken ca
private string _name;
private string _server;
private string _apiKey;
+ private bool _readApiKeyFromEnv = false;
private string _model;
private bool _streaming = true;
private string _analyzeDiffPrompt;
diff --git a/src/Models/Remote.cs b/src/Models/Remote.cs
index 6e36cfb9e..d1fa2cb4d 100644
--- a/src/Models/Remote.cs
+++ b/src/Models/Remote.cs
@@ -1,6 +1,7 @@
using System;
using System.IO;
using System.Text.RegularExpressions;
+using System.Web;
namespace SourceGit.Models
{
@@ -8,14 +9,17 @@ public partial class Remote
{
[GeneratedRegex(@"^https?://[^/]+/.+[^/\.]$")]
private static partial Regex REG_HTTPS();
+
[GeneratedRegex(@"^git://[^/]+/.+[^/\.]$")]
private static partial Regex REG_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]+)?/([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 = [
@@ -62,7 +66,6 @@ public bool TryGetVisitURL(out string url)
if (URL.StartsWith("http", StringComparison.Ordinal))
{
- // Try to remove the user before host and `.git` extension.
var uri = new Uri(URL.EndsWith(".git", StringComparison.Ordinal) ? URL.Substring(0, URL.Length - 4) : URL);
if (uri.Port != 80 && uri.Port != 443)
url = $"{uri.Scheme}://{uri.Host}:{uri.Port}{uri.LocalPath}";
@@ -75,7 +78,61 @@ public bool TryGetVisitURL(out string url)
var match = REG_TO_VISIT_URL_CAPTURE().Match(URL);
if (match.Success)
{
- url = $"https://{match.Groups[1].Value}/{match.Groups[2].Value}";
+ var host = match.Groups[1].Value;
+ var supportHTTPS = HTTPSValidator.IsSupported(host);
+ var scheme = supportHTTPS ? "https" : "http";
+ url = $"{scheme}://{host}/{match.Groups[2].Value}";
+ return true;
+ }
+
+ return false;
+ }
+
+ public bool TryGetCreatePullRequestURL(out string url, string mergeBranch)
+ {
+ url = null;
+
+ if (!TryGetVisitURL(out var baseURL))
+ return false;
+
+ var uri = new Uri(baseURL);
+ var host = uri.Host;
+ var route = uri.AbsolutePath.TrimStart('/');
+ var encodedBranch = HttpUtility.UrlEncode(mergeBranch);
+
+ if (host.Contains("github.com", StringComparison.Ordinal))
+ {
+ url = $"{baseURL}/compare/{encodedBranch}?expand=1";
+ return true;
+ }
+
+ if (host.Contains("gitlab", StringComparison.Ordinal))
+ {
+ url = $"{baseURL}/-/merge_requests/new?merge_request%5Bsource_branch%5D={encodedBranch}";
+ return true;
+ }
+
+ if (host.Equals("gitee.com", StringComparison.Ordinal))
+ {
+ url = $"{baseURL}/pulls/new?source={encodedBranch}";
+ return true;
+ }
+
+ if (host.Equals("bitbucket.org", StringComparison.Ordinal))
+ {
+ url = $"{baseURL}/pull-requests/new?source={encodedBranch}";
+ return true;
+ }
+
+ if (host.Equals("gitea.org", StringComparison.Ordinal))
+ {
+ url = $"{baseURL}/compare/{encodedBranch}";
+ return true;
+ }
+
+ if (host.Contains("azure.com", StringComparison.Ordinal))
+ {
+ url = $"{baseURL}/pullrequestcreate?sourceRef={encodedBranch}";
return true;
}
diff --git a/src/Models/RepositorySettings.cs b/src/Models/RepositorySettings.cs
index f287826c5..ddee7fe03 100644
--- a/src/Models/RepositorySettings.cs
+++ b/src/Models/RepositorySettings.cs
@@ -1,7 +1,4 @@
-using System;
using System.Collections.Generic;
-using System.Text;
-
using Avalonia.Collections;
namespace SourceGit.Models
@@ -62,6 +59,12 @@ public bool EnableForceOnFetch
set;
} = false;
+ public bool FetchAllRemotes
+ {
+ get;
+ set;
+ } = false;
+
public bool FetchWithoutTags
{
get;
@@ -104,18 +107,6 @@ public bool CheckoutBranchOnCreateBranch
set;
} = true;
- public bool UpdateSubmodulesOnCheckoutBranch
- {
- get;
- set;
- } = true;
-
- public AvaloniaList HistoriesFilters
- {
- get;
- set;
- } = [];
-
public AvaloniaList CommitTemplates
{
get;
@@ -128,12 +119,6 @@ public AvaloniaList CommitMessages
set;
} = [];
- public AvaloniaList IssueTrackerRules
- {
- get;
- set;
- } = [];
-
public AvaloniaList CustomActions
{
get;
@@ -158,6 +143,12 @@ public bool EnableSignOffForCommit
set;
} = false;
+ public bool NoVerifyOnCommit
+ {
+ get;
+ set;
+ } = false;
+
public bool IncludeUntrackedWhenStash
{
get;
@@ -230,165 +221,11 @@ public string LastCommitMessage
set;
} = string.Empty;
- public Dictionary CollectHistoriesFilters()
- {
- var map = new Dictionary();
- foreach (var filter in HistoriesFilters)
- map.Add(filter.Pattern, filter.Mode);
- return map;
- }
-
- public bool UpdateHistoriesFilter(string pattern, FilterType type, FilterMode mode)
- {
- // Clear all filters when there's a filter that has different mode.
- if (mode != FilterMode.None)
- {
- var clear = false;
- foreach (var filter in HistoriesFilters)
- {
- if (filter.Mode != mode)
- {
- clear = true;
- break;
- }
- }
-
- if (clear)
- {
- HistoriesFilters.Clear();
- HistoriesFilters.Add(new Filter(pattern, type, mode));
- return true;
- }
- }
- else
- {
- for (int i = 0; i < HistoriesFilters.Count; i++)
- {
- var filter = HistoriesFilters[i];
- if (filter.Type == type && filter.Pattern.Equals(pattern, StringComparison.Ordinal))
- {
- HistoriesFilters.RemoveAt(i);
- return true;
- }
- }
-
- return false;
- }
-
- foreach (var filter in HistoriesFilters)
- {
- if (filter.Type != type)
- continue;
-
- if (filter.Pattern.Equals(pattern, StringComparison.Ordinal))
- return false;
- }
-
- HistoriesFilters.Add(new Filter(pattern, type, mode));
- return true;
- }
-
- public void RemoveChildrenBranchFilters(string pattern)
+ public string ConventionalTypesOverride
{
- var dirty = new List();
- var prefix = $"{pattern}/";
-
- foreach (var filter in HistoriesFilters)
- {
- if (filter.Type == FilterType.Tag)
- continue;
-
- if (filter.Pattern.StartsWith(prefix, StringComparison.Ordinal))
- dirty.Add(filter);
- }
-
- foreach (var filter in dirty)
- HistoriesFilters.Remove(filter);
- }
-
- public string BuildHistoriesFilter()
- {
- var includedRefs = new List();
- var excludedBranches = new List();
- var excludedRemotes = new List();
- var excludedTags = new List();
- foreach (var filter in HistoriesFilters)
- {
- if (filter.Type == FilterType.LocalBranch)
- {
- if (filter.Mode == FilterMode.Included)
- includedRefs.Add(filter.Pattern);
- else if (filter.Mode == FilterMode.Excluded)
- excludedBranches.Add($"--exclude=\"{filter.Pattern.AsSpan(11)}\" --decorate-refs-exclude=\"{filter.Pattern}\"");
- }
- else if (filter.Type == FilterType.LocalBranchFolder)
- {
- if (filter.Mode == FilterMode.Included)
- includedRefs.Add($"--branches={filter.Pattern.AsSpan(11)}/*");
- else if (filter.Mode == FilterMode.Excluded)
- excludedBranches.Add($"--exclude=\"{filter.Pattern.AsSpan(11)}/*\" --decorate-refs-exclude=\"{filter.Pattern}/*\"");
- }
- else if (filter.Type == FilterType.RemoteBranch)
- {
- if (filter.Mode == FilterMode.Included)
- includedRefs.Add(filter.Pattern);
- else if (filter.Mode == FilterMode.Excluded)
- excludedRemotes.Add($"--exclude=\"{filter.Pattern.AsSpan(13)}\" --decorate-refs-exclude=\"{filter.Pattern}\"");
- }
- else if (filter.Type == FilterType.RemoteBranchFolder)
- {
- if (filter.Mode == FilterMode.Included)
- includedRefs.Add($"--remotes={filter.Pattern.AsSpan(13)}/*");
- else if (filter.Mode == FilterMode.Excluded)
- excludedRemotes.Add($"--exclude=\"{filter.Pattern.AsSpan(13)}/*\" --decorate-refs-exclude=\"{filter.Pattern}/*\"");
- }
- else if (filter.Type == FilterType.Tag)
- {
- if (filter.Mode == FilterMode.Included)
- includedRefs.Add($"refs/tags/{filter.Pattern}");
- else if (filter.Mode == FilterMode.Excluded)
- excludedTags.Add($"--exclude=\"{filter.Pattern}\" --decorate-refs-exclude=\"refs/tags/{filter.Pattern}\"");
- }
- }
-
- var builder = new StringBuilder();
- if (includedRefs.Count > 0)
- {
- 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(b);
- builder.Append(' ');
- }
-
- builder.Append("--exclude=HEAD --branches ");
-
- foreach (var r in excludedRemotes)
- {
- builder.Append(r);
- builder.Append(' ');
- }
-
- builder.Append("--exclude=origin/HEAD --remotes ");
-
- foreach (var t in excludedTags)
- {
- builder.Append(t);
- builder.Append(' ');
- }
-
- builder.Append("--tags ");
- }
-
- return builder.ToString();
- }
+ get;
+ set;
+ } = string.Empty;
public void PushCommitMessage(string message)
{
@@ -409,25 +246,6 @@ public void PushCommitMessage(string message)
CommitMessages.Insert(0, message);
}
- public IssueTrackerRule AddIssueTracker(string name, string regex, string url)
- {
- var rule = new IssueTrackerRule()
- {
- Name = name,
- RegexString = regex,
- URLTemplate = url,
- };
-
- IssueTrackerRules.Add(rule);
- return rule;
- }
-
- public void RemoveIssueTracker(IssueTrackerRule rule)
- {
- if (rule != null)
- IssueTrackerRules.Remove(rule);
- }
-
public CustomAction AddNewCustomAction()
{
var act = new CustomAction() { Name = "Unnamed Action" };
diff --git a/src/Models/RepositoryStatus.cs b/src/Models/RepositoryStatus.cs
new file mode 100644
index 000000000..c7c498ae5
--- /dev/null
+++ b/src/Models/RepositoryStatus.cs
@@ -0,0 +1,29 @@
+namespace SourceGit.Models
+{
+ public class RepositoryStatus
+ {
+ public string CurrentBranch { get; set; } = string.Empty;
+ public int Ahead { get; set; } = 0;
+ public int Behind { get; set; } = 0;
+ public int LocalChanges { get; set; } = 0;
+
+ public bool IsTrackingStatusVisible
+ {
+ get
+ {
+ return Ahead > 0 || Behind > 0;
+ }
+ }
+
+ public string TrackingDescription
+ {
+ get
+ {
+ if (Ahead > 0)
+ return Behind > 0 ? $"{Ahead}↑ {Behind}↓" : $"{Ahead}↑";
+
+ return Behind > 0 ? $"{Behind}↓" : string.Empty;
+ }
+ }
+ }
+}
diff --git a/src/Models/ShellOrTerminal.cs b/src/Models/ShellOrTerminal.cs
index 7dfb22373..84c9ae066 100644
--- a/src/Models/ShellOrTerminal.cs
+++ b/src/Models/ShellOrTerminal.cs
@@ -11,6 +11,7 @@ public class ShellOrTerminal
public string Type { get; set; }
public string Name { get; set; }
public string Exec { get; set; }
+ public string Args { get; set; }
public Bitmap Icon
{
@@ -32,18 +33,18 @@ static ShellOrTerminal()
new ShellOrTerminal("git-bash", "Git Bash", "bash.exe"),
new ShellOrTerminal("pwsh", "PowerShell", "pwsh.exe|powershell.exe"),
new ShellOrTerminal("cmd", "Command Prompt", "cmd.exe"),
- new ShellOrTerminal("wt", "Windows Terminal", "wt.exe")
+ new ShellOrTerminal("wt", "Windows Terminal", "wt.exe", "-d .")
};
}
else if (OperatingSystem.IsMacOS())
{
Supported = new List()
{
- new ShellOrTerminal("mac-terminal", "Terminal", ""),
- new ShellOrTerminal("iterm2", "iTerm", ""),
- new ShellOrTerminal("warp", "Warp", ""),
- new ShellOrTerminal("ghostty", "Ghostty", ""),
- new ShellOrTerminal("kitty", "kitty", "")
+ new ShellOrTerminal("mac-terminal", "Terminal", "Terminal"),
+ new ShellOrTerminal("iterm2", "iTerm", "iTerm"),
+ new ShellOrTerminal("warp", "Warp", "Warp"),
+ new ShellOrTerminal("ghostty", "Ghostty", "Ghostty"),
+ new ShellOrTerminal("kitty", "kitty", "kitty")
};
}
else
@@ -57,19 +58,20 @@ static ShellOrTerminal()
new ShellOrTerminal("deepin-terminal", "Deepin Terminal", "deepin-terminal"),
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("wezterm", "WezTerm", "wezterm", "start --cwd ."),
+ new ShellOrTerminal("ptyxis", "Ptyxis", "ptyxis", "--new-window --working-directory=."),
new ShellOrTerminal("kitty", "kitty", "kitty"),
new ShellOrTerminal("custom", "Custom", ""),
};
}
}
- public ShellOrTerminal(string type, string name, string exec)
+ public ShellOrTerminal(string type, string name, string exec, string args = null)
{
Type = type;
Name = name;
Exec = exec;
+ Args = args;
}
}
}
diff --git a/src/Models/Tag.cs b/src/Models/Tag.cs
index 87944637a..9e1654575 100644
--- a/src/Models/Tag.cs
+++ b/src/Models/Tag.cs
@@ -1,4 +1,4 @@
-using CommunityToolkit.Mvvm.ComponentModel;
+using System;
namespace SourceGit.Models
{
@@ -8,20 +8,18 @@ public enum TagSortMode
Name,
}
- public class Tag : ObservableObject
+ public class Tag
{
public string Name { get; set; } = string.Empty;
public bool IsAnnotated { get; set; } = false;
public string SHA { get; set; } = string.Empty;
+ public User Creator { get; set; } = null;
public ulong CreatorDate { get; set; } = 0;
public string Message { get; set; } = string.Empty;
- public FilterMode FilterMode
+ public string CreatorDateStr
{
- get => _filterMode;
- set => SetProperty(ref _filterMode, value);
+ get => DateTime.UnixEpoch.AddSeconds(CreatorDate).ToLocalTime().ToString(DateTimeFormat.Active.DateTime);
}
-
- private FilterMode _filterMode = FilterMode.None;
}
}
diff --git a/src/Models/TemplateEngine.cs b/src/Models/TemplateEngine.cs
index 87822fb11..12280006e 100644
--- a/src/Models/TemplateEngine.cs
+++ b/src/Models/TemplateEngine.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.IO;
using System.Text;
using System.Text.RegularExpressions;
@@ -285,7 +286,7 @@ private string ParseReplacement()
switch (c)
{
case ESCAPE:
- // allow to escape only }
+ // allow to escape only right-brace
if (Peek() == VARIABLE_END)
{
esc = true;
@@ -349,14 +350,10 @@ private static string EvalVariable(Context context, RegexVariable variable)
private delegate string VariableGetter(Context context);
private static readonly IReadOnlyDictionary s_variables = new Dictionary() {
- // legacy variables
{"branch_name", GetBranchName},
{"files_num", GetFilesCount},
{"files", GetFiles},
- //
- {"BRANCH", GetBranchName},
- {"FILES_COUNT", GetFilesCount},
- {"FILES", GetFiles},
+ {"pure_files", GetPureFiles},
};
private static string GetBranchName(Context context)
@@ -377,13 +374,19 @@ private static string GetFiles(Context context)
return string.Join(", ", paths);
}
+ private static string GetPureFiles(Context context)
+ {
+ var names = new List();
+ foreach (var c in context.changes)
+ names.Add(Path.GetFileName(c.Path));
+ return string.Join(", ", names);
+ }
+
private delegate string VariableSliceGetter(Context context, int count);
private static readonly IReadOnlyDictionary s_slicedVariables = new Dictionary() {
- // legacy variables
{"files", GetFilesSliced},
- //
- {"FILES", GetFilesSliced},
+ {"pure_files", GetPureFilesSliced}
};
private static string GetFilesSliced(Context context, int count)
@@ -400,5 +403,20 @@ private static string GetFilesSliced(Context context, int count)
return sb.ToString();
}
+
+ private static string GetPureFilesSliced(Context context, int count)
+ {
+ var sb = new StringBuilder();
+ var names = new List();
+ var max = Math.Min(count, context.changes.Count);
+ for (int i = 0; i < max; i++)
+ names.Add(Path.GetFileName(context.changes[i].Path));
+
+ sb.AppendJoin(", ", names);
+ if (max < context.changes.Count)
+ sb.Append($" and {context.changes.Count - max} other files");
+
+ return sb.ToString();
+ }
}
}
diff --git a/src/Models/TextMateHelper.cs b/src/Models/TextMateHelper.cs
index e9903890b..38c0aaa72 100644
--- a/src/Models/TextMateHelper.cs
+++ b/src/Models/TextMateHelper.cs
@@ -26,6 +26,7 @@ public static class GrammarUtility
new ExtraGrammar("source.hx", [".hx"], "haxe.json"),
new ExtraGrammar("source.hxml", [".hxml"], "hxml.json"),
new ExtraGrammar("text.html.jsp", [".jsp", ".jspf", ".tag"], "jsp.json"),
+ new ExtraGrammar("source.vue", [".vue"], "vue.json"),
];
public static string GetScope(string file, RegistryOptions reg)
diff --git a/src/Models/User.cs b/src/Models/User.cs
index d3faedf0d..15a45762b 100644
--- a/src/Models/User.cs
+++ b/src/Models/User.cs
@@ -21,7 +21,7 @@ public User(string data)
parts = [string.Empty, data];
Name = parts[0];
- Email = parts[1];
+ Email = parts[1].TrimStart('<').TrimEnd('>');
_hash = data.GetHashCode();
}
diff --git a/src/Models/Watcher.cs b/src/Models/Watcher.cs
index 9ba7ee9cb..cdeddd65f 100644
--- a/src/Models/Watcher.cs
+++ b/src/Models/Watcher.cs
@@ -8,9 +8,27 @@ namespace SourceGit.Models
{
public class Watcher : IDisposable
{
+ public class LockContext : IDisposable
+ {
+ public LockContext(Watcher target)
+ {
+ _target = target;
+ Interlocked.Increment(ref _target._lockCount);
+ }
+
+ public void Dispose()
+ {
+ Interlocked.Decrement(ref _target._lockCount);
+ }
+
+ private Watcher _target;
+ }
+
public Watcher(IRepository repo, string fullpath, string gitDir)
{
_repo = repo;
+ _root = new DirectoryInfo(fullpath).FullName;
+ _watchers = new List();
var testGitDir = new DirectoryInfo(Path.Combine(fullpath, ".git")).FullName;
var desiredDir = new DirectoryInfo(gitDir).FullName;
@@ -25,7 +43,7 @@ public Watcher(IRepository repo, string fullpath, string gitDir)
combined.Renamed += OnRepositoryChanged;
combined.Changed += OnRepositoryChanged;
combined.Deleted += OnRepositoryChanged;
- combined.EnableRaisingEvents = true;
+ combined.EnableRaisingEvents = false;
_watchers.Add(combined);
}
@@ -40,7 +58,7 @@ public Watcher(IRepository repo, string fullpath, string gitDir)
wc.Renamed += OnWorkingCopyChanged;
wc.Changed += OnWorkingCopyChanged;
wc.Deleted += OnWorkingCopyChanged;
- wc.EnableRaisingEvents = true;
+ wc.EnableRaisingEvents = false;
var git = new FileSystemWatcher();
git.Path = gitDir;
@@ -51,51 +69,58 @@ public Watcher(IRepository repo, string fullpath, string gitDir)
git.Renamed += OnGitDirChanged;
git.Changed += OnGitDirChanged;
git.Deleted += OnGitDirChanged;
- git.EnableRaisingEvents = true;
+ git.EnableRaisingEvents = false;
_watchers.Add(wc);
_watchers.Add(git);
}
_timer = new Timer(Tick, null, 100, 100);
+
+ // Starts filesystem watchers in another thread to avoid UI blocking
+ Task.Run(() =>
+ {
+ try
+ {
+ foreach (var watcher in _watchers)
+ watcher.EnableRaisingEvents = true;
+ }
+ catch
+ {
+ // Ignore exceptions. This may occur while `Dispose` is called.
+ }
+ });
}
- public void SetEnabled(bool enabled)
+ public IDisposable Lock()
{
- if (enabled)
- {
- if (_lockCount > 0)
- _lockCount--;
- }
- else
- {
- _lockCount++;
- }
+ return new LockContext(this);
}
- public void SetSubmodules(List submodules)
+ public void MarkBranchUpdated()
{
- lock (_lockSubmodule)
- {
- _submodules.Clear();
- foreach (var submodule in submodules)
- _submodules.Add(submodule.Path);
- }
+ Interlocked.Exchange(ref _updateBranch, 0);
+ Interlocked.Exchange(ref _updateWC, 0);
+ }
+
+ public void MarkTagUpdated()
+ {
+ Interlocked.Exchange(ref _updateTags, 0);
}
- public void MarkBranchDirtyManually()
+ public void MarkWorkingCopyUpdated()
{
- _updateBranch = DateTime.Now.ToFileTime() - 1;
+ Interlocked.Exchange(ref _updateWC, 0);
}
- public void MarkTagDirtyManually()
+ public void MarkStashUpdated()
{
- _updateTags = DateTime.Now.ToFileTime() - 1;
+ Interlocked.Exchange(ref _updateStashes, 0);
}
- public void MarkWorkingCopyDirtyManually()
+ public void MarkSubmodulesUpdated()
{
- _updateWC = DateTime.Now.ToFileTime() - 1;
+ Interlocked.Exchange(ref _updateSubmodules, 0);
}
public void Dispose()
@@ -113,57 +138,91 @@ public void Dispose()
private void Tick(object sender)
{
- if (_lockCount > 0)
+ if (Interlocked.Read(ref _lockCount) > 0)
return;
var now = DateTime.Now.ToFileTime();
- if (_updateBranch > 0 && now > _updateBranch)
+ var refreshCommits = false;
+ var refreshSubmodules = false;
+ var refreshWC = false;
+
+ var oldUpdateBranch = Interlocked.Exchange(ref _updateBranch, -1);
+ if (oldUpdateBranch > 0)
{
- _updateBranch = 0;
- _updateWC = 0;
+ if (now > oldUpdateBranch)
+ {
+ refreshCommits = true;
+ refreshSubmodules = _repo.MayHaveSubmodules();
+ refreshWC = true;
- if (_updateTags > 0)
+ _repo.RefreshBranches();
+ _repo.RefreshWorktrees();
+ }
+ else
{
- _updateTags = 0;
- Task.Run(_repo.RefreshTags);
+ Interlocked.CompareExchange(ref _updateBranch, oldUpdateBranch, -1);
}
+ }
- if (_updateSubmodules > 0 || _repo.MayHaveSubmodules())
+ if (refreshWC)
+ {
+ Interlocked.Exchange(ref _updateWC, -1);
+ _repo.RefreshWorkingCopyChanges();
+ }
+ else
+ {
+ var oldUpdateWC = Interlocked.Exchange(ref _updateWC, -1);
+ if (oldUpdateWC > 0)
{
- _updateSubmodules = 0;
- Task.Run(_repo.RefreshSubmodules);
+ if (now > oldUpdateWC)
+ _repo.RefreshWorkingCopyChanges();
+ else
+ Interlocked.CompareExchange(ref _updateWC, oldUpdateWC, -1);
}
-
- Task.Run(_repo.RefreshBranches);
- Task.Run(_repo.RefreshCommits);
- Task.Run(_repo.RefreshWorkingCopyChanges);
- Task.Run(_repo.RefreshWorktrees);
}
- if (_updateWC > 0 && now > _updateWC)
+ if (refreshSubmodules)
{
- _updateWC = 0;
- Task.Run(_repo.RefreshWorkingCopyChanges);
+ Interlocked.Exchange(ref _updateSubmodules, -1);
+ _repo.RefreshSubmodules();
}
-
- if (_updateSubmodules > 0 && now > _updateSubmodules)
+ else
{
- _updateSubmodules = 0;
- Task.Run(_repo.RefreshSubmodules);
+ var oldUpdateSubmodule = Interlocked.Exchange(ref _updateSubmodules, -1);
+ if (oldUpdateSubmodule > 0)
+ {
+ if (now > oldUpdateSubmodule)
+ _repo.RefreshSubmodules();
+ else
+ Interlocked.CompareExchange(ref _updateSubmodules, oldUpdateSubmodule, -1);
+ }
}
- if (_updateStashes > 0 && now > _updateStashes)
+ var oldUpdateStashes = Interlocked.Exchange(ref _updateStashes, -1);
+ if (oldUpdateStashes > 0)
{
- _updateStashes = 0;
- Task.Run(_repo.RefreshStashes);
+ if (now > oldUpdateStashes)
+ _repo.RefreshStashes();
+ else
+ Interlocked.CompareExchange(ref _updateStashes, oldUpdateStashes, -1);
}
- if (_updateTags > 0 && now > _updateTags)
+ var oldUpdateTags = Interlocked.Exchange(ref _updateTags, -1);
+ if (oldUpdateTags > 0)
{
- _updateTags = 0;
- Task.Run(_repo.RefreshTags);
- Task.Run(_repo.RefreshCommits);
+ if (now > oldUpdateTags)
+ {
+ refreshCommits = true;
+ _repo.RefreshTags();
+ }
+ else
+ {
+ Interlocked.CompareExchange(ref _updateTags, oldUpdateTags, -1);
+ }
}
+
+ if (refreshCommits)
+ _repo.RefreshCommits();
}
private void OnRepositoryChanged(object o, FileSystemEventArgs e)
@@ -178,7 +237,7 @@ private void OnRepositoryChanged(object o, FileSystemEventArgs e)
if (name.StartsWith(".git/", StringComparison.Ordinal))
HandleGitDirFileChanged(name.Substring(5));
else
- HandleWorkingCopyFileChanged(name);
+ HandleWorkingCopyFileChanged(name, e.FullPath);
}
private void OnGitDirChanged(object o, FileSystemEventArgs e)
@@ -201,7 +260,7 @@ private void OnWorkingCopyChanged(object o, FileSystemEventArgs e)
name.EndsWith("/.git", StringComparison.Ordinal))
return;
- HandleWorkingCopyFileChanged(name);
+ HandleWorkingCopyFileChanged(name, e.FullPath);
}
private void HandleGitDirFileChanged(string name)
@@ -216,23 +275,24 @@ private void HandleGitDirFileChanged(string name)
if (name.EndsWith("/HEAD", StringComparison.Ordinal) ||
name.EndsWith("/ORIG_HEAD", StringComparison.Ordinal))
{
- _updateSubmodules = DateTime.Now.AddSeconds(1).ToFileTime();
- _updateWC = DateTime.Now.AddSeconds(1).ToFileTime();
+ var desired = DateTime.Now.AddSeconds(1).ToFileTime();
+ Interlocked.Exchange(ref _updateSubmodules, desired);
+ Interlocked.Exchange(ref _updateWC, desired);
}
}
else if (name.Equals("MERGE_HEAD", StringComparison.Ordinal) ||
name.Equals("AUTO_MERGE", StringComparison.Ordinal))
{
if (_repo.MayHaveSubmodules())
- _updateSubmodules = DateTime.Now.AddSeconds(1).ToFileTime();
+ Interlocked.Exchange(ref _updateSubmodules, DateTime.Now.AddSeconds(1).ToFileTime());
}
else if (name.StartsWith("refs/tags", StringComparison.Ordinal))
{
- _updateTags = DateTime.Now.AddSeconds(.5).ToFileTime();
+ Interlocked.Exchange(ref _updateTags, DateTime.Now.AddSeconds(.5).ToFileTime());
}
else if (name.StartsWith("refs/stash", StringComparison.Ordinal))
{
- _updateStashes = DateTime.Now.AddSeconds(.5).ToFileTime();
+ Interlocked.Exchange(ref _updateStashes, DateTime.Now.AddSeconds(.5).ToFileTime());
}
else if (name.Equals("HEAD", StringComparison.Ordinal) ||
name.Equals("BISECT_START", StringComparison.Ordinal) ||
@@ -240,52 +300,58 @@ private void HandleGitDirFileChanged(string name)
name.StartsWith("refs/remotes/", StringComparison.Ordinal) ||
(name.StartsWith("worktrees/", StringComparison.Ordinal) && name.EndsWith("/HEAD", StringComparison.Ordinal)))
{
- _updateBranch = DateTime.Now.AddSeconds(.5).ToFileTime();
+ Interlocked.Exchange(ref _updateBranch, DateTime.Now.AddSeconds(.5).ToFileTime());
}
else if (name.StartsWith("objects/", StringComparison.Ordinal) || name.Equals("index", StringComparison.Ordinal))
{
- _updateWC = DateTime.Now.AddSeconds(1).ToFileTime();
+ Interlocked.Exchange(ref _updateWC, DateTime.Now.AddSeconds(1).ToFileTime());
}
}
- private void HandleWorkingCopyFileChanged(string name)
+ private void HandleWorkingCopyFileChanged(string name, string fullpath)
{
if (name.StartsWith(".vs/", StringComparison.Ordinal))
return;
if (name.Equals(".gitmodules", StringComparison.Ordinal))
{
- _updateSubmodules = DateTime.Now.AddSeconds(1).ToFileTime();
- _updateWC = DateTime.Now.AddSeconds(1).ToFileTime();
+ var desired = DateTime.Now.AddSeconds(1).ToFileTime();
+ Interlocked.Exchange(ref _updateSubmodules, desired);
+ Interlocked.Exchange(ref _updateWC, desired);
return;
}
- lock (_lockSubmodule)
+ var dir = Directory.Exists(fullpath) ? fullpath : Path.GetDirectoryName(fullpath);
+ if (IsInSubmodule(dir))
{
- foreach (var submodule in _submodules)
- {
- if (name.StartsWith(submodule, StringComparison.Ordinal))
- {
- _updateSubmodules = DateTime.Now.AddSeconds(1).ToFileTime();
- return;
- }
- }
+ Interlocked.Exchange(ref _updateSubmodules, DateTime.Now.AddSeconds(1).ToFileTime());
+ return;
}
- _updateWC = DateTime.Now.AddSeconds(1).ToFileTime();
+ Interlocked.Exchange(ref _updateWC, DateTime.Now.AddSeconds(1).ToFileTime());
+ }
+
+ private bool IsInSubmodule(string folder)
+ {
+ if (string.IsNullOrEmpty(folder) || folder.Equals(_root, StringComparison.Ordinal))
+ return false;
+
+ if (File.Exists($"{folder}/.git"))
+ return true;
+
+ return IsInSubmodule(Path.GetDirectoryName(folder));
}
- private readonly IRepository _repo = null;
- private List _watchers = [];
- private Timer _timer = null;
- private int _lockCount = 0;
- private long _updateWC = 0;
- private long _updateBranch = 0;
- private long _updateSubmodules = 0;
- private long _updateStashes = 0;
- private long _updateTags = 0;
-
- private readonly Lock _lockSubmodule = new();
- private List _submodules = new List();
+ private readonly IRepository _repo;
+ private readonly string _root;
+ private List _watchers;
+ private Timer _timer;
+
+ private long _lockCount;
+ private long _updateWC;
+ private long _updateBranch;
+ private long _updateSubmodules;
+ private long _updateStashes;
+ private long _updateTags;
}
}
diff --git a/src/Models/Worktree.cs b/src/Models/Worktree.cs
index 26f88a8a8..00eb33a05 100644
--- a/src/Models/Worktree.cs
+++ b/src/Models/Worktree.cs
@@ -9,7 +9,6 @@ public class Worktree : ObservableObject
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;
public bool IsLocked
diff --git a/src/Native/Linux.cs b/src/Native/Linux.cs
index f6eb4ebf3..c0b067e60 100644
--- a/src/Native/Linux.cs
+++ b/src/Native/Linux.cs
@@ -57,13 +57,20 @@ public string FindTerminal(Models.ShellOrTerminal shell)
finder.Fleet(() => FindJetBrainsFleet(localAppDataDir));
finder.FindJetBrainsFromToolbox(() => Path.Combine(localAppDataDir, "JetBrains/Toolbox"));
finder.SublimeText(() => FindExecutable("subl"));
- finder.Zed(() => FindExecutable("zeditor"));
+ finder.Zed(() =>
+ {
+ var exec = FindExecutable("zeditor");
+ return string.IsNullOrEmpty(exec) ? FindExecutable("zed") : exec;
+ });
return finder.Tools;
}
public void OpenBrowser(string url)
{
- Process.Start("xdg-open", url.Quoted());
+ var browser = Environment.GetEnvironmentVariable("BROWSER");
+ if (string.IsNullOrEmpty(browser))
+ browser = "xdg-open";
+ Process.Start(browser, url.Quoted());
}
public void OpenInFileManager(string path, bool select)
@@ -80,20 +87,15 @@ public void OpenInFileManager(string path, bool select)
}
}
- public void OpenTerminal(string workdir)
+ public void OpenTerminal(string workdir, string args)
{
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 = terminal;
-
- if (terminal.EndsWith("wezterm", StringComparison.OrdinalIgnoreCase))
- startInfo.Arguments = $"start --cwd {cwd.Quoted()}";
- else if (terminal.EndsWith("ptyxis", StringComparison.OrdinalIgnoreCase))
- startInfo.Arguments = $"--new-window --working-directory={cwd.Quoted()}";
+ startInfo.FileName = OS.ShellOrTerminal;
+ startInfo.Arguments = args;
try
{
@@ -130,7 +132,8 @@ private string FindExecutable(string filename)
return test;
}
- return string.Empty;
+ var local = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".local", "bin", filename);
+ return File.Exists(local) ? local : string.Empty;
}
private string FindJetBrainsFleet(string localAppDataDir)
diff --git a/src/Native/MacOS.cs b/src/Native/MacOS.cs
index a021a16d8..48d276496 100644
--- a/src/Native/MacOS.cs
+++ b/src/Native/MacOS.cs
@@ -62,15 +62,7 @@ public string FindGitExecutable()
public string FindTerminal(Models.ShellOrTerminal shell)
{
- return shell.Type switch
- {
- "mac-terminal" => "Terminal",
- "iterm2" => "iTerm",
- "warp" => "Warp",
- "ghostty" => "Ghostty",
- "kitty" => "kitty",
- _ => string.Empty,
- };
+ return shell.Exec;
}
public List FindExternalTools()
@@ -101,7 +93,7 @@ public void OpenInFileManager(string path, bool select)
Process.Start("open", $"{path.Quoted()} -R");
}
- public void OpenTerminal(string workdir)
+ public void OpenTerminal(string workdir, string _)
{
var home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
var dir = string.IsNullOrEmpty(workdir) ? home : workdir;
diff --git a/src/Native/OS.cs b/src/Native/OS.cs
index df72aff88..1fd4b34d9 100644
--- a/src/Native/OS.cs
+++ b/src/Native/OS.cs
@@ -21,7 +21,7 @@ public interface IBackend
string FindTerminal(Models.ShellOrTerminal shell);
List FindExternalTools();
- void OpenTerminal(string workdir);
+ void OpenTerminal(string workdir, string args);
void OpenInFileManager(string path, bool select);
void OpenBrowser(string url);
void OpenWithDefaultEditor(string file);
@@ -70,12 +70,42 @@ public static string ShellOrTerminal
set;
} = string.Empty;
+ public static string ShellOrTerminalArgs
+ {
+ get;
+ set;
+ } = string.Empty;
+
public static List ExternalTools
{
get;
set;
} = [];
+ public static int ExternalMergerType
+ {
+ get;
+ set;
+ } = 0;
+
+ public static string ExternalMergerExecFile
+ {
+ get;
+ set;
+ } = string.Empty;
+
+ public static string ExternalMergeArgs
+ {
+ get;
+ set;
+ } = string.Empty;
+
+ public static string ExternalDiffArgs
+ {
+ get;
+ set;
+ } = string.Empty;
+
public static bool UseSystemWindowFrame
{
get => OperatingSystem.IsLinux() && _enableSystemWindowFrame;
@@ -98,7 +128,7 @@ static OS()
}
else
{
- throw new Exception("Platform unsupported!!!");
+ throw new PlatformNotSupportedException();
}
}
@@ -112,7 +142,7 @@ public static void SetupDataDir()
if (OperatingSystem.IsWindows())
{
var execFile = Process.GetCurrentProcess().MainModule!.FileName;
- var portableDir = Path.Combine(Path.GetDirectoryName(execFile), "data");
+ var portableDir = Path.Combine(Path.GetDirectoryName(execFile)!, "data");
if (Directory.Exists(portableDir))
{
DataDir = portableDir;
@@ -156,6 +186,43 @@ public static void SetShellOrTerminal(Models.ShellOrTerminal shell)
ShellOrTerminal = string.Empty;
else
ShellOrTerminal = _backend.FindTerminal(shell);
+
+ ShellOrTerminalArgs = shell.Args;
+ }
+
+ public static Models.DiffMergeTool GetDiffMergeTool(bool onlyDiff)
+ {
+ if (ExternalMergerType < 0 || ExternalMergerType >= Models.ExternalMerger.Supported.Count)
+ return null;
+
+ if (ExternalMergerType != 0 && (string.IsNullOrEmpty(ExternalMergerExecFile) || !File.Exists(ExternalMergerExecFile)))
+ return null;
+
+ return new Models.DiffMergeTool(ExternalMergerExecFile, onlyDiff ? ExternalDiffArgs : ExternalMergeArgs);
+ }
+
+ public static void AutoSelectExternalMergeToolExecFile()
+ {
+ if (ExternalMergerType >= 0 && ExternalMergerType < Models.ExternalMerger.Supported.Count)
+ {
+ var merger = Models.ExternalMerger.Supported[ExternalMergerType];
+ var externalTool = ExternalTools.Find(x => x.Name.Equals(merger.Name, StringComparison.Ordinal));
+ if (externalTool != null)
+ ExternalMergerExecFile = externalTool.ExecFile;
+ else if (!OperatingSystem.IsWindows() && File.Exists(merger.Finder))
+ ExternalMergerExecFile = merger.Finder;
+ else
+ ExternalMergerExecFile = string.Empty;
+
+ ExternalDiffArgs = merger.DiffCmd;
+ ExternalMergeArgs = merger.MergeCmd;
+ }
+ else
+ {
+ ExternalMergerExecFile = string.Empty;
+ ExternalDiffArgs = string.Empty;
+ ExternalMergeArgs = string.Empty;
+ }
}
public static void OpenInFileManager(string path, bool select = false)
@@ -173,7 +240,7 @@ public static void OpenTerminal(string workdir)
if (string.IsNullOrEmpty(ShellOrTerminal))
App.RaiseException(workdir, "Terminal is not specified! Please confirm that the correct shell/terminal has been configured.");
else
- _backend.OpenTerminal(workdir);
+ _backend.OpenTerminal(workdir, ShellOrTerminalArgs);
}
public static void OpenWithDefaultEditor(string file)
@@ -190,6 +257,19 @@ public static string GetAbsPath(string root, string sub)
return fullpath;
}
+ public static string GetRelativePathToHome(string path)
+ {
+ if (OperatingSystem.IsWindows())
+ return path;
+
+ var home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
+ var prefixLen = home.EndsWith('/') ? home.Length - 1 : home.Length;
+ if (path.StartsWith(home, StringComparison.Ordinal))
+ return $"~{path.AsSpan(prefixLen)}";
+
+ return path;
+ }
+
private static void UpdateGitVersion()
{
if (string.IsNullOrEmpty(_gitExecutable) || !File.Exists(_gitExecutable))
@@ -211,7 +291,7 @@ private static void UpdateGitVersion()
try
{
- using var proc = Process.Start(start);
+ using var proc = Process.Start(start)!;
var rs = proc.StandardOutput.ReadToEnd();
proc.WaitForExit();
if (proc.ExitCode == 0 && !string.IsNullOrWhiteSpace(rs))
diff --git a/src/Native/Windows.cs b/src/Native/Windows.cs
index 69e8d842c..756eeecac 100644
--- a/src/Native/Windows.cs
+++ b/src/Native/Windows.cs
@@ -17,6 +17,7 @@ namespace SourceGit.Native
[SupportedOSPlatform("windows")]
internal class Windows : OS.IBackend
{
+ [StructLayout(LayoutKind.Sequential)]
internal struct RECT
{
public int left;
@@ -55,7 +56,7 @@ internal struct MARGINS
public void SetupApp(AppBuilder builder)
{
// Fix drop shadow issue on Windows 10
- if (!OperatingSystem.IsWindowsVersionAtLeast(10, 22000))
+ if (!OperatingSystem.IsWindowsVersionAtLeast(10, 0, 22000))
{
Window.WindowStateProperty.Changed.AddClassHandler((w, _) => FixWindowFrameOnWin10(w));
Control.LoadedEvent.AddClassHandler((w, _) => FixWindowFrameOnWin10(w));
@@ -66,18 +67,13 @@ public void SetupWindow(Window window)
{
window.ExtendClientAreaChromeHints = ExtendClientAreaChromeHints.NoChrome;
window.ExtendClientAreaToDecorationsHint = true;
- window.Classes.Add("fix_maximized_padding");
+ window.BorderThickness = new Thickness(1);
Win32Properties.AddWndProcHookCallback(window, (IntPtr hWnd, uint msg, IntPtr _, IntPtr lParam, ref bool handled) =>
{
- // Custom WM_NCHITTEST
- if (msg == 0x0084)
+ // Custom WM_NCHITTEST only used to limit the resize border to 4 * window.RenderScaling pixels.
+ if (msg == 0x0084 && window.WindowState == WindowState.Normal)
{
- handled = true;
-
- if (window.WindowState == WindowState.FullScreen || window.WindowState == WindowState.Maximized)
- return 1; // HTCLIENT
-
var p = IntPtrToPixelPoint(lParam);
GetWindowRect(hWnd, out var rcWindow);
@@ -94,18 +90,23 @@ public void SetupWindow(Window window)
else if (p.Y < rcWindow.bottom && p.Y >= rcWindow.bottom - borderThickness)
y = 2;
+ // If it's in the client area, do not handle it here.
var zone = y * 3 + x;
+ if (zone == 4)
+ return IntPtr.Zero;
+
+ // If it's in the resize border area, return the proper HT code.
+ handled = true;
return zone switch
{
0 => 13, // HTTOPLEFT
1 => 12, // HTTOP
2 => 14, // HTTOPRIGHT
3 => 10, // HTLEFT
- 4 => 1, // HTCLIENT
5 => 11, // HTRIGHT
6 => 16, // HTBOTTOMLEFT
7 => 15, // HTBOTTOM
- _ => 17,
+ _ => 17, // HTBOTTOMRIGHT
};
}
@@ -143,7 +144,7 @@ public string FindTerminal(Models.ShellOrTerminal shell)
break;
var binDir = Path.GetDirectoryName(OS.GitExecutable)!;
- var bash = Path.Combine(binDir, "bash.exe");
+ var bash = Path.GetFullPath(Path.Combine(binDir, "..", "git-bash.exe"));
if (!File.Exists(bash))
break;
@@ -186,10 +187,11 @@ public string FindTerminal(Models.ShellOrTerminal shell)
finder.VSCode(FindVSCode);
finder.VSCodeInsiders(FindVSCodeInsiders);
finder.VSCodium(FindVSCodium);
- finder.Cursor(FindCursor);
+ finder.Cursor(() => Path.Combine(localAppDataDir, @"Programs\Cursor\Cursor.exe"));
finder.Fleet(() => Path.Combine(localAppDataDir, @"Programs\Fleet\Fleet.exe"));
finder.FindJetBrainsFromToolbox(() => Path.Combine(localAppDataDir, @"JetBrains\Toolbox"));
finder.SublimeText(FindSublimeText);
+ finder.Zed(FindZed);
FindVisualStudio(finder);
return finder.Tools;
}
@@ -201,22 +203,22 @@ public void OpenBrowser(string url)
Process.Start(info);
}
- public void OpenTerminal(string workdir)
+ public void OpenTerminal(string workdir, string args)
{
- if (!File.Exists(OS.ShellOrTerminal))
+ var home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
+ var cwd = string.IsNullOrEmpty(workdir) ? home : workdir;
+ var terminal = OS.ShellOrTerminal;
+
+ if (!File.Exists(terminal))
{
App.RaiseException(workdir, "Terminal is not specified! Please confirm that the correct shell/terminal has been configured.");
return;
}
var startInfo = new ProcessStartInfo();
- startInfo.WorkingDirectory = workdir;
- startInfo.FileName = OS.ShellOrTerminal;
-
- // Directly launching `Windows Terminal` need to specify the `-d` parameter
- if (OS.ShellOrTerminal.EndsWith("wt.exe", StringComparison.OrdinalIgnoreCase))
- startInfo.Arguments = $"-d {workdir.Quoted()}";
-
+ startInfo.WorkingDirectory = cwd;
+ startInfo.FileName = terminal;
+ startInfo.Arguments = args;
Process.Start(startInfo);
}
@@ -389,7 +391,7 @@ private void FindVisualStudio(Models.ExternalToolsFinder finder)
try
{
- using var proc = Process.Start(startInfo);
+ using var proc = Process.Start(startInfo)!;
var output = proc.StandardOutput.ReadToEnd();
proc.WaitForExit();
@@ -410,16 +412,20 @@ private void FindVisualStudio(Models.ExternalToolsFinder finder)
}
}
- private string FindCursor()
+ private string FindZed()
{
- var cursorPath = Path.Combine(
- Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
- "Programs",
- "Cursor",
- "Cursor.exe");
+ var currentUser = Microsoft.Win32.RegistryKey.OpenBaseKey(
+ Microsoft.Win32.RegistryHive.CurrentUser,
+ Microsoft.Win32.RegistryView.Registry64);
- if (File.Exists(cursorPath))
- return cursorPath;
+ // NOTE: this is the official Zed Preview reg data.
+ var preview = currentUser.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{F70E4811-D0E2-4D88-AC99-D63752799F95}_is1");
+ if (preview != null)
+ return preview.GetValue("DisplayIcon") as string;
+
+ var findInPath = new StringBuilder("zed.exe", 512);
+ if (PathFindOnPath(findInPath, null))
+ return findInPath.ToString();
return string.Empty;
}
@@ -439,10 +445,15 @@ private void OpenFolderAndSelectFile(string folderPath)
}
}
- private string GenerateCommandlineArgsForVisualStudio(string repo)
+ private string GenerateCommandlineArgsForVisualStudio(string path)
{
- var sln = FindVSSolutionFile(new DirectoryInfo(repo), 4);
- return string.IsNullOrEmpty(sln) ? repo.Quoted() : sln.Quoted();
+ if (Directory.Exists(path))
+ {
+ var sln = FindVSSolutionFile(new DirectoryInfo(path), 4);
+ return string.IsNullOrEmpty(sln) ? path.Quoted() : sln.Quoted();
+ }
+
+ return path.Quoted();
}
private string FindVSSolutionFile(DirectoryInfo dir, int leftDepth)
@@ -450,7 +461,8 @@ private string FindVSSolutionFile(DirectoryInfo dir, int leftDepth)
var files = dir.GetFiles();
foreach (var f in files)
{
- if (f.Name.EndsWith(".sln", StringComparison.OrdinalIgnoreCase))
+ if (f.Name.EndsWith(".slnx", StringComparison.OrdinalIgnoreCase) ||
+ f.Name.EndsWith(".sln", StringComparison.OrdinalIgnoreCase))
return f.FullName;
}
diff --git a/src/Resources/Grammars/vue.json b/src/Resources/Grammars/vue.json
new file mode 100644
index 000000000..fd7e47c54
--- /dev/null
+++ b/src/Resources/Grammars/vue.json
@@ -0,0 +1,1326 @@
+{
+ "information_for_contributors": [
+ "This file has been copied from https://github.com/vuejs/language-tools/blob/68d98dc57f8486c2946ae28dc86bf8e91d45da4d/extensions/vscode/syntaxes/vue.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": "Vue",
+ "scopeName": "source.vue",
+ "patterns": [
+ {
+ "include": "#vue-comments"
+ },
+ {
+ "include": "#self-closing-tag"
+ },
+ {
+ "begin": "(<)",
+ "beginCaptures": {
+ "1": {
+ "name": "punctuation.definition.tag.begin.html.vue"
+ }
+ },
+ "end": "(>)",
+ "endCaptures": {
+ "1": {
+ "name": "punctuation.definition.tag.end.html.vue"
+ }
+ },
+ "patterns": [
+ {
+ "begin": "([a-zA-Z0-9:-]+)\\b(?=[^>]*\\blang\\s*=\\s*(['\"]?)md\\b\\2)",
+ "beginCaptures": {
+ "1": {
+ "name": "entity.name.tag.$1.html.vue"
+ }
+ },
+ "end": "()(\\1)\\s*(?=>)",
+ "endCaptures": {
+ "1": {
+ "name": "punctuation.definition.tag.begin.html.vue"
+ },
+ "2": {
+ "name": "entity.name.tag.$2.html.vue"
+ }
+ },
+ "patterns": [
+ {
+ "include": "#tag-stuff"
+ },
+ {
+ "begin": "(?<=>)",
+ "end": "(?=<\\/)",
+ "name": "text.html.markdown",
+ "patterns": [
+ {
+ "include": "text.html.markdown"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "begin": "([a-zA-Z0-9:-]+)\\b(?=[^>]*\\blang\\s*=\\s*(['\"]?)html\\b\\2)",
+ "beginCaptures": {
+ "1": {
+ "name": "entity.name.tag.$1.html.vue"
+ }
+ },
+ "end": "()(\\1)\\s*(?=>)",
+ "endCaptures": {
+ "1": {
+ "name": "punctuation.definition.tag.begin.html.vue"
+ },
+ "2": {
+ "name": "entity.name.tag.$2.html.vue"
+ }
+ },
+ "patterns": [
+ {
+ "include": "#tag-stuff"
+ },
+ {
+ "begin": "(?<=>)",
+ "end": "(?=<\\/)",
+ "name": "text.html.derivative",
+ "patterns": [
+ {
+ "include": "#html-stuff"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "begin": "([a-zA-Z0-9:-]+)\\b(?=[^>]*\\blang\\s*=\\s*(['\"]?)pug\\b\\2)",
+ "beginCaptures": {
+ "1": {
+ "name": "entity.name.tag.$1.html.vue"
+ }
+ },
+ "end": "()(\\1)\\s*(?=>)",
+ "endCaptures": {
+ "1": {
+ "name": "punctuation.definition.tag.begin.html.vue"
+ },
+ "2": {
+ "name": "entity.name.tag.$2.html.vue"
+ }
+ },
+ "patterns": [
+ {
+ "include": "#tag-stuff"
+ },
+ {
+ "begin": "(?<=>)",
+ "end": "(?=<\\/)",
+ "name": "text.pug",
+ "patterns": [
+ {
+ "include": "text.pug"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "begin": "([a-zA-Z0-9:-]+)\\b(?=[^>]*\\blang\\s*=\\s*(['\"]?)stylus\\b\\2)",
+ "beginCaptures": {
+ "1": {
+ "name": "entity.name.tag.$1.html.vue"
+ }
+ },
+ "end": "()(\\1)\\s*(?=>)",
+ "endCaptures": {
+ "1": {
+ "name": "punctuation.definition.tag.begin.html.vue"
+ },
+ "2": {
+ "name": "entity.name.tag.$2.html.vue"
+ }
+ },
+ "patterns": [
+ {
+ "include": "#tag-stuff"
+ },
+ {
+ "begin": "(?<=>)",
+ "end": "(?=<\\/)",
+ "name": "source.stylus",
+ "patterns": [
+ {
+ "include": "source.stylus"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "begin": "([a-zA-Z0-9:-]+)\\b(?=[^>]*\\blang\\s*=\\s*(['\"]?)postcss\\b\\2)",
+ "beginCaptures": {
+ "1": {
+ "name": "entity.name.tag.$1.html.vue"
+ }
+ },
+ "end": "()(\\1)\\s*(?=>)",
+ "endCaptures": {
+ "1": {
+ "name": "punctuation.definition.tag.begin.html.vue"
+ },
+ "2": {
+ "name": "entity.name.tag.$2.html.vue"
+ }
+ },
+ "patterns": [
+ {
+ "include": "#tag-stuff"
+ },
+ {
+ "begin": "(?<=>)",
+ "end": "(?=<\\/)",
+ "name": "source.postcss",
+ "patterns": [
+ {
+ "include": "source.postcss"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "begin": "([a-zA-Z0-9:-]+)\\b(?=[^>]*\\blang\\s*=\\s*(['\"]?)sass\\b\\2)",
+ "beginCaptures": {
+ "1": {
+ "name": "entity.name.tag.$1.html.vue"
+ }
+ },
+ "end": "()(\\1)\\s*(?=>)",
+ "endCaptures": {
+ "1": {
+ "name": "punctuation.definition.tag.begin.html.vue"
+ },
+ "2": {
+ "name": "entity.name.tag.$2.html.vue"
+ }
+ },
+ "patterns": [
+ {
+ "include": "#tag-stuff"
+ },
+ {
+ "begin": "(?<=>)",
+ "end": "(?=<\\/)",
+ "name": "source.sass",
+ "patterns": [
+ {
+ "include": "source.sass"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "begin": "([a-zA-Z0-9:-]+)\\b(?=[^>]*\\blang\\s*=\\s*(['\"]?)css\\b\\2)",
+ "beginCaptures": {
+ "1": {
+ "name": "entity.name.tag.$1.html.vue"
+ }
+ },
+ "end": "()(\\1)\\s*(?=>)",
+ "endCaptures": {
+ "1": {
+ "name": "punctuation.definition.tag.begin.html.vue"
+ },
+ "2": {
+ "name": "entity.name.tag.$2.html.vue"
+ }
+ },
+ "patterns": [
+ {
+ "include": "#tag-stuff"
+ },
+ {
+ "begin": "(?<=>)",
+ "end": "(?=<\\/)",
+ "name": "source.css",
+ "patterns": [
+ {
+ "include": "source.css"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "begin": "([a-zA-Z0-9:-]+)\\b(?=[^>]*\\blang\\s*=\\s*(['\"]?)scss\\b\\2)",
+ "beginCaptures": {
+ "1": {
+ "name": "entity.name.tag.$1.html.vue"
+ }
+ },
+ "end": "()(\\1)\\s*(?=>)",
+ "endCaptures": {
+ "1": {
+ "name": "punctuation.definition.tag.begin.html.vue"
+ },
+ "2": {
+ "name": "entity.name.tag.$2.html.vue"
+ }
+ },
+ "patterns": [
+ {
+ "include": "#tag-stuff"
+ },
+ {
+ "begin": "(?<=>)",
+ "end": "(?=<\\/)",
+ "name": "source.css.scss",
+ "patterns": [
+ {
+ "include": "source.css.scss"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "begin": "([a-zA-Z0-9:-]+)\\b(?=[^>]*\\blang\\s*=\\s*(['\"]?)less\\b\\2)",
+ "beginCaptures": {
+ "1": {
+ "name": "entity.name.tag.$1.html.vue"
+ }
+ },
+ "end": "()(\\1)\\s*(?=>)",
+ "endCaptures": {
+ "1": {
+ "name": "punctuation.definition.tag.begin.html.vue"
+ },
+ "2": {
+ "name": "entity.name.tag.$2.html.vue"
+ }
+ },
+ "patterns": [
+ {
+ "include": "#tag-stuff"
+ },
+ {
+ "begin": "(?<=>)",
+ "end": "(?=<\\/)",
+ "name": "source.css.less",
+ "patterns": [
+ {
+ "include": "source.css.less"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "begin": "([a-zA-Z0-9:-]+)\\b(?=[^>]*\\blang\\s*=\\s*(['\"]?)js\\b\\2)",
+ "beginCaptures": {
+ "1": {
+ "name": "entity.name.tag.$1.html.vue"
+ }
+ },
+ "end": "()(\\1)\\s*(?=>)",
+ "endCaptures": {
+ "1": {
+ "name": "punctuation.definition.tag.begin.html.vue"
+ },
+ "2": {
+ "name": "entity.name.tag.$2.html.vue"
+ }
+ },
+ "patterns": [
+ {
+ "include": "#tag-stuff"
+ },
+ {
+ "begin": "(?<=>)",
+ "end": "(?=<\\/)",
+ "name": "source.js",
+ "patterns": [
+ {
+ "include": "source.js"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "begin": "([a-zA-Z0-9:-]+)\\b(?=[^>]*\\blang\\s*=\\s*(['\"]?)ts\\b\\2)",
+ "beginCaptures": {
+ "1": {
+ "name": "entity.name.tag.$1.html.vue"
+ }
+ },
+ "end": "()(\\1)\\s*(?=>)",
+ "endCaptures": {
+ "1": {
+ "name": "punctuation.definition.tag.begin.html.vue"
+ },
+ "2": {
+ "name": "entity.name.tag.$2.html.vue"
+ }
+ },
+ "patterns": [
+ {
+ "include": "#tag-stuff"
+ },
+ {
+ "begin": "(?<=>)",
+ "end": "(?=<\\/)",
+ "name": "source.ts",
+ "patterns": [
+ {
+ "include": "source.ts"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "begin": "([a-zA-Z0-9:-]+)\\b(?=[^>]*\\blang\\s*=\\s*(['\"]?)jsx\\b\\2)",
+ "beginCaptures": {
+ "1": {
+ "name": "entity.name.tag.$1.html.vue"
+ }
+ },
+ "end": "()(\\1)\\s*(?=>)",
+ "endCaptures": {
+ "1": {
+ "name": "punctuation.definition.tag.begin.html.vue"
+ },
+ "2": {
+ "name": "entity.name.tag.$2.html.vue"
+ }
+ },
+ "patterns": [
+ {
+ "include": "#tag-stuff"
+ },
+ {
+ "begin": "(?<=>)",
+ "end": "(?=<\\/)",
+ "name": "source.js.jsx",
+ "patterns": [
+ {
+ "include": "source.js.jsx"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "begin": "([a-zA-Z0-9:-]+)\\b(?=[^>]*\\blang\\s*=\\s*(['\"]?)tsx\\b\\2)",
+ "beginCaptures": {
+ "1": {
+ "name": "entity.name.tag.$1.html.vue"
+ }
+ },
+ "end": "()(\\1)\\s*(?=>)",
+ "endCaptures": {
+ "1": {
+ "name": "punctuation.definition.tag.begin.html.vue"
+ },
+ "2": {
+ "name": "entity.name.tag.$2.html.vue"
+ }
+ },
+ "patterns": [
+ {
+ "include": "#tag-stuff"
+ },
+ {
+ "begin": "(?<=>)",
+ "end": "(?=<\\/)",
+ "name": "source.tsx",
+ "patterns": [
+ {
+ "include": "source.tsx"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "begin": "([a-zA-Z0-9:-]+)\\b(?=[^>]*\\blang\\s*=\\s*(['\"]?)coffee\\b\\2)",
+ "beginCaptures": {
+ "1": {
+ "name": "entity.name.tag.$1.html.vue"
+ }
+ },
+ "end": "()(\\1)\\s*(?=>)",
+ "endCaptures": {
+ "1": {
+ "name": "punctuation.definition.tag.begin.html.vue"
+ },
+ "2": {
+ "name": "entity.name.tag.$2.html.vue"
+ }
+ },
+ "patterns": [
+ {
+ "include": "#tag-stuff"
+ },
+ {
+ "begin": "(?<=>)",
+ "end": "(?=<\\/)",
+ "name": "source.coffee",
+ "patterns": [
+ {
+ "include": "source.coffee"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "begin": "([a-zA-Z0-9:-]+)\\b(?=[^>]*\\blang\\s*=\\s*(['\"]?)json\\b\\2)",
+ "beginCaptures": {
+ "1": {
+ "name": "entity.name.tag.$1.html.vue"
+ }
+ },
+ "end": "()(\\1)\\s*(?=>)",
+ "endCaptures": {
+ "1": {
+ "name": "punctuation.definition.tag.begin.html.vue"
+ },
+ "2": {
+ "name": "entity.name.tag.$2.html.vue"
+ }
+ },
+ "patterns": [
+ {
+ "include": "#tag-stuff"
+ },
+ {
+ "begin": "(?<=>)",
+ "end": "(?=<\\/)",
+ "name": "source.json",
+ "patterns": [
+ {
+ "include": "source.json"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "begin": "([a-zA-Z0-9:-]+)\\b(?=[^>]*\\blang\\s*=\\s*(['\"]?)jsonc\\b\\2)",
+ "beginCaptures": {
+ "1": {
+ "name": "entity.name.tag.$1.html.vue"
+ }
+ },
+ "end": "()(\\1)\\s*(?=>)",
+ "endCaptures": {
+ "1": {
+ "name": "punctuation.definition.tag.begin.html.vue"
+ },
+ "2": {
+ "name": "entity.name.tag.$2.html.vue"
+ }
+ },
+ "patterns": [
+ {
+ "include": "#tag-stuff"
+ },
+ {
+ "begin": "(?<=>)",
+ "end": "(?=<\\/)",
+ "name": "source.json.comments",
+ "patterns": [
+ {
+ "include": "source.json.comments"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "begin": "([a-zA-Z0-9:-]+)\\b(?=[^>]*\\blang\\s*=\\s*(['\"]?)json5\\b\\2)",
+ "beginCaptures": {
+ "1": {
+ "name": "entity.name.tag.$1.html.vue"
+ }
+ },
+ "end": "()(\\1)\\s*(?=>)",
+ "endCaptures": {
+ "1": {
+ "name": "punctuation.definition.tag.begin.html.vue"
+ },
+ "2": {
+ "name": "entity.name.tag.$2.html.vue"
+ }
+ },
+ "patterns": [
+ {
+ "include": "#tag-stuff"
+ },
+ {
+ "begin": "(?<=>)",
+ "end": "(?=<\\/)",
+ "name": "source.json5",
+ "patterns": [
+ {
+ "include": "source.json5"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "begin": "([a-zA-Z0-9:-]+)\\b(?=[^>]*\\blang\\s*=\\s*(['\"]?)yaml\\b\\2)",
+ "beginCaptures": {
+ "1": {
+ "name": "entity.name.tag.$1.html.vue"
+ }
+ },
+ "end": "()(\\1)\\s*(?=>)",
+ "endCaptures": {
+ "1": {
+ "name": "punctuation.definition.tag.begin.html.vue"
+ },
+ "2": {
+ "name": "entity.name.tag.$2.html.vue"
+ }
+ },
+ "patterns": [
+ {
+ "include": "#tag-stuff"
+ },
+ {
+ "begin": "(?<=>)",
+ "end": "(?=<\\/)",
+ "name": "source.yaml",
+ "patterns": [
+ {
+ "include": "source.yaml"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "begin": "([a-zA-Z0-9:-]+)\\b(?=[^>]*\\blang\\s*=\\s*(['\"]?)toml\\b\\2)",
+ "beginCaptures": {
+ "1": {
+ "name": "entity.name.tag.$1.html.vue"
+ }
+ },
+ "end": "()(\\1)\\s*(?=>)",
+ "endCaptures": {
+ "1": {
+ "name": "punctuation.definition.tag.begin.html.vue"
+ },
+ "2": {
+ "name": "entity.name.tag.$2.html.vue"
+ }
+ },
+ "patterns": [
+ {
+ "include": "#tag-stuff"
+ },
+ {
+ "begin": "(?<=>)",
+ "end": "(?=<\\/)",
+ "name": "source.toml",
+ "patterns": [
+ {
+ "include": "source.toml"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "begin": "([a-zA-Z0-9:-]+)\\b(?=[^>]*\\blang\\s*=\\s*(['\"]?)(gql|graphql)\\b\\2)",
+ "beginCaptures": {
+ "1": {
+ "name": "entity.name.tag.$1.html.vue"
+ }
+ },
+ "end": "()(\\1)\\s*(?=>)",
+ "endCaptures": {
+ "1": {
+ "name": "punctuation.definition.tag.begin.html.vue"
+ },
+ "2": {
+ "name": "entity.name.tag.$2.html.vue"
+ }
+ },
+ "patterns": [
+ {
+ "include": "#tag-stuff"
+ },
+ {
+ "begin": "(?<=>)",
+ "end": "(?=<\\/)",
+ "name": "source.graphql",
+ "patterns": [
+ {
+ "include": "source.graphql"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "begin": "([a-zA-Z0-9:-]+)\\b(?=[^>]*\\blang\\s*=\\s*(['\"]?)vue\\b\\2)",
+ "beginCaptures": {
+ "1": {
+ "name": "entity.name.tag.$1.html.vue"
+ }
+ },
+ "end": "()(\\1)\\s*(?=>)",
+ "endCaptures": {
+ "1": {
+ "name": "punctuation.definition.tag.begin.html.vue"
+ },
+ "2": {
+ "name": "entity.name.tag.$2.html.vue"
+ }
+ },
+ "patterns": [
+ {
+ "include": "#tag-stuff"
+ },
+ {
+ "begin": "(?<=>)",
+ "end": "(?=<\\/)",
+ "name": "source.vue",
+ "patterns": [
+ {
+ "include": "source.vue"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "begin": "(template)\\b",
+ "beginCaptures": {
+ "1": {
+ "name": "entity.name.tag.$1.html.vue"
+ }
+ },
+ "end": "()(\\1)\\s*(?=>)",
+ "endCaptures": {
+ "1": {
+ "name": "punctuation.definition.tag.begin.html.vue"
+ },
+ "2": {
+ "name": "entity.name.tag.$2.html.vue"
+ }
+ },
+ "patterns": [
+ {
+ "include": "#tag-stuff"
+ },
+ {
+ "begin": "(?<=>)",
+ "end": "(?=<\\/template\\b)",
+ "name": "text.html.derivative",
+ "patterns": [
+ {
+ "include": "#html-stuff"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "begin": "(script)\\b",
+ "beginCaptures": {
+ "1": {
+ "name": "entity.name.tag.$1.html.vue"
+ }
+ },
+ "end": "()(\\1)\\s*(?=>)",
+ "endCaptures": {
+ "1": {
+ "name": "punctuation.definition.tag.begin.html.vue"
+ },
+ "2": {
+ "name": "entity.name.tag.$2.html.vue"
+ }
+ },
+ "patterns": [
+ {
+ "include": "#tag-stuff"
+ },
+ {
+ "begin": "(?<=>)",
+ "end": "(?=<\\/script\\b)",
+ "name": "source.js",
+ "patterns": [
+ {
+ "include": "source.js"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "begin": "(style)\\b",
+ "beginCaptures": {
+ "1": {
+ "name": "entity.name.tag.$1.html.vue"
+ }
+ },
+ "end": "()(\\1)\\s*(?=>)",
+ "endCaptures": {
+ "1": {
+ "name": "punctuation.definition.tag.begin.html.vue"
+ },
+ "2": {
+ "name": "entity.name.tag.$2.html.vue"
+ }
+ },
+ "patterns": [
+ {
+ "include": "#tag-stuff"
+ },
+ {
+ "begin": "(?<=>)",
+ "end": "(?=<\\/style\\b)",
+ "name": "source.css",
+ "patterns": [
+ {
+ "include": "source.css"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "begin": "([a-zA-Z0-9:-]+)",
+ "beginCaptures": {
+ "1": {
+ "name": "entity.name.tag.$1.html.vue"
+ }
+ },
+ "end": "()(\\1)\\s*(?=>)",
+ "endCaptures": {
+ "1": {
+ "name": "punctuation.definition.tag.begin.html.vue"
+ },
+ "2": {
+ "name": "entity.name.tag.$2.html.vue"
+ }
+ },
+ "patterns": [
+ {
+ "include": "#tag-stuff"
+ },
+ {
+ "begin": "(?<=>)",
+ "end": "(?=<\\/)",
+ "name": "text"
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "repository": {
+ "self-closing-tag": {
+ "begin": "(<)([a-zA-Z0-9:-]+)(?=([^>]+/>))",
+ "beginCaptures": {
+ "1": {
+ "name": "punctuation.definition.tag.begin.html.vue"
+ },
+ "2": {
+ "name": "entity.name.tag.$2.html.vue"
+ }
+ },
+ "end": "(/>)",
+ "endCaptures": {
+ "1": {
+ "name": "punctuation.definition.tag.end.html.vue"
+ }
+ },
+ "name": "self-closing-tag",
+ "patterns": [
+ {
+ "include": "#tag-stuff"
+ }
+ ]
+ },
+ "template-tag": {
+ "patterns": [
+ {
+ "include": "#template-tag-1"
+ },
+ {
+ "include": "#template-tag-2"
+ }
+ ]
+ },
+ "template-tag-1": {
+ "begin": "(<)(template)\\b(>)",
+ "beginCaptures": {
+ "1": {
+ "name": "punctuation.definition.tag.begin.html.vue"
+ },
+ "2": {
+ "name": "entity.name.tag.$2.html.vue"
+ },
+ "3": {
+ "name": "punctuation.definition.tag.end.html.vue"
+ }
+ },
+ "end": "(/?>)",
+ "endCaptures": {
+ "1": {
+ "name": "punctuation.definition.tag.end.html.vue"
+ }
+ },
+ "name": "meta.template-tag.start",
+ "patterns": [
+ {
+ "begin": "\\G",
+ "end": "(?=/>)|(()(template)\\b)",
+ "endCaptures": {
+ "2": {
+ "name": "punctuation.definition.tag.begin.html.vue"
+ },
+ "3": {
+ "name": "entity.name.tag.$3.html.vue"
+ }
+ },
+ "name": "meta.template-tag.end",
+ "patterns": [
+ {
+ "include": "#html-stuff"
+ }
+ ]
+ }
+ ]
+ },
+ "template-tag-2": {
+ "begin": "(<)(template)\\b",
+ "beginCaptures": {
+ "1": {
+ "name": "punctuation.definition.tag.begin.html.vue"
+ },
+ "2": {
+ "name": "entity.name.tag.$2.html.vue"
+ }
+ },
+ "end": "(/?>)",
+ "endCaptures": {
+ "1": {
+ "name": "punctuation.definition.tag.end.html.vue"
+ }
+ },
+ "name": "meta.template-tag.start",
+ "patterns": [
+ {
+ "begin": "\\G",
+ "end": "(?=/>)|(()(template)\\b)",
+ "endCaptures": {
+ "2": {
+ "name": "punctuation.definition.tag.begin.html.vue"
+ },
+ "3": {
+ "name": "entity.name.tag.$3.html.vue"
+ }
+ },
+ "name": "meta.template-tag.end",
+ "patterns": [
+ {
+ "include": "#tag-stuff"
+ },
+ {
+ "include": "#html-stuff"
+ }
+ ]
+ }
+ ]
+ },
+ "html-stuff": {
+ "patterns": [
+ {
+ "include": "#template-tag"
+ },
+ {
+ "include": "text.html.derivative"
+ },
+ {
+ "include": "text.html.basic"
+ }
+ ]
+ },
+ "tag-stuff": {
+ "begin": "\\G",
+ "end": "(?=/>)|(>)",
+ "endCaptures": {
+ "1": {
+ "name": "punctuation.definition.tag.end.html.vue"
+ }
+ },
+ "name": "meta.tag-stuff",
+ "patterns": [
+ {
+ "include": "#vue-directives"
+ },
+ {
+ "include": "text.html.basic#attribute"
+ }
+ ]
+ },
+ "vue-directives": {
+ "patterns": [
+ {
+ "include": "#vue-directives-control"
+ },
+ {
+ "include": "#vue-directives-generic-attr"
+ },
+ {
+ "include": "#vue-directives-style-attr"
+ },
+ {
+ "include": "#vue-directives-original"
+ }
+ ]
+ },
+ "vue-directives-original": {
+ "begin": "(?:(?:(v-[\\w-]+)(:)?)|([:\\.])|(@)|(#))(?:(?:(\\[)([^\\]]*)(\\]))|([\\w-]+))?",
+ "beginCaptures": {
+ "1": {
+ "name": "entity.other.attribute-name.html.vue"
+ },
+ "2": {
+ "name": "punctuation.separator.key-value.html.vue"
+ },
+ "3": {
+ "name": "punctuation.attribute-shorthand.bind.html.vue"
+ },
+ "4": {
+ "name": "punctuation.attribute-shorthand.event.html.vue"
+ },
+ "5": {
+ "name": "punctuation.attribute-shorthand.slot.html.vue"
+ },
+ "6": {
+ "name": "punctuation.separator.key-value.html.vue"
+ },
+ "7": {
+ "name": "source.ts.embedded.html.vue",
+ "patterns": [
+ {
+ "include": "source.ts#expression"
+ }
+ ]
+ },
+ "8": {
+ "name": "punctuation.separator.key-value.html.vue"
+ },
+ "9": {
+ "name": "entity.other.attribute-name.html.vue"
+ }
+ },
+ "end": "(?=\\s*[^=\\s])",
+ "name": "meta.attribute.directive.vue",
+ "patterns": [
+ {
+ "match": "(\\.)([\\w-]*)",
+ "1": {
+ "name": "punctuation.separator.key-value.html.vue"
+ },
+ "2": {
+ "name": "entity.other.attribute-name.html.vue"
+ }
+ },
+ {
+ "include": "#vue-directives-expression"
+ }
+ ]
+ },
+ "vue-directives-control": {
+ "begin": "(?:(v-for)|(v-if|v-else-if|v-else))(?=[=/>)\\s])",
+ "beginCaptures": {
+ "1": {
+ "name": "keyword.control.loop.vue"
+ },
+ "2": {
+ "name": "keyword.control.conditional.vue"
+ }
+ },
+ "end": "(?=\\s*[^=\\s])",
+ "name": "meta.attribute.directive.control.vue",
+ "patterns": [
+ {
+ "include": "#vue-directives-expression"
+ }
+ ]
+ },
+ "vue-directives-expression": {
+ "patterns": [
+ {
+ "begin": "(=)\\s*('|\"|`)",
+ "beginCaptures": {
+ "1": {
+ "name": "punctuation.separator.key-value.html.vue"
+ },
+ "2": {
+ "name": "punctuation.definition.string.begin.html.vue"
+ }
+ },
+ "end": "(\\2)",
+ "endCaptures": {
+ "1": {
+ "name": "punctuation.definition.string.end.html.vue"
+ }
+ },
+ "patterns": [
+ {
+ "begin": "(?<=('|\"|`))",
+ "end": "(?=\\1)",
+ "name": "source.ts.embedded.html.vue",
+ "patterns": [
+ {
+ "include": "source.ts#expression"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "begin": "(=)\\s*(?=[^'\"`])",
+ "beginCaptures": {
+ "1": {
+ "name": "punctuation.separator.key-value.html.vue"
+ }
+ },
+ "end": "(?=(\\s|>|\\/>))",
+ "patterns": [
+ {
+ "begin": "(?=[^'\"`])",
+ "end": "(?=(\\s|>|\\/>))",
+ "name": "source.ts.embedded.html.vue",
+ "patterns": [
+ {
+ "include": "source.ts#expression"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "vue-directives-style-attr": {
+ "begin": "\\b(style)\\s*(=)",
+ "beginCaptures": {
+ "1": {
+ "name": "entity.other.attribute-name.html.vue"
+ },
+ "2": {
+ "name": "punctuation.separator.key-value.html.vue"
+ }
+ },
+ "end": "(?<='|\")",
+ "name": "meta.attribute.style.vue",
+ "patterns": [
+ {
+ "comment": "Copy from source.css#rule-list-innards",
+ "begin": "('|\")",
+ "beginCaptures": {
+ "1": {
+ "name": "punctuation.definition.string.begin.html.vue"
+ }
+ },
+ "end": "(\\1)",
+ "endCaptures": {
+ "1": {
+ "name": "punctuation.definition.string.end.html.vue"
+ }
+ },
+ "name": "source.css.embedded.html.vue",
+ "patterns": [
+ {
+ "include": "source.css#comment-block"
+ },
+ {
+ "include": "source.css#escapes"
+ },
+ {
+ "include": "source.css#font-features"
+ },
+ {
+ "match": "(?x) (?)"
+ }
+ ]
+ }
+ ]
+ },
+ "vue-interpolations": {
+ "patterns": [
+ {
+ "begin": "(\\{\\{)",
+ "beginCaptures": {
+ "1": {
+ "name": "punctuation.definition.interpolation.begin.html.vue"
+ }
+ },
+ "end": "(\\}\\})",
+ "endCaptures": {
+ "1": {
+ "name": "punctuation.definition.interpolation.end.html.vue"
+ }
+ },
+ "name": "expression.embedded.vue",
+ "patterns": [
+ {
+ "begin": "\\G",
+ "end": "(?=\\}\\})",
+ "name": "source.ts.embedded.html.vue",
+ "patterns": [
+ {
+ "include": "source.ts#expression"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "vue-comments": {
+ "patterns": [
+ {
+ "include": "#vue-comments-key-value"
+ },
+ {
+ "begin": "",
+ "name": "comment.block.vue"
+ }
+ ]
+ },
+ "vue-comments-key-value": {
+ "begin": "()",
+ "endCaptures": {
+ "1": {
+ "name": "punctuation.definition.comment.vue"
+ }
+ },
+ "name": "comment.block.vue",
+ "patterns": [
+ {
+ "include": "source.json#value"
+ }
+ ]
+ }
+ }
+}
diff --git a/src/Resources/Icons.axaml b/src/Resources/Icons.axaml
index c7011bce1..4fd176dfa 100644
--- a/src/Resources/Icons.axaml
+++ b/src/Resources/Icons.axaml
@@ -14,20 +14,20 @@
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
M523 398 918 3l113 113-396 396 397 397-113 113-397-397-397 397-113-113 397-397L14 116l113-113 396 396z
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
- M684 736 340 736l0-53 344 1-0 53zM552 565l-213-2 0-53 212 2-0 53zM684 392 340 392l0-53 344 1-0 53zM301 825c-45 0-78-9-100-27-22-18-33-43-33-75v-116c0-22-4-37-12-45-7-9-20-13-40-13v-61c19 0 32-4 40-12 8-9 12-24 12-46v-116c0-32 11-57 33-75 22-18 56-27 100-27h24v61h-24a35 35 0 00-27 12 41 41 0 00-11 29v116c0 35-10 60-31 75a66 66 0 01-31 14c11 2 22 6 31 14 20 17 31 42 31 75v116c0 12 4 22 11 29 7 8 16 12 27 12h24v61h-24zM701 764h24c10 0 19-4 27-12a41 41 0 0011-29v-116c0-33 10-58 31-75 9-7 19-12 31-14a66 66 0 01-31-14c-20-15-31-40-31-75v-116a41 41 0 00-11-29 35 35 0 00-27-12h-24v-61h24c45 0 78 9 100 27 22 18 33 43 33 75v116c0 22 4 37 11 46 8 8 21 12 40 12v61c-19 0-33 4-40 13-7 8-11 23-11 45v116c0 32-11 57-33 75-22 18-55 27-100 27h-24v-61z
M128 854h768v86H128zM390 797c13 13 29 19 48 19s35-6 45-19l291-288c26-22 26-64 0-90L435 83l-61 61L426 192l-272 269c-22 22-22 64 0 90l237 246zm93-544 211 211-32 32H240l243-243zM707 694c0 48 38 86 86 86 48 0 86-38 86-86 0-22-10-45-26-61L794 576l-61 61c-13 13-26 35-26 58z
+ M325 312l-60 60L404 513 265 652l60 60 200-200L325 312zm194 345h236v97h-236v-97zM29 77v870h968V77H29zm870 774H125V173h774v678z
M0 512M1024 512M512 0M512 1024M796 471A292 292 0 00512 256a293 293 0 00-284 215H0v144h228A293 293 0 00512 832a291 291 0 00284-217H1024V471h-228M512 688A146 146 0 01366 544A145 145 0 01512 400c80 0 146 63 146 144A146 146 0 01512 688
M796 561a5 5 0 014 7l-39 90a5 5 0 004 7h100a5 5 0 014 8l-178 247a5 5 0 01-9-4l32-148a5 5 0 00-5-6h-89a5 5 0 01-4-7l86-191a5 5 0 014-3h88zM731 122a73 73 0 0173 73v318a54 54 0 00-8-1H731V195H244v634h408l-16 73H244a73 73 0 01-73-73V195a73 73 0 0173-73h488zm-219 366v73h-195v-73h195zm146-146v73H317v-73h341z
M645 448l64 64 220-221L704 64l-64 64 115 115H128v90h628zM375 576l-64-64-220 224L314 960l64-64-116-115H896v-90H262z
M608 0q48 0 88 23t63 63 23 87v70h55q35 0 67 14t57 38 38 57 14 67V831q0 34-14 66t-38 57-57 38-67 13H426q-34 0-66-13t-57-38-38-57-14-66v-70h-56q-34 0-66-14t-57-38-38-57-13-67V174q0-47 23-87T109 23 196 0h412m175 244H426q-46 0-86 22T278 328t-26 85v348H608q47 0 86-22t63-62 25-85l1-348m-269 318q18 0 31 13t13 31-13 31-31 13-31-13-13-31 13-31 31-13m0-212q13 0 22 9t11 22v125q0 14-9 23t-22 10-23-7-11-22l-1-126q0-13 10-23t23-10z
M896 811l-128 0c-23 0-43-19-43-43 0-23 19-43 43-43l107 0c13 0 21-9 21-21L896 107c0-13-9-21-21-21L448 85c-13 0-21 9-21 21l0 21c0 23-19 43-43 43-23 0-43-19-43-43L341 85c0-47 38-85 85-85l469 0c47 0 85 38 85 85l0 640C981 772 943 811 896 811zM683 299l0 640c0 47-38 85-85 85L128 1024c-47 0-85-38-85-85L43 299c0-47 38-85 85-85l469 0C644 213 683 252 683 299zM576 299 149 299c-13 0-21 9-21 21l0 597c0 13 9 21 21 21l427 0c13 0 21-9 21-21L597 320C597 307 589 299 576 299z
+ M339 297c17-23 25-51 25-83 2-42-12-79-43-108S255 62 215 65c-32 0-60 8-84 25s-42 39-54 67-15 56-10 86 19 55 40 76c21 21 47 35 76 41v303c-30 6-55 20-76 41-21 21-35 47-40 76-5 30-2 58 10 86s30 50 54 67 52 25 83 25 59-8 84-25c25-17 45-39 57-67 6-19 10-39 10-61 0-30-8-57-25-83-21-34-52-55-92-64v-299l25-6c28-13 50-32 67-57zm-45 471c8 15 12 30 11 46-1 16-6 31-16 46-10 15-23 25-40 32s-34 8-51 5-32-11-46-24-22-28-24-45c-6-28-1-53 18-75s41-33 68-33c17 0 32 4 46 13 14 8 25 20 33 35zM167 288c-15-11-26-24-33-41-7-17-10-34-6-51 3-17 11-32 24-45s28-21 46-25 36-3 53 5c17 7 30 18 40 32 10 14 15 29 16 46 1 17-3 33-11 48-8 15-20 27-33 35-14 8-29 13-46 13s-33-5-48-16zm615 45c2-19-1-38-10-57-11-28-29-50-54-67s-53-25-83-25h-111l76-76-45-41-127 127v41l127 127 45-41-76-76h111c23 0 44 8 62 25 18 17 27 38 27 64v89h57V332zm0 449H960v-61H782V542h-61v178H543v61h178v178h61V781z
M280 145l243 341 0-0 45 63-0 0 79 110a143 143 0 11-36 75l-88-123-92 126c1 4 1 9 1 13l0 5a143 143 0 11-36-95l82-113L221 188l60-43zm473 541a70 70 0 100 140 70 70 0 000-140zm-463 0a70 70 0 100 140 70 70 0 000-140zM772 145l59 43-232 319-45-63L772 145z
M128 183C128 154 154 128 183 128h521c30 0 55 26 55 55v38c0 17-17 34-34 34s-34-17-34-34v-26H196v495h26c17 0 34 17 34 34s-17 34-34 34h-38c-30 0-55-26-55-55V183zM380 896h-34c-26 0-47-21-47-47v-90h68V828h64V896H380c4 0 0 0 0 0zM759 828V896h90c26 0 47-21 47-47v-90h-68V828h-68zM828 435H896V346c0-26-21-47-47-47h-90v68H828v68zM435 299v68H367V439H299V346C299 320 320 299 346 299h90zM367 649H299v-107h68v107zM546 367V299h107v68h-107zM828 546H896v107h-68v-107zM649 828V896h-107v-68h107zM730 508v188c0 17-17 34-34 34h-188c-17 0-34-17-34-34s17-34 34-34h102l-124-124c-13-13-13-34 0-47 13-13 34-13 47 0l124 124V512c0-17 17-34 34-34 21-4 38 9 38 30z
M889 0H135c-32 0-59 26-59 59v906c0 32 26 59 59 59h753c32 0 59-26 59-59v-906c1-33-26-59-58-59zm-165 177c31 0 56 25 56 56s-25 56-56 56-56-25-56-56 25-56 56-56zm-212 0c31 0 56 25 56 56S543 288 512 288s-56-25-56-56S481 177 512 177zm-212 0c31 0 56 25 56 56s-25 56-56 56-56-25-56-56 25-56 56-56zm209 606H285c-25 0-44-20-44-44 0-25 20-44 44-44h224c25 0 44 20 44 44 0 24-20 44-44 44zm230-212H285c-25 0-44-20-44-44 0-25 20-44 44-44h453c25 0 44 20 44 44 1 24-20 44-44 44z
@@ -36,6 +36,7 @@
M768 800V685L512 480 256 685V800l256-205L768 800zM512 339 768 544V429L512 224 256 429V544l256-205z
M509 546l271-271 91 91-348 349-1-1-13 13-363-361 91-91z
M652 157a113 113 0 11156 161L731 395 572 236l80-80 1 1zM334 792v0H175v-159l358-358 159 159-358 358zM62 850h900v113H62v-113z
+ M926 356V780a73 73 0 01-73 73H171a73 73 0 01-73-73V356l304 258a171 171 0 00221 0L926 356zM853 171a74 74 0 0126 5 73 73 0 0131 22 74 74 0 0111 18c3 8 5 16 6 24L926 244v24L559 581a73 73 0 01-91 3l-4-3L98 268v-24a73 73 0 0140-65A73 73 0 01171 171h683z
M469 235V107h85v128h-85zm-162-94 85 85-60 60-85-85 60-60zm469 60-85 85-60-60 85-85 60 60zm-549 183A85 85 0 01302 341H722a85 85 0 0174 42l131 225A85 85 0 01939 652V832a85 85 0 01-85 85H171a85 85 0 01-85-85v-180a85 85 0 0112-43l131-225zM722 427H302l-100 171h255l10 29a59 59 0 002 5c2 4 5 9 9 14 8 9 18 17 34 17 16 0 26-7 34-17a72 72 0 0011-18l0-0 10-29h255l-100-171zM853 683H624a155 155 0 01-12 17C593 722 560 747 512 747c-48 0-81-25-99-47a155 155 0 01-12-17H171v149h683v-149z
M576 832C576 867 547 896 512 896 477 896 448 867 448 832 448 797 477 768 512 768 547 768 576 797 576 832ZM512 256C477 256 448 285 448 320L448 640C448 675 477 704 512 704 547 704 576 675 576 640L576 320C576 285 547 256 512 256ZM1024 896C1024 967 967 1024 896 1024L128 1024C57 1024 0 967 0 896 0 875 5 855 14 837L14 837 398 69 398 69C420 28 462 0 512 0 562 0 604 28 626 69L1008 835C1018 853 1024 874 1024 896ZM960 896C960 885 957 875 952 865L952 864 951 863 569 98C557 77 536 64 512 64 488 64 466 77 455 99L452 105 92 825 93 825 71 867C66 876 64 886 64 896 64 931 93 960 128 960L896 960C931 960 960 931 960 896Z
M928 128l-416 0-32-64-352 0-64 128 896 0zM904 704l75 0 45-448-1024 0 64 640 484 0c-105-38-180-138-180-256 0-150 122-272 272-272s272 122 272 272c0 22-3 43-8 64zM1003 914l-198-175c17-29 27-63 27-99 0-106-86-192-192-192s-192 86-192 192 86 192 192 192c36 0 70-10 99-27l175 198c23 27 62 28 87 3l6-6c25-25 23-64-3-87zM640 764c-68 0-124-56-124-124s56-124 124-124 124 56 124 124-56 124-124 124z
@@ -49,7 +50,7 @@
M416 832H128V128h384v192C512 355 541 384 576 384L768 384v32c0 19 13 32 32 32S832 435 832 416v-64c0-6 0-19-6-25l-256-256c-6-6-19-6-25-6H128A64 64 0 0064 128v704C64 867 93 896 129 896h288c19 0 32-13 32-32S435 832 416 832zM576 172 722 320H576V172zM736 512C614 512 512 614 512 736S614 960 736 960s224-102 224-224S858 512 736 512zM576 736C576 646 646 576 736 576c32 0 58 6 83 26l-218 218c-19-26-26-51-26-83zm160 160c-32 0-64-13-96-32l224-224c19 26 32 58 32 96 0 90-70 160-160 160z
M896 320c0-19-6-32-19-45l-192-192c-13-13-26-19-45-19H192c-38 0-64 26-64 64v768c0 38 26 64 64 64h640c38 0 64-26 64-64V320zm-256 384H384c-19 0-32-13-32-32s13-32 32-32h256c19 0 32 13 32 32s-13 32-32 32zm166-384H640V128l192 192h-26z
M599 425 599 657 425 832 425 425 192 192 832 192Z
- M505 74c-145 3-239 68-239 68-12 8-15 25-7 37 9 13 25 15 38 6 0 0 184-136 448 2 12 7 29 3 36-10 8-13 3-29-12-37-71-38-139-56-199-63-23-3-44-3-65-3m17 111c-254-3-376 201-376 201-8 12-5 29 7 37 12 8 29 4 39-10 0 0 103-178 329-175 226 3 325 173 325 173 8 12 24 17 37 9 14-8 17-24 9-37 0 0-117-195-370-199m-31 106c-72 5-140 31-192 74C197 449 132 603 204 811c5 14 20 21 34 17 14-5 21-20 16-34-66-191-7-316 79-388 84-69 233-85 343-17 54 34 96 93 118 151 22 58 20 114 3 141-18 28-54 38-86 30-32-8-58-31-59-80-1-73-58-118-118-125-57-7-123 24-140 92-32 125 49 302 238 361 14 4 29-3 34-17 4-14-3-29-18-34-163-51-225-206-202-297 10-41 46-55 84-52 37 4 69 26 69 73 2 70 48 117 100 131 52 13 112-3 144-52 33-50 28-120 3-188-26-68-73-136-140-178a356 356 0 00-213-52m15 104v0c-76 3-152 42-195 125-56 106-31 215 7 293 38 79 90 131 90 131 10 11 27 11 38 0s11-26 0-38c0 0-46-47-79-116s-54-157-8-244c48-90 133-111 208-90 76 22 140 88 138 186-2 15 9 28 24 29 15 1 27-10 29-27 3-122-79-210-176-239a246 246 0 00-75-9m9 213c-15 0-26 13-26 27 0 0 1 63 36 124 36 61 112 119 244 107 15-1 26-13 25-28-1-15-14-26-30-25-116 11-165-33-193-81-28-47-29-98-29-98a27 27 0 00-27-27z
+ M320 239 213 299l60-107L213 85l107 60L427 85 367 192 427 299 320 239m512 418L939 597l-60 107L939 811l-107-60L725 811l60-107L725 597l107 60M939 85l-60 107L939 299l-107-60L725 299l60-107L725 85l107 60L939 85m-369 460 104-104-90-90-104 104 90 90m44-234 100 100c17 16 17 44 0 60L215 969c-17 17-44 17-60 0l-100-100c-17-16-17-44 0-60L553 311c17-17 44-17 60 0z
M853 267H514c-4 0-6-2-9-4l-38-66c-13-21-38-36-64-36H171c-41 0-75 34-75 75v555c0 41 34 75 75 75h683c41 0 75-34 75-75V341c0-41-34-75-75-75zm-683-43h233c4 0 6 2 9 4l38 66c13 21 38 36 64 36H853c6 0 11 4 11 11v75h-704V235c0-6 4-11 11-11zm683 576H171c-6 0-11-4-11-11V480h704V789c0 6-4 11-11 11z
M1088 227H609L453 78a11 11 0 00-7-3H107a43 43 0 00-43 43v789a43 43 0 0043 43h981a43 43 0 0043-43V270a43 43 0 00-43-43zM757 599c0 5-5 9-10 9h-113v113c0 5-4 9-9 9h-56c-5 0-9-4-9-9V608h-113c-5 0-10-4-10-9V543c0-5 5-9 10-9h113V420c0-5 4-9 9-9h56c5 0 9 4 9 9V533h113c5 0 10 4 10 9v56z
M922 450c-6-9-15-13-26-13h-11V341c0-41-34-75-75-75H514c-4 0-6-2-9-4l-38-66c-13-21-38-36-64-36H171c-41 0-75 34-75 75v597c0 6 2 13 6 19 6 9 15 13 26 13h640c13 0 26-9 30-21l128-363c4-11 2-21-4-30zM171 224h233c4 0 6 2 9 4l38 66c13 21 38 36 64 36H811c6 0 11 4 11 11v96H256c-13 0-26 9-30 21l-66 186V235c0-6 4-11 11-11zm574 576H173l105-299h572l-105 299z
@@ -59,7 +60,9 @@
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
+ M727 641c-78 0-142 55-157 128H256V320h251c16 108 108 192 221 192 124 0 224-100 224-224S851 64 727 64c-113 0-205 84-221 192H96c-18 0-32 14-32 32s14 32 32 32h96v482c0 18 14 32 32 32h347c15 73 79 128 157 128 88 0 160-72 160-160s-72-160-160-160zm0 256c-53 0-96-43-96-96s43-96 96-96 96 43 96 96-43 96-96 96z
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
+ M566 585l37-146-145 0-37 146 145 0zM1005 297l-32 128q-4 14-18 14l-187 0-37 146 178 0q9 0 14 7 6 8 3 16l-32 128q-3 14-18 14l-187 0-46 187q-4 14-18 14l-128 0q-9 0-15-7-5-7-3-16l45-178-145 0-46 187q-4 14-18 14l-129 0q-9 0-14-7-5-7-3-16l45-178-178 0q-9 0-14-7-5-7-3-16l32-128q4-14 18-14l187 0 37-146-178 0q-9 0-14-7-6-8-3-16l32-128q3-14 18-14l187 0 46-187q4-14 18-14l128 0q9 0 14 7 5 7 3 16l-45 178 145 0 46-187q4-14 18-14l128 0q9 0 14 7 5 7 3 16l-45 178 178 0q9 0 14 7 5 7 3 16z
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
M416 64H768v64h-64v704h64v64H448v-64h64V512H416a224 224 0 1 1 0-448zM576 832h64V128H576v704zM416 128H512v320H416a160 160 0 0 1 0-320z
M24 512A488 488 0 01512 24A488 488 0 011000 512A488 488 0 01512 1000A488 488 0 0124 512zm447-325v327L243 619l51 111 300-138V187H471z
@@ -87,7 +90,6 @@
M0 512M1024 512M512 0M512 1024M64 576h896V448H64z
M896 64H128C96 64 64 96 64 128v768c0 32 32 64 64 64h768c32 0 64-32 64-64V128c0-32-32-64-64-64z m-64 736c0 16-17 32-32 32H224c-18 0-32-12-32-32V224c0-16 16-32 32-32h576c15 0 32 16 32 32v576zM512 384c-71 0-128 57-128 128s57 128 128 128 128-57 128-128-57-128-128-128z
M0 512M1024 512M512 0M512 1024M813 448c-46 0-83 37-83 83 0 46 37 83 83 83 46 0 83-37 83-83 0-46-37-83-83-83zM211 448C165 448 128 485 128 531c0 46 37 83 83 83 46 0 83-37 83-83 0-46-37-83-83-83zM512 448c-46 0-83 37-83 83 0 46 37 83 83 83 46 0 83-37 83-83C595 485 558 448 512 448z
- M299 811 299 725 384 725 384 811 299 811M469 811 469 725 555 725 555 811 469 811M640 811 640 725 725 725 725 811 640 811M299 640 299 555 384 555 384 640 299 640M469 640 469 555 555 555 555 640 469 640M640 640 640 555 725 555 725 640 640 640M299 469 299 384 384 384 384 469 299 469M469 469 469 384 555 384 555 469 469 469M640 469 640 384 725 384 725 469 640 469M299 299 299 213 384 213 384 299 299 299M469 299 469 213 555 213 555 299 469 299M640 299 640 213 725 213 725 299 640 299Z
M64 363l0 204 265 0L329 460c0-11 6-18 14-20C349 437 355 437 362 441c93 60 226 149 226 149 33 22 34 60 0 82 0 0-133 89-226 149-14 9-32-3-32-18l-1-110L64 693l0 117c0 41 34 75 75 75l746 0c41 0 75-34 75-74L960 364c0-0 0-1 0-1L64 363zM64 214l0 75 650 0-33-80c-16-38-62-69-103-69l-440 0C97 139 64 173 64 214z
M683 409v204L1024 308 683 0v191c-413 0-427 526-427 526c117-229 203-307 427-307zm85 492H102V327h153s38-63 114-122H51c-28 0-51 27-51 61v697c0 34 23 61 51 61h768c28 0 51-27 51-61V614l-102 100v187z
M841 627A43 43 0 00811 555h-299v85h196l-183 183A43 43 0 00555 896h299v-85h-196l183-183zM299 170H213v512H85l171 171 171-171H299zM725 128h-85c-18 0-34 11-40 28l-117 313h91L606 384h154l32 85h91l-117-313A43 43 0 00725 128zm-88 171 32-85h26l32 85h-90z
@@ -111,8 +113,10 @@
M883 567l-128-128c-17-17-43-17-60 0l-128 128c-17 17-17 43 0 60 17 17 43 17 60 0l55-55V683c0 21-21 43-43 43H418c-13-38-43-64-77-77V375c51-17 85-64 85-119 0-73-60-128-128-128-73 0-128 55-128 128 0 55 34 102 85 119v269c-51 17-85 64-85 119 0 73 55 128 128 128 55 0 102-34 119-85H640c73 0 128-55 128-128v-111l55 55c9 9 17 13 30 13 13 0 21-4 30-13 17-13 17-43 0-55zM299 213c26 0 43 17 43 43 0 21-21 43-43 43-26 0-43-21-43-43 0-26 17-43 43-43zm0 597c-26 0-43-21-43-43 0-26 17-43 43-43s43 17 43 43c0 21-17 43-43 43zM725 384c-73 0-128-60-128-128 0-73 55-128 128-128s128 55 128 128c0 68-55 128-128 128zm0-171c-26 0-43 17-43 43s17 43 43 43 43-17 43-43-17-43-43-43z
M293 122v244h439V146l171 175V829a73 73 0 01-73 73h-98V536H293v366H195a73 73 0 01-73-73V195a73 73 0 0173-73h98zm366 512v268H366V634h293zm-49 49h-195v73h195v-73zm49-561v171H366V122h293z
M0 551V472c0-11 9-19 19-19h984c11 0 19 9 19 19v79c0 11-9 19-19 19H19c-11 0-19-9-19-19zM114 154v240c0 11-9 19-19 19H19C9 413 0 404 0 394V79C0 35 35 0 79 0h315c11 0 19 9 19 19v75c0 11-9 19-19 19H154c-21 0-39 18-39 39zm795 0c0-22-17-39-39-39h-240c-11 0-19-9-19-19V19c0-11 9-19 19-19h315c43 0 79 35 79 79v315c0 11-9 19-19 19h-75c-11 0-19-9-19-19l-1-240zm0 716v-240c0-11 9-19 19-19h75c11 0 19 9 19 19v315c0 43-35 79-79 79h-315c-11 0-19-9-19-19v-75c0-11 9-19 19-19H870c21-1 39-18 39-40zm-795 0c0 21 18 39 39 39h240c11 0 19 9 19 19v75c0 11-9 19-19 19H79C35 1023 0 988 0 945v-315c0-11 9-19 19-19h75c11 0 19 9 19 19V870z
+ M155 143h715v81H155V143zm358 94 358 369H662l1 278H363V605H155l358-369z
M702 677 590 565a148 148 0 10-25 27L676 703zm-346-200a115 115 0 11115 115A115 115 0 01355 478z
M928 500a21 21 0 00-19-20L858 472a11 11 0 01-9-9c-1-6-2-13-3-19a11 11 0 015-12l46-25a21 21 0 0010-26l-8-22a21 21 0 00-24-13l-51 10a11 11 0 01-12-6c-3-6-6-11-10-17a11 11 0 011-13l34-39a21 21 0 001-28l-15-18a20 20 0 00-27-4l-45 27a11 11 0 01-13-1c-5-4-10-9-15-12a11 11 0 01-3-12l19-49a21 21 0 00-9-26l-20-12a21 21 0 00-27 6L650 193a9 9 0 01-11 3c-1-1-12-5-20-7a11 11 0 01-7-10l1-52a21 21 0 00-17-22l-23-4a21 21 0 00-24 14L532 164a11 11 0 01-11 7h-20a11 11 0 01-11-7l-17-49a21 21 0 00-24-15l-23 4a21 21 0 00-17 22l1 52a11 11 0 01-8 11c-5 2-15 6-19 7c-4 1-8 0-12-4l-33-40A21 21 0 00313 146l-20 12A21 21 0 00285 184l19 49a11 11 0 01-3 12c-5 4-10 8-15 12a11 11 0 01-13 1L228 231a21 21 0 00-27 4L186 253a21 21 0 001 28L221 320a11 11 0 011 13c-3 5-7 11-10 17a11 11 0 01-12 6l-51-10a21 21 0 00-24 13l-8 22a21 21 0 0010 26l46 25a11 11 0 015 12l0 3c-1 6-2 11-3 16a11 11 0 01-9 9l-51 8A21 21 0 0096 500v23A21 21 0 00114 544l51 8a11 11 0 019 9c1 6 2 13 3 19a11 11 0 01-5 12l-46 25a21 21 0 00-10 26l8 22a21 21 0 0024 13l51-10a11 11 0 0112 6c3 6 6 11 10 17a11 11 0 01-1 13l-34 39a21 21 0 00-1 28l15 18a20 20 0 0027 4l45-27a11 11 0 0113 1c5 4 10 9 15 12a11 11 0 013 12l-19 49a21 21 0 009 26l20 12a21 21 0 0027-6L374 832c3-3 7-5 10-4c7 3 12 5 20 7a11 11 0 018 10l-1 52a21 21 0 0017 22l23 4a21 21 0 0024-14l17-50a11 11 0 0111-7h20a11 11 0 0111 7l17 49a21 21 0 0020 15a19 19 0 004 0l23-4a21 21 0 0017-22l-1-52a11 11 0 018-10c8-3 13-5 18-7l1 0c6-2 9 0 11 3l34 41A21 21 0 00710 878l20-12a21 21 0 009-26l-18-49a11 11 0 013-12c5-4 10-8 15-12a11 11 0 0113-1l45 27a21 21 0 0027-4l15-18a21 21 0 00-1-28l-34-39a11 11 0 01-1-13c3-5 7-11 10-17a11 11 0 0112-6l51 10a21 21 0 0024-13l8-22a21 21 0 00-10-26l-46-25a11 11 0 01-5-12l0-3c1-6 2-11 3-16a11 11 0 019-9l51-8a21 21 0 0018-21v-23zm-565 188a32 32 0 01-51 5a270 270 0 011-363a32 32 0 0151 6l91 161a32 32 0 010 31zM512 782a270 270 0 01-57-6a32 32 0 01-20-47l92-160a32 32 0 0127-16h184a32 32 0 0130 41c-35 109-137 188-257 188zm15-328L436 294a32 32 0 0121-47a268 268 0 0155-6c120 0 222 79 257 188a32 32 0 01-30 41h-184a32 32 0 01-28-16z
+ M653 435l-26 119H725c9 0 13 4 13 13v47c0 9-4 13-13 13h-107l-21 115c0 9-4 13-13 13h-47c-9 0-13-4-13-13l21-111H427l-21 115c0 9-4 13-13 13H346c-9 0-13-4-13-13l21-107h-85c-4-9-9-21-13-34v-38c0-9 4-13 13-13h98l26-119H294c-9 0-13-4-13-13V375c0-9 4-13 13-13h115l13-81c0-9 4-13 13-13h43c9 0 13 4 13 13L469 363h119l13-81c0-9 4-13 13-13h47c9 0 13 4 13 13l-13 77h85c9 0 13 4 13 13v47c0 9-4 13-13 13h-98v4zM512 0C230 0 0 230 0 512c0 145 60 282 166 375L90 1024H512c282 0 512-230 512-512S794 0 512 0zm-73 559h124l26-119h-128l-21 119z
M900 287c40 69 60 144 60 225s-20 156-60 225c-40 69-94 123-163 163-69 40-144 60-225 60s-156-20-225-60c-69-40-123-94-163-163C84 668 64 593 64 512s20-156 60-225 94-123 163-163c69-40 144-60 225-60s156 20 225 60 123 94 163 163zM762 512c0-9-3-16-9-22L578 315l-44-44c-6-6-13-9-22-9s-16 3-22 9l-44 44-176 176c-6 6-9 13-9 22s3 16 9 22l44 44c6 6 13 9 22 9s16-3 22-9l92-92v269c0 9 3 16 9 22 6 6 13 9 22 9h62c8 0 16-3 22-9 6-6 9-13 9-22V486l92 92c6 6 13 9 22 9 8 0 16-3 22-9l44-44c6-6 9-13 9-22z
M512 939C465 939 427 900 427 853 427 806 465 768 512 768 559 768 597 806 597 853 597 900 559 939 512 939M555 85 555 555 747 363 807 423 512 719 217 423 277 363 469 555 469 85 555 85Z
M961 320 512 577 63 320 512 62l449 258zM512 628 185 442 63 512 512 770 961 512l-123-70L512 628zM512 821 185 634 63 704 512 962l449-258L839 634 512 821z
@@ -122,8 +126,9 @@
M558 545 790 403c24-15 31-47 16-71-15-24-46-31-70-17L507 457 277 315c-24-15-56-7-71 17-15 24-7 56 17 71l232 143V819c0 28 23 51 51 51 28 0 51-23 51-51V545h0zM507 0l443 256v512L507 1024 63 768v-512L507 0z
M770 320a41 41 0 00-56-14l-252 153L207 306a41 41 0 10-43 70l255 153 2 296a41 41 0 0082 0l-2-295 255-155a41 41 0 0014-56zM481 935a42 42 0 01-42 0L105 741a42 42 0 01-21-36v-386a42 42 0 0121-36L439 89a42 42 0 0142 0l335 193a42 42 0 0121 36v87h84v-87a126 126 0 00-63-109L523 17a126 126 0 00-126 0L63 210a126 126 0 00-63 109v386a126 126 0 0063 109l335 193a126 126 0 00126 0l94-54-42-72zM1029 700h-126v-125a42 42 0 00-84 0v126h-126a42 42 0 000 84h126v126a42 42 0 1084 0v-126h126a42 42 0 000-84z
M416 587c21 0 37 17 37 37v299A37 37 0 01416 960h-299a37 37 0 01-37-37v-299c0-21 17-37 37-37h299zm448 0c21 0 37 17 37 37v299A37 37 0 01864 960h-299a37 37 0 01-37-37v-299c0-21 17-37 37-37h299zM758 91l183 189a37 37 0 010 52l-182 188a37 37 0 01-53 1l-183-189a37 37 0 010-52l182-188a37 37 0 0153-1zM416 139c21 0 37 17 37 37v299A37 37 0 01416 512h-299a37 37 0 01-37-37v-299c0-21 17-37 37-37h299z
- M653 435l-26 119H725c9 0 13 4 13 13v47c0 9-4 13-13 13h-107l-21 115c0 9-4 13-13 13h-47c-9 0-13-4-13-13l21-111H427l-21 115c0 9-4 13-13 13H346c-9 0-13-4-13-13l21-107h-85c-4-9-9-21-13-34v-38c0-9 4-13 13-13h98l26-119H294c-9 0-13-4-13-13V375c0-9 4-13 13-13h115l13-81c0-9 4-13 13-13h43c9 0 13 4 13 13L469 363h119l13-81c0-9 4-13 13-13h47c9 0 13 4 13 13l-13 77h85c9 0 13 4 13 13v47c0 9-4 13-13 13h-98v4zM512 0C230 0 0 230 0 512c0 145 60 282 166 375L90 1024H512c282 0 512-230 512-512S794 0 512 0zm-73 559h124l26-119h-128l-21 119z
+ M512 0C230 0 0 230 0 512c0 145 60 282 166 375L90 1024H512c282 0 512-230 512-512S794 0 512 0z
M875 128h-725A107 107 0 0043 235v555A107 107 0 00149 896h725a107 107 0 00107-107v-555A107 107 0 00875 128zm-115 640h-183v-58l25-3c15 0 19-8 14-24l-22-61H419l-28 82 39 2V768h-166v-58l18-3c18-2 22-11 26-24l125-363-40-4V256h168l160 448 39 3zM506 340l-72 218h145l-71-218h-2z
+ M1097 372h-460l-146-299H146a73 73 0 00-73 73v731a73 73 0 0073 73h878a73 73 0 0073-73V372zM146 0h390l146 299h488V878a146 146 0 01-146 146H146a146 146 0 01-146-146V146a146 146 0 01146-146zm439 0h195l146 246h-195l-146-246zm244 0h195a146 146 0 01146 146v100h-195l-146-246z
M177 156c-22 5-33 17-36 37c-10 57-33 258-13 278l445 445c23 23 61 23 84 0l246-246c23-23 23-61 0-84l-445-445C437 120 231 145 177 156zM331 344c-26 26-69 26-95 0c-26-26-26-69 0-95s69-26 95 0C357 276 357 318 331 344z
M683 537h-144v-142h-142V283H239a44 44 0 00-41 41v171a56 56 0 0014 34l321 321a41 41 0 0058 0l174-174a41 41 0 000-58zm-341-109a41 41 0 110-58a41 41 0 010 58zM649 284V142h-69v142h-142v68h142v142h69v-142h142v-68h-142z
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
@@ -146,7 +151,7 @@
M153 154h768v768h-768v-768zm64 64v640h640v-640h-640z
M796 231v727H64V231h732zm-82 78H146V880h567V309zM229 66H960v732H796v-82h82V148h-567v82h-82V66z
M248 221a77 77 0 00-30-21c-18-7-40-10-68-5a224 224 0 00-45 13c-5 2-10 5-15 8l-3 2v68l11-9c10-8 21-14 34-19 13-5 26-7 39-7 12 0 21 3 28 10 6 6 9 16 9 29l-62 9c-14 2-26 6-36 11a80 80 0 00-25 20c-7 8-12 17-15 27-6 21-6 44 1 65a70 70 0 0041 43c10 4 21 6 34 6a80 80 0 0063-28v22h64V298c0-16-2-31-6-44a91 91 0 00-18-33zm-41 121v15c0 8-1 15-4 22a48 48 0 01-24 29 44 44 0 01-33 2 29 29 0 01-10-6 25 25 0 01-6-9 30 30 0 01-2-12c0-5 1-9 2-14a21 21 0 015-9 28 28 0 0110-7 83 83 0 0120-5l42-6zm323-68a144 144 0 00-16-42 87 87 0 00-28-29 75 75 0 00-41-11 73 73 0 00-44 14c-6 5-12 11-17 17V64H326v398h59v-18c8 10 18 17 30 21 6 2 13 3 21 3 16 0 31-4 43-11 12-7 23-18 31-31a147 147 0 0019-46 248 248 0 006-57c0-17-2-33-5-49zm-55 49c0 15-1 28-4 39-2 11-6 20-10 27a41 41 0 01-15 15 37 37 0 01-36 1 44 44 0 01-13-12 59 59 0 01-9-18A76 76 0 01384 352v-33c0-10 1-20 4-29 2-8 6-15 10-22a43 43 0 0115-13 37 37 0 0119-5 35 35 0 0132 18c4 6 7 14 9 23 2 9 3 20 3 31zM154 634a58 58 0 0120-15c14-6 35-7 49-1 7 3 13 6 20 12l21 17V572l-6-4a124 124 0 00-58-14c-20 0-38 4-54 11-16 7-30 17-41 30-12 13-20 29-26 46-6 17-9 36-9 57 0 18 3 36 8 52 6 16 14 30 24 42 10 12 23 21 38 28 15 7 32 10 50 10 15 0 28-2 39-5 11-3 21-8 30-14l5-4v-57l-13 6a26 26 0 01-5 2c-3 1-6 2-8 3-2 1-15 6-15 6-4 2-9 3-14 4a63 63 0 01-38-4 53 53 0 01-20-14 70 70 0 01-13-24 111 111 0 01-5-34c0-13 2-26 5-36 3-10 8-19 14-26zM896 384h-256V320h288c21 1 32 12 32 32v384c0 18-12 32-32 32H504l132 133-45 45-185-185c-16-21-16-25 0-45l185-185L637 576l-128 128H896V384z
- M128 691H6V38h838v160h-64V102H70v525H128zM973 806H154V250h819v557zm-755-64h691V314H218v429zM365 877h448v64h-448z
+ M0 512M1024 512M512 0M512 1024M128 691H6V38h838v160h-64V102H70v525H128zM973 806H154V250h819v557zm-755-64h691V314H218v429zM365 877h448v64h-448z
M853 267H514c-4 0-6-2-9-4l-38-66c-13-21-38-36-64-36H171c-41 0-75 34-75 75v555c0 41 34 75 75 75h683c41 0 75-34 75-75V341c0-41-34-75-75-75zm-683-43h233c4 0 6 2 9 4l38 66c13 21 38 36 64 36H853c6 0 11 4 11 11v75h-704V235c0-6 4-11 11-11zm683 576H171c-6 0-11-4-11-11V480h704V789c0 6-4 11-11 11z
M896 96 614 96c-58 0-128-19-179-51C422 38 390 19 358 19L262 19 128 19c-70 0-128 58-128 128l0 736c0 70 58 128 128 128l768 0c70 0 128-58 128-128L1024 224C1024 154 966 96 896 96zM704 685 544 685l0 160c0 19-13 32-32 32s-32-13-32-32l0-160L320 685c-19 0-32-13-32-32 0-19 13-32 32-32l160 0L480 461c0-19 13-32 32-32s32 13 32 32l0 160L704 621c19 0 32 13 32 32C736 666 723 685 704 685zM890 326 102 326 102 250c0-32 32-64 64-64l659 0c38 0 64 32 64 64L890 326z
M1182 527a91 91 0 00-88-117H92a91 91 0 00-88 117l137 441A80 80 0 00217 1024h752a80 80 0 0076-56zM133 295a31 31 0 0031 31h858a31 31 0 0031-31A93 93 0 00959 203H226a93 93 0 00-94 92zM359 123h467a31 31 0 0031-31A92 92 0 00765 0H421a92 92 0 00-92 92 31 31 0 0031 31z
diff --git a/src/Resources/Locales/de_DE.axaml b/src/Resources/Locales/de_DE.axaml
index 7bbeca503..7d2e27c08 100644
--- a/src/Resources/Locales/de_DE.axaml
+++ b/src/Resources/Locales/de_DE.axaml
@@ -5,6 +5,7 @@
Info
Über SourceGit
+ Hinweise zur Veröffentlichung
Open Source & freier Git GUI Client
Zu ignorierende Datei(en) hinzufügen
Muster:
@@ -23,6 +24,8 @@
Neu generieren
Verwende OpenAI, um Commit-Nachrichten zu generieren
Als Commit-Nachricht verwenden
+ SourceGit minimieren
+ Alles anzeigen
Patch
Patch-Datei:
Wähle die anzuwendende .patch-Datei
@@ -53,14 +56,18 @@
Überspringen
Bisecting. Aktuellen Commit als gut oder schlecht markieren und einen anderen auschecken.
Blame
- BLAME WIRD BEI DIESER DATEI NICHT UNTERSTÜTZT!!!
+ Blame auf vorheriger Revision
+ BLAME WIRD BEI DIESER DATEI NICHT UNTERSTÜTZT!!!
Auschecken von ${0}$...
Mit ${0}$ vergleichen
Mit Worktree vergleichen
Branch-Namen kopieren
+ PR erstellen...
+ PR für Upstream ${0}$ erstellen...
Benutzerdefinierte Aktion
Lösche ${0}$...
Lösche alle ausgewählten {0} Branches
+ Beschreibung für ${0}$ bearbeiten...
Fast-Forward zu ${0}$
Fetche ${0}$ in ${1}$ hinein...
Git Flow - Abschließen ${0}$
@@ -72,13 +79,18 @@
Rebase ${0}$ auf ${1}$...
Benenne ${0}$ um...
Setze ${0}$ zurück auf ${1}$...
+ Zu ${0}$ wechseln (Worktree)
Setze verfolgten Branch...
Branch Vergleich
- LOKAL
+ {0} Commit(s) voraus
+ {0} Commit(s) voraus, {1} Commit(s) zurück
+ {0} Commit(s) zurück
+ Ungültig
REMOTE
+ STATUS
VERFOLGT
URL
- Ungültiger Upstream!
+ WORKTREE
ABBRECHEN
Auf Vorgänger-Revision zurücksetzen
Auf diese Revision zurücksetzen
@@ -96,8 +108,7 @@
Warnung: Beim Auschecken eines Commits wird dein HEAD losgelöst (detached) sein!
Lokale Änderungen:
Verwerfen
- Stashen & wieder anwenden
- Alle Submodule updaten
+ Stashen & wieder anwenden
Branch:
Dein aktueller HEAD enthält Commit(s) ohne Verbindung zu einem Branch/Tag. Möchtest du trotzdem fortfahren?
Auschecken & Fast-Forward
@@ -106,7 +117,7 @@
Quelle an Commit-Nachricht anhängen
Commit(s):
Alle Änderungen committen
- Hautplinie:
+ Hauptlinie:
Normalerweise ist es nicht möglich einen Merge zu cherry-picken, da unklar ist welche Seite des Merges die Hauptlinie ist. Diese Option ermöglicht es die Änderungen relativ zum ausgewählten Vorgänger zu wiederholen.
Stashes löschen
Du versuchst alle Stashes zu löschen. Möchtest du wirklich fortfahren?
@@ -131,7 +142,8 @@
SHA
Betreff
Benutzerdefinierte Aktion
- Interakives Rebase
+ Commit entfernen
+ Interaktives Rebase
Entfernen...
Bearbeiten...
Fixup in den Vorgänger...
@@ -147,6 +159,7 @@
Umformulieren
Als Patch speichern...
Squash in den Vorgänger
+ Fixup in den Vorgänger
ÄNDERUNGEN
geänderte Datei(en)
Änderungen durchsuchen...
@@ -160,6 +173,9 @@
COMMITTER
Prüfe Refs, die diesen Commit enthalten
COMMIT ENTHALTEN IN
+ Email kopieren
+ Name kopieren
+ Name & Email kopieren
Zeigt nur die ersten 100 Änderungen. Alle Änderungen im ÄNDERUNGEN Tab.
Schlüssel:
COMMIT-NACHRICHT
@@ -168,25 +184,42 @@
SHA
Unterzeichner:
Im Browser öffnen
- Details
+ Commit-Nachricht eingeben. Leerzeile zum Trennen von Betreff und Beschreibung verwenden!
Betreff
- Commit-Nachricht
Repository Einstellungen
COMMIT TEMPLATE
- Du kannst ${files_num}, ${branch_name}, ${files} und ${files:N} verwenden, wobei N die maximale Anzahl an auszugebenden Dateipfaden ist.
+ Vordefinierte Parameter:
+
+ ${branch_name} Name des aktuellen lokalen Branches.
+ ${files_num} Anzahl der geänderten Dateien
+ ${files} Pfade der geänderten Dateien
+ ${files:N} Maximale Anzahl N an Pfaden geänderter Dateien
+ ${pure_files} Wie ${files}, aber nur die reinen Dateinamen
+ ${pure_files:N} Wie ${files:N}, aber ohne Ordner
Template Inhalt:
Template Name:
BENUTZERDEFINIERTE AKTION
Argumente:
- Vordefinierte Parameter: ${REPO} - Repository Pfad; ${BRANCH} - selektierter Branch; ${SHA} - Hash des selektierten Commits; ${TAG} - selektiertes Tag
+ Vordefinierte Parameter:
+
+ ${REPO} Repository-Pfad
+ ${REMOTE} selektierter Remote oder selektierter Branch-Remote
+ ${BRANCH} selektierter Branch, ohne ${REMOTE}-Teil für Remote-Branches
+ ${BRANCH_FRIENDLY_NAME} Freundlicher Name des selektierten Branches, enthält ${REMOTE}-Teil für Remote-Branches
+ ${SHA} Hash des selektierten Commits
+ ${TAG} selektiertes Tag
+ ${FILE} Ausgewählte Datei, relativ zum Stammverzeichnis des Repositorys
+ $1, $2 ... Werte der Eingabe-Steuerelemente
+
Ausführbare Datei:
Eingabe-Steuerelemente:
Bearbeiten
- $1, $2 ... können als Argumente in Eingabe-Steuerelementen benutzt werden
Name:
Geltungsbereich:
Branch
Commit
+ Datei
+ Remote
Repository
Tag
Auf Beenden der Aktion warten
@@ -195,10 +228,12 @@
GIT
Remotes automatisch fetchen
Minute(n)
+ Typen für konventionellen Commit
Standard Remote
Bevorzugter Merge Modus
TICKETSYSTEM
Beispiel für Azure DevOps Regel hinzufügen
+ Beispiel für Gerrit Change-Id hinzufügen
Beispiel für Gitee Issue Regel hinzufügen
Beispiel für Gitee Pull Request Regel hinzufügen
Beispiel für GitHub Regel hinzufügen
@@ -213,7 +248,7 @@
Verwende bitte $1, $2 um auf Regex-Gruppenwerte zuzugreifen.
OPEN AI
Bevorzugter Service:
- Der ausgewählte 'Bevorzugte Service' wird nur in diesem Repository gesetzt und verwendet. Wenn keiner gesetzt ist und mehrere Servies verfügbar sind wird ein Kontextmenü zur Auswahl angezeigt.
+ Der ausgewählte 'Bevorzugte Service' wird nur in diesem Repository gesetzt und verwendet. Wenn keiner gesetzt ist und mehrere Services verfügbar sind wird ein Kontextmenü zur Auswahl angezeigt.
HTTP Proxy
HTTP Proxy für dieses Repository
Benutzername
@@ -227,6 +262,7 @@
Bezeichnung:
Einträge:
Nutze '|', um Einträge zu trennen
+ Die vordefinierten Parameter ${REPO}, ${REMOTE}, ${BRANCH}, ${BRANCH_FRIENDLY_NAME}, ${SHA}, ${FILE} und ${TAG} bleiben hier verwendbar
Typ:
Arbeitsplätze
Farbe
@@ -254,10 +290,9 @@
Erstellten Branch auschecken
Lokale Änderungen:
Verwerfen
- Stashen & wieder anwenden
+ Stashen & wieder anwenden
Neuer Branch-Name:
Branch-Name
- Leerzeichen werden durch Bindestriche ersetzt.
Lokalen Branch erstellen
Überschreibe existierenden Branch
Tag erstellen...
@@ -283,6 +318,9 @@
Auch Remote-Branch ${0}$ löschen
Mehrere Branches löschen
Du versuchst mehrere Branches auf einmal zu löschen. Kontrolliere noch einmal vor dem Fortfahren!
+ Mehrere Tags löschen
+ von Remotes löschen
+ Du versuchst, mehrere Tags gleichzeitig zu löschen. Sei dir sicher, das doppelt zu prüfen, bevor du loslegst!
Remote löschen
Remote:
Pfad:
@@ -301,6 +339,7 @@
Erste Differenz
Ignoriere Leerzeichenänderungen
Überblenden
+ Differenz
Nebeneinander
Wischen
Letzte Differenz
@@ -319,13 +358,15 @@
Seiten wechseln
Syntax Hervorhebung
Zeilenumbruch
- Aktiviere Block-Navigation
Öffne in Merge Tool
Alle Zeilen anzeigen
Weniger Zeilen anzeigen
Mehr Zeilen anzeigen
WÄHLE EINE DATEI AUS UM ÄNDERUNGEN ANZUZEIGEN
Verzeichnisverlauf
+ Hat lokale Änderungen
+ Abweichungen vom Upstream
+ Schon aktuell
Änderungen verwerfen
Alle Änderungen in der Arbeitskopie.
Änderungen:
@@ -333,6 +374,11 @@
Nicht-verfolgte Dateien einbeziehen
Insgesamt {0} Änderungen werden verworfen
Du kannst das nicht rückgängig machen!!!
+ Commit entfernen
+ Commit:
+ Neuer HEAD:
+ Beschreibung eines Branches bearbeiten
+ Ziel-Branch:
Lesezeichen:
Neuer Name:
Ziel:
@@ -347,6 +393,7 @@
Remote:
Remote-Änderungen fetchen
Als unverändert betrachten
+ Benutzerdefinierte Aktion
Verwerfen...
Verwerfe {0} Dateien...
Löse mit ${0}$
@@ -402,11 +449,13 @@
Zeige nur meine Sperren
LFS Sperren
Entsperren
+ Alle meine Dateien entsperren
+ Sollen alle meine Dateien entsperrt werden?
Erzwinge entsperren
Prune
Führt `git lfs prune` aus um alte LFS Dateien vom lokalen Speicher zu löschen
Pull
- Führt `git lfs pull` aus um alle Git LFS Dasteien für aktuellen Ref & Checkout herunterzuladen
+ Führt `git lfs pull` aus um alle Git LFS-Dateien für aktuellen Ref & Checkout herunterzuladen
LFS Objekte pullen
Push
Pushe große Dateien in der Warteschlange zum Git LFS Endpunkt
@@ -432,7 +481,6 @@
Zum vorherigen Tab wechseln
Neuen Tab erstellen
Einstellungen öffnen
- Aktiven Arbeitsplatz wechseln
Aktiven Tab wechseln
REPOSITORY
Gestagte Änderungen committen
@@ -440,6 +488,7 @@
Alle Änderungen stagen und committen
Fetch, wird direkt ausgeführt
Dashboard Modus (Standard)
+ Befehlspalette öffnen
Commit-Suchmodus
Pull, wird direkt ausgeführt
Push, wird direkt ausgeführt
@@ -473,10 +522,12 @@
Ziel Branch:
Link kopieren
In Browser öffnen
+ Befehle
FEHLER
INFO
- Arbeitsplätze
+ Repositorys öffnen
Tabs
+ Arbeitsplätze
Branch mergen
Merge-Nachricht anpassen
Ziel-Branch:
@@ -493,9 +544,11 @@
Wähle Vorgänger-Knoten für:
Name:
Git wurde NICHT konfiguriert. Gehe bitte zuerst in die [Einstellungen] und konfiguriere Git.
+ Öffnen
+ Standard-Texteditor (System)
App-Daten Ordner öffnen
+ Datei öffnen
Öffne in Merge Tool
- Öffne mit...
Optional.
Neue Seite erstellen
Lesezeichen
@@ -503,6 +556,7 @@
Andere Tabs schließen
Rechte Tabs schließen
Kopiere Repository-Pfad
+ Aktualisieren
Repositories
Einfügen
Vor {0} Tagen
@@ -510,12 +564,11 @@
Vor {0} Stunden
Gerade eben
Letzter Monat
- Leztes Jahr
+ Letztes Jahr
Vor {0} Minuten
Vor {0} Monaten
Vor {0} Jahren
Gestern
- Verwende 'Shift+Enter' um eine neue Zeile einzufügen. 'Enter' ist das Kürzel für den OK Button
Einstellungen
OPEN AI
System-Prompt für Diff Analyse
@@ -523,6 +576,7 @@
System-Prompt für Erstellung von Commit-Nachricht
Modell
Name
+ Der eingegebene Wert ist der Name der Environment-Variable, von der der Schlüssel gelesen wird
Server
Streaming aktivieren
DARSTELLUNG
@@ -532,9 +586,9 @@
Standard
Texteditor
Monospace-Schriftart
- Verwende die Monospace-Schriftart nur im Texteditor
Design
Design-Anpassungen
+ Scrollbars automatisch ausblenden
Fixe Tab-Breite in Titelleiste
Verwende nativen Fensterrahmen
DIFF/MERGE TOOL
@@ -544,12 +598,16 @@
ALLGEMEIN
Beim Starten nach Updates suchen
Datumsformat
+ Aktiviere kompakte Ordner im Änderungsbaum
Sprache
Commit-Historie
Zeige Autor Zeitpunkt anstatt Commit Zeitpunkt
+ Standardmäßig Seite `Änderungen` anzeigen
+ Standardmäßig Tab `ÄNDERUNGEN` in Commit-Details anzeigen
Zeige Nachfolger in den Commit Details
Zeige Tags im Commit Verlauf
Längenvorgabe für Commit-Nachrichten
+ Standard-Avatar im GitHub-Stil generieren
GIT
Aktiviere Auto-CRLF
Standard Klon-Ordner
@@ -585,8 +643,7 @@
Lokaler Branch:
Lokale Änderungen:
Verwerfen
- Stashen & wieder anwenden
- Alle Submodule aktualisieren
+ Stashen & wieder anwenden
Remote:
Pull (Fetch & Merge)
Rebase anstatt Merge verwenden
@@ -606,6 +663,8 @@
Zu allen Remotes pushen
Remote:
Tag:
+ Push zu NEUEM Branch
+ Eingabe des Namens des neuen Remote-Branch:
Schließen
Aktuellen Branch rebasen
Lokale Änderungen stashen & wieder anwenden
@@ -617,6 +676,7 @@
Repository URL:
Remote Git Repository URL
URL kopieren
+ Benutzerdefinierte Aktion
Löschen...
Bearbeiten...
Fetch
@@ -642,6 +702,7 @@
WEITER
Benutzerdefinierte Aktionen
Keine benutzerdefinierten Aktionen
+ Dashboard
Alle Änderungen verwerfen
Öffne im Datei-Browser
Suche Branches/Tags/Submodule
@@ -656,6 +717,7 @@
Commit Zeitpunkt
Topologie
LOKALE BRANCHES
+ Mehr Optionen...
Zum HEAD wechseln
Erstelle Branch
BENACHRICHTIGUNGEN LÖSCHEN
@@ -714,6 +776,7 @@
Patch wurde erfolgreich gespeichert!
Durchsuche Repositories
Hauptverzeichnis:
+ Anderes benutzerdefiniertes Verzeichnis durchsuchen
Suche nach Updates...
Neue Version ist verfügbar:
Suche nach Updates fehlgeschlagen!
@@ -732,8 +795,6 @@
Upstream:
SHA kopieren
Zum Commit wechseln
- Squash Commits
- In:
SSH privater Schlüssel:
Pfad zum privaten SSH Schlüssel
START
@@ -743,7 +804,7 @@
Optional. Informationen zu diesem Stash
Modus:
Nur gestagte Änderungen
- Gestagte und unstagte Änderungen der ausgewähleten Datei(en) werden gestasht!!!
+ Gestagte und ungestagte Änderungen der ausgewählten Datei(en) werden gestasht!!!
Lokale Änderungen stashen
Anwenden
Kopiere Nachricht
@@ -763,6 +824,7 @@
SUBMODULE
Submodul hinzufügen
BRANCH
+ Branch
Relativen Pfad
De-initialisiere Submodul
Untergeordnete Submodule fetchen
@@ -782,10 +844,15 @@
Update
URL
OK
- Tag-Namen kopieren
- Tag-Nachricht kopieren
+ TAGGER
+ TIME
+ Nachricht
+ Name
+ Tagger
+ Name des Tags kopieren
Benutzerdefinierte Aktion
Lösche ${0}$...
+ Selektierte {0} Tags löschen...
Merge ${0}$ in ${1}$ hinein...
Pushe ${0}$...
Submodule aktualisieren
@@ -816,11 +883,13 @@
Änderungen
Git Ignore
Ignoriere alle *{0} Dateien
- Ignoriere *{0} Datein im selben Ordner
+ Ignoriere *{0} Dateien im selben Ordner
Ignoriere nicht-verfolgte Dateien in diesem Ordner
Ignoriere nur diese Datei
Amend
Du kannst diese Datei jetzt stagen.
+ Verlauf löschen
+ Soll wirklich der Verlauf aller Commit-Nachrichten gelöscht werden? Das kann nicht rückgängig gemacht werden.
COMMIT
COMMIT & PUSH
Template/Historie
@@ -838,6 +907,7 @@
NICHT-VERFOLGTE DATEIEN EINBEZIEHEN
KEINE BISHERIGEN COMMIT-NACHRICHTEN
KEINE COMMIT TEMPLATES
+ Ohne Überprüfung
Autor zurücksetzen
SignOff
GESTAGED
@@ -853,6 +923,7 @@
WORKTREE
Pfad kopieren
Sperren
+ Öffnen
Entfernen
Entsperren
diff --git a/src/Resources/Locales/en_US.axaml b/src/Resources/Locales/en_US.axaml
index 2166f05f4..d60e868e3 100644
--- a/src/Resources/Locales/en_US.axaml
+++ b/src/Resources/Locales/en_US.axaml
@@ -1,6 +1,7 @@
About
About SourceGit
+ Release Notes
Opensource & Free Git GUI Client
Add File(s) To Ignore
Pattern:
@@ -19,6 +20,8 @@
RE-GENERATE
Use AI to generate commit message
APPLY AS COMMIT MESSAGE
+ Hide SourceGit
+ Show All
Patch
Patch File:
Select .patch file to apply
@@ -49,14 +52,18 @@
Skip
Bisecting. Mark current commit as good or bad and checkout another one.
Blame
- BLAME ON THIS FILE IS NOT SUPPORTED!!!
+ Blame on Previous Revision
+ BLAME ON THIS FILE IS NOT SUPPORTED!!!
Checkout ${0}$...
Compare with ${0}$
Compare with Worktree
Copy Branch Name
+ Create PR...
+ Create PR for upstream ${0}$...
Custom Action
Delete ${0}$...
Delete selected {0} branches
+ Edit description for ${0}$...
Fast-Forward to ${0}$
Fetch ${0}$ into ${1}$...
Git Flow - Finish ${0}$
@@ -68,13 +75,18 @@
Rebase ${0}$ on ${1}$...
Rename ${0}$...
Reset ${0}$ to ${1}$...
+ Switch to ${0}$ (worktree)
Set Tracking Branch...
Branch Compare
- LOCAL
+ {0} commit(s) ahead
+ {0} commit(s) ahead, {1} commit(s) behind
+ {0} commit(s) behind
+ Invalid
REMOTE
+ STATUS
TRACKING
URL
- Invalid upstream!
+ WORKTREE
CANCEL
Reset to Parent Revision
Reset to This Revision
@@ -92,8 +104,7 @@
Warning: By doing a commit checkout, your Head will be detached
Local Changes:
Discard
- Stash & Reapply
- Update all submodules
+ Stash & Reapply
Branch:
Your current HEAD contains commit(s) not connected to any branches/tags! Do you want to continue?
Checkout & Fast-Forward
@@ -127,6 +138,7 @@
SHA
Subject
Custom Action
+ Drop Commit
Interactive Rebase
Drop...
Edit...
@@ -143,6 +155,7 @@
Reword
Save as Patch...
Squash into Parent
+ Fixup into Parent
CHANGES
changed file(s)
Search Changes...
@@ -156,6 +169,9 @@
COMMITTER
Check refs that contains this commit
COMMIT IS CONTAINED BY
+ Copy Email
+ Copy Name
+ Copy Name & Email
Shows only the first 100 changes. See all changes on the CHANGES tab.
Key:
MESSAGE
@@ -164,25 +180,41 @@
SHA
Signer:
Open in Browser
- Description
+ Enter commit message. Please use an empty-line to separate subject and description!
SUBJECT
- Enter commit subject
Repository Configure
COMMIT TEMPLATE
- You can use ${files_num}, ${branch_name}, ${files} and ${files:N} where N is the max number of file paths to output.
+ Built-in parameters:
+
+ ${branch_name} Current local branch name.
+ ${files_num} Number of changed files
+ ${files} Paths of changed files
+ ${files:N} Max N number of paths of changed files
+ ${pure_files} Likes ${files}, but only pure file names
+ ${pure_files:N} Likes ${files:N}, but without folders
Template Content:
Template Name:
CUSTOM ACTION
Arguments:
- Built-in parameters: ${REPO} - repository's path; ${BRANCH} - selected branch; ${SHA} - selected commit's hash; ${TAG} - selected tag
+ Built-in parameters:
+
+ ${REPO} Repository's path
+ ${REMOTE} Selected remote or selected branch's remote
+ ${BRANCH} Selected branch, without ${REMOTE} part for remote branches
+ ${BRANCH_FRIENDLY_NAME} Friendly name of selected branch, contains ${REMOTE} part for remote branches
+ ${SHA} Selected commit's hash
+ ${TAG} Selected tag
+ ${FILE} Selected file, relative to repository root
+ $1, $2 ... Input control values
Executable File:
Input Controls:
Edit
- You can use $1, $2 ... in arguments for input control values
Name:
Scope:
Branch
Commit
+ File
+ Remote
Repository
Tag
Wait for action exit
@@ -191,16 +223,18 @@
GIT
Fetch remotes automatically
Minute(s)
+ Conventional Commit Types
Default Remote
Preferred Merge Mode
ISSUE TRACKER
- Add Sample Azure DevOps Rule
- Add Sample Gitee Issue Rule
- Add Sample Gitee Pull Request Rule
- Add Sample GitHub Rule
- Add Sample GitLab Issue Rule
- Add Sample GitLab Merge Request Rule
- Add Sample Jira Rule
+ Add Azure DevOps Rule
+ Add Gerrit Change-Id Commit Rule
+ Add Gitee Issue Rule
+ Add Gitee Pull Request Rule
+ Add GitHub Rule
+ Add GitLab Issue Rule
+ Add GitLab Merge Request Rule
+ Add Jira Rule
New Rule
Issue Regex Expression:
Rule Name:
@@ -222,7 +256,8 @@
Is Folder:
Label:
Options:
- Use '|' as delimitter for options
+ Use '|' as delimiter for options
+ The built-in variables ${REPO}, ${REMOTE}, ${BRANCH}, ${BRANCH_FRIENDLY_NAME}, ${SHA}, ${FILE}, and ${TAG} remain available here
Type:
Workspaces
Color
@@ -250,10 +285,9 @@
Check out the created branch
Local Changes:
Discard
- Stash & Reapply
+ Stash & Reapply
New Branch Name:
Enter branch name.
- Spaces will be replaced with dashes.
Create Local Branch
Overwrite existing branch
Create Tag...
@@ -279,6 +313,9 @@
Also delete remote branch ${0}$
Delete Multiple Branches
You are trying to delete multiple branches at one time. Be sure to double-check before taking action!
+ Delete Multiple Tags
+ Delete them from remotes
+ You are trying to delete multiple tags at one time. Be sure to double-check before taking action!
Delete Remote
Remote:
Path:
@@ -295,8 +332,9 @@
BINARY DIFF
File Mode Changed
First Difference
- Ignore All Whitespace Changes
+ Ignore Whitespace Changes
BLEND
+ DIFFERENCE
SIDE-BY-SIDE
SWIPE
Last Difference
@@ -315,13 +353,15 @@
Swap
Syntax Highlighting
Line Word Wrap
- Enable Block-Navigation
Open in Merge Tool
Show All Lines
Decrease Number of Visible Lines
Increase Number of Visible Lines
SELECT FILE TO VIEW CHANGES
Dir History
+ Has Local Changes
+ Mismatched with Upstream
+ Already Up-To-Date
Discard Changes
All local changes in working copy.
Changes:
@@ -329,6 +369,11 @@
Include untracked files
{0} changes will be discarded
You can't undo this action!!!
+ Drop Commit
+ Commit:
+ New HEAD:
+ Edit Branch's Description
+ Target:
Bookmark:
New Name:
Target:
@@ -343,6 +388,7 @@
Remote:
Fetch Remote Changes
Assume unchanged
+ Custom Action
Discard...
Discard {0} files...
Resolve Using ${0}$
@@ -398,6 +444,8 @@
Show only my locks
LFS Locks
Unlock
+ Unlock all of my locks
+ Are you sure you want to unlock all your locked files?
Force Unlock
Prune
Run `git lfs prune` to delete old LFS files from local storage
@@ -428,7 +476,7 @@
Go to previous tab
Create new tab
Open Preferences dialog
- Switch active workspace
+ Show workspace dropdown menu
Switch active tab
REPOSITORY
Commit staged changes
@@ -436,6 +484,7 @@
Stage all changes and commit
Fetch, starts directly
Dashboard mode (Default)
+ Open command palette
Commit search mode
Pull, starts directly
Push, starts directly
@@ -469,10 +518,12 @@
Target Branch:
Copy Link
Open in Browser
+ Commands
ERROR
NOTICE
- Workspaces
+ Open Repositories
Tabs
+ Workspaces
Merge Branch
Customize merge message
Into:
@@ -489,9 +540,11 @@
Select parent node for:
Name:
Git has NOT been configured. Please to go [Preferences] and configure it first.
+ Open
+ Default Editor (System)
Open Data Storage Directory
+ Open File
Open in Merge Tool
- Open with...
Optional.
Create New Tab
Bookmark
@@ -499,6 +552,8 @@
Close Other Tabs
Close Tabs to the Right
Copy Repository Path
+ Move to Workspace
+ Refresh
Repositories
Paste
{0} days ago
@@ -511,7 +566,6 @@
{0} months ago
{0} years ago
Yesterday
- Use 'Shift+Enter' to input a new line. 'Enter' is the hotkey of OK button
Preferences
AI
Analyze Diff Prompt
@@ -519,6 +573,7 @@
Generate Subject Prompt
Model
Name
+ Entered value is the name to load API key from ENV
Server
Enable Streaming
APPEARANCE
@@ -528,24 +583,32 @@
Default
Editor
Monospace Font
- Use monospace font only in text editor
Theme
Theme Overrides
+ Use auto-hide scrollbars
Use fixed tab width in titlebar
Use native window frame
DIFF/MERGE TOOL
+ Diff Arguments
+ Available variables: $LOCAL, $REMOTE
+ Merge Arguments
+ Available variables: $BASE, $LOCAL, $REMOTE, $MERGED
Install Path
Input path for diff/merge tool
Tool
GENERAL
Check for updates on startup
Date Format
+ Enable compact folders in changes tree
Language
History Commits
Show author time instead of commit time in graph
+ Show `LOCAL CHANGES` page by default
+ Show `CHANGES` tab in commit detail by default
Show children in the commit details
Show tags in commit graph
Subject Guide Length
+ Generate Github style default avatar
GIT
Enable Auto CRLF
Default Clone Dir
@@ -570,6 +633,8 @@
User's gpg signing key
INTEGRATION
SHELL/TERMINAL
+ Arguments
+ Please use '.' to indicate working directory
Path
Shell/Terminal
Prune Remote
@@ -581,8 +646,7 @@
Into:
Local Changes:
Discard
- Stash & Reapply
- Update all submodules
+ Stash & Reapply
Remote:
Pull (Fetch & Merge)
Use rebase instead of merge
@@ -602,6 +666,8 @@
Push to all remotes
Remote:
Tag:
+ Push to a NEW branch
+ Input name of the new remote branch:
Quit
Rebase Current Branch
Stash & reapply local changes
@@ -613,6 +679,7 @@
Repository URL:
Remote git repository URL
Copy URL
+ Custom Action
Delete...
Edit...
Fetch
@@ -638,6 +705,7 @@
CONTINUE
Custom Actions
No Custom Actions
+ Dashboard
Discard all changes
Open in File Browser
Search Branches/Tags/Submodules
@@ -652,6 +720,7 @@
Commit Date
Topologically
LOCAL BRANCHES
+ More options...
Navigate to HEAD
Create Branch
CLEAR NOTIFICATIONS
@@ -710,6 +779,7 @@
Patch has been saved successfully!
Scan Repositories
Root Dir:
+ Scan another custom directory
Check for Updates...
New version of this software is available:
Check for updates failed!
@@ -728,8 +798,9 @@
Upstream:
Copy SHA
Go to
- Squash Commits
- Into:
+ Squash HEAD into Parent
+ Fixup HEAD into Parent
+ Into:
SSH Private Key:
Private SSH key store path
START
@@ -759,6 +830,7 @@
SUBMODULES
Add Submodule
BRANCH
+ Branch
Relative Path
De-initialize
Fetch nested submodules
@@ -778,10 +850,15 @@
Update
URL
OK
- Copy Tag Name
- Copy Tag Message
+ TAGGER
+ TIME
+ Message
+ Name
+ Tagger
+ Copy Tag Name
Custom Action
Delete ${0}$...
+ Delete selected {0} tags...
Merge ${0}$ into ${1}$...
Push ${0}$...
Update Submodules
@@ -817,6 +894,8 @@
Ignore this file only
Amend
You can stage this file now.
+ Clear History
+ Are you sure you want to clear all commit message history? This action cannot be undone.
COMMIT
COMMIT & PUSH
Template/History
@@ -834,6 +913,7 @@
INCLUDE UNTRACKED FILES
NO RECENT INPUT MESSAGES
NO COMMIT TEMPLATES
+ No-Verify
Reset Author
SignOff
STAGED
@@ -849,6 +929,7 @@
WORKTREE
Copy Path
Lock
+ Open
Remove
Unlock
diff --git a/src/Resources/Locales/es_ES.axaml b/src/Resources/Locales/es_ES.axaml
index 9e0c08de0..0aa2d2483 100644
--- a/src/Resources/Locales/es_ES.axaml
+++ b/src/Resources/Locales/es_ES.axaml
@@ -5,6 +5,7 @@
Acerca de
Acerca de SourceGit
+ Notas de la versión (Release)
Cliente Git GUI de código abierto y gratuito
Agregar Archivo(s) Para Ignorar
Patrón:
@@ -22,7 +23,9 @@
Asistente OpenAI
RE-GENERAR
Usar OpenAI para generar mensaje de commit
- APLICAR CÓMO MENSAJE DE COMMIT
+ APLICAR COMO MENSAJE DE COMMIT
+ Ocultar SourceGit
+ Mostrar Todo
Aplicar Parche
Archivo del Parche:
Seleccionar archivo .patch para aplicar
@@ -51,16 +54,20 @@
Bisecting. ¿Es el HEAD actual bueno o malo?
Bueno
Saltar
- Bisecting. Marcar el commit actual cómo bueno o malo y revisar otro.
+ Bisecting. Marcar el commit actual como bueno o malo y revisar otro.
Blame
- ¡BLAME EN ESTE ARCHIVO NO SOPORTADO!
+ Blame sobre la Revisión Previa
+ ¡BLAME EN ESTE ARCHIVO NO SOPORTADO!
Checkout ${0}$...
Comparar con ${0}$
Comparar con Worktree
- Copiar Nombre de Rama
+ Copiar Nombre de la Rama
+ Crear PR...
+ Crear PR para upstream ${0}$...
Acción personalizada
Eliminar ${0}$...
Eliminar {0} ramas seleccionadas
+ Editar la descripción para ${0}$...
Fast-Forward a ${0}$
Fetch ${0}$ en ${1}$...
Git Flow - Finalizar ${0}$
@@ -72,13 +79,18 @@
Rebase ${0}$ en ${1}$...
Renombrar ${0}$...
Resetear ${0}$ a ${1}$...
+ Cambiar a ${0}$ (worktree)
Establecer Rama de Seguimiento...
Comparar Ramas
- LOCAL
+ {0} commit(s) adelante
+ {0} commit(s) adelante, {1} commit(s) detrás
+ {0} commit(s) detrás
+ Inválido
REMOTO
+ ESTADO
SEGUIMIENTO
URL
- ¡Upstream inválido!
+ WORKTREE
CANCELAR
Resetear a Revisión Padre
Resetear a Esta Revisión
@@ -96,8 +108,7 @@
Advertencia: Al hacer un checkout de commit, tu Head se separará
Cambios Locales:
Descartar
- Stash & Reaplicar
- Actualizar todos los submódulos
+ Stash & Reaplicar
Rama:
¡Tu HEAD actual contiene commit(s) que no están conectados a ningunas ramas/etiquetas! ¿Quieres continuar?
Checkout & Fast-Forward
@@ -131,6 +142,7 @@
SHA
Asunto
Acción personalizada
+ Eliminar Commit
Rebase interactivo
Eliminar...
Editar...
@@ -146,7 +158,8 @@
Revertir Commit
Reescribir
Guardar como Parche...
- Squash en Parent
+ Squash en el Padre
+ Arreglar en el Padre
CAMBIOS
archivo(s) modificado(s)
Buscar Cambios...
@@ -160,6 +173,9 @@
COMMITTER
Ver refs que contienen este commit
COMMIT ESTÁ CONTENIDO EN
+ Copiar Email
+ Copiar Nombre
+ Copiar Nombre & Email
Muestra solo los primeros 100 cambios. Ver todos los cambios en la pestaña CAMBIOS.
Clave:
MENSAJE
@@ -168,25 +184,41 @@
SHA
Firmante:
Abrir en Navegador
- Descripción
+ Ingresa el mensaje de commit. ¡Por favor usa una línea en blanco para separar el título y la descripción!
ASUNTO
- Introducir asunto del commit
Configurar Repositorio
PLANTILLA DE COMMIT
- Puedes usar ${files_num}, ${branch_name}, ${files} y ${files:N} donde N es el número máximo de rutas de archivo a la salida.
+ Parámetros incorporados:
+
+ ${branch_name} Nombre de la rama local actual.
+ ${files_num} Número de archivos modificados
+ ${files} Rutas de archivos modificados
+ ${files:N} Número N máximo de rutas de archivos modificados
+ ${pure_files} Cómo ${files}, pero solo nombres de archivos puros
+ ${pure_files:N} Cómo ${files:N}, pero sin carpetas
Contenido de la Plantilla:
Nombre de la Plantilla:
ACCIÓN PERSONALIZADA
Argumentos:
- Parámetros incorporados: ${REPO} - ruta del repositorio; ${BRANCH} - rama seleccionada; ${SHA} - hash del commit seleccionado; ${TAG} - etiqueta seleccionada
+ Parámetros incorporados:
+
+ ${REPO} Ruta del repositorio
+ ${REMOTE} Remoto seleccionado o Remoto de la rama seleccionada
+ ${BRANCH} Rama seleccionada, sin la parte ${REMOTE} para ramas remotas
+ ${BRANCH_FRIENDLY_NAME} Nombre amigable de la rama seleccionada, contiene la parte ${REMOTE} para ramas remotas
+ ${SHA} Hash del commit seleccionado
+ ${TAG} Etiqueta seleccionada
+ ${FILE} Archivo seleccionado, relativo a la raíz del repositorio
+ $1, $2 ... Valores de control de entrada
Archivo Ejecutable:
Controles de entrada:
Editar
- Puedes usar $1, $2 ... en argumentos, para valores de los controles de entrada
Nombre:
Alcance:
Rama
Commit
+ Archivo
+ Remoto
Repositorio
Etiqueta
Esperar la acción de salida
@@ -195,10 +227,12 @@
GIT
Fetch remotos automáticamente
Minuto(s)
+ Tipos de Commit Convencionales
Remoto por Defecto
Modo preferido de Merge
SEGUIMIENTO DE INCIDENCIAS
Añadir Regla de Ejemplo para Azure DevOps
+ Añadir Regla de "Gerrit Change-Id Commit"
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
@@ -216,8 +250,8 @@
Si el 'Servicio Preferido' está establecido, SourceGit sólo lo usará en este repositorio. De lo contrario, si hay más de un servicio disponible, se mostrará un menú de contexto para elegir uno.
Proxy HTTP
Proxy HTTP utilizado por este repositorio
- Nombre de Usuario
- Nombre de usuario para este repositorio
+ Nombre del Usuario
+ Nombre del usuario para este repositorio
Editar Controles de Acción Personalizados
Valor Comprobado:
Cuando sea comprobado, este valor será usado en argumentos de la línea de comandos
@@ -227,6 +261,7 @@
Etiqueta:
Opciones:
Usar '|' como delimitador para las opciones
+ La variables incorporadas ${REPO}, ${REMOTE}, ${BRANCH}, ${BRANCH_FRIENDLY_NAME}, ${SHA}, ${FILE}, y ${TAG} permanecen disponibles aquí
Tipo:
Espacios de Trabajo
Color
@@ -254,10 +289,9 @@
Checkout de la rama creada
Cambios Locales:
Descartar
- Stash & Reaplicar
+ Stash & Reaplicar
Nombre de la Nueva Rama:
Introduzca el nombre de la rama.
- Los espacios serán reemplazados con guiones.
Crear Rama Local
Sobrescribir la rama existente
Crear Etiqueta...
@@ -282,7 +316,10 @@
¡Estás a punto de eliminar una rama remota!
También eliminar la rama remota ${0}$
Eliminar Múltiples Ramas
- Estás intentando eliminar múltiples ramas a la vez. ¡Asegúrate de revisar antes de tomar acción!
+ Estás intentando eliminar múltiples ramas a la vez. ¡Asegúrate de comprobar dos veces antes de realizar esta acción!
+ Eliminar Múltiples Etiquetas
+ Eliminarlas de los remotos
+ Estás intentando eliminar múltiples etiquetas a la vez. ¡Asegúrate de comprobar dos veces antes de realizar esta acción!
Eliminar Remoto
Remoto:
Ruta:
@@ -301,6 +338,7 @@
Primera Diferencia
Ignorar Cambio de Espacios en Blanco
MEZCLAR
+ DIFERENCIA
LADO-A-LADO
DESLIZAR
Última Diferencia
@@ -319,13 +357,15 @@
Intercambiar
Resaltado de Sintaxis
Ajuste de Línea
- Habilitar navegación en bloque
Abrir en Herramienta de Merge
Mostrar Todas las Líneas
Disminuir Número de Líneas Visibles
Aumentar Número de Líneas Visibles
SELECCIONA ARCHIVO PARA VER CAMBIOS
Historial del directorio
+ Tiene Cambios Locales
+ No coincide con Upstream
+ Ya se encuentra actualizado
Descartar Cambios
Todos los cambios locales en la copia de trabajo.
Cambios:
@@ -333,6 +373,11 @@
Incluir archivos no rastreados
Total {0} cambios serán descartados
¡No puedes deshacer esta acción!
+ Eliminar Commit
+ Commit:
+ Nuevo HEAD:
+ Editar la descripción de la rama
+ Destino:
Marcador:
Nuevo Nombre:
Destino:
@@ -346,7 +391,8 @@
Fetch sin etiquetas
Remoto:
Fetch Cambios Remotos
- Asumir sin cambios
+ Asumir como sin cambios
+ Acción Personalizada
Descartar...
Descartar {0} archivos...
Resolver usando ${0}$
@@ -402,6 +448,8 @@
Mostrar solo mis bloqueos
Bloqueos LFS
Desbloquear
+ Desbloquear todos mis candados
+ ¿Estás seguro de querer desbloquear todos tus archivos bloqueados?
Forzar Desbloqueo
Prune
Ejecuta `git lfs prune` para eliminar archivos LFS antiguos del almacenamiento local
@@ -432,7 +480,7 @@
Ir a la página anterior
Crear nueva página
Abrir diálogo de preferencias
- Cambiar espacio de trabajo activo
+ Mostrar menú desplegable del espacio de trabajo
Cambiar página activa
REPOSITORIO
Commit cambios staged
@@ -440,6 +488,7 @@
Stage todos los cambios y commit
Fetch, empieza directamente
Modo Dashboard (Por Defecto)
+ Abrir paleta de comandos
Modo de búsqueda de commits
Pull, empieza directamente
Push, empieza directamente
@@ -473,10 +522,12 @@
Rama Objetivo:
Copiar Enlace
Abrir en el Navegador
+ Comandos
ERROR
AVISO
- Espacios de trabajo
+ Abrir Repositorios
Páginas
+ Espacios de trabajo
Merge Rama
Personalizar mensaje de merge
En:
@@ -493,9 +544,11 @@
Seleccionar nodo padre para:
Nombre:
Git NO ha sido configurado. Por favor, ve a [Preferencias] y configúralo primero.
+ Abrir
+ Editor por defecto (Sistema)
Abrir Directorio de Datos de la App
+ Abrir Archivo
Abrir en Herramienta de Merge
- Abrir Con...
Opcional.
Crear Nueva Página
Marcador
@@ -503,6 +556,8 @@
Cerrar Otras Pestañas
Cerrar Pestañas a la Derecha
Copiar Ruta del Repositorio
+ Mover al Espacio de trabajo
+ Actualizar
Repositorios
Pegar
Hace {0} días
@@ -515,7 +570,6 @@
Hace {0} meses
Hace {0} años
Ayer
- Usa 'Shift+Enter' para introducir una nueva línea. 'Enter' es el atajo del botón OK
Preferencias
OPEN AI
Analizar Diff Prompt
@@ -523,8 +577,9 @@
Generar Subject Prompt
Modelo
Nombre
+ El valor ingresado es el nombre de la clave API a cargar desde ENV
Servidor
- Activar Transmisión
+ Habilitar Transmisión
APARIENCIA
Fuente por defecto
Ancho de la Pestaña del Editor
@@ -532,28 +587,36 @@
Por defecto
Editor
Fuente Monospace
- Usar solo fuente monospace en el editor de texto
Tema
Sobreescritura de temas
+ Usar barras de desplazamiento que se oculten automáticamente
Usar ancho de pestaña fijo en la barra de título
Usar marco de ventana nativo
HERRAMIENTA DIFF/MERGE
+ Argumentos para Diff
+ Variables disponibles: $LOCAL, $REMOTE
+ Argumentos para Merge
+ Variables disponibles: $BASE, $LOCAL, $REMOTE, $MERGED
Ruta de instalación
Introducir ruta para la herramienta diff/merge
Herramienta
GENERAL
Buscar actualizaciones al iniciar
Formato de Fecha
+ Habilitar carpetas compactas en el árbol de cambios
Idioma
Commits en el historial
Mostrar hora del autor en lugar de la hora del commit en el gráfico
+ Mostrar la página `CAMBIOS LOCALES` por defecto
+ Mostrar pestaña de `CAMBIOS` en los detalles del commit por defecto
Mostrar hijos en los detalles de commit
Mostrar etiquetas en el gráfico de commit
Longitud de la guía del asunto
+ Generar avatar con estilo por defecto de Github
GIT
Habilitar Auto CRLF
Directorio de clonado por defecto
- Email de usuario
+ Email del usuario
Email global del usuario git
Habilitar --prune para fetch
Habilitar --ignore-cr-at-eol en diff
@@ -561,7 +624,7 @@
Ruta de instalación
Habilitar verificación HTTP SSL
Usar git-credential-libsecret en lugar de git-credential-manager
- Nombre de usuario
+ Nombre del usuario
Nombre global del usuario git
Versión de Git
FIRMA GPG
@@ -574,6 +637,8 @@
Clave de firma gpg del usuario
INTEGRACIÓN
SHELL/TERMINAL
+ Argumentos
+ Por favor utiliza '.' para indicar el directorio de trabajo
Ruta
Shell/Terminal
Podar Remoto
@@ -585,8 +650,7 @@
En:
Cambios Locales:
Descartar
- Stash & Reaplicar
- Actualizar todos los submódulos
+ Stash & Reaplicar
Remoto:
Pull (Fetch & Merge)
Usar rebase en lugar de merge
@@ -606,6 +670,8 @@
Push a todos los remotos
Remoto:
Etiqueta:
+ Push a una NUEVA rama
+ Nombre de entrada de la nueva rama remota:
Salir
Rebase Rama Actual
Stash & reaplicar cambios locales
@@ -617,6 +683,7 @@
URL del Repositorio:
URL del repositorio git remoto
Copiar URL
+ Acción Personalizada
Borrar...
Editar...
Fetch
@@ -642,6 +709,7 @@
CONTINUAR
Acciones Personalizadas
No hay ninguna Acción Personalizada
+ Dashboard
Descartar todos los cambios
Abrir en el Explorador
Buscar Ramas/Etiquetas/Submódulos
@@ -656,6 +724,7 @@
Fecha de Commit
Topológicamente
RAMAS LOCALES
+ Más opciones...
Navegar a HEAD
Crear Rama
LIMPIAR NOTIFICACIONES
@@ -714,6 +783,7 @@
¡El parche se ha guardado exitosamente!
Escanear Repositorios
Directorio Raíz:
+ Escanear otro directorio personalizado
Buscar Actualizaciones...
Nueva versión de este software disponible:
¡Error al buscar actualizaciones!
@@ -732,8 +802,9 @@
Upstream:
Copiar SHA
Ir a
- Squash Commits
- En:
+ Squash HEAD en el Padre
+ Fixup HEAD en el Padre
+ En:
Clave Privada SSH:
Ruta de almacenamiento de la clave privada SSH
INICIAR
@@ -763,6 +834,7 @@
SUBMÓDULOS
Añadir Submódulo
RAMA
+ Rama
Ruta Relativa
Desinicializar Submódulo
Fetch submódulos anidados
@@ -782,10 +854,15 @@
Actualizar
URL
OK
- Copiar Nombre de la Etiqueta
- Copiar Mensaje de la Etiqueta
+ ETIQUETADOR
+ HORA
+ Mensaje
+ Nombre
+ Etiquetador
+ Copiar Nombre de la Etiqueta
Acción Personalizada
Eliminar ${0}$...
+ Eliminar {0} etiquetas seleccionadas...
Merge ${0}$ en ${1}$...
Push ${0}$...
Actualizar Submódulos
@@ -821,6 +898,8 @@
Ignorar solo este archivo
Enmendar
Puedes hacer stage a este archivo ahora.
+ Limpiar Historial
+ ¿Estás seguro de querer limpiar todo el historial de los mensajes de commit? Esta acción no se puede deshacer.
COMMIT
COMMIT & PUSH
Plantilla/Historias
@@ -838,6 +917,7 @@
INCLUIR ARCHIVOS NO RASTREADOS
NO HAY MENSAJES DE ENTRADA RECIENTES
NO HAY PLANTILLAS DE COMMIT
+ Sin verificar
Restablecer Autor
Firmar
STAGED
@@ -846,13 +926,14 @@
UNSTAGED
STAGE
STAGE TODO
- VER ASSUME UNCHANGED
+ VER ASUMIR COMO SIN CAMBIOS
Plantilla: ${0}$
ESPACIO DE TRABAJO:
Configura Espacios de Trabajo...
WORKTREE
Copiar Ruta
Bloquear
+ Abrir
Eliminar
Desbloquear
diff --git a/src/Resources/Locales/fr_FR.axaml b/src/Resources/Locales/fr_FR.axaml
index e5e443ea1..5f0c6f109 100644
--- a/src/Resources/Locales/fr_FR.axaml
+++ b/src/Resources/Locales/fr_FR.axaml
@@ -5,7 +5,11 @@
À propos
À propos de SourceGit
+ Notes de Version
Client Git Open Source et Gratuit
+ Ajouter le(s) Fichier(s) à Ignorer
+ Modèle :
+ Fichier de Stockage :
Ajouter un Worktree
Emplacement :
Chemin vers ce worktree. Relatif supporté.
@@ -20,6 +24,8 @@
RE-GÉNÉRER
Utiliser l'IA pour générer un message de commit
APPLIQUER COMME MESSAGE DE COMMIT
+ Masquer SourceGit
+ Tout Afficher
Appliquer
Fichier de patch :
Selectionner le fichier .patch à appliquer
@@ -36,16 +42,28 @@
Révision :
Archiver
SourceGit Askpass
+ Saisir la phrase secrète :
FICHIERS PRÉSUMÉS INCHANGÉS
PAS DE FICHIERS PRÉSUMÉS INCHANGÉS
+ Charger l'Image...
Rafraîchir
FICHIER BINAIRE NON SUPPORTÉ !!!
+ Bisect
+ Annuler
+ Mauvais
+ Bisect en cours. Le HEAD actuel est-il bon ou mauvais ?
+ Bon
+ Passer
+ Bisect en cours. Marquer le commit actuel comme bon ou mauvais et en récupérer un autre.
Blâme
- LE BLÂME SUR CE FICHIER N'EST PAS SUPPORTÉ!!!
+ Blâmer sur la révision précédente
+ LE BLÂME SUR CE FICHIER N'EST PAS SUPPORTÉ!!!
Récupérer ${0}$...
Comparer avec ${0}$
Comparer avec le worktree
Copier le nom de la branche
+ Créer une PR...
+ Créer une PR pour l'upstream ${0}$...
Action personnalisée
Supprimer ${0}$...
Supprimer {0} branches sélectionnées
@@ -59,9 +77,19 @@
Pousser ${0}$
Rebaser ${0}$ sur ${1}$...
Renommer ${0}$...
+ Réinitialiser ${0}$ sur ${1}$...
+ Basculer vers ${0}$ (worktree)
Définir la branche de suivi...
Comparer les branches
- Branche en amont invalide!
+ {0} commit(s) en avance
+ {0} commit(s) en avance, {1} commit(s) en retard
+ {0} commit(s) en retard
+ Invalide
+ DISTANT
+ STATUT
+ SUIVI
+ URL
+ WORKTREE
ANNULER
Réinitialiser à la révision parente
Réinitialiser à cette révision
@@ -70,14 +98,20 @@
Afficher comme liste de dossiers/fichiers
Afficher comme liste de chemins
Afficher comme arborescence
+ Changer l'URL du sous-module
+ Sous-module :
+ URL :
Récupérer la branche
Récupérer ce commit
Commit :
Avertissement: une récupération vers un commit aboutiera vers un HEAD détaché
Changements locaux :
Annuler
- Mettre en stash et réappliquer
+ Mettre en stash et réappliquer
Branche :
+ Votre HEAD actuel contient un ou plusieurs commits non connectés à une branche/tag ! Voulez-vous continuer ?
+ Récupérer & Fast-Forward
+ Fast-Forward vers :
Cherry-Pick de ce commit
Ajouter la source au message de commit
Commit :
@@ -101,15 +135,32 @@
Cherry-Pick ...
Comparer avec HEAD
Comparer avec le worktree
+ Auteur
+ Message
+ Committer
SHA
+ Sujet
Action personnalisée
+ Supprimer le Commit
+ Rebase Interactif
+ Supprimer...
+ Modifier...
+ Fixup dans le Parent...
+ Rebaser Interactivement ${0}$ sur ${1}$
+ Reformuler...
+ Squash dans le Parent...
Fusionner dans ${0}$
Fusionner ...
+ Pousser ${0}$ vers ${1}$
+ Rebaser ${0}$ sur ${1}$
+ Réinitialiser ${0}$ sur ${1}$
Annuler le commit
Reformuler
Enregistrer en tant que patch...
- Squash dans le parent
+ Squash dans le Parent
+ Fixup dans le Parent
CHANGEMENTS
+ fichier(s) modifié(s)
Rechercher les changements...
FICHIERS
Fichier LFS
@@ -121,35 +172,65 @@
COMMITTER
Vérifier les références contenant ce commit
LE COMMIT EST CONTENU PAR
+ Copier l'E-mail
+ Copier le Nom
+ Copier le Nom & l'E-mail
Afficher seulement les 100 premiers changements. Voir tous les changements dans l'onglet CHANGEMENTS.
+ Clé :
MESSAGE
PARENTS
REFS
SHA
+ Signataire :
Ouvrir dans le navigateur
- Description
- Entrez le message du commit
+ SUJET
Configurer le dépôt
MODÈLE DE COMMIT
+ Paramètres intégrés :
+
+ ${branch_name} Nom de la branche locale actuelle.
+ ${files_num} Nombre de fichiers modifiés
+ ${files} Chemins des fichiers modifiés
+ ${files:N} Nombre maximum N de chemins de fichiers modifiés
+ ${pure_files} Comme ${files}, mais uniquement les noms de fichiers purs
+ ${pure_files:N} Comme ${files:N}, mais sans les dossiers
Contenu de modèle:
Nom de modèle:
ACTION PERSONNALISÉE
Arguments :
+ Paramètres intégrés :
+
+ ${REPO} Chemin du dépôt
+ ${REMOTE} Dépôt distant sélectionné ou dépôt distant de la branche sélectionnée
+ ${BRANCH} Branche sélectionnée, sans la partie ${REMOTE} pour les branches distantes
+ ${BRANCH_FRIENDLY_NAME} Nom d'affichage de la branche sélectionnée, contient la partie ${REMOTE} pour les branches distantes
+ ${SHA} Hash du commit sélectionné
+ ${TAG} Tag sélectionné
+ ${FILE} Fichier sélectionné, relatif à la racine du dépôt
+ $1, $2 ... Paramètres d'entrée utilisateur
Fichier exécutable :
+ Paramètres d'entrée utilisateur :
+ Modifier
Nom :
Portée :
Branche
Commit
- Repository
+ Fichier
+ Remote
+ Dépôt
+ Tag
Attendre la fin de l'action
Adresse e-mail
Adresse e-mail
GIT
Fetch les dépôts distants automatiquement
minute(s)
+ Types de commit conventionnels
Dépôt par défaut
+ Mode de fusion préféré
SUIVI DES PROBLÈMES
Ajouter une règle d'exemple Azure DevOps
+ Ajouter une règle de commit Gerrit Change-Id
Ajouter une règle d'exemple Gitee
Ajouter une règle d'exemple pour Pull Request Gitee
Ajouter une règle d'exemple GitHub
@@ -159,6 +240,7 @@
Nouvelle règle
Issue Regex Expression:
Nom de règle :
+ Partager cette règle dans le fichier .issuetracker
URL résultant:
Veuillez utiliser $1, $2 pour accéder aux valeurs des groupes regex.
IA
@@ -168,10 +250,27 @@
Proxy HTTP utilisé par ce dépôt
Nom d'utilisateur
Nom d'utilisateur pour ce dépôt
+ Modifier les Contrôles d'Action Personnalisée
+ Valeur Cochée :
+ Lorsque cochée, cette valeur sera utilisée dans les arguments de la ligne de commande
+ Description :
+ Défaut :
+ Est un dossier :
+ Libellé :
+ Options :
+ Utiliser '|' comme délimiteur pour les options
+ Les variables intégrées ${REPO}, ${REMOTE}, ${BRANCH}, ${BRANCH_FRIENDLY_NAME}, ${SHA}, ${FILE}, et ${TAG} restent disponibles ici
+ Type :
Espaces de travail
Couleur
Nom
Restaurer les onglets au démarrage
+ CONTINUER
+ Commit vide détecté ! Voulez-vous continuer (--allow-empty) ?
+ TOUT INDEXER & COMMIT
+ Commit vide détecté ! Voulez-vous continuer (--allow-empty) ou tout indexer puis commit ?
+ Redémarrage Requis
+ Vous devez redémarrer cette application pour appliquer les changements.
Assistant Commits Conventionnels
Changement Radical :
Incident Clos :
@@ -188,11 +287,11 @@
Récupérer la branche créée
Changements locaux :
Rejeter
- Stash & Réappliquer
+ 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
+ Écraser la branche existante
Créer un tag...
Nouveau tag à :
Signature GPG
@@ -207,12 +306,18 @@
léger
Maintenir Ctrl pour commencer directement
Couper
+ Désinitialiser le sous-module
+ Forcer la désinitialisation même s'il contient des modifications locales.
+ Sous-module :
Supprimer la branche
Branche :
Vous êtes sur le point de supprimer une branche distante !!!
Supprimer également la branche distante ${0}$
Supprimer plusieurs branches
Vous essayez de supprimer plusieurs branches à la fois. Assurez-vous de revérifier avant de procéder !
+ Supprimer plusieurs tags
+ Les supprimer des dépôts distants
+ Vous essayez de supprimer plusieurs tags à la fois. Assurez-vous de bien vérifier avant d'agir !
Supprimer Remote
Remote :
Chemin:
@@ -230,36 +335,52 @@
Mode de fichier changé
Première différence
Ignorer les changements d'espaces
+ FUSIONNER
+ DIFFÉRENCE
+ CÔTE À CÔTE
+ BALAYER
Dernière différence
CHANGEMENT D'OBJET LFS
+ NOUVEAU
Différence suivante
PAS DE CHANGEMENT OU SEULEMENT EN FIN DE LIGNE
+ ANCIEN
Différence précédente
Enregistrer en tant que patch
Afficher les caractères invisibles
Diff côte-à-côte
SOUS-MODULE
+ SUPPRIMÉ
NOUVEAU
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
Augmente le nombre de ligne visibles
SÉLECTIONNEZ UN FICHIER POUR VOIR LES CHANGEMENTS
+ Historique du Répertoire
+ A des Modifications Locales
+ Divergence avec le Dépôt Distant
+ Déjà à jour
Rejeter les changements
Tous les changements dans la copie de travail.
Changements :
Inclure les fichiers ignorés
+ Inclure les fichiers non suivis
{0} changements seront rejetés
Vous ne pouvez pas annuler cette action !!!
+ Supprimer le Commit
+ Commit :
+ Nouveau HEAD :
Signet :
Nouveau nom :
Cible :
Éditer le groupe sélectionné
Éditer le dépôt sélectionné
+ Cible :
+ Ce dépôt
Fetch
Fetch toutes les branches distantes
Outrepasser les vérifications de refs
@@ -290,6 +411,8 @@
FLOW - Terminer Hotfix
FLOW - Terminer Release
Cible:
+ Pousser vers le(s) dépôt(s) distant(s) après avoir terminé
+ Squash lors de la fusion
Hotfix:
Hotfix Prefix:
Initialiser Git-Flow
@@ -320,6 +443,8 @@
Afficher seulement mes verrous
Verrous LFS
Déverouiller
+ Déverrouiller tous mes verrous
+ Êtes-vous sûr de vouloir déverrouiller tous vos fichiers verrouillés ?
Forcer le déverouillage
Elaguer
Lancer `git lfs prune` pour supprimer les anciens fichier LFS du stockage local
@@ -350,12 +475,14 @@
Aller à la page précédente
Créer une nouvelle page
Ouvrir le dialogue des préférences
+ Changer d'onglet actif
DÉPÔT
Commit les changements de l'index
Commit et pousser les changements de l'index
Ajouter tous les changements et commit
Fetch, démarre directement
Mode tableau de bord (Défaut)
+ Ouvrir la palette de commandes
Recherche de commit
Pull, démarre directement
Push, démarre directement
@@ -367,6 +494,7 @@
Fermer le panneau de recherche
Trouver la prochaine correspondance
Trouver la correspondance précédente
+ Ouvrir avec l'outil externe de diff/fusion
Ouvrir le panneau de recherche
Rejeter
Indexer
@@ -384,12 +512,18 @@
Rebase interactif
Stash & réappliquer changements locaux
Sur :
+ Glisser-déposer pour réorganiser les commits
Branche cible :
Copier le lien
Ouvrir dans le navigateur
+ Commandes
ERREUR
NOTICE
+ Ouvrir des dépôts
+ Onglets
+ Espaces de travail
Merger la branche
+ Personnaliser le message de fusion
Dans :
Option de merge:
Source:
@@ -397,13 +531,17 @@
Commit tous les changement
Stratégie:
Cibles:
+ Déplacer le sous-module
+ Déplacer vers :
+ Sous-module :
Déplacer le noeud du repository
Sélectionnier le noeud parent pour :
Nom :
Git n'a PAS été configuré. Veuillez d'abord le faire dans le menu Préférence.
+ Ouvrir
+ Éditeur par défaut (Système)
Ouvrir le dossier AppData
Ouvrir dans l'outil de fusion
- Ouvrir avec...
Optionnel.
Créer un nouvel onglet
Bookmark
@@ -423,7 +561,6 @@
il y a {0} mois
il y a {0} ans
Hier
- Utiliser 'Maj+Entrée' pour insérer une nouvelle ligne. 'Entrée' est la touche pour valider
Préférences
IA
Analyser Diff Prompt
@@ -431,6 +568,7 @@
Générer le sujet de Prompt
Modèle
Nom
+ La valeur saisie est le nom pour charger la clé API depuis l'ENV
Serveur
Activer le streaming
APPARENCE
@@ -440,9 +578,9 @@
Défaut
Éditeur
Police monospace
- N'utiliser que des polices monospace pour l'éditeur de texte
Thème
Dérogations de thème
+ Utiliser les barres de défilement masquées automatiquement
Utiliser des onglets de taille fixe dans la barre de titre
Utiliser un cadre de fenêtre natif
OUTIL DIFF/MERGE
@@ -452,21 +590,27 @@
GÉNÉRAL
Vérifier les mises à jour au démarrage
Format de date
+ Activer les dossiers compacts dans l'arborescence des changements
Language
Historique de commits
Afficher l'heure de l'auteur au lieu de l'heure de validation dans le graphique
+ Afficher la page 'CHANGEMENTS LOCAUX' par défaut
+ Afficher l'onglet 'CHANGEMENTS' dans les détails du commit par défaut
Afficher les enfants dans les détails du commit
Afficher les tags dans le graphique des commits
Guide de longueur du sujet
+ Générer un avatar par défaut de style GitHub
GIT
Activer auto CRLF
Répertoire de clônage par défaut
E-mail utilsateur
E-mail utilsateur global
Activer --prune pour fetch
+ Activer --ignore-cr-at-eol dans la diff
Cette application requière Git (>= 2.25.1)
Chemin d'installation
Activer la vérification HTTP SSL
+ Utiliser git-credential-libsecret au lieu de git-credential-manager
Nom d'utilisateur
Nom d'utilisateur global
Version de Git
@@ -491,7 +635,7 @@
Dans :
Changements locaux :
Rejeter
- Stash & Réappliquer
+ Stash & Réappliquer
Dépôt distant :
Pull (Fetch & Merge)
Utiliser rebase au lieu de merge
@@ -499,7 +643,10 @@
Assurez-vous que les submodules ont été poussés
Poussage forcé
Branche locale :
+ NOUVEAU
Dépôt distant :
+ Révision :
+ Pousser la Révision vers le Dépôt Distant
Pousser les changements vers le dépôt distant
Branche distante :
Définir comme branche de suivi
@@ -508,6 +655,8 @@
Pousser tous les dépôts distants
Dépôt distant :
Tag :
+ Pousser vers une NOUVELLE branche
+ Saisir le nom de la nouvelle branche distante :
Quitter
Rebase la branche actuelle
Stash & réappliquer changements locaux
@@ -519,6 +668,7 @@
URL du repository :
URL du dépôt distant
Copier l'URL
+ Action personnalisée
Supprimer...
Editer...
Fetch
@@ -527,19 +677,24 @@
Confirmer la suppression du Worktree
Activer l'option `--force`
Cible :
- la branche
+ Renommer la branche
Nouveau nom :
Nom unique pour cette branche
Branche :
ABORT
Fetch automatique des changements depuis les dépôts...
+ Trier
+ Par date du Committer
+ Par Nom
Nettoyage(GC & Elaguage)
Lancer `git gc` pour ce repository.
Tout effacer
+ Nettoyer
Configurer ce repository
CONTINUER
Actions personnalisées
Pas d'actions personnalisées
+ Tableau de bord
Rejeter tous les changements
Ouvrir dans l'explorateur de fichiers
Rechercher Branches/Tags/Submodules
@@ -554,9 +709,11 @@
Date du commit
Topologiquement
BRANCHES LOCALES
+ Plus d'options...
Naviguer vers le HEAD
Créer une branche
EFFACER LES NOTIFICATIONS
+ Surligner uniquement la branche actuelle
Ouvrir dans {0}
Ouvrir dans un outil externe
DEPOTS DISTANTS
@@ -564,9 +721,16 @@
Rechercher un commit
Auteur
Committer
+ Contenu
Message
+ Chemin
SHA
Branche actuelle
+ Commits décorés uniquement
+ Premier parent uniquement
+ AFFICHER LES FLAGS
+ Afficher les commits perdus
+ Afficher les sous-modules en tant qu'arbre
Voir les Tags en tant qu'arbre
PASSER
Statistiques
@@ -579,6 +743,9 @@
Par nom
Trier
Ouvrir dans un terminal
+ Utiliser l'heure relative
+ Voir les Logs
+ Visiter '{0}' dans le navigateur
WORKTREES
AJOUTER WORKTREE
ELAGUER
@@ -587,6 +754,9 @@
Reset Mode:
Déplacer vers :
Branche actuelle :
+ Réinitialiser la Branche (Sans Récupération)
+ Déplacer Vers :
+ Branche :
Ouvrir dans l'explorateur de fichier
Annuler le Commit
Commit :
@@ -598,6 +768,7 @@
Le patch a été sauvegardé !
Analyser les repositories
Dossier racine :
+ Scanner un autre répertoire personnalisé
Rechercher des mises à jour...
Une nouvelle version du logiciel est disponible :
La vérification de mise à jour à échouée !
@@ -605,14 +776,17 @@
Passer cette version
Mise à jour du logiciel
Il n'y a pas de mise à jour pour le moment.
+ Définir la Branche du Sous-module
+ Sous-module :
+ Actuel :
+ Changer pour :
+ Optionnel. Défini par défaut si vide.
Définir la branche suivie
Branche:
Retirer la branche amont
En amont:
Copier le SHA
Aller à
- Squash les commits
- Dans :
Clé privée SSH :
Chemin du magasin de clés privées SSH
START
@@ -620,10 +794,12 @@
Inclure les fichiers non-suivis
Message :
Optionnel. Information de ce stash
+ Mode :
Seulement les changements indexés
Les modifications indexées et non-indexées des fichiers sélectionnés seront stockées!!!
Stash les changements locaux
Appliquer
+ Copier le Message
Effacer
Sauver comme Patch...
Effacer le Stash
@@ -639,14 +815,36 @@
COMMITS:
SOUS-MODULES
Ajouter un sous-module
+ BRANCHE
+ Branche
Chemin relatif
+ Désinitialiser
Fetch les sous-modules imbriqués
+ Historique
+ Déplacer Vers
Ouvrir le dépôt de sous-module
+ Chemin relatif :
+ Dossier relatif pour stocker ce module.
Supprimer le sous-module
+ Définir la Branche
+ Changer l'URL
+ STATUT
+ modifié
+ non initialisé
+ révision changée
+ non fusionné
+ Mettre à jour
+ URL
OK
- Copier le nom du Tag
- Copier le message du tag
+ TAGUEUR
+ HEURE
+ Message
+ Nom
+ Tagueur
+ Copier le nom du tag
+ Action personnalisée
Supprimer ${0}$...
+ Supprimer les {0} tags sélectionnés...
Fusionner ${0}$ dans ${1}$...
Pousser ${0}$...
Actualiser les sous-modules
@@ -654,7 +852,12 @@
Initialiser au besoin
Récursivement
Sous-module :
+ Mettre à jour vers la branche de suivi distante du sous-module
URL :
+ Logs
+ TOUT EFFACER
+ Copier
+ Supprimer
Avertissement
Page d'accueil
Créer un groupe
@@ -673,21 +876,32 @@
Git Ignore
Ignorer tous les *{0} fichiers
Ignorer *{0} fichiers dans le même dossier
+ Ignorer les fichiers non suivis dans ce dossier
N'ignorer que ce fichier
Amender
Vous pouvez indexer ce fichier.
+ Effacer l'historique
+ Êtes-vous sûr de vouloir effacer tout l'historique des messages de commit ? Cette action est irréversible.
COMMIT
COMMIT & POUSSER
Modèles/Historiques
Trigger click event
Commit (Modifier)
Indexer tous les changements et commit
+ Vous êtes en train de créer un commit sur un HEAD détaché. Voulez-vous continuer ?
+ Vous avez indexé {0} fichier(s) mais seulement {1} fichier(s) sont affichés ({2} fichiers sont filtrés). Voulez-vous continuer ?
CONFLITS DÉTECTÉS
+ OUVRIR L'OUTIL DE FUSION EXTERNE
+ OUVRIR TOUS LES CONFLITS DANS L'OUTIL DE FUSION EXTERNE
LES CONFLITS DE FICHIER SONT RÉSOLUS
+ UTILISER LES MIENS
+ UTILISER LES LEURS
INCLURE LES FICHIERS NON-SUIVIS
PAS DE MESSAGE D'ENTRÉE RÉCENT
PAS DE MODÈLES DE COMMIT
- SignOff
+ No-Verify
+ Réinitialiser l'Auteur
+ Signer
INDEXÉ
RETIRER DE L'INDEX
RETIRER TOUT DE L'INDEX
@@ -701,6 +915,7 @@
WORKTREE
Copier le chemin
Verrouiller
+ Ouvrir
Supprimer
Déverrouiller
diff --git a/src/Resources/Locales/id_ID.axaml b/src/Resources/Locales/id_ID.axaml
new file mode 100644
index 000000000..77eb5cc57
--- /dev/null
+++ b/src/Resources/Locales/id_ID.axaml
@@ -0,0 +1,894 @@
+
+
+
+
+
+ Tentang
+ Tentang SourceGit
+ Klien Git GUI Opensource & Gratis
+ Tambahkan Berkas ke Abaikan
+ Pola:
+ Berkas Penyimpanan:
+ Tambah Worktree
+ Lokasi:
+ Jalur untuk worktree ini. Jalur relatif didukung.
+ Nama Branch:
+ Opsional. Standar adalah nama folder tujuan.
+ Track Branch:
+ Track remote branch
+ Yang Akan Di-Checkout:
+ Buat Branch Baru
+ Branch Yang Ada
+ Asisten AI
+ BUAT ULANG
+ Gunakan AI untuk membuat pesan commit
+ TERAPKAN SEBAGAI PESAN COMMIT
+ Sembunyikan SourceGit
+ Tampilkan Semua
+ Patch
+ Berkas Patch:
+ Pilih berkas .patch untuk diterapkan
+ Abaikan perubahan whitespace
+ Terapkan Patch
+ Whitespace:
+ Terapkan Stash
+ Hapus setelah diterapkan
+ Pulihkan perubahan indeks
+ Stash:
+ Arsip...
+ Simpan Arsip Ke:
+ Pilih jalur berkas arsip
+ Revisi:
+ Arsip
+ SourceGit Askpass
+ Masukkan passphrase:
+ BERKAS DIASUMSIKAN TIDAK BERUBAH
+ TIDAK ADA BERKAS YANG DIASUMSIKAN TIDAK BERUBAH
+ Muat Gambar...
+ Segarkan
+ BERKAS BINARY TIDAK DIDUKUNG!!!
+ Bisect
+ Batalkan
+ Buruk
+ Bisect berjalan. Apakah HEAD saat ini baik atau buruk?
+ Baik
+ Lewati
+ Bisect berjalan. Tandai commit saat ini sebagai baik atau buruk dan checkout yang lain.
+ Blame
+ BLAME PADA BERKAS INI TIDAK DIDUKUNG!!!
+ Checkout ${0}$...
+ Bandingkan dengan ${0}$
+ Bandingkan dengan Worktree
+ Salin Nama Branch
+ Aksi Kustom
+ Hapus ${0}$...
+ Hapus {0} branch yang dipilih
+ Fast-Forward ke ${0}$
+ Fetch ${0}$ ke ${1}$...
+ Git Flow - Selesaikan ${0}$
+ Merge ${0}$ ke ${1}$...
+ Merge {0} branch yang dipilih ke saat ini
+ Pull ${0}$
+ Pull ${0}$ ke ${1}$...
+ Push ${0}$
+ Rebase ${0}$ pada ${1}$...
+ Ganti Nama ${0}$...
+ Reset ${0}$ ke ${1}$...
+ Pindah ke ${0}$ (worktree)
+ Atur Tracking Branch...
+ Perbandingan Branch
+ {0} commit di depan
+ {0} commit di depan, {1} commit di belakang
+ {0} commit di belakang
+ Tidak Valid
+ REMOTE
+ STATUS
+ TRACKING
+ URL
+ WORKTREE
+ BATAL
+ Reset ke Revisi Parent
+ Reset ke Revisi Ini
+ Buat pesan commit
+ UBAH MODE TAMPILAN
+ Tampilkan sebagai Daftar Berkas dan Direktori
+ Tampilkan sebagai Daftar Jalur
+ Tampilkan sebagai Pohon Sistem Berkas
+ Ubah URL Submodule
+ Submodule:
+ URL:
+ Checkout Branch
+ Checkout Commit
+ Commit:
+ Peringatan: Dengan melakukan checkout commit, Head akan terlepas
+ Perubahan Lokal:
+ Buang
+ Stash & Terapkan Ulang
+ Branch:
+ HEAD saat ini mengandung commit yang tidak terhubung ke branch/tag manapun! Lanjutkan?
+ Checkout & Fast-Forward
+ Fast-Forward ke:
+ Cherry Pick
+ Tambahkan sumber ke pesan commit
+ Commit:
+ Commit semua perubahan
+ Mainline:
+ Biasanya Anda tidak dapat cherry-pick merge karena tidak tahu sisi mana dari merge yang dianggap mainline. Opsi ini memungkinkan cherry-pick untuk memutar ulang perubahan relatif terhadap parent yang ditentukan.
+ Hapus Stash
+ Anda akan menghapus semua stash. Lanjutkan?
+ Clone Repositori Remote
+ Parameter Tambahan:
+ Argumen tambahan untuk clone repositori. Opsional.
+ Nama Lokal:
+ Nama repositori. Opsional.
+ Folder Parent:
+ Inisialisasi & perbarui submodule
+ URL Repositori:
+ TUTUP
+ Editor
+ Checkout Commit
+ Cherry-Pick Commit
+ Cherry-Pick ...
+ Bandingkan dengan HEAD
+ Bandingkan dengan Worktree
+ Author
+ Pesan
+ Committer
+ SHA
+ Subjek
+ Aksi Kustom
+ Interactive Rebase
+ Drop...
+ Edit...
+ Fixup ke Parent...
+ Rebase ${0}$ pada ${1}$ secara Interaktif
+ Reword...
+ Squash ke Parent...
+ Merge ke ${0}$
+ Merge ...
+ Push ${0}$ ke ${1}$
+ Rebase ${0}$ pada ${1}$
+ Reset ${0}$ ke ${1}$
+ Revert Commit
+ Reword
+ Simpan sebagai Patch...
+ Squash ke Parent
+ Fixup ke Parent
+ PERUBAHAN
+ berkas berubah
+ Cari Perubahan...
+ BERKAS
+ Berkas LFS
+ Cari Berkas...
+ Submodule
+ INFORMASI
+ AUTHOR
+ CHILDREN
+ COMMITTER
+ Periksa ref yang mengandung commit ini
+ COMMIT TERKANDUNG DALAM
+ Salin Email
+ Salin Nama
+ Salin Nama & Email
+ Menampilkan hanya 100 perubahan pertama. Lihat semua perubahan di tab PERUBAHAN.
+ Kunci:
+ PESAN
+ PARENTS
+ REFS
+ SHA
+ Penanda Tangan:
+ Buka di Browser
+ SUBJEK
+ Konfigurasi Repositori
+ TEMPLATE COMMIT
+ Konten Template:
+ Nama Template:
+ AKSI KUSTOM
+ Argumen:
+ Parameter bawaan:
+
+ ${REPO} Jalur repositori
+ ${REMOTE} Remote yang dipilih atau remote dari branch yang dipilih
+ ${BRANCH} Branch yang dipilih, tanpa bagian ${REMOTE} untuk remote branch
+ ${BRANCH_FRIENDLY_NAME} Nama ramah dari branch yang dipilih, mengandung bagian ${REMOTE} untuk remote branch
+ ${SHA} Hash commit yang dipilih
+ ${TAG} Tag yang dipilih
+ ${FILE} Berkas yang dipilih, relatif terhadap akar repositori
+ $1, $2 ... Nilai kontrol input
+ Berkas Eksekusi:
+ Kontrol Input:
+ Sunting
+ Nama:
+ Lingkup:
+ Branch
+ Commit
+ Berkas
+ Remote
+ Repositori
+ Tag
+ Tunggu aksi selesai
+ Alamat Email
+ Alamat email
+ GIT
+ Fetch remote secara otomatis
+ Menit
+ Remote Default
+ Mode Merge Pilihan
+ ISSUE TRACKER
+ Tambah Aturan Azure DevOps
+ Tambah Aturan Gerrit Change-Id Commit
+ Tambah Aturan Gitee Issue
+ Tambah Aturan Gitee Pull Request
+ Tambah Aturan GitHub
+ Tambah Aturan GitLab Issue
+ Tambah Aturan GitLab Merge Request
+ Tambah Aturan Jira
+ Aturan Baru
+ Ekspresi Regex Issue:
+ Nama Aturan:
+ Bagikan aturan ini di berkas .issuetracker
+ URL Hasil:
+ Gunakan $1, $2 untuk mengakses nilai grup regex.
+ AI
+ Layanan Pilihan:
+ Jika 'Layanan Pilihan' diatur, SourceGit hanya akan menggunakannya di repositori ini. Jika tidak, jika ada lebih dari satu layanan yang tersedia, menu konteks untuk memilih salah satunya akan ditampilkan.
+ Proksi HTTP
+ Proksi HTTP yang digunakan oleh repositori ini
+ Nama Pengguna
+ Nama pengguna untuk repositori ini
+ Sunting Kontrol Aksi Kustom
+ Nilai Tercentang:
+ Saat dicentang, nilai ini akan digunakan dalam argumen command-line
+ Deskripsi:
+ Default:
+ Adalah Folder:
+ Label:
+ Opsi:
+ Gunakan '|' sebagai pembatas untuk opsi
+ Jenis:
+ Workspace
+ Warna
+ Nama
+ Pulihkan tab saat startup
+ LANJUTKAN
+ Commit kosong terdeteksi! Lanjutkan (--allow-empty)?
+ STAGE SEMUA & COMMIT
+ Commit kosong terdeteksi! Lanjutkan (--allow-empty) atau stage semua lalu commit?
+ Perlu Mulai Ulang
+ Anda perlu memulai ulang aplikasi ini untuk menerapkan perubahan.
+ Pembantu Conventional Commit
+ Breaking Change:
+ Issue Ditutup:
+ Detail Perubahan:
+ Lingkup:
+ Deskripsi Singkat:
+ Jenis Perubahan:
+ Salin
+ Salin Semua Teks
+ Salin Jalur Lengkap
+ Salin Jalur
+ Buat Branch...
+ Berdasarkan:
+ Checkout branch yang dibuat
+ Perubahan Lokal:
+ Buang
+ Stash & Terapkan Ulang
+ Nama Branch Baru:
+ Masukkan nama branch.
+ Buat Branch Lokal
+ Timpa branch yang ada
+ Buat Tag...
+ Tag Baru Pada:
+ Tanda tangan GPG
+ Pesan Tag:
+ Opsional.
+ Nama Tag:
+ Format rekomendasi: v1.0.0-alpha
+ Push ke semua remote setelah dibuat
+ Buat Tag Baru
+ Jenis:
+ annotated
+ lightweight
+ Tahan Ctrl untuk memulai langsung
+ Potong
+ De-initialize Submodule
+ Paksa de-init meski mengandung perubahan lokal.
+ Submodule:
+ Hapus Branch
+ Branch:
+ Anda akan menghapus remote branch!!!
+ Juga hapus remote branch ${0}$
+ Hapus Beberapa Branch
+ Anda akan menghapus beberapa branch sekaligus. Pastikan untuk memeriksa ulang sebelum bertindak!
+ Hapus Beberapa Tag
+ Hapus dari remote
+ Anda akan menghapus beberapa tag sekaligus. Pastikan untuk memeriksa ulang sebelum bertindak!
+ Hapus Remote
+ Remote:
+ Jalur:
+ Target:
+ Semua anak akan dihapus dari daftar.
+ Ini hanya akan menghapusnya dari daftar, bukan dari disk!
+ Konfirmasi Hapus Grup
+ Konfirmasi Hapus Repositori
+ Hapus Submodule
+ Jalur Submodule:
+ Hapus Tag
+ Tag:
+ Hapus dari repositori remote
+ DIFF BINARY
+ Mode Berkas Berubah
+ Perbedaan Pertama
+ Abaikan Perubahan Whitespace
+ BLEND
+ DIFFERENCE
+ SIDE-BY-SIDE
+ SWIPE
+ Perbedaan Terakhir
+ PERUBAHAN OBJEK LFS
+ BARU
+ Perbedaan Berikutnya
+ TIDAK ADA PERUBAHAN ATAU HANYA PERUBAHAN EOL
+ LAMA
+ Perbedaan Sebelumnya
+ Simpan sebagai Patch
+ Tampilkan Simbol Tersembunyi
+ Diff Side-By-Side
+ PERUBAHAN SUBMODULE
+ DIHAPUS
+ BARU
+ Tukar
+ Syntax Highlighting
+ Word Wrap Baris
+ Buka di Merge Tool
+ Tampilkan Semua Baris
+ Kurangi Jumlah Baris yang Tampak
+ Tambah Jumlah Baris yang Tampak
+ PILIH BERKAS UNTUK MELIHAT PERUBAHAN
+ Riwayat Direktori
+ Memiliki Perubahan Lokal
+ Tidak Cocok dengan Upstream
+ Sudah Up-To-Date
+ Buang Perubahan
+ Semua perubahan lokal dalam working copy.
+ Perubahan:
+ Termasuk berkas yang diabaikan
+ Termasuk berkas yang tidak dilacak
+ {0} perubahan akan dibuang
+ Anda tidak dapat membatalkan aksi ini!!!
+ Bookmark:
+ Nama Baru:
+ Target:
+ Sunting Grup yang Dipilih
+ Sunting Repositori yang Dipilih
+ Target:
+ Repositori ini
+ Fetch
+ Fetch semua remote
+ Paksa override ref lokal
+ Fetch tanpa tag
+ Remote:
+ Fetch Perubahan dari Remote
+ Asumsikan tidak berubah
+ Buang...
+ Buang {0} berkas...
+ Selesaikan Menggunakan ${0}$
+ Simpan sebagai Patch...
+ Stage
+ Stage {0} berkas
+ Stash...
+ Stash {0} berkas...
+ Unstage
+ Unstage {0} berkas
+ Gunakan Milik Saya (checkout --ours)
+ Gunakan Milik Mereka (checkout --theirs)
+ Riwayat Berkas
+ PERUBAHAN
+ KONTEN
+ Git-Flow
+ Branch Development:
+ Feature:
+ Prefix Feature:
+ FLOW - Selesaikan Feature
+ FLOW - Selesaikan Hotfix
+ FLOW - Selesaikan Release
+ Target:
+ Push ke remote setelah selesai
+ Squash saat merge
+ Hotfix:
+ Prefix Hotfix:
+ Inisialisasi Git-Flow
+ Simpan branch
+ Branch Production:
+ Release:
+ Prefix Release:
+ Mulai Feature...
+ FLOW - Mulai Feature
+ Mulai Hotfix...
+ FLOW - Mulai Hotfix
+ Masukkan nama
+ Mulai Release...
+ FLOW - Mulai Release
+ Prefix Tag Versi:
+ Git LFS
+ Tambah Pola Track...
+ Pola adalah nama berkas
+ Pola Kustom:
+ Tambah Pola Track ke Git LFS
+ Fetch
+ Jalankan `git lfs fetch` untuk mengunduh objek Git LFS. Ini tidak memperbarui working copy.
+ Fetch Objek LFS
+ Instal hook Git LFS
+ Tampilkan Lock
+ Tidak Ada Berkas Terkunci
+ Lock
+ Hanya tampilkan lock saya
+ Lock LFS
+ Unlock
+ Paksa Unlock
+ Prune
+ Jalankan `git lfs prune` untuk menghapus berkas LFS lama dari penyimpanan lokal
+ Pull
+ Jalankan `git lfs pull` untuk mengunduh semua berkas Git LFS untuk ref & checkout saat ini
+ Pull Objek LFS
+ Push
+ Push berkas besar yang diantre ke endpoint Git LFS
+ Push Objek LFS
+ Remote:
+ Track berkas bernama '{0}'
+ Track semua berkas *{0}
+ RIWAYAT
+ AUTHOR
+ WAKTU AUTHOR
+ GRAFIK & SUBJEK
+ SHA
+ WAKTU COMMIT
+ DIPILIH {0} COMMIT
+ Tahan 'Ctrl' atau 'Shift' untuk memilih beberapa commit.
+ Tahan ⌘ atau ⇧ untuk memilih beberapa commit.
+ TIPS:
+ Referensi Shortcut Keyboard
+ GLOBAL
+ Clone repositori baru
+ Tutup tab saat ini
+ Ke tab berikutnya
+ Ke tab sebelumnya
+ Buat tab baru
+ Buka dialog Preferensi
+ Ganti tab aktif
+ REPOSITORI
+ Commit perubahan yang di-stage
+ Commit dan push perubahan yang di-stage
+ Stage semua perubahan dan commit
+ Fetch, langsung dimulai
+ Mode dashboard (Default)
+ Mode pencarian commit
+ Pull, langsung dimulai
+ Push, langsung dimulai
+ Paksa muat ulang repositori ini
+ Pindah ke 'Changes'
+ Pindah ke 'History'
+ Pindah ke 'Stashes'
+ TEXT EDITOR
+ Tutup panel pencarian
+ Cari kecocokan berikutnya
+ Cari kecocokan sebelumnya
+ Buka dengan diff/merge tool eksternal
+ Buka panel pencarian
+ Buang
+ Stage
+ Unstage
+ Inisialisasi Repositori
+ Jalur:
+ Cherry-Pick sedang berjalan.
+ Memproses commit
+ Merge sedang berjalan.
+ Melakukan merge
+ Rebase sedang berjalan.
+ Berhenti di
+ Revert sedang berjalan.
+ Melakukan revert commit
+ Interactive Rebase
+ Stash & terapkan ulang perubahan lokal
+ Pada:
+ Drag-drop untuk mengurutkan ulang commit
+ Branch Target:
+ Salin Link
+ Buka di Browser
+ ERROR
+ PEMBERITAHUAN
+ Tab
+ Workspace
+ Merge Branch
+ Sesuaikan pesan merge
+ Ke:
+ Opsi Merge:
+ Sumber:
+ Merge (Beberapa)
+ Commit semua perubahan
+ Strategi:
+ Target:
+ Pindahkan Submodule
+ Pindahkan Ke:
+ Submodule:
+ Pindahkan Node Repositori
+ Pilih node parent untuk:
+ Nama:
+ Git BELUM dikonfigurasi. Silakan ke [Preferences] dan konfigurasikan terlebih dahulu.
+ Buka Direktori Penyimpanan Data
+ Buka di Merge Tool
+ Opsional.
+ Buat Tab Baru
+ Bookmark
+ Tutup Tab
+ Tutup Tab Lain
+ Tutup Tab di Kanan
+ Salin Jalur Repositori
+ Repositori
+ Tempel
+ {0} hari lalu
+ 1 jam lalu
+ {0} jam lalu
+ Baru saja
+ Bulan lalu
+ Tahun lalu
+ {0} menit lalu
+ {0} bulan lalu
+ {0} tahun lalu
+ Kemarin
+ Preferensi
+ AI
+ Prompt Analisis Diff
+ API Key
+ Prompt Generate Subjek
+ Model
+ Nama
+ Nilai yang dimasukkan adalah nama untuk memuat API key dari ENV
+ Server
+ Aktifkan Streaming
+ TAMPILAN
+ Font Default
+ Lebar Tab Editor
+ Ukuran Font
+ Default
+ Editor
+ Font Monospace
+ Tema
+ Override Tema
+ Gunakan scrollbar auto-hide
+ Gunakan lebar tab tetap di titlebar
+ Gunakan frame window native
+ DIFF/MERGE TOOL
+ Jalur Instalasi
+ Masukkan jalur untuk diff/merge tool
+ Tool
+ UMUM
+ Periksa pembaruan saat startup
+ Format Tanggal
+ Aktifkan folder kompak di pohon perubahan
+ Bahasa
+ Commit Riwayat
+ Tampilkan waktu author alih-alih waktu commit di grafik
+ Tampilkan halaman `LOCAL CHANGES` secara default
+ Tampilkan tab `CHANGES` di detail commit secara default
+ Tampilkan children di detail commit
+ Tampilkan tag di grafik commit
+ Panjang Panduan Subjek
+ Generate avatar default bergaya GitHub
+ GIT
+ Aktifkan Auto CRLF
+ Direktori Clone Default
+ Email Pengguna
+ Email pengguna git global
+ Aktifkan --prune saat fetch
+ Aktifkan --ignore-cr-at-eol di diff
+ Git (>= 2.25.1) diperlukan oleh aplikasi ini
+ Jalur Instalasi
+ Aktifkan HTTP SSL Verify
+ Gunakan git-credential-libsecret alih-alih git-credential-manager
+ Nama Pengguna
+ Nama pengguna git global
+ Versi Git
+ PENANDATANGANAN GPG
+ Penandatanganan GPG commit
+ Format GPG
+ Jalur Instalasi Program
+ Masukkan jalur untuk program gpg yang terinstal
+ Penandatanganan GPG tag
+ Kunci Penandatanganan Pengguna
+ Kunci penandatanganan gpg pengguna
+ INTEGRASI
+ SHELL/TERMINAL
+ Jalur
+ Shell/Terminal
+ Prune Remote
+ Target:
+ Prune Worktree
+ Prune informasi worktree di `$GIT_COMMON_DIR/worktrees`
+ Pull
+ Remote Branch:
+ Ke:
+ Perubahan Lokal:
+ Buang
+ Stash & Terapkan Ulang
+ Remote:
+ Pull (Fetch & Merge)
+ Gunakan rebase alih-alih merge
+ Push
+ Pastikan submodule sudah di-push
+ Paksa push
+ Branch Lokal:
+ BARU
+ Remote:
+ Revisi:
+ Push Revisi ke Remote
+ Push Perubahan ke Remote
+ Remote Branch:
+ Atur sebagai tracking branch
+ Push semua tag
+ Push Tag ke Remote
+ Push ke semua remote
+ Remote:
+ Tag:
+ Keluar
+ Rebase Branch Saat Ini
+ Stash & terapkan ulang perubahan lokal
+ Pada:
+ Tambah Remote
+ Sunting Remote
+ Nama:
+ Nama remote
+ URL Repositori:
+ URL repositori git remote
+ Salin URL
+ Aksi Kustom
+ Hapus...
+ Sunting...
+ Fetch
+ Buka di Browser
+ Prune
+ Konfirmasi Hapus Worktree
+ Aktifkan Opsi `--force`
+ Target:
+ Ganti Nama Branch
+ Nama Baru:
+ Nama unik untuk branch ini
+ Branch:
+ BATALKAN
+ Auto fetch perubahan dari remote...
+ Urut
+ Berdasarkan Tanggal Committer
+ Berdasarkan Nama
+ Bersihkan (GC & Prune)
+ Jalankan perintah `git gc` untuk repositori ini.
+ Bersihkan semua
+ Bersihkan
+ Konfigurasikan repositori ini
+ LANJUTKAN
+ Aksi Kustom
+ Tidak Ada Aksi Kustom
+ Dashboard
+ Buang semua perubahan
+ Buka di File Browser
+ Cari Branch/Tag/Submodule
+ Visibilitas di Grafik
+ Tidak Diatur
+ Sembunyikan di grafik commit
+ Filter di grafik commit
+ TATA LETAK
+ Horizontal
+ Vertikal
+ URUTAN COMMIT
+ Tanggal Commit
+ Topologis
+ BRANCH LOKAL
+ Opsi lainnya...
+ Navigasi ke HEAD
+ Buat Branch
+ BERSIHKAN NOTIFIKASI
+ Hanya highlight branch saat ini
+ Buka di {0}
+ Buka di Tool Eksternal
+ REMOTE
+ Tambah Remote
+ Cari Commit
+ Author
+ Committer
+ Konten
+ Pesan
+ Jalur
+ SHA
+ Branch Saat Ini
+ Hanya commit yang didekorasi
+ Hanya first-parent
+ TAMPILKAN FLAG
+ Tampilkan commit yang hilang
+ Tampilkan Submodule sebagai Pohon
+ Tampilkan Tag sebagai Pohon
+ LEWATI
+ Statistik
+ SUBMODULE
+ Tambah Submodule
+ Perbarui Submodule
+ TAG
+ Tag Baru
+ Berdasarkan Tanggal Pembuat
+ Berdasarkan Nama
+ Urut
+ Buka di Terminal
+ Gunakan waktu relatif
+ Lihat Log
+ Kunjungi '{0}' di Browser
+ WORKTREE
+ Tambah Worktree
+ Prune
+ URL Repositori Git
+ Reset Branch Saat Ini ke Revisi
+ Mode Reset:
+ Pindah Ke:
+ Branch Saat Ini:
+ Reset Branch (Tanpa Checkout)
+ Pindah Ke:
+ Branch:
+ Tampilkan di File Explorer
+ Revert Commit
+ Commit:
+ Commit perubahan revert
+ Reword Pesan Commit
+ Sedang berjalan. Harap tunggu...
+ SIMPAN
+ Simpan Sebagai...
+ Patch berhasil disimpan!
+ Pindai Repositori
+ Direktori Root:
+ Pindai direktori kustom lain
+ Periksa Pembaruan...
+ Versi baru dari perangkat lunak ini tersedia:
+ Pemeriksaan pembaruan gagal!
+ Unduh
+ Lewati Versi Ini
+ Pembaruan Perangkat Lunak
+ Saat ini tidak ada pembaruan yang tersedia.
+ Atur Branch Submodule
+ Submodule:
+ Saat Ini:
+ Ubah Ke:
+ Opsional. Atur ke default jika kosong.
+ Atur Tracking Branch
+ Branch:
+ Hapus upstream
+ Upstream:
+ Salin SHA
+ Ke
+ Kunci SSH Privat:
+ Jalur penyimpanan kunci SSH privat
+ MULAI
+ Stash
+ Termasuk berkas yang tidak dilacak
+ Pesan:
+ Opsional. Pesan untuk stash ini
+ Mode:
+ Hanya perubahan yang di-stage
+ Perubahan staged dan unstaged dari berkas yang dipilih akan di-stash!!!
+ Stash Perubahan Lokal
+ Terapkan
+ Salin Pesan
+ Drop
+ Simpan sebagai Patch...
+ Drop Stash
+ Drop:
+ STASH
+ PERUBAHAN
+ STASH
+ Statistik
+ IKHTISAR
+ BULAN
+ MINGGU
+ AUTHOR:
+ COMMIT:
+ SUBMODULE
+ Tambah Submodule
+ BRANCH
+ Branch
+ Jalur Relatif
+ De-initialize
+ Fetch submodule bersarang
+ Riwayat
+ Pindahkan Ke
+ Buka Repositori
+ Jalur Relatif:
+ Folder relatif untuk menyimpan modul ini.
+ Hapus
+ Atur Branch
+ Ubah URL
+ STATUS
+ dimodifikasi
+ tidak diinisialisasi
+ revisi berubah
+ belum di-merge
+ Perbarui
+ URL
+ OK
+ TAGGER
+ WAKTU
+ Pesan
+ Nama
+ Tagger
+ Salin Nama Tag
+ Aksi Kustom
+ Hapus ${0}$...
+ Hapus {0} tag yang dipilih...
+ Merge ${0}$ ke ${1}$...
+ Push ${0}$...
+ Perbarui Submodule
+ Semua submodule
+ Inisialisasi sesuai kebutuhan
+ Telusuri submodule secara rekursif
+ Submodule:
+ Perbarui ke remote tracking branch submodule
+ URL:
+ Log
+ BERSIHKAN SEMUA
+ Salin
+ Hapus
+ Peringatan
+ Halaman Selamat Datang
+ Buat Grup
+ Buat Sub-Grup
+ Clone Repositori
+ Hapus
+ DRAG & DROP FOLDER DIDUKUNG. PENGELOMPOKAN KUSTOM DIDUKUNG.
+ Sunting
+ Pindah ke Grup Lain
+ Buka Semua Repositori
+ Buka Repositori
+ Buka Terminal
+ Pindai Ulang Repositori di Direktori Clone Default
+ Cari Repositori...
+ PERUBAHAN LOKAL
+ Git Ignore
+ Abaikan semua berkas *{0}
+ Abaikan berkas *{0} di folder yang sama
+ Abaikan berkas yang tidak dilacak di folder ini
+ Abaikan hanya berkas ini
+ Amend
+ Anda dapat stage berkas ini sekarang.
+ Bersihkan Riwayat
+ Yakin ingin membersihkan semua riwayat pesan commit? Aksi ini tidak dapat dibatalkan.
+ COMMIT
+ COMMIT & PUSH
+ Template/Riwayat
+ Picu event klik
+ Commit (Sunting)
+ Stage semua perubahan dan commit
+ Anda membuat commit pada HEAD yang terlepas. Lanjutkan?
+ Anda telah stage {0} berkas tetapi hanya {1} berkas yang ditampilkan ({2} berkas disaring). Lanjutkan?
+ KONFLIK TERDETEKSI
+ BUKA MERGETOOL EKSTERNAL
+ BUKA SEMUA KONFLIK DI MERGETOOL EKSTERNAL
+ KONFLIK BERKAS DISELESAIKAN
+ GUNAKAN MILIK SAYA
+ GUNAKAN MILIK MEREKA
+ TERMASUK BERKAS YANG TIDAK DILACAK
+ TIDAK ADA PESAN INPUT TERBARU
+ TIDAK ADA TEMPLATE COMMIT
+ No-Verify
+ Reset Author
+ SignOff
+ STAGED
+ UNSTAGE
+ UNSTAGE SEMUA
+ UNSTAGED
+ STAGE
+ STAGE SEMUA
+ LIHAT ASSUME UNCHANGED
+ Template: ${0}$
+ WORKSPACE:
+ Konfigurasikan Workspace...
+ WORKTREE
+ Salin Jalur
+ Lock
+ Buka
+ Hapus
+ Unlock
+
diff --git a/src/Resources/Locales/it_IT.axaml b/src/Resources/Locales/it_IT.axaml
index c83a8bdb9..c56954628 100644
--- a/src/Resources/Locales/it_IT.axaml
+++ b/src/Resources/Locales/it_IT.axaml
@@ -6,6 +6,9 @@
Informazioni
Informazioni su SourceGit
Client GUI Git open source e gratuito
+ Aggiungi file a Ignora
+ Pattern:
+ File di storage:
Aggiungi Worktree
Posizione:
Percorso per questo worktree. Supportato il percorso relativo.
@@ -20,6 +23,8 @@
RIGENERA
Usa AI per generare il messaggio di commit
APPLICA COME MESSAGGIO DI COMMIT
+ Nascondi SourceGit
+ Mostra Tutto
Applica
File Patch:
Seleziona file .patch da applicare
@@ -36,8 +41,10 @@
Revisione:
Archivia
Richiedi Password SourceGit
+ Inserisci passphrase:
FILE ASSUNTI COME INVARIATI
NESSUN FILE ASSUNTO COME INVARIATO
+ Carico l'Immagine...
Aggiorna
FILE BINARIO NON SUPPORTATO!!!
Biseca
@@ -48,7 +55,7 @@
Salta
Bisecando. Marca il commit corrente come buono o cattivo e fai checkout di un altro.
Attribuisci
- L'ATTRIBUZIONE SU QUESTO FILE NON È SUPPORTATA!!!
+ L'ATTRIBUZIONE SU QUESTO FILE NON È SUPPORTATA!!!
Checkout ${0}$...
Confronta con ${0}$
Confronta con Worktree
@@ -66,9 +73,13 @@
Invia ${0}$
Riallinea ${0}$ su ${1}$...
Rinomina ${0}$...
+ Resetta ${0}$ a ${1}$...
Imposta Branch di Tracciamento...
Confronto Branch
- Upstream non valido
+ Invalido
+ REMOTO
+ TRACCIAMENTO
+ URL
ANNULLA
Ripristina la Revisione Padre
Ripristina Questa Revisione
@@ -77,15 +88,20 @@
Mostra come elenco di file e cartelle
Mostra come elenco di percorsi
Mostra come albero del filesystem
+ Cambia l'URL del Sottomodulo
+ Sottomodulo:
+ URL:
Checkout Branch
Checkout Commit
Commit:
Avviso: Effettuando un checkout del commit, la tua HEAD sarà separata
Modifiche Locali:
Scarta
- Stasha e Ripristina
- Aggiorna tutti i sottomoduli
+ Stasha e Ripristina
Branch:
+ Il tuo HEAD attuale contiene commit non connessi ad alcun branch/tag! Sicuro di voler continuare?
+ Checkout & Avanzamento Veloce
+ Avanzamento Veloce verso:
Cherry Pick
Aggiungi sorgente al messaggio di commit
Commit(s):
@@ -110,17 +126,30 @@
Confronta con HEAD
Confronta con Worktree
Autore
+ Messaggio
Committer
SHA
Oggetto
Azione Personalizzata
+ Rebase Interattivo
+ Scarta...
+ Modifica...
+ Correggi nel Genitore...
+ Ribasare interattivamente ${0}$ su ${1}$
+ Riformula...
+ Compatta nel Genitore...
Unisci a ${0}$
Unisci ...
+ Invia ${0}$ a ${1}$
+ Ribasa ${0}$ su ${1}$
+ Resetta ${0}$ su ${1}$
Annulla Commit
Modifica
Salva come Patch...
Compatta nel Genitore
+ Correggi nel Genitore
MODIFICHE
+ file modificati
Cerca Modifiche...
FILE
File LFS
@@ -133,26 +162,41 @@
Controlla i riferimenti che contengono questo commit
IL COMMIT È CONTENUTO DA
Mostra solo le prime 100 modifiche. Vedi tutte le modifiche nella scheda MODIFICHE.
+ Chiave:
MESSAGGIO
GENITORI
RIFERIMENTI
SHA
+ Firmatario:
Apri nel Browser
- Descrizione
OGGETTO
- Inserisci l'oggetto del commit
Configura Repository
TEMPLATE DI COMMIT
Contenuto Template:
Nome Template:
AZIONE PERSONALIZZATA
Argomenti:
+ Parametri integrati:
+
+ ${REPO} Percorso del repository
+ ${REMOTE} Remoto selezionato o remoto del branch selezionato
+ ${BRANCH} Branch selezionato, senza la parte ${REMOTE} per i branch remoti
+ ${BRANCH_FRIENDLY_NAME} Nome amichevole del branch selezionato, contiene la parte ${REMOTE} per i branch remoti
+ ${SHA} Hash del commit selezionato
+ ${TAG} Tag selezionato
+ ${FILE} File selezionato, relativo alla radice del repository
+ $1, $2 ... Valori dei controlli di input
File Eseguibile:
+ Controlli di Input:
+ Modifica
Nome:
Ambito:
Branch
Commit
+ File
+ Remoto
Repository
+ Tag
Attendi la fine dell'azione
Indirizzo Email
Indirizzo email
@@ -163,6 +207,7 @@
Modalità di Merge Preferita
TRACCIAMENTO ISSUE
Aggiungi una regola di esempio per Azure DevOps
+ Aggiungi regola per Gerrit Change-Id Commit
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
@@ -172,6 +217,7 @@
Nuova Regola
Espressione Regex Issue:
Nome Regola:
+ Condividi questa regola nel file .issuetracker
URL Risultato:
Utilizza $1, $2 per accedere ai valori dei gruppi regex.
AI
@@ -181,6 +227,16 @@
Proxy HTTP usato da questo repository
Nome Utente
Nome utente per questo repository
+ Modifica Controlli Azione Personalizzata
+ Valore Selezionato:
+ Quando selezionato, questo valore sarà usato negli argomenti della riga di comando
+ Descrizione:
+ Predefinito:
+ È una Cartella:
+ Etichetta:
+ Opzioni:
+ Usa '|' come delimitatore per le opzioni
+ Tipo:
Spazi di Lavoro
Colore
Nome
@@ -189,6 +245,8 @@
Trovato un commit vuoto! Vuoi procedere (--allow-empty)?
STAGE DI TUTTO E COMMITTA
Trovato un commit vuoto! Vuoi procedere (--allow-empty) o fare lo stage di tutto e committare?
+ Riavvio Necessario
+ È necessario riavviare l'applicazione per applicare le modifiche.
Guida Commit Convenzionali
Modifica Sostanziale:
Issue Chiusa:
@@ -205,11 +263,11 @@
Checkout del Branch Creato
Modifiche Locali:
Scarta
- Stasha e Ripristina
+ Stasha e Ripristina
Nome Nuovo Branch:
Inserisci il nome del branch.
- Gli spazi verranno rimpiazzati con dei trattini.
Crea Branch Locale
+ Sovrascrivi branch esistente
Crea Tag...
Nuovo Tag Su:
Firma con GPG
@@ -224,12 +282,18 @@
leggero
Tieni premuto Ctrl per avviare direttamente
Taglia
+ Deinizializza Sottomodulo
+ Forza deinizializzazione anche se contiene modifiche locali.
+ Sottomodulo:
Elimina Branch
Branch:
Stai per eliminare un branch remoto!!!
Elimina anche il branch remoto ${0}$
Elimina Branch Multipli
Stai per eliminare più branch contemporaneamente. Controlla attentamente prima di procedere!
+ Elimina Tag Multipli
+ Eliminali dai remoti
+ Stai cercando di eliminare più tag contemporaneamente. Assicurati di controllare attentamente prima di procedere!
Elimina Remoto
Remoto:
Percorso:
@@ -247,29 +311,36 @@
Modalità File Modificata
Prima differenza
Ignora Modifiche agli Spazi
+ FUSIONE
+ AFFIANCATI
+ SCORRIMENTO
Ultima differenza
MODIFICA OGGETTO LFS
+ NUOVO
Differenza Successiva
NESSUNA MODIFICA O SOLO CAMBIAMENTI DI FINE LINEA
+ VECCHIO
Differenza Precedente
Salva come Patch
Mostra Simboli Nascosti
Diff Affiancato
SOTTOMODULO
+ ELIMINATO
NUOVO
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
Aumenta Numero di Righe Visibili
SELEZIONA UN FILE PER VISUALIZZARE LE MODIFICHE
+ Cronologia Cartella
Scarta Modifiche
Tutte le modifiche locali nella copia di lavoro.
Modifiche:
Includi file ignorati
+ Includi file non tracciati
Un totale di {0} modifiche saranno scartate
Questa azione non può essere annullata!!!
Segnalibro:
@@ -277,6 +348,8 @@
Destinazione:
Modifica Gruppo Selezionato
Modifica Repository Selezionato
+ Destinazione:
+ Questo repository
Recupera
Recupera da tutti i remoti
Forza la sovrascrittura dei riferimenti locali
@@ -369,6 +442,7 @@
Vai alla pagina precedente
Crea una nuova pagina
Apri la finestra delle preferenze
+ Cambia scheda attiva
REPOSITORY
Committa le modifiche in tsage
Committa e invia le modifiche in stage
@@ -404,12 +478,16 @@
Riallinea Interattivamente
Stasha e Riapplica modifiche locali
Su:
+ Trascina per riordinare i commit
Branch di destinazione:
Copia il Link
Apri nel Browser
ERRORE
AVVISO
+ Schede
+ Workspaces
Unisci Branch
+ Personalizza messaggio di merge
In:
Opzione di Unione:
Sorgente:
@@ -417,13 +495,15 @@
Commit di tutte le modifiche
Strategia:
Obiettivi:
+ Sposta Sottomodulo
+ Sposta Verso:
+ Sottomodulo:
Sposta Nodo Repository
Seleziona nodo padre per:
Nome:
Git NON è configurato. Prima vai su [Preferenze] per configurarlo.
Apri Cartella Dati App
Apri nello Strumento di Merge
- Apri con...
Opzionale.
Crea Nuova Pagina
Segnalibro
@@ -443,7 +523,6 @@
{0} mesi fa
{0} anni fa
Ieri
- Usa 'Shift+Enter' per inserire una nuova riga. 'Enter' è il tasto rapido per il pulsante OK
Preferenze
AI
Analizza il Prompt Differenza
@@ -460,7 +539,6 @@
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
@@ -488,6 +566,7 @@
Questa applicazione richiede Git (>= 2.25.1)
Percorso Installazione
Abilita la verifica HTTP SSL
+ Usa git-credential-libsecret invece di git-credential-manager
Nome Utente
Nome utente Git globale
Versione di Git
@@ -512,7 +591,7 @@
In:
Modifiche Locali:
Scarta
- Stasha e Riapplica
+ Stasha e Riapplica
Remoto:
Scarica (Recupera e Unisci)
Riallineare anziché unire
@@ -520,10 +599,13 @@
Assicurati che i sottomoduli siano stati inviati
Forza l'invio
Branch Locale:
+ NUOVO
Remoto:
+ Revisione:
+ Invia Revisione Al Remoto
Invia modifiche al remoto
Branch Remoto:
- Imposta come branch di tracking
+ Imposta come branch di tracciamento
Invia tutti i tag
Invia Tag al Remoto
Invia a tutti i remoti
@@ -540,6 +622,7 @@
URL del Repository:
URL del repository Git remoto
Copia URL
+ Azione Personalizzata
Elimina...
Modifica...
Recupera
@@ -560,10 +643,12 @@
Pulizia (GC e Potatura)
Esegui il comando `git gc` per questo repository.
Cancella tutto
+ Cancella
Configura questo repository
CONTINUA
Azioni Personalizzate
Nessuna Azione Personalizzata
+ Dashboard
Scarta tutte le modifiche
Apri nell'Esplora File
Cerca Branch/Tag/Sottomodulo
@@ -578,9 +663,11 @@
Per data del commit
Topologicamente
BRANCH LOCALI
+ Altre opzioni...
Vai a HEAD
Crea Branch
CANCELLA LE NOTIFICHE
+ Evidenzia solo il branch corrente
Apri in {0}
Apri in Strumenti Esterni
REMOTI
@@ -590,8 +677,13 @@
Committer
Contenuto
Messaggio
+ Percorso
SHA
Branch Corrente
+ Solo commit decorati
+ Solo primo genitore
+ MOSTRA FLAG
+ Mostra commit persi
Mostra i Sottomoduli Come Albero
Mostra Tag come Albero
SALTA
@@ -605,6 +697,7 @@
Per nome
Ordina
Apri nel Terminale
+ Usa tempo relativo
Visualizza i Log
Visita '{0}' nel Browser
WORKTREE
@@ -615,6 +708,9 @@
Modalità Reset:
Sposta a:
Branch Corrente:
+ Resetta Branch (Senza Checkout)
+ Sposta Verso:
+ Branch:
Mostra nell'Esplora File
Ripristina Commit
Commit:
@@ -633,14 +729,17 @@
Salta questa versione
Aggiornamento Software
Non ci sono aggiornamenti disponibili.
+ Imposta Branch del Sottomodulo
+ Sottomodulo:
+ Attuale:
+ Cambia In:
+ Opzionale. Imposta al valore predefinito quando è vuoto.
Imposta il Branch
Branch:
Rimuovi upstream
Upstream:
Copia SHA
Vai a
- Compatta Commit
- In:
Chiave Privata SSH:
Percorso per la chiave SSH privata
AVVIA
@@ -648,10 +747,12 @@
Includi file non tracciati
Messaggio:
Opzionale. Informazioni di questo stash
+ Modalità:
Solo modifiche in stage
Sia le modifiche in stage che quelle non in stage dei file selezionati saranno stashate!!!
Stasha Modifiche Locali
Applica
+ Copia Messaggio
Elimina
Salva come Patch...
Elimina Stash
@@ -667,22 +768,36 @@
COMMIT:
SOTTOMODULI
Aggiungi Sottomodulo
+ BRANCH
+ Branch
Percorso Relativo
+ Deinizializza
Recupera sottomoduli annidati
+ Cronologia
+ Sposta
Apri Repository del Sottomodulo
Percorso Relativo:
Cartella relativa per memorizzare questo modulo.
Elimina Sottomodulo
+ Imposta Branch
+ Cambia URL
STATO
modificato
non inizializzato
revisione cambiata
non unito
+ Aggiorna
URL
OK
- Copia Nome Tag
- Copia Messaggio Tag
+ AUTORE TAG
+ DATA
+ Messaggio
+ Nome
+ Autore
+ Copia Nome Tag
+ Azione Personalizzata
Elimina ${0}$...
+ Elimina i {0} tag selezionati...
Unisci ${0}$ in ${1}$...
Invia ${0}$...
Aggiorna Sottomoduli
@@ -690,6 +805,7 @@
Inizializza se necessario
Ricorsivamente
Sottomodulo:
+ Aggiorna al branch di tracciamento remoto del sottomodulo
URL:
Log
CANCELLA TUTTO
@@ -713,6 +829,7 @@
Git Ignore
Ignora tutti i file *{0}
Ignora i file *{0} nella stessa cartella
+ Ignora file non tracciati in questa cartella
Ignora solo questo file
Modifica
Puoi aggiungere in stage questo file ora.
@@ -722,6 +839,7 @@
Attiva evento click
Commit (Modifica)
Stage di tutte le modifiche e fai il commit
+ Stai creando un commit su un HEAD distaccato. Vuoi continuare?
Hai stageato {0} file ma solo {1} file mostrati ({2} file sono stati filtrati). Vuoi procedere?
CONFLITTI RILEVATI
APRI STRUMENTO DI MERGE ESTERNO
@@ -732,6 +850,7 @@
INCLUDI FILE NON TRACCIATI
NESSUN MESSAGGIO RECENTE INSERITO
NESSUN TEMPLATE DI COMMIT
+ Reimposta Autore
SignOff
IN STAGE
RIMUOVI DA STAGE
diff --git a/src/Resources/Locales/ja_JP.axaml b/src/Resources/Locales/ja_JP.axaml
index 63e4736d1..77d8edcc6 100644
--- a/src/Resources/Locales/ja_JP.axaml
+++ b/src/Resources/Locales/ja_JP.axaml
@@ -41,7 +41,7 @@
更新
バイナリファイルはサポートされていません!!!
Blame
- BLAMEではこのファイルはサポートされていません!!!
+ BLAMEではこのファイルはサポートされていません!!!
${0}$ をチェックアウトする...
ワークツリーと比較
ブランチ名をコピー
@@ -60,7 +60,6 @@
${0}$ をリネームする...
トラッキングブランチを設定...
ブランチの比較
- 無効な上流ブランチ!
キャンセル
親リビジョンにリセット
このリビジョンにリセット
@@ -75,7 +74,7 @@
警告: コミットをチェックアウトするとHEADが切断されます
ローカルの変更:
破棄
- スタッシュして再適用
+ スタッシュして再適用
ブランチ:
チェリーピック
ソースをコミットメッセージに追加
@@ -126,8 +125,6 @@
参照
SHA
ブラウザで開く
- 説明
- コミットのタイトルを入力
リポジトリの設定
コミットテンプレート
テンプレート内容:
@@ -187,10 +184,9 @@
作成したブランチにチェックアウト
ローカルの変更:
破棄
- スタッシュして再適用
+ スタッシュして再適用
新しいブランチの名前:
ブランチの名前を入力
- スペースはダッシュに置き換えられます。
ローカルブランチを作成
タグを作成...
付与されるコミット:
@@ -242,7 +238,6 @@
スワップ
シンタックスハイライト
行の折り返し
- ブロックナビゲーションを有効化
マージツールで開く
すべての行を表示
表示する行数を減らす
@@ -402,7 +397,6 @@
Gitが設定されていません。まず[設定]に移動して設定を行ってください。
アプリケーションデータのディレクトリを開く
マージツールで開く
- 外部ツールで開く...
任意。
新しいページを開く
ブックマーク
@@ -422,7 +416,6 @@
{0} ヶ月前
{0} 年前
昨日
- 改行には'Shift+Enter'キーを使用します。 'Enter"はOKボタンのホットキーとして機能します。
設定
AI
差分分析プロンプト
@@ -439,7 +432,6 @@
デフォルト
エディタ
等幅フォント
- テキストエディタでは等幅フォントのみを使用する
テーマ
テーマの上書き
タイトルバーの固定タブ幅を使用
@@ -490,7 +482,7 @@
宛先:
ローカルの変更:
破棄
- スタッシュして再適用
+ スタッシュして再適用
リモート:
プル (フェッチ & マージ)
マージの代わりにリベースを使用
@@ -609,8 +601,6 @@
上流ブランチ:
SHAをコピー
Go to
- スカッシュコミット
- 宛先:
SSH プライベートキー:
プライベートSSHキーストアのパス
スタート
@@ -644,8 +634,6 @@
このモジュールを保存するフォルダの相対パス
サブモジュールを削除
OK
- タグ名をコピー
- タグメッセージをコピー
${0}$ を削除...
${0}$ を ${1}$ にマージ...
${0}$ をプッシュ...
diff --git a/src/Resources/Locales/ko_KR.axaml b/src/Resources/Locales/ko_KR.axaml
new file mode 100644
index 000000000..5cc2a06a1
--- /dev/null
+++ b/src/Resources/Locales/ko_KR.axaml
@@ -0,0 +1,894 @@
+
+
+ 정보
+ SourceGit 정보
+ 릴리스 노트
+ 오픈소스 & 무료 Git GUI 클라이언트
+ 무시할 파일 추가
+ 패턴:
+ 저장 파일:
+ 워크트리 추가
+ 위치:
+ 이 워크트리의 경로입니다. 상대 경로를 지원합니다.
+ 브랜치 이름:
+ 선택 사항. 기본값은 대상 폴더 이름입니다.
+ 추적할 브랜치:
+ 원격 브랜치 추적
+ 체크아웃할 대상:
+ 새 브랜치 생성
+ 기존 브랜치
+ AI 어시스턴트
+ 재생성
+ AI를 사용하여 커밋 메시지 생성
+ 커밋 메시지로 적용
+ SourceGit 숨기기
+ 모두 보기
+ 패치
+ 패치 파일:
+ 적용할 .patch 파일을 선택하세요
+ 공백 변경 사항 무시
+ 패치 적용
+ 공백:
+ 스태시 적용
+ 적용 후 삭제
+ 인덱스의 변경 사항 복원
+ 스태시:
+ 아카이브...
+ 아카이브 저장 위치:
+ 아카이브 파일 경로 선택
+ 리비전:
+ 아카이브
+ SourceGit Askpass
+ 암호 입력:
+ 변경되지 않음으로 간주된 파일
+ 변경되지 않음으로 간주된 파일 없음
+ 이미지 불러오기...
+ 새로 고침
+ 바이너리 파일은 지원되지 않습니다!!!
+ 이진 탐색
+ 중단
+ 나쁨
+ 이진 탐색 중. 현재 HEAD가 '좋음' 상태입니까, '나쁨' 상태입니까?
+ 좋음
+ 건너뛰기
+ 이진 탐색 중. 현재 커밋을 '좋음' 또는 '나쁨'으로 표시하고 다른 커밋을 체크아웃하세요.
+ 블레임
+ ${0}$ 체크아웃...
+ ${0}$와(과) 비교
+ 워크트리와 비교
+ 브랜치 이름 복사
+ 사용자 지정 작업
+ ${0}$ 삭제...
+ 선택한 {0}개의 브랜치 삭제
+ ${0}$(으)로 Fast-Forward
+ ${0}$에서 ${1}$(으)로 Fetch...
+ Git Flow - ${0}$ 완료
+ ${0}$을(를) ${1}$(으)로 병합...
+ 선택한 {0}개의 브랜치를 현재 브랜치로 병합
+ ${0}$ Pull
+ ${0}$에서 ${1}$(으)로 Pull...
+ ${0}$ Push
+ ${1}$을(를) 기반으로 ${0}$ 리베이스...
+ ${0}$ 이름 바꾸기...
+ ${0}$을(를) ${1}$(으)로 리셋...
+ ${0}$(워크트리)로 전환
+ 추적 브랜치 설정...
+ 브랜치 비교
+ {0}개 커밋 앞섬
+ {0}개 커밋 앞섬, {1}개 커밋 뒤처짐
+ {0}개 커밋 뒤처짐
+ 유효하지 않음
+ 원격
+ 상태
+ 추적 중
+ URL
+ 워크트리
+ 취소
+ 부모 리비전으로 리셋
+ 이 리비전으로 리셋
+ 커밋 메시지 생성
+ 표시 모드 변경
+ 파일 및 디렉터리 목록으로 보기
+ 경로 목록으로 보기
+ 파일 시스템 트리로 보기
+ 서브모듈 URL 변경
+ 서브모듈:
+ URL:
+ 브랜치 체크아웃
+ 커밋 체크아웃
+ 커밋:
+ 경고: 커밋 체크아웃을 하면, HEAD가 분리됩니다(detached)
+ 로컬 변경 사항:
+ 폐기
+ 스태시 & 재적용
+ 브랜치:
+ 현재 HEAD에 브랜치/태그에 연결되지 않은 커밋이 있습니다! 계속하시겠습니까?
+ 체크아웃 & Fast-Forward
+ Fast-Forward 대상:
+ 체리픽
+ 커밋 메시지에 원본 추가
+ 커밋:
+ 모든 변경 사항 커밋
+ 메인라인:
+ 어느 쪽을 메인라인으로 간주해야 할지 알 수 없기 때문에 일반적으로 병합(merge)을 체리픽할 수 없습니다. 이 옵션을 사용하면 지정된 부모를 기준으로 변경 사항을 다시 적용할 수 있습니다.
+ 모든 스태시 지우기
+ 모든 스태시를 지우려고 합니다. 계속하시겠습니까?
+ 원격 저장소 복제
+ 추가 파라미터:
+ 저장소 복제 시 추가 인수. 선택 사항.
+ 로컬 이름:
+ 저장소 이름. 선택 사항.
+ 상위 폴더:
+ 서브모듈 초기화 & 업데이트
+ 저장소 URL:
+ 닫기
+ 에디터
+ 커밋 체크아웃
+ 커밋 체리픽
+ 체리픽...
+ HEAD와 비교
+ 워크트리와 비교
+ 작성자
+ 메시지
+ 커밋터
+ SHA
+ 제목
+ 사용자 지정 작업
+ 커밋 삭제
+ 대화형 리베이스
+ 삭제(Drop)...
+ 수정(Edit)...
+ 부모에 합치기(Fixup)...
+ ${1}$을(를) 기반으로 ${0}$ 대화형 리베이스
+ 메시지 수정(Reword)...
+ 부모에 합치기(Squash)...
+ ${0}$(으)로 병합
+ 병합...
+ ${0}$을(를) ${1}$(으)로 푸시
+ ${1}$을(를) 기반으로 ${0}$ 리베이스
+ ${0}$을(를) ${1}$(으)로 리셋
+ 커밋 되돌리기
+ 메시지 수정
+ 패치로 저장...
+ 부모에 합치기
+ 부모에 합치기(Fixup)
+ 변경 사항
+ 변경된 파일
+ 변경 사항 검색...
+ 파일
+ LFS 파일
+ 파일 검색...
+ 서브모듈
+ 정보
+ 작성자
+ 자식
+ 커밋터
+ 이 커밋을 포함하는 ref 확인
+ 커밋 포함 REF
+ 이메일 복사
+ 이름 복사
+ 이름 & 이메일 복사
+ 처음 100개의 변경 사항만 표시합니다. 모든 변경 사항은 '변경 사항' 탭에서 확인하세요.
+ 키:
+ 메시지
+ 부모
+ REFS
+ SHA
+ 서명자:
+ 브라우저에서 열기
+ 제목
+ 저장소 설정
+ 커밋 템플릿
+ ${files_num}, ${branch_name}, ${files} 및 ${files:N} (N은 출력할 최대 파일 경로 수)을(를) 사용할 수 있습니다.
+ 템플릿 내용:
+ 템플릿 이름:
+ 사용자 지정 작업
+ 인수:
+ 내장 파라미터:
+
+ ${REPO} 저장소 경로
+ ${REMOTE} 선택한 원격 또는 선택한 브랜치의 원격
+ ${BRANCH} 선택한 브랜치 (원격 브랜치의 경우 ${REMOTE} 부분 제외)
+ ${BRANCH_FRIENDLY_NAME} 선택한 브랜치의 식별하기 쉬운 이름 (원격 브랜치의 경우 ${REMOTE} 부분 포함)
+ ${SHA} 선택한 커밋의 해시
+ ${TAG} 선택한 태그
+ ${FILE} 저장소 루트에 상대적인 선택된 파일
+ $1, $2 ... 입력 컨트롤 값
+ 실행 파일:
+ 입력 컨트롤:
+ 편집
+ 이름:
+ 범위:
+ 브랜치
+ 커밋
+ 파일
+ 원격
+ 저장소
+ 태그
+ 작업이 끝날 때까지 대기
+ 이메일 주소
+ 이메일 주소
+ GIT
+ 원격 자동 Fetch
+ 분
+ 기본 원격
+ 선호하는 병합 모드
+ 이슈 트래커
+ Azure DevOps 규칙 추가
+ Gerrit Change-Id 커밋 규칙 추가
+ Gitee 이슈 규칙 추가
+ Gitee Pull Request 규칙 추가
+ GitHub 규칙 추가
+ GitLab 이슈 규칙 추가
+ GitLab Merge Request 규칙 추가
+ Jira 규칙 추가
+ 새 규칙
+ 이슈 정규식:
+ 규칙 이름:
+ .issuetracker 파일에 이 규칙 공유
+ 결과 URL:
+ 정규식 그룹 값에 접근하려면 $1, $2를 사용하세요.
+ AI
+ 선호하는 서비스:
+ '선호하는 서비스'가 설정되면, SourceGit은 이 저장소에서 해당 서비스만 사용합니다. 그렇지 않고 사용 가능한 서비스가 두 개 이상인 경우, 하나를 선택할 수 있는 컨텍스트 메뉴가 표시됩니다.
+ HTTP 프록시
+ 이 저장소에서 사용하는 HTTP 프록시
+ 사용자 이름
+ 이 저장소의 사용자 이름
+ 사용자 지정 작업 컨트롤 편집
+ 선택 시 값:
+ 선택 시, 이 값이 명령줄 인수로 사용됩니다
+ 설명:
+ 기본값:
+ 폴더 여부:
+ 레이블:
+ 옵션:
+ 옵션 구분자로 '|'를 사용하세요
+ 유형:
+ 작업 공간
+ 색상
+ 이름
+ 시작 시 탭 복원
+ 계속
+ 빈 커밋이 감지되었습니다! 계속하시겠습니까 (--allow-empty)?
+ 모두 스테이징 & 커밋
+ 빈 커밋이 감지되었습니다! 계속하시겠습니까 (--allow-empty) 아니면 모두 스테이징 후 커밋하시겠습니까?
+ 재시작 필요
+ 변경 사항을 적용하려면 앱을 다시 시작해야 합니다.
+ Conventional Commit 도우미
+ 주요 변경 사항(Breaking Change):
+ 종료된 이슈:
+ 상세 변경 내역:
+ 범위:
+ 간단한 설명:
+ 변경 유형:
+ 복사
+ 전체 텍스트 복사
+ 전체 경로 복사
+ 경로 복사
+ 브랜치 생성...
+ 기준:
+ 생성된 브랜치로 체크아웃
+ 로컬 변경 사항:
+ 폐기
+ 스태시 & 재적용
+ 새 브랜치 이름:
+ 브랜치 이름을 입력하세요.
+ 로컬 브랜치 생성
+ 기존 브랜치 덮어쓰기
+ 태그 생성...
+ 태그 생성 위치:
+ GPG 서명
+ 태그 메시지:
+ 선택 사항.
+ 태그 이름:
+ 권장 형식: v1.0.0-alpha
+ 생성 후 모든 원격에 푸시
+ 새 태그 생성
+ 종류:
+ 주석 태그
+ 경량 태그
+ Ctrl을 누른 채 클릭하면 바로 시작합니다
+ 잘라내기
+ 서브모듈 초기화 해제
+ 로컬 변경 사항이 있어도 강제로 초기화 해제합니다.
+ 서브모듈:
+ 브랜치 삭제
+ 브랜치:
+ 원격 브랜치를 삭제하려고 합니다!!!
+ 원격 브랜치 ${0}$도 함께 삭제
+ 여러 브랜치 삭제
+ 한 번에 여러 브랜치를 삭제하려고 합니다. 실행하기 전에 다시 한번 확인하세요!
+ 여러 태그 삭제
+ 원격 저장소에서도 삭제
+ 한 번에 여러 태그를 삭제하려고 합니다. 실행하기 전에 다시 한번 확인하세요!
+ 원격 삭제
+ 원격:
+ 경로:
+ 대상:
+ 모든 하위 항목이 목록에서 제거됩니다.
+ 목록에서만 제거되며, 디스크에서 삭제되지 않습니다!
+ 그룹 삭제 확인
+ 저장소 삭제 확인
+ 서브모듈 삭제
+ 서브모듈 경로:
+ 태그 삭제
+ 태그:
+ 원격 저장소에서도 삭제
+ 바이너리 비교
+ 파일 모드 변경됨
+ 첫 번째 차이점
+ 공백 변경 사항 무시
+ 혼합
+ 차이점
+ 나란히 보기
+ 스와이프
+ 마지막 차이점
+ LFS 객체 변경
+ 신규
+ 다음 차이점
+ 변경 사항 없음 또는 줄바꿈(EOL) 변경만 있음
+ 기존
+ 이전 차이점
+ 패치로 저장
+ 숨겨진 기호 표시
+ 나란히 비교
+ 서브모듈
+ 삭제됨
+ 신규
+ 전환
+ 구문 강조
+ 줄 바꿈
+ 병합 도구에서 열기
+ 모든 줄 표시
+ 표시 줄 수 줄이기
+ 표시 줄 수 늘리기
+ 파일을 선택하여 변경 사항 보기
+ 디렉터리 히스토리
+ 로컬 변경 사항 있음
+ 업스트림과 불일치
+ 이미 최신 상태
+ 변경 사항 폐기
+ 작업 사본의 모든 로컬 변경 사항.
+ 변경 사항:
+ 무시된 파일 포함
+ 추적하지 않는 파일 포함
+ {0}개의 변경 사항이 폐기됩니다
+ 이 작업은 되돌릴 수 없습니다!!!
+ 커밋 삭제
+ 커밋:
+ 새 HEAD:
+ 북마크:
+ 새 이름:
+ 대상:
+ 선택한 그룹 편집
+ 선택한 저장소 편집
+ 대상:
+ 이 저장소
+ Fetch
+ 모든 원격 Fetch
+ 로컬 ref 강제 덮어쓰기
+ 태그 없이 Fetch
+ 원격:
+ 원격 변경 사항 Fetch
+ 변경되지 않음으로 간주
+ 폐기...
+ {0}개 파일 폐기...
+ ${0}$을(를) 사용하여 해결
+ 패치로 저장...
+ 스테이지
+ {0}개 파일 스테이지
+ 스태시...
+ {0}개 파일 스태시...
+ 언스테이지
+ {0}개 파일 언스테이지
+ 내 것 사용 (checkout --ours)
+ 상대방 것 사용 (checkout --theirs)
+ 파일 히스토리
+ 변경 사항
+ 내용
+ Git-Flow
+ 개발 브랜치:
+ Feature:
+ Feature 접두사:
+ FLOW - Feature 완료
+ FLOW - Hotfix 완료
+ FLOW - Release 완료
+ 대상:
+ 완료 후 원격(들)에 푸시
+ 병합 시 스쿼시
+ 핫픽스:
+ Hotfix 접두사:
+ Git-Flow 초기화
+ 브랜치 유지
+ 운영 브랜치:
+ 릴리스:
+ Release 접두사:
+ Feature 시작...
+ FLOW - Feature 시작
+ Hotfix 시작...
+ FLOW - Hotfix 시작
+ 이름 입력
+ Release 시작...
+ FLOW - Release 시작
+ 버전 태그 접두사:
+ Git LFS
+ 추적 패턴 추가...
+ 패턴이 파일 이름임
+ 사용자 정의 패턴:
+ Git LFS에 추적 패턴 추가
+ Fetch
+ Git LFS 객체를 다운로드하려면 `git lfs fetch`를 실행하세요. 이 작업은 작업 사본을 업데이트하지 않습니다.
+ LFS 객체 Fetch
+ Git LFS 훅(hook) 설치
+ 잠금 보기
+ 잠긴 파일 없음
+ 잠금
+ 내 잠금만 보기
+ LFS 잠금
+ 잠금 해제
+ 강제 잠금 해제
+ 정리
+ 로컬 저장소에서 오래된 LFS 파일을 삭제하려면 `git lfs prune`을 실행하세요
+ Pull
+ 현재 ref 및 체크아웃에 대한 모든 Git LFS 파일을 다운로드하려면 `git lfs pull`을 실행하세요
+ LFS 객체 Pull
+ 푸시
+ 대기 중인 대용량 파일을 Git LFS 엔드포인트로 푸시합니다
+ LFS 객체 푸시
+ 원격:
+ '{0}' 이름의 파일 추적
+ 모든 *{0} 파일 추적
+ 히스토리
+ 작성자
+ 작성 시간
+ 그래프 & 제목
+ SHA
+ 커밋 시간
+ {0}개 커밋 선택됨
+ 'Ctrl' 또는 'Shift' 키를 누른 채로 여러 커밋을 선택하세요.
+ ⌘ 또는 ⇧ 키를 누른 채로 여러 커밋을 선택하세요.
+ 팁:
+ 키보드 단축키 참조
+ 전역
+ 새 저장소 복제
+ 현재 탭 닫기
+ 다음 탭으로 이동
+ 이전 탭으로 이동
+ 새 탭 만들기
+ 환경설정 대화상자 열기
+ 활성 탭 전환
+ 저장소
+ 스테이징된 변경 사항 커밋
+ 스테이징된 변경 사항 커밋 및 푸시
+ 모든 변경 사항 스테이징 후 커밋
+ Fetch (바로 시작)
+ 대시보드 모드 (기본)
+ 커밋 검색 모드 열기
+ Pull (바로 시작)
+ 푸시 (바로 시작)
+ 이 저장소 강제 새로고침
+ '변경 사항'으로 전환
+ '히스토리'로 전환
+ '스태시'로 전환
+ 텍스트 에디터
+ 검색 패널 닫기
+ 다음 일치 항목 찾기
+ 이전 일치 항목 찾기
+ 외부 diff/merge 도구로 열기
+ 검색 패널 열기
+ 폐기
+ 스테이지
+ 언스테이지
+ 저장소 초기화
+ 경로:
+ 체리픽 진행 중.
+ 커밋 처리 중
+ 병합 진행 중.
+ 병합 중
+ 리베이스 진행 중.
+ 중단 지점
+ 되돌리기 진행 중.
+ 커밋 되돌리는 중
+ 대화형 리베이스
+ 로컬 변경 사항 스태시 & 재적용
+ 기준:
+ 드래그 앤 드롭으로 커밋 순서 변경
+ 대상 브랜치:
+ 링크 복사
+ 브라우저에서 열기
+ 오류
+ 알림
+ 탭
+ 작업 공간
+ 브랜치 병합
+ 병합 메시지 수정
+ 대상:
+ 병합 옵션:
+ 소스:
+ 병합 (다중)
+ 모든 변경 사항 커밋
+ 전략:
+ 대상:
+ 서브모듈 이동
+ 이동 위치:
+ 서브모듈:
+ 저장소 노드 이동
+ 상위 노드 선택:
+ 이름:
+ Git이 구성되지 않았습니다. [환경설정]으로 이동하여 먼저 구성하세요.
+ 데이터 저장 디렉터리 열기
+ 병합 도구에서 열기
+ 선택 사항.
+ 새 탭 만들기
+ 북마크
+ 탭 닫기
+ 다른 탭 닫기
+ 오른쪽 탭 닫기
+ 저장소 경로 복사
+ 저장소
+ 붙여넣기
+ {0}일 전
+ 1시간 전
+ {0}시간 전
+ 방금 전
+ 지난 달
+ 작년
+ {0}분 전
+ {0}개월 전
+ {0}년 전
+ 어제
+ 환경설정
+ AI
+ Diff 분석 프롬프트
+ API 키
+ 제목 생성 프롬프트
+ 모델
+ 이름
+ 입력된 값은 환경변수(ENV)에서 API 키를 불러올 이름입니다
+ 서버
+ 스트리밍 활성화
+ 모양
+ 기본 글꼴
+ 에디터 탭 너비
+ 글꼴 크기
+ 기본
+ 에디터
+ 고정폭 글꼴
+ 테마
+ 테마 재정의
+ 스크롤바 자동 숨기기 사용
+ 네이티브 윈도우 프레임 사용
+ DIFF/MERGE 도구
+ 설치 경로
+ diff/merge 도구 경로 입력
+ 도구
+ 일반
+ 시작 시 업데이트 확인
+ 날짜 형식
+ 변경 사항 트리에서 폴더 압축 활성화
+ 언어
+ 히스토리 커밋 수
+ 그래프에 커밋 시간 대신 작성자 시간 표시
+ 기본으로 `로컬 변경 사항` 페이지 표시
+ 커밋 세부 정보에서 기본으로 `변경 사항` 탭 표시
+ 커밋 세부 정보에 자식 커밋 표시
+ 커밋 그래프에 태그 표시
+ 제목 가이드 길이
+ GitHub 스타일 기본 아바타 생성
+ GIT
+ 자동 CRLF 활성화
+ 기본 복제 디렉터리
+ 사용자 이메일
+ 전역 git 사용자 이메일
+ Fetch 시 --prune 활성화
+ diff 시 --ignore-cr-at-eol 활성화
+ 이 앱은 Git (>= 2.25.1)을(를) 필요로 합니다
+ 설치 경로
+ HTTP SSL 검증 활성화
+ git-credential-manager 대신 git-credential-libsecret 사용
+ 사용자 이름
+ 전역 git 사용자 이름
+ Git 버전
+ GPG 서명
+ 커밋 GPG 서명
+ GPG 형식
+ 프로그램 설치 경로
+ 설치된 gpg 프로그램 경로 입력
+ 태그 GPG 서명
+ 사용자 서명 키
+ 사용자의 gpg 서명 키
+ 연동
+ 셸/터미널
+ 경로
+ 셸/터미널
+ 원격 정리
+ 대상:
+ 워크트리 정리
+ `$GIT_COMMON_DIR/worktrees`의 워크트리 정보 정리
+ Pull
+ 원격 브랜치:
+ 대상:
+ 로컬 변경 사항:
+ 폐기
+ 스태시 & 재적용
+ 원격:
+ Pull (Fetch & 병합)
+ 병합 대신 리베이스 사용
+ 푸시
+ 서브모듈이 푸시되었는지 확인
+ 강제 푸시
+ 로컬 브랜치:
+ 신규
+ 원격:
+ 리비전:
+ 리비전을 원격에 푸시
+ 변경 사항을 원격에 푸시
+ 원격 브랜치:
+ 추적 브랜치로 설정
+ 모든 태그 푸시
+ 태그를 원격에 푸시
+ 모든 원격에 푸시
+ 원격:
+ 태그:
+ 종료
+ 현재 브랜치 리베이스
+ 로컬 변경 사항 스태시 & 재적용
+ 기준:
+ 원격 추가
+ 원격 편집
+ 이름:
+ 원격 이름
+ 저장소 URL:
+ 원격 git 저장소 URL
+ URL 복사
+ 사용자 지정 작업
+ 삭제...
+ 편집...
+ Fetch
+ 브라우저에서 열기
+ 정리
+ 워크트리 제거 확인
+ `--force` 옵션 활성화
+ 대상:
+ 브랜치 이름 변경
+ 새 이름:
+ 이 브랜치의 고유한 이름
+ 브랜치:
+ 중단
+ 원격에서 변경 사항 자동 Fetch 중...
+ 정렬
+ 커밋 날짜 순
+ 이름 순
+ 정리 (GC & Prune)
+ 이 저장소에 대해 `git gc` 명령을 실행합니다.
+ 모두 지우기
+ 지우기
+ 이 저장소 설정
+ 계속
+ 사용자 지정 작업
+ 사용자 지정 작업 없음
+ 대시보드
+ 모든 변경 사항 폐기
+ 파일 탐색기에서 열기
+ 브랜치/태그/서브모듈 검색
+ 그래프에 표시 여부
+ 설정 안 함
+ 커밋 그래프에서 숨기기
+ 커밋 그래프에서 필터링
+ 레이아웃
+ 수평
+ 수직
+ 커밋 순서
+ 커밋 날짜
+ 위상 정렬
+ 로컬 브랜치
+ 추가 옵션...
+ HEAD로 이동
+ 브랜치 생성
+ 알림 지우기
+ 현재 브랜치만 강조
+ {0}에서 열기
+ 외부 도구에서 열기
+ 원격
+ 원격 추가
+ 커밋 검색
+ 작성자
+ 커밋터
+ 내용
+ 메시지
+ 경로
+ SHA
+ 현재 브랜치
+ 장식된(Decorated) 커밋만
+ 첫 번째 부모만
+ 플래그 표시
+ 유실된(Lost) 커밋 표시
+ 서브모듈을 트리로 표시
+ 태그를 트리로 표시
+ 건너뛰기
+ 통계
+ 서브모듈
+ 서브모듈 추가
+ 서브모듈 업데이트
+ 태그
+ 새 태그
+ 생성 날짜 순
+ 이름 순
+ 정렬
+ 터미널에서 열기
+ 상대 시간 사용
+ 로그 보기
+ 브라우저에서 '{0}' 방문
+ 워크트리
+ 워크트리 추가
+ 정리
+ Git 저장소 URL
+ 현재 브랜치를 리비전으로 리셋
+ 리셋 모드:
+ 이동 대상:
+ 현재 브랜치:
+ 브랜치 리셋 (체크아웃 없음)
+ 이동 대상:
+ 브랜치:
+ 파일 탐색기에서 보기
+ 커밋 되돌리기
+ 커밋:
+ 되돌린 변경 사항 커밋
+ 커밋 메시지 수정
+ 실행 중. 잠시만 기다려주세요...
+ 저장
+ 다른 이름으로 저장...
+ 패치가 성공적으로 저장되었습니다!
+ 저장소 스캔
+ 루트 디렉터리:
+ 다른 사용자 정의 디렉터리 스캔
+ 업데이트 확인...
+ 이 소프트웨어의 새 버전을 사용할 수 있습니다:
+ 업데이트 확인 실패!
+ 다운로드
+ 이 버전 건너뛰기
+ 소프트웨어 업데이트
+ 현재 사용 가능한 업데이트가 없습니다.
+ 서브모듈 브랜치 설정
+ 서브모듈:
+ 현재:
+ 변경:
+ 선택 사항. 비어 있으면 기본값으로 설정됩니다.
+ 추적 브랜치 설정
+ 브랜치:
+ 업스트림 설정 해제
+ 업스트림:
+ SHA 복사
+ 이동
+ SSH 개인 키:
+ 개인 SSH 키 저장 경로
+ 시작
+ 스태시
+ 추적하지 않는 파일 포함
+ 메시지:
+ 선택 사항. 이 스태시의 메시지
+ 모드:
+ 스테이징된 변경 사항만
+ 선택한 파일의 스테이징된 변경 사항과 스테이징되지 않은 변경 사항이 모두 스태시됩니다!!!
+ 로컬 변경 사항 스태시
+ 적용
+ 메시지 복사
+ 삭제
+ 패치로 저장...
+ 스태시 삭제
+ 삭제:
+ 스태시
+ 변경 사항
+ 스태시
+ 통계
+ 개요
+ 이번 달
+ 이번 주
+ 작성자:
+ 커밋:
+ 서브모듈
+ 서브모듈 추가
+ 브랜치
+ 브랜치
+ 상대 경로
+ 초기화 해제
+ 중첩된 서브모듈 Fetch
+ 히스토리
+ 이동
+ 저장소 열기
+ 상대 경로:
+ 이 모듈을 저장할 상대 폴더입니다.
+ 삭제
+ 브랜치 설정
+ URL 변경
+ 상태
+ 수정됨
+ 초기화 안 됨
+ 리비전 변경됨
+ 업데이트
+ URL
+ 확인
+ 태그 생성자
+ 시간
+ 메시지
+ 이름
+ 태그 생성자
+ 태그 이름 복사
+ 사용자 지정 작업
+ ${0}$ 삭제...
+ 선택한 {0}개의 태그 삭제...
+ ${0}$을(를) ${1}$(으)로 병합...
+ ${0}$ 푸시...
+ 서브모듈 업데이트
+ 모든 서브모듈
+ 필요시 초기화
+ 서브모듈 재귀적으로 탐색
+ 서브모듈:
+ 서브모듈의 원격 추적 브랜치로 업데이트
+ URL:
+ 로그
+ 모두 지우기
+ 복사
+ 삭제
+ 경고
+ 시작 페이지
+ 그룹 생성
+ 하위 그룹 생성
+ 저장소 복제
+ 삭제
+ 폴더 끌어다 놓기 지원. 사용자 정의 그룹화 지원.
+ 편집
+ 다른 그룹으로 이동
+ 모든 저장소 열기
+ 저장소 열기
+ 터미널 열기
+ 기본 복제 디렉터리의 저장소 다시 스캔
+ 저장소 검색...
+ 로컬 변경 사항
+ Git 무시
+ 모든 *{0} 파일 무시
+ 같은 폴더의 *{0} 파일 무시
+ 이 폴더의 추적하지 않는 파일 무시
+ 이 파일만 무시
+ 수정
+ 이제 이 파일을 스테이징할 수 있습니다.
+ 히스토리 지우기
+ 모든 커밋 메시지 히스토리를 지우시겠습니까? 이 작업은 되돌릴 수 없습니다.
+ 커밋
+ 커밋 & 푸시
+ 템플릿/히스토리
+ 클릭 이벤트 트리거
+ 커밋 (수정)
+ 모든 변경 사항 스테이징 후 커밋
+ 분리된(detached) HEAD에 커밋을 생성하고 있습니다. 계속하시겠습니까?
+ {0}개의 파일을 스테이징했지만 {1}개의 파일만 표시됩니다 ({2}개의 파일은 필터링됨). 계속하시겠습니까?
+ 충돌 감지됨
+ 외부 병합 도구 열기
+ 모든 충돌을 외부 병합 도구에서 열기
+ 파일 충돌 해결됨
+ 내 것 사용
+ 상대방 것 사용
+ 추적하지 않는 파일 포함
+ 최근 입력한 메시지 없음
+ 커밋 템플릿 없음
+ 검증 안 함
+ 작성자 리셋
+ 서명(SignOff)
+ 스테이징됨
+ 언스테이지
+ 모두 언스테이지
+ 스테이징 안 됨
+ 스테이지
+ 모두 스테이지
+ 변경되지 않음으로 간주된 파일 보기
+ 템플릿: ${0}$
+ 작업 공간:
+ 작업 공간 설정...
+ 워크트리
+ 경로 복사
+ 잠금
+ 열기
+ 제거
+ 잠금 해제
+
diff --git a/src/Resources/Locales/pt_BR.axaml b/src/Resources/Locales/pt_BR.axaml
index 87a14a3af..b8681a11a 100644
--- a/src/Resources/Locales/pt_BR.axaml
+++ b/src/Resources/Locales/pt_BR.axaml
@@ -35,7 +35,7 @@
Atualizar
ARQUIVO BINÁRIO NÃO SUPORTADO!!!
Blame
- BLAME NESTE ARQUIVO NÃO É SUPORTADO!!!
+ BLAME NESTE ARQUIVO NÃO É SUPORTADO!!!
Checkout ${0}$...
Comparar com ${0}$
Comparar com Worktree
@@ -67,7 +67,7 @@
Aviso: Ao fazer o checkout de um commit, seu Head ficará desanexado
Alterações Locais:
Descartar
- Stash & Reaplicar
+ Stash & Reaplicar
Branch:
Cherry-Pick
Adicionar origem à mensagem de commit
@@ -113,8 +113,6 @@
REFERÊNCIAS
SHA
Abrir no navegador
- Descrição
- Insira o assunto do commit
Configurar Repositório
TEMPLATE DE COMMIT
Conteúdo do Template:
@@ -169,7 +167,7 @@
Checar o branch criado
Alterações Locais:
Descartar
- Guardar & Reaplicar
+ Guardar & Reaplicar
Nome do Novo Branch:
Insira o nome do branch.
Criar Branch Local
@@ -365,7 +363,6 @@
O Git NÃO foi configurado. Por favor, vá para [Preferências] e configure primeiro.
Abrir Pasta de Dados do Aplicativo
Abrir na Ferramenta de Mesclagem
- Abrir Com...
Opcional.
Criar Nova Página
Adicionar aos Favoritos
@@ -385,7 +382,6 @@
{0} meses atrás
{0} anos atrás
Ontem
- Use 'Shift+Enter' para inserir uma nova linha. 'Enter' é a tecla de atalho do botão OK
Preferências
INTELIGÊNCIA ARTIFICIAL
Prompt para Analisar Diff
@@ -400,7 +396,6 @@
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
@@ -447,7 +442,7 @@
Para:
Alterações Locais:
Descartar
- Guardar & Reaplicar
+ Guardar & Reaplicar
Remoto:
Puxar (Buscar & Mesclar)
Usar rebase em vez de merge
@@ -552,8 +547,6 @@
Atualização de Software
Não há atualizações disponíveis no momento.
Copiar SHA
- Squash Commits
- Squash commits em:
Chave SSH Privada:
Caminho para a chave SSH privada
INICIAR
@@ -586,8 +579,6 @@
Pasta relativa para armazenar este módulo.
Excluir Submódulo
OK
- Copiar Nome da Tag
- Copiar mensage da Tag
Excluir ${0}$...
Mesclar ${0}$ em ${1}$...
Enviar ${0}$...
diff --git a/src/Resources/Locales/ru_RU.axaml b/src/Resources/Locales/ru_RU.axaml
index c5472492a..ea658ef9e 100644
--- a/src/Resources/Locales/ru_RU.axaml
+++ b/src/Resources/Locales/ru_RU.axaml
@@ -5,6 +5,7 @@
О программе
О SourceGit
+ Примечания выпуска
Бесплатный графический клиент Git с исходным кодом
Добавить файл(ы) к игнорируемым
Шаблон:
@@ -13,7 +14,7 @@
Расположение:
Путь к рабочему каталогу (поддерживается относительный путь)
Имя ветки:
- Имя целевого каталога по умолчанию. (необязательно)
+ Имя целевого каталога по умолчанию (необязательно)
Отслеживание ветки:
Отслеживание внешней ветки
Переключиться на:
@@ -23,6 +24,8 @@
ПЕРЕСОЗДАТЬ
Использовать OpenAI для создания сообщения о ревизии
ПРИМЕНИТЬ КАК СООБЩЕНИЕ РЕВИЗИИ
+ Скрыть SourceGit
+ Показать все
Исправить
Файл заплатки:
Выберите файл .patch для применения
@@ -53,14 +56,18 @@
Пропустить
Раздвоение. Сделать текущую ревизию хорошей или плохой и переключиться на другой.
Расследование
- РАССЛЕДОВАНИЕ В ЭТОМ ФАЙЛЕ НЕ ПОДДЕРЖИВАЕТСЯ!!!
+ Расследование на предыдущей редакции
+ РАССЛЕДОВАНИЕ В ЭТОМ ФАЙЛЕ НЕ ПОДДЕРЖИВАЕТСЯ!!!
Переключиться на ${0}$...
Сравнить с ${0}$
Сравнить с рабочим каталогом
Копировать имя ветки
+ Создать PR...
+ Создать PR для основной ветки ${0}$...
Изменить действие
Удалить ${0}$...
Удалить выбранные {0} ветки
+ Править описание для ${0}$...
Перемотать вперёд к ${0}$
Извлечь ${0}$ в ${1}$...
Git-процесс - Завершение ${0}$
@@ -72,13 +79,18 @@
Переместить ${0}$ на ${1}$...
Переименовать ${0}$...
Сбросить ${0}$ к ${1}$...
+ Переключить на ${0}$ (рабочий каталог)
Отслеживать ветку...
Сравнение веток
- ЛОКАЛЬНЫЙ
+ {0} ревизий вперёд
+ {0} ревизий вперёд, {1} ревизий назад
+ {0} ревизий назад
+ Неверно
УДАЛЁННЫЙ
+ СОСТОЯНИЕ
ОТСЛЕЖИВАНИЕ
URL-АДРЕС
- Недопустимая основная ветка!
+ РАБОЧИЙ КАТАЛОГ
ОТМЕНА
Сбросить родительскую ревизию
Сбросить эту ревизию
@@ -96,8 +108,7 @@
Предупреждение: После переключения ревизии ваша Голова (HEAD) будет отсоединена
Локальные изменения:
Отклонить
- Отложить и примненить повторно
- Обновить все подкаталоги
+ Отложить и применить повторно
Ветка:
Ваша текущая ГОЛОВА содержит ревизию(и), не связанные ни с к какими ветками или метками! Вы хотите продолжить?
Переключиться и перемотать
@@ -111,12 +122,12 @@
Очистить отложенные
Вы пытаетесь очистить все отложенные. Вы уверены, что хотите продолжить?
Клонировать внешний репозиторий
- Расширенные параметры:
- Дополнительные аргументы для клонирования репозитория. (необязательно).
+ Параметры:
+ Аргументы git clone (необязательно)
Локальное имя:
- Имя репозитория. (необязательно).
+ Имя репозитория (необязательно)
Родительский каталог:
- Создать и обновить подмодуль
+ Создать и обновить подмодули
Адрес репозитория:
ЗАКРЫТЬ
Редактор
@@ -131,13 +142,14 @@
SHA
Субъект
Пользовательское действие
+ Бросить ревизию
Интерактивное перемещение
Бросить...
Редактировать...
Исправить в родительском...
Интерактивное перемещение ${0}$ в ${1}$
- Имзенить комментарий...
- Втиуснуть в родительский...
+ Изменить комментарий...
+ Втиснуть в родительский...
Влить в ${0}$
Влить ...
Выложить ${0}$ в ${1}$
@@ -147,6 +159,7 @@
Изменить комментарий
Сохранить как заплатки...
Объединить с предыдущей ревизией
+ Исправить в родительском
ИЗМЕНЕНИЯ
изменённый(х) файл(ов)
Найти изменения....
@@ -160,6 +173,9 @@
РЕВИЗОР (ИСПОЛНИТЕЛЬ)
Найти все ветки с этой ревизией
ВЕТКИ С ЭТОЙ РЕВИЗИЕЙ
+ Копировать адрес почты
+ Копировать имя
+ Копировать имя и адрес почты
Отображаются только первые 100 изменений. Смотрите все изменения на вкладке ИЗМЕНЕНИЯ.
Ключ:
СООБЩЕНИЕ
@@ -168,25 +184,41 @@
SHA
Подписант:
Открыть в браузере
- Описание
+ Введите сообщение ревизии. Пожалуйста, используйте пустые строки для разделения субъекта и описания!
СУБЪЕКТ
- Введите тему ревизии
Настройка репозитория
ШАБЛОН РЕВИЗИИ
- Вы можете использовать ${files_num}, ${branch_name}, ${files} и ${files:N}, где N — максимальное количество путей к файлам для вывода.
+ Встроенные параметры:
+
+ ${branch_name} Имя текущей локальной ветки
+ ${files_num} Количество изменённых файлов
+ ${files} Пути изменённых файлов
+ ${files:N} Пути изменённых файлов, не более N
+ ${pure_files} То же, что и ${files}, но только имена файлов
+ ${pure_files:N} То же, что и ${files:N}, но только имена файлов
Cодержание:
Название:
ПОЛЬЗОВАТЕЛЬСКОЕ ДЕЙСТВИЕ
Аргументы:
- Встроенные параметры: ${REPO} — путь к репозиторию; ${BRANCH} — выбранная ветка; ${SHA} — хеш выбранной ревизии; ${TAG} — выбранная метка
+ Встроенные параметры:
+
+ ${REPO} Путь репозитория
+ ${REMOTE} Выбранная удаённая ветка
+ ${BRANCH} Выбранная ветка, без ${REMOTE} удалённых веток
+ ${BRANCH_FRIENDLY_NAME} Понятное имя выбранной ветки, содержащую ${REMOTE} удалённые ветки
+ ${SHA} Хеш выбранной ревизии
+ ${TAG} Выбранная метка
+ ${FILE} Выбранный файл, относительно корня репозитория
+ $1, $2 ... Ввод управляющих значений
Исполняемый файл:
Элементы управления вводом:
Редактор
- Вы можете использовать $1, $2 ... в аргументах для значений элемента управления вводом
Имя:
Диапазон:
Ветка
Ревизия
+ Файл
+ Удалённый
Репозиторий
Метка
Ждать для выполения выхода
@@ -195,10 +227,12 @@
GIT
Автозагрузка изменений
Минут(а/ы)
+ Общепринятые типы ревизии
Внешний репозиторий по умолчанию
Предпочтительный режим слияния
ОТСЛЕЖИВАНИЕ ПРОБЛЕМ
Добавить пример правила Azure DevOps
+ Добавить правило Gerrit ревизии идентификатора изменения
Добавить пример правила для тем в Gitea
Добавить пример правила запроса скачивания из Gitea
Добавить пример правила для Git
@@ -227,6 +261,7 @@
Метка:
Опции:
Используйте разделитель «|» для опций
+ Встроенные переменные ${REPO}, ${REMOTE}, ${BRANCH}, ${BRANCH_FRIENDLY_NAME}, ${SHA}, ${FILE}, и ${TAG} останутся здесь доступными
Тип:
Рабочие пространства
Цвет
@@ -235,7 +270,7 @@
ПРОДОЛЖИТЬ
Обнаружена пустая ревизия! Вы хотите продолжить (--allow-empty)?
Сформировать всё и зафиксировать ревизию
- Обнаружена пустая ревизия! Вы хотите продолжить (--allow-empty) или отложить всё, затем зафиксировать ревизию?
+ Обнаружена пустая ревизия! Вы хотите продолжить (--allow-empty) или отложить всё, а затем зафиксировать ревизию?
Требуется перезапуск
Вы должны перезапустить приложение после применения изменений.
Общепринятый помощник по ревизии
@@ -254,10 +289,9 @@
Переключиться на созданную ветку
Локальные изменения:
Отклонить
- Отложить и применить повторно
+ Отложить и применить повторно
Имя новой ветки:
Введите имя ветки.
- Пробелы будут заменены на тире.
Создать локальную ветку
Перезаписать существующую ветку
Создать метку...
@@ -283,6 +317,9 @@
Также удалите внешнюю ветку ${0}$
Удаление нескольких веток
Вы пытаетесь удалить несколько веток одновременно. Обязательно перепроверьте, прежде чем предпринимать какие-либо действия!
+ Удалить несколько меток
+ Удалить их с удалённого
+ Вы пытаетесь удалить сразу несколько меток. Перепроверьте обязательно перед выполнением!
Удалить внешний репозиторий
Внешний репозиторий:
Путь:
@@ -301,6 +338,7 @@
Первое сравнение
Игнорировать изменения пробелов
СМЕСЬ
+ СРАВНЕНИЕ
РЯДОМ
СМАХИВАНИЕ
Последнее сравнение
@@ -319,13 +357,15 @@
Обмен
Подсветка синтаксиса
Перенос слов в строке
- Разрешить навигацию по блокам
Открыть в инструменте слияния
Показывать все строки
Меньше видимых строк
Больше видимых строк
ВЫБЕРИТЕ ФАЙЛ ДЛЯ ПРОСМОТРА ИЗМЕНЕНИЙ
Каталог историй
+ Есть локальные изменения
+ Не соответствует с исходящим потоком
+ В актуальном состоянии
Отклонить изменения
Все локальные изменения в рабочей копии.
Изменения:
@@ -333,6 +373,11 @@
Включить неотслеживаемые файлы
{0} изменений будут отменены
Вы не можете отменить это действие!!!
+ Бросить ревизию
+ Ревизия:
+ Новая ГОЛОВА:
+ Править описание ветки
+ Цель:
Закладка:
Новое имя:
Цель:
@@ -347,6 +392,7 @@
Внешний репозиторий:
Извлечь внешние изменения
Не отслеживать
+ Пользовательское действие
Отклонить...
Отклонить {0} файлов...
Взять версию ${0}$
@@ -402,6 +448,8 @@
Показывать только мои блокировки
Блокировки LFS
Разблокировать
+ Снять все мои блокировки
+ Вы уверены, что хотите снять все свои блокировки?
Принудительно разблокировать
Обрезать
Запустить (git lfs prune), чтобы удалить старые файлы LFS из локального хранилища
@@ -424,34 +472,35 @@
Удерживайте Ctrl или Shift, чтобы выбрать несколько ревизий.
Удерживайте ⌘ или ⇧, чтобы выбрать несколько ревизий.
ПОДСКАЗКИ:
- Ссылка на сочетания клавиш
- ОБЩЕЕ
+ Справка по сочетаниям клавиш
+ ГЛОБАЛЬНЫЕ
Клонировать репозиторий
- Закрыть вкладку
+ Закрыть текущую вкладку
Перейти на следующую вкладку
Перейти на предыдущую вкладку
Создать новую вкладку
Открыть диалоговое окно настроек
- Переключить активное рабочее место
- Переключить активную страницу
+ Показать рабочее пространство в выпадющем меню
+ Переключиться на вкладку
РЕПОЗИТОРИЙ
Зафиксировать сформированные изменения
Зафиксировать и выложить сформированные изменения
Сформировать все изменения и зафиксировать
- Извлечение, запускается сразу
+ Извлечь (fetch), запускается сразу
Режим доски (по умолчанию)
+ Открыть палитру команд
Режим поиска ревизий
- Загрузить, запускается сразу
- Выложить, запускается сразу
- Принудительно перезагрузить репозиторий
+ Загрузить (pull), запускается сразу
+ Выложить (push), запускается сразу
+ Принудительно перечитать репозиторий
Переключить на «Изменения»
- Переключить на «Истории»
+ Переключить на «Историю»
Переключить на «Отложенные»
ТЕКСТОВЫЙ РЕДАКТОР
Закрыть панель поиска
Найти следующее совпадение
Найти предыдущее совпадение
- Открыть с внешним инструментом сравнения/слияния
+ Открыть во внешнем инструменте сравнения/слияния
Открыть панель поиска
Отклонить
Сформировать
@@ -473,10 +522,12 @@
Целевая ветка:
Копировать ссылку
Открыть в браузере
+ Команды
ОШИБКА
УВЕДОМЛЕНИЕ
+ Открыть репозитории
+ Вкладки
Рабочие места
- Страницы
Влить ветку
Изменить сообщение слияния
В:
@@ -493,16 +544,20 @@
Выбрать группу для:
Имя:
Git НЕ был настроен. Пожалуйста, перейдите в [Настройки] и сначала настройте его.
+ Открыть
+ Редактор по умолчанию (Системный)
Открыть каталог данных программы
+ Открыть файл
Открыть в инструменте слияния
- Окрыть с...
Необязательно.
- Создать новую страницу
+ Создать новую вкладку
Закладка
Закрыть вкладку
Закрыть другие вкладки
Закрыть вкладки справа
Копировать путь репозитория
+ Переместить в рабочее пространство
+ Обновить
Репозитории
Вставить
{0} дней назад
@@ -515,7 +570,6 @@
{0} месяцев назад
{0} лет назад
Вчера
- Используйте «Shift+Enter» для ввода новой строки. «Enter» - это горячая клавиша кнопки «OK»
Параметры
ОТКРЫТЬ ИИ
Запрос на анализ сравнения
@@ -523,6 +577,7 @@
Создать запрос на тему
Модель
Имя:
+ Введённое значение — это имя для загрузки API-ключа из ENV
Сервер
Разрешить потоковую передачу
ВИД
@@ -532,24 +587,32 @@
По умолчанию
Редактор
Моноширный шрифт
- В текстовом редакторе используется только моноширный шрифт
Тема
Переопределение темы
+ Автоматически скрывать прокрутку
Использовать фиксированную ширину табуляции в строке заголовка.
Использовать системное окно
ИНСТРУМЕНТ СРАВНЕНИЙ/СЛИЯНИЯ
+ Аргументы сравнения
+ Доступны переменные: $LOCAL, $REMOTE
+ Слить аргументы
+ Доступны переменные: $BASE, $LOCAL, $REMOTE, $MERGED
Путь установки
Введите путь для инструмента сравнения/слияния
Инструмент
ОСНОВНЫЕ
Проверить обновления при старте
Формат даты
+ Включить компактные каталоги в дереве изменений
Язык
Максимальная длина истории
Показывать время автора вместо времени ревизии на графике
+ Показывать вкладку «ЛОКАЛЬНЫЕ ИЗМЕНЕНИЯ» по умолчанию
+ Показывать вкладку «Изменения» в сведении ревизии по умолчанию
Показать наследника в деталях комментария
Показывать метки на графике
Длина темы ревизии
+ Создать Github-подобный аватар по умолчанию
GIT
Включить автозавершение CRLF
Каталог клонирования по умолчанию
@@ -574,6 +637,8 @@
Ключ GPG подписи пользователя
ВНЕДРЕНИЕ
ОБОЛОЧКА/ТЕРМИНАЛ
+ Аргументы
+ Используйте, пожалуйста, точку «.» для индикации рабочего каталога
Путь
Оболочка/Терминал
Удалить внешний репозиторий
@@ -585,8 +650,7 @@
В:
Локальные изменения:
Отклонить
- Отложить и применить повторно
- Обновить все подмодули
+ Отложить и применить повторно
Внешний репозиторий:
Загрузить (Получить и слить)
Использовать перемещение вместо слияния
@@ -606,6 +670,8 @@
Выложить на все внешние репозитории
Внешний репозиторий:
Метка:
+ Отправить к НОВОЙ ветке
+ Введитте имя для новой удалённой ветки:
Выйти
Перемещение текущей ветки
Отложить и применить повторно локальные изменения
@@ -617,6 +683,7 @@
Адрес:
Адрес внешнего репозитория git
Копировать адрес
+ Пользовательские действия
Удалить...
Редактировать...
Извлечь
@@ -642,6 +709,7 @@
ПРОДОЛЖИТЬ
Изменить действия
Не изменять действия
+ Панель
Отклонить все изменения.
Открыть в файловом менеджере
Поиск веток, меток и подмодулей
@@ -656,6 +724,7 @@
Дата ревизии
Топологически
ЛОКАЛЬНЫЕ ВЕТКИ
+ Больше опций...
Навигация по ГОЛОВЕ (HEAD)
Создать ветку
ОЧИСТКА УВЕДОМЛЕНИЙ
@@ -712,15 +781,16 @@
СОХРАНИТЬ
Сохранить как...
Заплатка успешно сохранена!
- Сканирование репозиторий
+ Обнаружение репозиториев
Корневой каталог:
- Проверка для обновления...
+ Сканировать другой пользовательский каталог
+ Проверить обновления...
Доступна новая версия программного обеспечения:
Не удалось проверить наличие обновлений!
Загрузка
Пропустить эту версию
Обновление ПО
- В настоящее время обновления недоступны.
+ Сейчас нет обновлений.
Установить ветку подмодуля
Подмодуль:
Текущий:
@@ -732,8 +802,9 @@
Основная ветка:
Копировать SHA
Перейти
- Втиснуть ревизии
- В:
+ Втиснуть ГОЛОВУ (HEAD) в родительскую
+ Исправить ГОЛОВУ (HEAD) в родительском
+ В:
Приватный ключ SSH:
Путь хранения приватного ключа SSH
ЗАПУСК
@@ -762,7 +833,8 @@
РЕВИЗИИ:
ПОДМОДУЛИ
Добавить подмодули
- Ветка
+ ВЕТКА
+ Ветка
Каталог
Удалить подмодуль
Извлечение вложенных подмодулей
@@ -782,10 +854,15 @@
Обновить
URL-адрес
ОК
- Копировать имя метки
- Копировать сообщение метки
+ РАЗМЕТЧИК
+ ВРЕМЯ
+ Сообщение
+ Имя
+ Разметчик
+ Копировать имя метки
Пользовательское действие
Удалить ${0}$...
+ Удалить выбранные метки ({0})...
Влить ${0}$ в ${1}$...
Выложить ${0}$...
Обновление подмодулей
@@ -802,17 +879,17 @@
Предупреждение
Приветствие
Создать группу
- Создать подгруппу
+ Создать подгруппу...
Клонировать репозиторий
- Удалить
+ Удалить...
ПОДДЕРЖИВАЕТСЯ: ПЕРЕТАСКИВАНИЕ КАТАЛОГОВ, ПОЛЬЗОВАТЕЛЬСКАЯ ГРУППИРОВКА.
- Редактировать
- Перейти в другую группу
+ Редактировать...
+ Переместить в другую группу...
Открыть все репозитории
Открыть репозиторий
Открыть терминал
- Повторное сканирование репозиториев в каталоге клонирования по умолчанию
- Поиск репозиториев...
+ Обнаружить репозитории в каталоге клонирования по умолчанию
+ Найти репозиторий...
Изменения
Игнорировать Git
Игнорировать все *{0} файлы
@@ -821,6 +898,8 @@
Игнорировать только эти файлы
Изменить
Теперь вы можете сформировать этот файл.
+ Очистить историю
+ Вы действительно хотите очистить всю историю сообщений ревизии? Данное действие нельзя отменить.
ЗАФИКСИРОВАТЬ
ЗАФИКСИРОВАТЬ и ОТПРАВИТЬ
Шаблон/Истории
@@ -838,6 +917,7 @@
ВКЛЮЧИТЬ НЕОТСЛЕЖИВАЕМЫЕ ФАЙЛЫ
НЕТ ПОСЛЕДНИХ ВХОДНЫХ СООБЩЕНИЙ
НЕТ ШАБЛОНОВ РЕВИЗИИ
+ Не проверять
Сбросить автора
Завершение работы
СФОРМИРОВАННЫЕ
@@ -853,6 +933,7 @@
РАБОЧИЙ КАТАЛОГ
Копировать путь
Заблокировать
+ Открыть
Удалить
Разблокировать
diff --git a/src/Resources/Locales/ta_IN.axaml b/src/Resources/Locales/ta_IN.axaml
index 7604b3bd2..3dc6b1c30 100644
--- a/src/Resources/Locales/ta_IN.axaml
+++ b/src/Resources/Locales/ta_IN.axaml
@@ -41,7 +41,7 @@
புதுப்பி
இருமம் கோப்பு ஆதரிக்கப்படவில்லை!!!
குற்றச்சாட்டு
- இந்த கோப்பில் குற்றம் சாட்ட ஆதரிக்கப்படவில்லை!!!
+ இந்த கோப்பில் குற்றம் சாட்ட ஆதரிக்கப்படவில்லை!!!
${0}$ சரிபார்...
பணிமரத்துடன் ஒப்பிடுக
கிளை பெயரை நகலெடு
@@ -60,7 +60,6 @@
மறுபெயரிடு ${0}$...
கண்காணிப்பு கிளையை அமை...
கிளை ஒப்பிடு
- தவறான மேல்ஓடை!
விடு
பெற்றோர் திருத்தத்திற்கு மீட்டமை
இந்த திருத்தத்திற்கு மீட்டமை
@@ -75,7 +74,7 @@
முன்னறிவிப்பு: ஒரு உறுதிமொழி சரிபார்பதன் மூலம், உங்கள் தலை பிரிக்கப்படும்
உள்ளக மாற்றங்கள்:
நிராகரி
- பதுக்கிவை & மீண்டும் இடு
+ பதுக்கிவை & மீண்டும் இடு
கிளை:
கனி பறி
உறுதிமொழி செய்திக்கு மூலத்தைச் சேர்
@@ -126,8 +125,6 @@
குறிகள்
பாகொவ
உலாவியில் திற
- விளக்கம்
- உறுதிமொழி பொருளை உள்ளிடவும்
களஞ்சியம் உள்ளமை
உறுதிமொழி வளர்புரு
வார்ப்புரு உள்ளடக்கம்:
@@ -187,10 +184,9 @@
உருவாக்கப்பட்ட கிளையைப் சரிபார்
உள்ளக மாற்றங்கள்:
நிராகரி
- பதுக்கிவை & மீண்டும் இடு
+ பதுக்கிவை & மீண்டும் இடு
புதிய கிளை பெயர்:
கிளை பெயரை உள்ளிடவும்.
- இடைவெளிகள் கோடுகளால் மாற்றப்படும்.
உள்ளக கிளையை உருவாக்கு
குறிச்சொல்லை உருவாக்கு...
இங்கு புதிய குறிச்சொல்:
@@ -242,7 +238,6 @@
இடமாற்று
தொடரியல் சிறப்பம்சமாக்கல்
வரி சொல் மடக்கு
- தடுப்பு-வழிசெலுத்தலை இயக்கு
ஒன்றிணை கருவியில் திற
அனைத்து வரிகளையும் காட்டு
தெரியும் வரிகளின் எண்ணிக்கையைக் குறை
@@ -402,7 +397,6 @@
அறிவிலி உள்ளமைக்கப்படவில்லை. [விருப்பத்தேர்வுகள்]க்குச் சென்று முதலில் அதை உள்ளமை.
தரவு சேமிப்பக கோப்பகத்தைத் திற
ஒன்றிணை கருவியில் திற
- இதனுடன் திற...
விருப்பத்தேர்வு.
புதிய பக்கத்தை உருவாக்கு
புத்தகக்குறி
@@ -422,7 +416,6 @@
{0} திங்களுக்கு முன்பு
{0} ஆண்டுகளுக்கு முன்பு
நேற்று
- புதிய வரியை உள்ளிட 'உயர்த்து+நுழை' ஐப் பயன்படுத்தவும். 'நுழை' என்பது சரி பொத்தானின் சூடானவிசை ஆகும்
விருப்பத்தேர்வுகள்
செநு
வேறுபாடு உடனடியாக பகுப்பாய்வு செய்
@@ -439,7 +432,6 @@
இயல்புநிலை
திருத்தி
ஒற்றைவெளி எழுத்துரு
- ஒற்றைவெளி எழுத்துருவை உரை திருத்தியில் மட்டும் பயன்படுத்து
கருப்பொருள்
கருப்பொருள் மேலெழுதப்படுகிறது
தலைப்புப்பட்டியில் நிலையான தாவல் அகலத்தைப் பயன்படுத்து
@@ -490,7 +482,7 @@
இதனுள்:
உள்ளக மாற்றங்கள்:
நிராகரி
- பதுக்கிவை & மீண்டும் இடு
+ பதுக்கிவை & மீண்டும் இடு
தொலை:
இழு (எடுத்து ஒன்றிணை)
ஒன்றிணை என்பதற்குப் பதிலாக மறுதளத்தைப் பயன்படுத்து
@@ -610,8 +602,6 @@
மேல்ஓடை:
SHA ஐ நகலெடு
இதற்கு செல்
- நொறுக்கு உறுதிமொழிகள்
- இதில்:
பாஓடு தனியார் திறவுகோல்:
தனியார் பாஓடு திறவுகோல் கடை பாதை
தொடங்கு
@@ -645,8 +635,6 @@
இந்த தொகுதியை சேமிப்பதற்கான தொடர்புடைய கோப்புறை.
துணை தொகுதியை நீக்கு
சரி
- குறிச்சொல் பெயரை நகலெடு
- குறிச்சொல் செய்தியை நகலெடு
நீக்கு ${0}$...
${0}$ இதை ${1}$ இல் இணை...
தள்ளு ${0}$...
diff --git a/src/Resources/Locales/uk_UA.axaml b/src/Resources/Locales/uk_UA.axaml
index b4b4ccbfd..fa15b7c4b 100644
--- a/src/Resources/Locales/uk_UA.axaml
+++ b/src/Resources/Locales/uk_UA.axaml
@@ -41,7 +41,7 @@
Оновити
БІНАРНИЙ ФАЙЛ НЕ ПІДТРИМУЄТЬСЯ!!!
Автор рядка
- ПОШУК АВТОРА РЯДКА ДЛЯ ЦЬОГО ФАЙЛУ НЕ ПІДТРИМУЄТЬСЯ!!!
+ ПОШУК АВТОРА РЯДКА ДЛЯ ЦЬОГО ФАЙЛУ НЕ ПІДТРИМУЄТЬСЯ!!!
Перейти на ${0}$...
Порівняти з ${0}$
Порівняти з робочим деревом
@@ -61,7 +61,6 @@
Перейменувати ${0}$...
Встановити відстежувану гілку...
Порівняти гілки
- Недійсний upstream!
СКАСУВАТИ
Скинути до батьківської ревізії
Скинути до цієї ревізії
@@ -76,7 +75,7 @@
Попередження: Перехід на коміт призведе до стану "від'єднаний HEAD"
Локальні зміни:
Скасувати
- Сховати та Застосувати
+ Сховати та Застосувати
Гілка:
Cherry-pick
Додати джерело до повідомлення коміту
@@ -127,8 +126,6 @@
ПОСИЛАННЯ (Refs)
SHA
Відкрити в браузері
- Опис
- Введіть тему коміту
Налаштування сховища
ШАБЛОН КОМІТУ
Зміст шаблону:
@@ -192,10 +189,9 @@
Перейти на створену гілку
Локальні зміни:
Скасувати
- Сховати та Застосувати
+ Сховати та Застосувати
Назва нової гілки:
Введіть назву гілки.
- Пробіли будуть замінені на тире.
Створити локальну гілку
Створити тег...
Новий тег для:
@@ -247,7 +243,6 @@
Поміняти місцями
Підсвітка синтаксису
Перенос слів
- Увімкнути навігацію блоками
Відкрити в інструменті злиття
Показати всі рядки
Зменшити кількість видимих рядків
@@ -407,7 +402,6 @@
Git не налаштовано. Будь ласка, перейдіть до [Налаштування] та налаштуйте його.
Відкрити теку зберігання даних
Відкрити в інструменті злиття
- Відкрити за допомогою...
Необов'язково.
Створити нову вкладку
Закладка
@@ -427,7 +421,6 @@
{0} місяців тому
{0} років тому
Вчора
- Використовуйте 'Shift+Enter' для введення нового рядка. 'Enter' - гаряча клавіша кнопки OK
Налаштування
AI
Промпт для аналізу різниці
@@ -444,7 +437,6 @@
За замовчуванням
Редактор
Моноширинний шрифт
- Використовувати моноширинний шрифт лише в текстовому редакторі
Тема
Перевизначення теми
Використовувати фіксовану ширину вкладки в заголовку
@@ -495,7 +487,7 @@
В:
Локальні зміни:
Скасувати
- Сховати та Застосувати
+ Сховати та Застосувати
Віддалене сховище:
Pull (Fetch & Merge)
Використовувати rebase замість merge
@@ -615,8 +607,6 @@
Upstream:
Копіювати SHA
Перейти до
- Squash (Склеїти коміти)
- В:
Приватний ключ SSH:
Шлях до сховища приватного ключа SSH
ПОЧАТИ
@@ -650,8 +640,6 @@
Відносна тека для зберігання цього модуля.
Видалити підмодуль
OK
- Копіювати назву тегу
- Копіювати повідомлення тегу
Видалити ${0}$...
Злиття ${0}$ в ${1}$...
Надіслати ${0}$...
diff --git a/src/Resources/Locales/zh_CN.axaml b/src/Resources/Locales/zh_CN.axaml
index 1f024429f..bab627b7f 100644
--- a/src/Resources/Locales/zh_CN.axaml
+++ b/src/Resources/Locales/zh_CN.axaml
@@ -5,6 +5,7 @@
关于软件
关于本软件
+ 浏览版本更新说明
开源免费的Git客户端
新增忽略文件
匹配模式 :
@@ -23,6 +24,8 @@
重新生成
使用AI助手生成提交信息
应用本次生成
+ 隐藏 SourceGit
+ 显示所有窗口
应用补丁(apply)
补丁文件 :
选择补丁文件
@@ -53,14 +56,18 @@
无法判定
二分定位进行中。请标记当前的提交是 '正确' 还是 '错误',然后检出另一个提交。
逐行追溯(blame)
- 选中文件不支持该操作!!!
+ 对当前版本的前一版本执行逐行追溯操作
+ 选中文件不支持该操作!!!
检出(checkout) ${0}$...
与当前 ${0}$ 比较
与本地工作树比较
复制分支名
+ 创建合并请求 ...
+ 为上游分支 ${0}$ 创建合并请求 ...
自定义操作
删除 ${0}$...
删除选中的 {0} 个分支
+ 编辑 ${0}$ 的描述...
快进(fast-forward)到 ${0}$
拉取(fetch) ${0}$ 至 ${1}$...
GIT工作流 - 完成 ${0}$
@@ -72,13 +79,18 @@
变基(rebase) ${0}$ 至 ${1}$...
重命名 ${0}$...
重置 ${0}$ 到 ${1}$...
+ 切换到 ${0}$ (工作树)
切换上游分支 ...
分支比较
- 本地
+ 领先 {0} 个提交
+ 领先 {0} 个提交,落后 {1} 个提交
+ 落后 {0} 个提交
+ 不存在
远程
+ 状态
上游分支
远程地址
- 跟踪的上游分支不存在或已删除!
+ 工作树
取 消
重置文件到上一版本
重置文件到该版本
@@ -96,8 +108,7 @@
注意:执行该操作后,当前HEAD会变为游离(detached)状态!
未提交更改 :
丢弃更改
- 贮藏并自动恢复
- 同时更新所有子模块
+ 贮藏并自动恢复
目标分支 :
您当前游离的HEAD包含未被任何分支及标签引用的提交!是否继续?
检出分支并快进
@@ -131,6 +142,7 @@
提交指纹
主题
自定义操作
+ 丢弃此提交
交互式变基(rebase -i)
丢弃...
编辑...
@@ -147,6 +159,7 @@
编辑提交信息
另存为补丁 ...
合并此提交到上一个提交
+ 修复至父提交
变更对比
个文件发生变更
查找变更...
@@ -160,6 +173,9 @@
提交者
查看包含此提交的分支/标签
本提交已被以下分支/标签包含
+ 复制电子邮箱
+ 复制用户名
+ 复制用户名及邮箱
仅显示前100项变更。请前往【变更对比】页面查看全部。
签名密钥 :
提交信息
@@ -168,25 +184,41 @@
提交指纹
签名者 :
浏览器中查看
- 详细描述
+ 请输入提交的信息。注意:主题与具体描述中间需要空白行分隔!
主题
- 填写提交信息主题
仓库配置
提交信息模板
- 您可使用 ${files_num}, ${branch_name}, ${files} 或 ${files:N}(N表示最大显示的文件数)
+ 内置变量:
+
+ ${branch_name} 当前分支名
+ ${files_num} 变更文件数量
+ ${files} 变更文件路径列表
+ ${files:N} 变更文件路径列表(仅输出指定 N 条)
+ ${pure_files} 与 ${files} 类似,但仅输出文件名
+ ${pure_files:N} 与 ${files:N} 类似,但仅输出文件名
模板内容 :
模板名 :
自定义操作
命令行参数 :
- 内置变量:${REPO} 仓库路径、${BRANCH} 选中的分支、${SHA} 选中的提交哈希,${TAG} 选中的标签
+ 内置变量:
+
+ ${REPO} 仓库路径
+ ${REMOTE} 选中的远程仓库或选中分支所属的远程仓库
+ ${BRANCH} 选中的分支,对于远程分支不包含远程名
+ ${BRANCH_FRIENDLY_NAME} 选中的分支,对于远程分支包含远程名
+ ${SHA} 选中的提交哈希
+ ${TAG} 选中的标签
+ ${FILE} 选中的文件
+ $1, $2 ... 输入控件中填写的值
可执行文件路径 :
输入控件 :
编辑
- 请在命令行参数中使用 $1, $2 等占位符表示输入控件的值
名称 :
作用目标 :
选中的分支
选中的提交
+ 选中的文件
+ 远程仓库
仓库
选中的标签
等待操作执行完成
@@ -195,10 +227,12 @@
GIT配置
启用定时自动拉取远程更新
分钟
+ 自定义规范化提交类型
默认远程
默认合并方式
ISSUE追踪
新增匹配Azure DevOps规则
+ 新增匹配Gerrit Change-Id规则
新增匹配Gitee议题规则
新增匹配Gitee合并请求规则
新增匹配GitHub Issue规则
@@ -227,6 +261,7 @@
名称 :
选项列表 :
选项之间请使用英文 '|' 作为分隔符
+ 内置变量 ${REPO}, ${REMOTE}, ${BRANCH}, ${BRANCH_FRIENDLY_NAME}, ${SHA}, ${FILE} 与 ${TAG} 在这里仍然可用
类型 :
工作区
颜色
@@ -254,10 +289,9 @@
完成后切换到新分支
未提交更改 :
丢弃更改
- 贮藏并自动恢复
+ 贮藏并自动恢复
新分支名 :
填写分支名称。
- 空格将被替换为'-'符号
创建本地分支
允许重置已存在的分支
新建标签 ...
@@ -283,6 +317,9 @@
同时删除远程分支 ${0}$
删除多个分支
您正在尝试一次性删除多个分支,请务必仔细检查后再执行操作!
+ 删除多个标签
+ 同时在远程仓库中删除
+ 您正在尝试一次性删除多个标签,请务必仔细检查后再执行操作!
删除远程确认
远程名 :
路径 :
@@ -301,6 +338,7 @@
首个差异
忽略空白符号变化
混合对比
+ 差异比较
分列对比
填充对比
最后一个差异
@@ -319,13 +357,15 @@
交换比对双方
语法高亮
自动换行
- 启用基于变更块的跳转
使用外部合并工具查看
显示完整文件
减少可见的行数
增加可见的行数
请选择需要对比的文件
目录内容变更历史
+ 未提交的本地变更
+ 当前分支HEAD与远端不一致
+ 已是最新
放弃更改确认
所有本仓库未提交的修改。
变更 :
@@ -333,6 +373,11 @@
包括未跟踪的文件
总计{0}项选中更改
本操作不支持回退,请确认后继续!!!
+ 丢弃提交
+ 提交 :
+ 丢弃后 HEAD :
+ 编辑分支描述
+ 目标 :
书签 :
名称 :
目标 :
@@ -347,6 +392,7 @@
远程仓库 :
拉取远程仓库内容
不跟踪此文件的更改
+ 自定义操作
放弃更改...
放弃 {0} 个文件的更改...
应用 ${0}$
@@ -402,6 +448,8 @@
仅显示被我锁定的文件
LFS对象锁状态
解锁
+ 解锁所有被我锁定的文件
+ 确定要解锁所有被您锁定的文件吗?
强制解锁
精简本地LFS对象存储
运行`git lfs prune`命令,从本地存储中精简当前版本不需要的LFS对象
@@ -432,7 +480,7 @@
切换到上一个页面
新建页面
打开偏好设置面板
- 切换工作区
+ 显示工作区下拉菜单
切换显示页面
仓库页面快捷键
提交暂存区更改
@@ -440,6 +488,7 @@
自动暂存全部变更并提交
拉取 (fetch) 远程变更
切换左边栏为分支/标签等显示模式(默认)
+ 打开快捷命令面板
切换左边栏为提交搜索模式
拉回 (pull) 远程变更
推送本地变更到远程
@@ -473,10 +522,12 @@
目标分支 :
复制链接地址
在浏览器中访问
+ 命令列表
出错了
系统提示
- 工作区列表
+ 打开其他仓库
页面列表
+ 工作区列表
合并分支
编辑合并信息
目标分支 :
@@ -493,9 +544,11 @@
请选择目标分组:
名称 :
GIT尚未配置。请打开【偏好设置】配置GIT路径。
+ 打开
+ 系统默认编辑器
浏览应用数据目录
+ 打开文件
使用外部对比工具查看
- 打开文件...
选填。
新建空白页
设置书签
@@ -503,6 +556,8 @@
关闭其他标签页
关闭右侧标签页
复制仓库路径
+ 移至工作区
+ 刷新
新标签页
粘贴
{0}天前
@@ -515,7 +570,6 @@
{0}个月前
{0}年前
昨天
- 请使用Shift+Enter换行。Enter键已被【确 定】按钮占用。
偏好设置
AI
Analyze Diff Prompt
@@ -523,6 +577,7 @@
Generate Subject Prompt
模型
配置名称
+ 从环境变量(填写环境变量名)中读取API密钥
服务地址
启用流式输出
外观配置
@@ -532,24 +587,32 @@
默认
代码编辑器
等宽字体
- 仅在文本编辑器中使用等宽字体
主题
主题自定义
+ 允许滚动条自动隐藏
主标签使用固定宽度
使用系统默认窗体样式
对比/合并工具
+ 对比命令参数
+ 可用参数:$LOCAL, $REMOTE
+ 合并命令参数
+ 可用参数:$BASE, $LOCAL, $REMOTE, $MERGED
安装路径
填写工具可执行文件所在位置
工具
通用配置
启动时检测软件更新
日期时间格式
+ 在变更列表树中启用紧凑文件夹模式
显示语言
最大历史提交数
在提交路线图中显示修改时间而非提交时间
+ 默认显示【本地更改】页
+ 在提交详情页默认打开【变更对比】标签页
在提交详情页中显示子提交列表
在提交路线图中显示标签
SUBJECT字数检测
+ 生成GitHub风格的默认头像
GIT配置
自动换行转换
默认克隆路径
@@ -574,6 +637,8 @@
输入签名提交所使用的KEY
第三方工具集成
终端/SHELL
+ 启动参数
+ 请使用 '.' 来指定工作目录
安装路径
终端/SHELL
清理远程已删除分支
@@ -585,8 +650,7 @@
本地分支 :
未提交更改 :
丢弃更改
- 贮藏并自动恢复
- 同时更新所有子模块
+ 贮藏并自动恢复
远程 :
拉回(拉取并合并)
使用变基方式合并分支
@@ -606,6 +670,8 @@
推送到所有远程仓库
远程仓库 :
标签 :
+ 推送到新的分支
+ 输入新的远端分支名
退出
变基(rebase)操作
自动贮藏并恢复本地变更
@@ -617,6 +683,7 @@
仓库地址 :
远程仓库的地址
复制远程地址
+ 自定义操作
删除 ...
编辑 ...
拉取(fetch)更新
@@ -642,6 +709,7 @@
下一步
自定义操作
自定义操作未设置
+ 主页
放弃所有更改
在文件浏览器中打开
快速查找分支/标签/子模块
@@ -656,6 +724,7 @@
按提交时间
按拓扑排序
本地分支
+ 更多选项...
定位HEAD
新建分支
清空通知列表
@@ -714,6 +783,7 @@
补丁已成功保存!
扫描仓库
根路径 :
+ 扫描其他自定义路径
检测更新...
检测到软件有版本更新:
获取最新版本信息失败!
@@ -732,8 +802,9 @@
上游分支 :
复制提交指纹
跳转到提交
- 压缩为单个提交
- 合并入:
+ 合并修改至父提交
+ 修复至父提交
+ 父提交:
SSH密钥 :
SSH密钥文件
开 始
@@ -763,6 +834,7 @@
子模块
添加子模块
跟踪分支
+ 跟踪分支
相对路径
取消初始化
拉取子孙模块
@@ -782,10 +854,15 @@
更新
仓库
确 定
- 复制标签名
- 复制标签信息
+ 创建者
+ 创建时间
+ 标签信息
+ 标签名
+ 创建者
+ 复制标签名
自定义操作
删除 ${0}$...
+ 删除选中 {0} 个标签...
合并 ${0}$ 到 ${1}$...
推送 ${0}$...
更新子模块
@@ -821,6 +898,8 @@
忽略本文件
修补
现在您已可将其加入暂存区中
+ 清空历史提交信息
+ 您确定要清空所有的历史提交信息记录吗(执行操作后无法撤回)?
提交
提交并推送
历史输入/模板
@@ -838,6 +917,7 @@
显示未跟踪文件
没有提交信息记录
没有可应用的提交信息模板
+ 跳过GIT钩子
重置提交者
署名
已暂存
@@ -853,6 +933,7 @@
本地工作树
复制工作树路径
锁定工作树
+ 打开工作树
移除工作树
解除工作树锁定
diff --git a/src/Resources/Locales/zh_TW.axaml b/src/Resources/Locales/zh_TW.axaml
index dee236eb3..a2a4443c8 100644
--- a/src/Resources/Locales/zh_TW.axaml
+++ b/src/Resources/Locales/zh_TW.axaml
@@ -5,10 +5,11 @@
關於
關於 SourceGit
+ 版本說明
開源免費的 Git 客戶端
新增忽略檔案
- 匹配模式 :
- 儲存路徑 :
+ 比對模式:
+ 儲存路徑:
新增工作區
工作區路徑:
填寫該工作區的路徑。支援相對路徑。
@@ -23,6 +24,8 @@
重新產生
使用 AI 產生提交訊息
套用為提交訊息
+ 隱藏 SourceGit
+ 顯示所有
套用修補檔 (apply patch)
修補檔:
選擇修補檔
@@ -53,14 +56,18 @@
無法確認
二分搜尋進行中。請標記目前的提交為「良好」或「錯誤」,然後簽出另一個提交。
逐行溯源 (blame)
- 所選擇的檔案不支援該操作!
+ 對上一個版本執行逐行溯源
+ 所選擇的檔案不支援該操作!
簽出 (checkout) ${0}$...
與目前 ${0}$ 比較
與本機工作區比較
複製分支名稱
+ 建立拉取請求...
+ 為上游分支 ${0}$ 建立拉取請求...
自訂動作
刪除 ${0}$...
刪除所選的 {0} 個分支
+ 編輯 ${0}$ 的描述...
快轉 (fast-forward) 到 ${0}$
提取 (fetch) ${0}$ 到 ${1}$...
Git 工作流 - 完成 ${0}$
@@ -72,13 +79,18 @@
重定基底 (rebase) ${0}$ 分支至 ${1}$...
重新命名 ${0}$...
重設 ${0}$ 至 ${1}$...
+ 切換到 ${0}$ (工作區)
切換上游分支...
分支比較
- 本機
+ 領先 {0} 次提交
+ 領先 {0} 次提交,落後 {0} 次提交
+ 落後 {0} 次提交
+ 無效
遠端
+ 狀態
上游分支
遠端網址
- 追蹤上游分支不存在或已刪除!
+ 工作區
取 消
重設檔案到上一版本
重設檔案為此版本
@@ -96,12 +108,11 @@
注意: 執行該操作後,目前 HEAD 會變為分離 (detached) 狀態!
未提交變更:
捨棄變更
- 擱置變更並自動復原
- 同時更新所有子模組
+ 擱置變更並自動復原
目標分支:
- 您目前的分離的 HEAD 包含與任何分支/標籤無關的提交!您要繼續嗎?
+ 您目前的分離的 HEAD 包含與任何分支/標籤無關的提交! 您要繼續嗎?
簽出分支並快轉
- 上游分支 :
+ 上游分支:
揀選提交
提交資訊中追加來源資訊
提交列表:
@@ -115,7 +126,7 @@
其他複製參數,選填。
本機存放庫名稱:
本機存放庫目錄的名稱,選填。
- 父級目錄:
+ 上層目錄:
初始化並更新子模組
遠端存放庫:
關閉
@@ -131,6 +142,7 @@
提交編號
標題
自訂動作
+ 捨棄此提交
互動式重定基底 (rebase -i)
捨棄...
編輯...
@@ -147,6 +159,7 @@
編輯提交訊息
另存為修補檔 (patch)...
合併此提交到上一個提交
+ 修正至父提交
變更對比
個檔案已變更
搜尋變更...
@@ -160,33 +173,52 @@
提交者
檢視包含此提交的分支或標籤
本提交包含於以下分支或標籤
+ 複製電子郵件
+ 複製名稱
+ 複製名稱及電子郵件
僅顯示前 100 項變更。請前往 [變更對比] 頁面以瀏覽所有變更。
- 簽名鑰匙:
+ 簽章金鑰:
提交訊息
前次提交
相關參照
提交編號
簽署人:
在瀏覽器中檢視
- 詳細描述
+ 請輸入提交訊息,標題與詳細描述之間請使用單行空白區隔。
標題
- 填寫提交訊息標題
存放庫設定
提交訊息範本
- 您可以使用 ${files_num}、${branch_name}、${files} 或 ${files:N} 其中 N 是要輸出的檔案路徑的最大數目。
+ 內建參數:
+
+ ${branch_name} 目前分支名稱
+ ${files_num} 已變更檔案數
+ ${files} 已變更檔案路徑清單
+ ${files:N} 已變更檔案路徑清單 (僅列出前 N 個)
+ ${pure_files} 類似 ${files},不含資料夾的純檔案名稱
+ ${pure_files:N} 類似 ${files:N},不含資料夾的純檔案名稱
範本內容:
範本名稱:
自訂動作
指令參數:
- 內建參數: ${REPO} 存放庫路徑、${BRANCH} 所選的分支、${SHA} 所選的提交編號、${TAG} 所選的標籤
+ 內建參數:
+
+ ${REPO} 存放庫路徑
+ ${REMOTE} 所選的遠端存放庫或所選分支的遠端
+ ${BRANCH} 所選的分支。對於遠端分支,不包含遠端名稱
+ ${BRANCH_FRIENDLY_NAME} 所選的分支。對於遠端分支,不包含遠端名稱
+ ${SHA} 所選的提交編號
+ ${TAG} 所選的標籤
+ ${FILE} 所選的檔案,相對於存放庫根目錄的路徑
+ $1, $2 ... 輸入控制項中的值
可執行檔案路徑:
- 輸入控件:
+ 輸入控制項:
編輯
- 請使用占位符如 $1, $2 來代表輸入控制項的值
名稱:
執行範圍:
選取的分支
選取的提交
+ 選取的檔案
+ 遠端存放庫
存放庫
選取的標籤
等待自訂動作執行結束
@@ -195,10 +227,12 @@
Git 設定
啟用定時自動提取 (fetch) 遠端更新
分鐘
+ 自訂約定式提交類型
預設遠端存放庫
預設合併模式
Issue 追蹤
新增符合 Azure DevOps 規則
+ 新增符合 Gerrit Change-Id 規則
新增符合 Gitee 議題規則
新增符合 Gitee 合併請求規則
新增符合 GitHub Issue 規則
@@ -208,7 +242,7 @@
新增自訂規則
符合 Issue 的正規表達式:
規則名稱:
- 寫入 .issuetracker 檔案以分享此規則
+ 寫入 .issuetracker 檔案以共用此規則
為 Issue 產生的網址連結:
可在網址中使用 $1、$2 等變數填入正規表達式相符的內容
AI
@@ -218,15 +252,16 @@
HTTP 網路代理
使用者名稱
用於本存放庫的使用者名稱
- 編輯自訂動作輸入控件
- 啟用時的指令行參數:
- 勾選 CheckBox 後,此值將用於命令列參數中
+ 編輯自訂動作輸入控制項
+ 啟用時的指令參數:
+ 勾選 CheckBox 後,此值將用於指令參數中
描述:
預設值:
目標路徑是否為資料夾:
名稱:
選項列表:
請使用英文「|」符號分隔選項
+ 內建變數 ${REPO}、${REMOTE}、${BRANCH}、${BRANCH_FRIENDLY_NAME}、${SHA}、${FILE} 及 ${TAG} 在此處仍可使用
類型:
工作區
顏色
@@ -237,7 +272,7 @@
自動暫存並提交
未包含任何檔案變更! 您是否仍要提交 (--allow-empty) 或者自動暫存全部變更並提交?
系統提示
- 您需要重新啟動此應用程式才能套用變更!
+ 您需要重新啟動此應用程式才能套用變更!
產生約定式提交訊息
破壞性變更:
關閉的 Issue:
@@ -254,10 +289,9 @@
完成後切換到新分支
未提交變更:
捨棄變更
- 擱置變更並自動復原
+ 擱置變更並自動復原
新分支名稱:
輸入分支名稱。
- 空格將以英文破折號取代
建立本機分支
允許覆寫現有分支
新增標籤...
@@ -275,14 +309,17 @@
按住 Ctrl 鍵將直接以預設參數執行
剪下
取消初始化子模組
- 強制取消,即使它包含本地變更
- 子模組 :
+ 強制取消,即使包含本機變更
+ 子模組:
刪除分支確認
分支名稱:
您正在刪除遠端上的分支,請務必小心!
同時刪除遠端分支 ${0}$
刪除多個分支
您正在嘗試一次性刪除多個分支,請務必仔細檢查後再刪除!
+ 刪除多個標籤
+ 同時刪除遠端存放庫中的這些標籤
+ 您正在嘗試一次性刪除多個標籤,請務必仔細檢查後再刪除!
刪除遠端確認
遠端名稱:
路徑:
@@ -301,8 +338,9 @@
第一個差異
忽略空白符號變化
混合對比
+ 差異對比
並排對比
- 填充對比
+ 滑桿對比
最後一個差異
LFS 物件變更
變更後
@@ -319,13 +357,15 @@
交換比對雙方
語法上色
自動換行
- 區塊切換上/下一個差異
使用外部合併工具檢視
顯示檔案的全部內容
減少可見的行數
增加可見的行數
請選擇需要對比的檔案
目錄内容變更歷史
+ 未提交的本機變更
+ 目前分支 HEAD 與上游不相符
+ 已更新至最新
捨棄變更
所有本機未提交的變更。
變更:
@@ -333,6 +373,11 @@
包含未追蹤檔案
將捨棄總計 {0} 項已選取的變更
您無法復原此操作,請確認後再繼續!
+ 捨棄提交
+ 提交:
+ 捨棄後新的 HEAD:
+ 編輯分支的描述
+ 目標:
書籤:
名稱:
目標:
@@ -347,6 +392,7 @@
遠端存放庫:
提取遠端存放庫內容
不追蹤此檔案的變更
+ 自訂動作
捨棄變更...
捨棄已選的 {0} 個檔案變更...
使用 ${0}$
@@ -402,6 +448,8 @@
僅顯示被我鎖定的檔案
LFS 物件鎖
解鎖
+ 解鎖所有由我鎖定的檔案
+ 您確定要解鎖所有由您自己鎖定的檔案嗎?
強制解鎖
清理 (prune)
執行 `git lfs prune` 以從本機中清理目前版本不需要的 LFS 物件
@@ -432,7 +480,7 @@
切換到上一個頁面
新增頁面
開啟偏好設定面板
- 切換工作區
+ 顯示工作區的下拉式選單
切換目前頁面
存放庫頁面快速鍵
提交暫存區變更
@@ -440,6 +488,7 @@
自動暫存全部變更並提交
提取 (fetch) 遠端的變更
切換左邊欄為分支/標籤等顯示模式 (預設)
+ 開啟命令面板
切換左邊欄為歷史搜尋模式
拉取 (pull) 遠端的變更
推送 (push) 本機變更到遠端存放庫
@@ -473,10 +522,12 @@
目標分支:
複製連結
在瀏覽器中開啟連結
+ 命令列表
發生錯誤
系統提示
- 工作區列表
+ 開啟存放庫
頁面列表
+ 工作區列表
合併分支
編輯合併訊息
目標分支:
@@ -493,9 +544,11 @@
請選擇目標分組:
名稱:
尚未設定 Git。請開啟 [偏好設定] 以設定 Git 路徑。
+ 開啟
+ 系統預設編輯器
瀏覽程式資料目錄
+ 開啟檔案
使用外部比對工具檢視
- 開啟檔案...
選填。
新增分頁
設定書籤
@@ -503,6 +556,8 @@
關閉其他分頁
關閉右側分頁
複製存放庫路徑
+ 移至工作區
+ 重新整理
新分頁
貼上
{0} 天前
@@ -515,7 +570,6 @@
{0} 個月前
{0} 年前
昨天
- 請使用 Shift + Enter 換行。Enter 鍵已被 [確定] 按鈕佔用。
偏好設定
AI
分析變更差異提示詞
@@ -523,6 +577,7 @@
產生提交訊息提示詞
模型
名稱
+ 從環境變數中 (輸入環境變數名稱) 讀取 API 金鑰
伺服器
啟用串流輸出
外觀設定
@@ -532,31 +587,39 @@
預設
程式碼
等寬字型
- 僅在文字編輯器中使用等寬字型
佈景主題
自訂主題
+ 允許自動隱藏捲軸
使用固定寬度的分頁標籤
使用系統原生預設視窗樣式
對比/合併工具
+ 對比命令參數
+ 可用參數:$LOCAL, $REMOTE
+ 合併命令參數
+ 可用參數:$BASE, $LOCAL, $REMOTE, $MERGED
安裝路徑
填寫可執行檔案所在路徑
工具
一般設定
啟動時檢查軟體更新
日期時間格式
+ 在樹狀變更目錄中啟用密集資料夾模式
顯示語言
最大歷史提交數
在提交路線圖中顯示修改時間而非提交時間
+ 預設顯示 [本機變更] 頁面
+ 在提交詳細資訊頁面預設顯示 [變更對比]
在提交詳細資訊中顯示後續提交
在路線圖中顯示標籤
提交標題字數偵測
+ 產生 GitHub 風格的預設頭貼
Git 設定
自動換行轉換
預設複製 (clone) 路徑
電子郵件
預設 Git 使用者電子郵件
拉取變更時進行清理 (--prune)
- 對比檔案時,預設忽略行尾的 CR 變更 (--ignore-cr-at-eol)
+ 對比檔案時,預設忽略行末的 CR 變更 (--ignore-cr-at-eol)
本軟體要求 Git 最低版本為 2.25.1
安裝路徑
啟用 HTTP SSL 驗證
@@ -574,6 +637,8 @@
填寫簽章提交所使用的金鑰
第三方工具整合
終端機/Shell
+ 啟動參數
+ 請使用「.」標示當前工作目錄
安裝路徑
終端機/Shell
清理遠端已刪除分支
@@ -585,8 +650,7 @@
本機分支:
未提交變更:
捨棄變更
- 擱置變更並自動復原
- 同時更新所有子模組
+ 擱置變更並自動復原
遠端:
拉取 (提取並合併)
使用重定基底 (rebase) 合併分支
@@ -606,6 +670,8 @@
推送到所有遠端存放庫
遠端存放庫:
標籤:
+ 推送到新的分支
+ 輸入新的遠端分支名稱:
結束
重定基底 (rebase) 操作
自動擱置變更並復原本機變更
@@ -617,6 +683,7 @@
存放庫網址:
遠端存放庫的網址
複製遠端網址
+ 自訂動作
刪除...
編輯...
提取 (fetch) 更新
@@ -635,13 +702,14 @@
依建立時間
依名稱升序
清理本存放庫 (GC)
- 本操作將執行 `git gc` 命令。
+ 本操作將執行 `git gc` 指令。
清空篩選規則
清空
設定本存放庫
下一步
自訂動作
沒有自訂的動作
+ 首頁
捨棄所有變更
在檔案瀏覽器中開啟
快速搜尋分支/標籤/子模組
@@ -656,6 +724,7 @@
依時間排序
依拓撲排序
本機分支
+ 更多選項...
回到 HEAD
新增分支
清除所有通知
@@ -675,7 +744,7 @@
只顯示分支和標籤引用的提交
只顯示合併提交的第一父提交
顯示內容
- 顯示遺失參照的提交
+ 顯示失去參照的提交
以樹型結構展示
以樹型結構展示
跳過此提交
@@ -700,9 +769,9 @@
重設模式:
移至提交:
目前分支:
- 重設選取的分支(非目前分支)
- 重設位置 :
- 選取分支 :
+ 重設選取的分支 (非目前分支)
+ 重設位置:
+ 選取分支:
在檔案瀏覽器中檢視
復原操作確認
目標提交:
@@ -714,6 +783,7 @@
修補檔已成功儲存!
掃描存放庫
頂層目錄:
+ 掃描其他自訂目錄
檢查更新...
軟體有版本更新:
取得最新版本資訊失敗!
@@ -725,15 +795,16 @@
子模組:
目前追蹤分支:
變更為:
- 選購。為空時設定為預設值。
+ 選填。留空時設定為預設值。
切換上游分支
本機分支:
取消設定上游分支
上游分支:
複製提交編號
前往此提交
- 壓縮為單個提交
- 合併入:
+ 合併變更入父提交
+ 修正至父提交
+ 父提交:
SSH 金鑰:
SSH 金鑰檔案
開 始
@@ -763,6 +834,7 @@
子模組
新增子模組
追蹤分支
+ 追蹤分支
相對路徑
取消初始化
提取子模組
@@ -782,15 +854,20 @@
更新
存放庫
確 定
- 複製標籤名稱
- 複製標籤訊息
+ 建立者
+ 建立時間
+ 標籤訊息
+ 標籤名稱
+ 建立者
+ 複製標籤名稱
自訂動作
刪除 ${0}$...
+ 刪除所選的 {0} 個標籤...
合併 ${0}$ 到 ${1}$...
推送 ${0}$...
更新子模組
更新所有子模組
- 如果子模組尚未初始化,則初始化它
+ 如果子模組尚未初始化,則將其初始化
遞迴更新子孫模組
子模組:
更新至子模組的遠端追蹤分支
@@ -821,6 +898,8 @@
忽略本檔案
修補
現在您已可將其加入暫存區中
+ 清除提交訊息歷史
+ 您確定要清除所有提交訊息記錄嗎 (執行後無法復原)?
提 交
提交並推送
歷史輸入/範本
@@ -838,6 +917,7 @@
顯示未追蹤檔案
沒有提交訊息記錄
沒有可套用的提交訊息範本
+ 繞過 Hooks 檢查
重設作者
署名
已暫存
@@ -848,11 +928,12 @@
暫存所有檔案
檢視不追蹤變更的檔案
範本: ${0}$
- 工作區:
+ 工作區:
設定工作區...
本機工作區
複製工作區路徑
鎖定工作區
+ 開啟工作區
移除工作區
解除鎖定工作區
diff --git a/src/Resources/Styles.axaml b/src/Resources/Styles.axaml
index e1ebf0061..f259fd32d 100644
--- a/src/Resources/Styles.axaml
+++ b/src/Resources/Styles.axaml
@@ -5,6 +5,7 @@
xmlns:v="using:SourceGit.Views"
xmlns:c="using:SourceGit.Converters"
xmlns:ae="using:AvaloniaEdit"
+ xmlns:acc="using:AvaloniaEdit.CodeCompletion"
xmlns:aee="using:AvaloniaEdit.Editing"
xmlns:aes="using:AvaloniaEdit.Search">
@@ -12,35 +13,39 @@
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
@@ -519,72 +706,19 @@
-
-
-
-
-
-
-
-
+
+
+
+
@@ -1221,6 +1363,9 @@
+
@@ -1272,13 +1417,14 @@
Fill="{DynamicResource Brush.FG1}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
- Opacity="0.65"/>
+ Opacity="0.8"/>
+
+
+
+
diff --git a/src/Resources/Themes.axaml b/src/Resources/Themes.axaml
index 3b4637331..84b89f43b 100644
--- a/src/Resources/Themes.axaml
+++ b/src/Resources/Themes.axaml
@@ -3,7 +3,7 @@
#FFF0F5F9
- #00000000
+ #FF999999
#FFCFDEEA
#FFF0F5F9
#FFF8F8F8
@@ -30,9 +30,9 @@
#FF252525
- #FF444444
+ #FF606060
#FF1F1F1F
- #FF2C2C2C
+ #FF2F2F2F
#FF2B2B2B
#FF1C1C1C
#FF8F8F8F
@@ -85,5 +85,4 @@
fonts:Inter#Inter
fonts:SourceGit#JetBrains Mono
- fonts:SourceGit#JetBrains Mono
diff --git a/src/SourceGit.csproj b/src/SourceGit.csproj
index 8d76934c7..165fdc46c 100644
--- a/src/SourceGit.csproj
+++ b/src/SourceGit.csproj
@@ -1,7 +1,7 @@
WinExe
- net9.0
+ net10.0
App.manifest
App.ico
$([System.IO.File]::ReadAllText("$(MSBuildProjectDirectory)\\..\\VERSION"))
@@ -24,6 +24,10 @@
link
+
+ 13.0
+
+
$(DefineConstants);DISABLE_UPDATE_DETECTION
@@ -39,30 +43,26 @@
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
-
-
-
-
diff --git a/src/ViewModels/AIAssistant.cs b/src/ViewModels/AIAssistant.cs
index 920fafcf5..d538ce1b5 100644
--- a/src/ViewModels/AIAssistant.cs
+++ b/src/ViewModels/AIAssistant.cs
@@ -1,5 +1,4 @@
-using System;
-using System.Collections.Generic;
+using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
@@ -23,12 +22,11 @@ public string Text
private set => SetProperty(ref _text, value);
}
- public AIAssistant(Repository repo, Models.OpenAIService service, List changes, Action onApply)
+ public AIAssistant(Repository repo, Models.OpenAIService service, List changes)
{
_repo = repo;
_service = service;
_changes = changes;
- _onApply = onApply;
_cancel = new CancellationTokenSource();
Gen();
@@ -44,7 +42,7 @@ public void Regen()
public void Apply()
{
- _onApply?.Invoke(Text);
+ _repo.SetCommitMessage(Text);
}
public void Cancel()
@@ -72,7 +70,6 @@ private void Gen()
private readonly Repository _repo = null;
private Models.OpenAIService _service = null;
private List _changes = null;
- private Action _onApply = null;
private CancellationTokenSource _cancel = null;
private bool _isGenerating = false;
private string _text = string.Empty;
diff --git a/src/ViewModels/AddRemote.cs b/src/ViewModels/AddRemote.cs
index 5a6c019fc..fb5f0264b 100644
--- a/src/ViewModels/AddRemote.cs
+++ b/src/ViewModels/AddRemote.cs
@@ -89,7 +89,7 @@ public static ValidationResult ValidateSSHKey(string sshkey, ValidationContext c
public override async Task Sure()
{
- _repo.SetWatcherEnabled(false);
+ using var lockWatcher = _repo.LockWatcher();
ProgressDescription = "Adding remote ...";
var log = _repo.CreateLog("Add Remote");
@@ -114,7 +114,6 @@ public override async Task Sure()
_repo.MarkFetched();
_repo.MarkBranchesDirtyManually();
- _repo.SetWatcherEnabled(true);
return succ;
}
diff --git a/src/ViewModels/AddSubmodule.cs b/src/ViewModels/AddSubmodule.cs
index 313b2e8e2..e9554ea34 100644
--- a/src/ViewModels/AddSubmodule.cs
+++ b/src/ViewModels/AddSubmodule.cs
@@ -42,7 +42,7 @@ public static ValidationResult ValidateURL(string url, ValidationContext ctx)
public override async Task Sure()
{
- _repo.SetWatcherEnabled(false);
+ using var lockWatcher = _repo.LockWatcher();
ProgressDescription = "Adding submodule...";
var log = _repo.CreateLog("Add Submodule");
@@ -64,7 +64,6 @@ public override async Task Sure()
.AddAsync(_url, relativePath, Recursive);
log.Complete();
- _repo.SetWatcherEnabled(true);
return succ;
}
diff --git a/src/ViewModels/AddToIgnore.cs b/src/ViewModels/AddToIgnore.cs
index d2a194f43..a502c1725 100644
--- a/src/ViewModels/AddToIgnore.cs
+++ b/src/ViewModels/AddToIgnore.cs
@@ -29,13 +29,13 @@ public AddToIgnore(Repository repo, string pattern)
public override async Task Sure()
{
- _repo.SetWatcherEnabled(false);
+ using var lockWatcher = _repo.LockWatcher();
ProgressDescription = "Adding Ignored File(s) ...";
var file = StorageFile.GetFullPath(_repo.FullPath, _repo.GitDir);
if (!File.Exists(file))
{
- await File.WriteAllLinesAsync(file, [_pattern]);
+ await File.WriteAllLinesAsync(file!, [_pattern]);
}
else
{
@@ -47,7 +47,6 @@ public override async Task Sure()
}
_repo.MarkWorkingCopyDirtyManually();
- _repo.SetWatcherEnabled(true);
return true;
}
diff --git a/src/ViewModels/AddWorktree.cs b/src/ViewModels/AddWorktree.cs
index 3c3d69ff5..5c7b21d25 100644
--- a/src/ViewModels/AddWorktree.cs
+++ b/src/ViewModels/AddWorktree.cs
@@ -1,4 +1,5 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.IO;
using System.Threading.Tasks;
@@ -51,7 +52,11 @@ public string SelectedBranch
public bool SetTrackingBranch
{
get => _setTrackingBranch;
- set => SetProperty(ref _setTrackingBranch, value);
+ set
+ {
+ if (SetProperty(ref _setTrackingBranch, value))
+ AutoSelectTrackingBranch();
+ }
}
public string SelectedTrackingBranch
@@ -73,11 +78,6 @@ public AddWorktree(Repository repo)
else
RemoteBranches.Add(branch.FriendlyName);
}
-
- if (RemoteBranches.Count > 0)
- SelectedTrackingBranch = RemoteBranches[0];
- else
- SelectedTrackingBranch = string.Empty;
}
public static ValidationResult ValidateWorktreePath(string path, ValidationContext ctx)
@@ -106,7 +106,7 @@ public static ValidationResult ValidateWorktreePath(string path, ValidationConte
public override async Task Sure()
{
- _repo.SetWatcherEnabled(false);
+ using var lockWatcher = _repo.LockWatcher();
ProgressDescription = "Adding worktree ...";
var branchName = _selectedBranch;
@@ -120,10 +120,26 @@ public override async Task Sure()
.AddAsync(_path, branchName, _createNewBranch, tracking);
log.Complete();
- _repo.SetWatcherEnabled(true);
return succ;
}
+ private void AutoSelectTrackingBranch()
+ {
+ if (!_setTrackingBranch || RemoteBranches.Count == 0)
+ return;
+
+ var name = string.IsNullOrEmpty(_selectedBranch) ? System.IO.Path.GetFileName(_path.TrimEnd('/', '\\')) : _selectedBranch;
+ var remoteBranch = RemoteBranches.Find(b => b.EndsWith(name, StringComparison.Ordinal));
+ if (string.IsNullOrEmpty(remoteBranch))
+ remoteBranch = RemoteBranches[0];
+
+ if (!remoteBranch.Equals(SelectedTrackingBranch, StringComparison.Ordinal))
+ {
+ SelectedTrackingBranch = remoteBranch;
+ OnPropertyChanged(nameof(SelectedTrackingBranch));
+ }
+ }
+
private Repository _repo = null;
private string _path = string.Empty;
private bool _createNewBranch = true;
diff --git a/src/ViewModels/Apply.cs b/src/ViewModels/Apply.cs
index 709a66fd6..3eab5ef7a 100644
--- a/src/ViewModels/Apply.cs
+++ b/src/ViewModels/Apply.cs
@@ -43,7 +43,7 @@ public static ValidationResult ValidatePatchFile(string file, ValidationContext
public override async Task Sure()
{
- _repo.SetWatcherEnabled(false);
+ using var lockWatcher = _repo.LockWatcher();
ProgressDescription = "Apply patch...";
var log = _repo.CreateLog("Apply Patch");
@@ -54,7 +54,6 @@ public override async Task Sure()
.ExecAsync();
log.Complete();
- _repo.SetWatcherEnabled(true);
return succ;
}
diff --git a/src/ViewModels/ApplyStash.cs b/src/ViewModels/ApplyStash.cs
index b21d6fe80..8fb9d4b72 100644
--- a/src/ViewModels/ApplyStash.cs
+++ b/src/ViewModels/ApplyStash.cs
@@ -30,7 +30,7 @@ public ApplyStash(Repository repo, Models.Stash stash)
public override async Task Sure()
{
- _repo.SetWatcherEnabled(false);
+ using var lockWatcher = _repo.LockWatcher();
ProgressDescription = $"Applying stash: {Stash.Name}";
var log = _repo.CreateLog("Apply Stash");
@@ -40,13 +40,21 @@ public override async Task Sure()
.Use(log)
.ApplyAsync(Stash.Name, RestoreIndex);
- if (succ && DropAfterApply)
- await new Commands.Stash(_repo.FullPath)
- .Use(log)
- .DropAsync(Stash.Name);
+ if (succ)
+ {
+ _repo.MarkWorkingCopyDirtyManually();
+
+ if (DropAfterApply)
+ {
+ await new Commands.Stash(_repo.FullPath)
+ .Use(log)
+ .DropAsync(Stash.Name);
+
+ _repo.MarkStashesDirtyManually();
+ }
+ }
log.Complete();
- _repo.SetWatcherEnabled(true);
return true;
}
diff --git a/src/ViewModels/Archive.cs b/src/ViewModels/Archive.cs
index 6f86357df..182ec562b 100644
--- a/src/ViewModels/Archive.cs
+++ b/src/ViewModels/Archive.cs
@@ -46,7 +46,7 @@ public Archive(Repository repo, Models.Tag tag)
public override async Task Sure()
{
- _repo.SetWatcherEnabled(false);
+ using var lockWatcher = _repo.LockWatcher();
ProgressDescription = "Archiving ...";
var log = _repo.CreateLog("Archive");
@@ -57,7 +57,6 @@ public override async Task Sure()
.ExecAsync();
log.Complete();
- _repo.SetWatcherEnabled(true);
if (succ)
App.SendNotification(_repo.FullPath, $"Save archive to : {_saveFile}");
diff --git a/src/ViewModels/Blame.cs b/src/ViewModels/Blame.cs
index affe40d92..fda29964c 100644
--- a/src/ViewModels/Blame.cs
+++ b/src/ViewModels/Blame.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Avalonia.Threading;
@@ -20,6 +21,12 @@ public Models.Commit Revision
private set => SetProperty(ref _revision, value);
}
+ public Models.Commit PrevRevision
+ {
+ get => _prevRevision;
+ private set => SetProperty(ref _prevRevision, value);
+ }
+
public Models.BlameData Data
{
get => _data;
@@ -51,10 +58,10 @@ public Blame(string repo, string file, Models.Commit commit)
FilePath = file;
Revision = commit;
+ PrevRevision = null;
_repo = repo;
_navigationHistory.Add(sha);
- _commits.Add(sha, commit);
SetBlameData(sha);
}
@@ -63,10 +70,7 @@ public string GetCommitMessage(string sha)
if (_commitMessages.TryGetValue(sha, out var msg))
return msg;
- msg = new Commands.QueryCommitFullMessage(_repo, sha)
- .GetResultAsync()
- .Result;
-
+ msg = new Commands.QueryCommitFullMessage(_repo, sha).GetResult();
_commitMessages[sha] = msg;
return msg;
}
@@ -79,7 +83,7 @@ public void Back()
_navigationActiveIndex--;
OnPropertyChanged(nameof(CanBack));
OnPropertyChanged(nameof(CanForward));
- NavigateToCommit(_navigationHistory[_navigationActiveIndex]);
+ NavigateToCommit(_navigationHistory[_navigationActiveIndex], true);
}
public void Forward()
@@ -90,21 +94,35 @@ public void Forward()
_navigationActiveIndex++;
OnPropertyChanged(nameof(CanBack));
OnPropertyChanged(nameof(CanForward));
- NavigateToCommit(_navigationHistory[_navigationActiveIndex]);
+ NavigateToCommit(_navigationHistory[_navigationActiveIndex], true);
+ }
+
+ public void GotoPrevRevision()
+ {
+ if (_prevRevision == null)
+ return;
+
+ NavigateToCommit(_prevRevision.SHA, false);
}
- public void NavigateToCommit(string commitSHA)
+ public void NavigateToCommit(string commitSHA, bool isBackOrForward)
{
- if (!_navigationHistory[_navigationActiveIndex].Equals(commitSHA, StringComparison.Ordinal))
+ if (Revision.SHA.StartsWith(commitSHA, StringComparison.Ordinal))
+ return;
+
+ if (!isBackOrForward)
{
+ var count = _navigationHistory.Count;
+ if (_navigationActiveIndex < count - 1)
+ _navigationHistory.RemoveRange(_navigationActiveIndex + 1, count - _navigationActiveIndex - 1);
+
_navigationHistory.Add(commitSHA);
- _navigationActiveIndex = _navigationHistory.Count - 1;
+ _navigationActiveIndex++;
OnPropertyChanged(nameof(CanBack));
OnPropertyChanged(nameof(CanForward));
}
- if (!Revision.SHA.StartsWith(commitSHA, StringComparison.Ordinal))
- SetBlameData(commitSHA);
+ SetBlameData(commitSHA);
if (App.GetLauncher() is { Pages: { } pages })
{
@@ -127,28 +145,28 @@ private void SetBlameData(string commitSHA)
_cancellationSource = new CancellationTokenSource();
var token = _cancellationSource.Token;
- if (_commits.TryGetValue(commitSHA, out var c))
- {
- Revision = c;
- }
- else
+ Task.Run(async () =>
{
- Task.Run(async () =>
- {
- var result = await new Commands.QuerySingleCommit(_repo, commitSHA)
- .GetResultAsync()
- .ConfigureAwait(false);
+ var argsBuilder = new StringBuilder();
+ argsBuilder
+ .Append("--date-order -n 2 ")
+ .Append(commitSHA ?? string.Empty)
+ .Append(" -- ")
+ .Append(FilePath.Quoted());
+
+ var commits = await new Commands.QueryCommits(_repo, argsBuilder.ToString(), false)
+ .GetResultAsync()
+ .ConfigureAwait(false);
- Dispatcher.UIThread.Post(() =>
+ Dispatcher.UIThread.Post(() =>
+ {
+ if (!token.IsCancellationRequested)
{
- if (!token.IsCancellationRequested)
- {
- _commits.Add(commitSHA, result);
- Revision = result ?? new Models.Commit() { SHA = commitSHA };
- }
- });
- }, token);
- }
+ Revision = commits.Count > 0 ? commits[0] : null;
+ PrevRevision = commits.Count == 2 ? commits[1] : null;
+ }
+ });
+ });
Task.Run(async () =>
{
@@ -166,11 +184,11 @@ private void SetBlameData(string commitSHA)
private string _repo;
private Models.Commit _revision;
+ private Models.Commit _prevRevision;
private CancellationTokenSource _cancellationSource = null;
private int _navigationActiveIndex = 0;
private List _navigationHistory = [];
private Models.BlameData _data = null;
- private Dictionary _commits = new();
private Dictionary _commitMessages = new();
}
}
diff --git a/src/ViewModels/BlameCommandPalette.cs b/src/ViewModels/BlameCommandPalette.cs
new file mode 100644
index 000000000..fa24faf6a
--- /dev/null
+++ b/src/ViewModels/BlameCommandPalette.cs
@@ -0,0 +1,129 @@
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Avalonia.Threading;
+
+namespace SourceGit.ViewModels
+{
+ public class BlameCommandPalette : ICommandPalette
+ {
+ public bool IsLoading
+ {
+ get => _isLoading;
+ private set => SetProperty(ref _isLoading, value);
+ }
+
+ public List VisibleFiles
+ {
+ get => _visibleFiles;
+ private set => SetProperty(ref _visibleFiles, value);
+ }
+
+ public string Filter
+ {
+ get => _filter;
+ set
+ {
+ if (SetProperty(ref _filter, value))
+ UpdateVisible();
+ }
+ }
+
+ public string SelectedFile
+ {
+ get => _selectedFile;
+ set => SetProperty(ref _selectedFile, value);
+ }
+
+ public BlameCommandPalette(Launcher launcher, string repo)
+ {
+ _launcher = launcher;
+ _repo = repo;
+ _isLoading = true;
+
+ Task.Run(async () =>
+ {
+ var files = await new Commands.QueryRevisionFileNames(_repo, "HEAD")
+ .GetResultAsync()
+ .ConfigureAwait(false);
+
+ var head = await new Commands.QuerySingleCommit(_repo, "HEAD")
+ .GetResultAsync()
+ .ConfigureAwait(false);
+
+ Dispatcher.UIThread.Post(() =>
+ {
+ IsLoading = false;
+ _repoFiles = files;
+ _head = head;
+ UpdateVisible();
+ });
+ });
+ }
+
+ public override void Cleanup()
+ {
+ _launcher = null;
+ _repo = null;
+ _head = null;
+ _repoFiles.Clear();
+ _filter = null;
+ _visibleFiles.Clear();
+ _selectedFile = null;
+ }
+
+ public void ClearFilter()
+ {
+ Filter = string.Empty;
+ }
+
+ public void Launch()
+ {
+ if (!string.IsNullOrEmpty(_selectedFile))
+ App.ShowWindow(new Blame(_repo, _selectedFile, _head));
+ _launcher.CancelCommandPalette();
+ }
+
+ private void UpdateVisible()
+ {
+ if (_repoFiles is { Count: > 0 })
+ {
+ if (string.IsNullOrEmpty(_filter))
+ {
+ VisibleFiles = _repoFiles;
+
+ if (string.IsNullOrEmpty(_selectedFile))
+ SelectedFile = _repoFiles[0];
+ }
+ else
+ {
+ var visible = new List();
+
+ foreach (var f in _repoFiles)
+ {
+ if (f.Contains(_filter, StringComparison.OrdinalIgnoreCase))
+ visible.Add(f);
+ }
+
+ var autoSelected = _selectedFile;
+ if (visible.Count == 0)
+ autoSelected = null;
+ else if (string.IsNullOrEmpty(_selectedFile) || !visible.Contains(_selectedFile))
+ autoSelected = visible[0];
+
+ VisibleFiles = visible;
+ SelectedFile = autoSelected;
+ }
+ }
+ }
+
+ private Launcher _launcher = null;
+ private string _repo = null;
+ private bool _isLoading = false;
+ private Models.Commit _head = null;
+ private List _repoFiles = null;
+ private string _filter = string.Empty;
+ private List _visibleFiles = [];
+ private string _selectedFile = null;
+ }
+}
diff --git a/src/ViewModels/BlockNavigation.cs b/src/ViewModels/BlockNavigation.cs
index 4a51244cb..96f47146b 100644
--- a/src/ViewModels/BlockNavigation.cs
+++ b/src/ViewModels/BlockNavigation.cs
@@ -1,70 +1,54 @@
+using System;
using System.Collections.Generic;
-using Avalonia.Collections;
using CommunityToolkit.Mvvm.ComponentModel;
namespace SourceGit.ViewModels
{
+ public enum BlockNavigationDirection
+ {
+ First = 0,
+ Prev,
+ Next,
+ Last
+ }
+
public class BlockNavigation : ObservableObject
{
- public class Block
+ public record Block(int Start, int End)
{
- public int Start { get; set; } = 0;
- public int End { get; set; } = 0;
-
- public Block(int start, int end)
- {
- Start = start;
- End = end;
- }
-
- public bool IsInRange(int line)
+ public bool Contains(int line)
{
return line >= Start && line <= End;
}
}
- public AvaloniaList Blocks
- {
- get;
- } = [];
-
- public int Current
- {
- get => _current;
- private set => SetProperty(ref _current, value);
- }
-
public string Indicator
{
get
{
- if (Blocks.Count == 0)
+ if (_blocks.Count == 0)
return "-/-";
- if (_current >= 0 && _current < Blocks.Count)
- return $"{_current + 1}/{Blocks.Count}";
+ if (_current >= 0 && _current < _blocks.Count)
+ return $"{_current + 1}/{_blocks.Count}";
- return $"-/{Blocks.Count}";
+ return $"-/{_blocks.Count}";
}
}
- public BlockNavigation(object context)
+ public BlockNavigation(List lines, int cur)
{
- Blocks.Clear();
- Current = -1;
-
- var lines = new List();
- if (context is Models.TextDiff combined)
- lines = combined.Lines;
- else if (context is TwoSideTextDiff twoSide)
- lines = twoSide.Old;
+ _blocks.Clear();
if (lines.Count == 0)
+ {
+ _current = -1;
return;
+ }
var lineIdx = 0;
var blockStartIdx = 0;
- var isNewBlock = true;
+ var isReadingBlock = false;
var blocks = new List();
foreach (var line in lines)
@@ -72,73 +56,86 @@ public BlockNavigation(object context)
lineIdx++;
if (line.Type is Models.TextDiffLineType.Added or Models.TextDiffLineType.Deleted or Models.TextDiffLineType.None)
{
- if (isNewBlock)
+ if (!isReadingBlock)
{
- isNewBlock = false;
+ isReadingBlock = true;
blockStartIdx = lineIdx;
}
}
else
{
- if (!isNewBlock)
+ if (isReadingBlock)
{
blocks.Add(new Block(blockStartIdx, lineIdx - 1));
- isNewBlock = true;
+ isReadingBlock = false;
}
}
}
- if (!isNewBlock)
- blocks.Add(new Block(blockStartIdx, lines.Count - 1));
+ if (isReadingBlock)
+ blocks.Add(new Block(blockStartIdx, lines.Count));
- Blocks.AddRange(blocks);
+ _blocks.AddRange(blocks);
+ _current = Math.Min(_blocks.Count - 1, cur);
}
- public Block GetCurrentBlock()
+ public int GetCurrentBlockIndex()
{
- return (_current >= 0 && _current < Blocks.Count) ? Blocks[_current] : null;
+ return _current;
}
- public Block GotoFirst()
+ public Block GetCurrentBlock()
{
- if (Blocks.Count == 0)
- return null;
+ if (_current >= 0 && _current < _blocks.Count)
+ return _blocks[_current];
- Current = 0;
- return Blocks[_current];
+ return null;
}
- public Block GotoPrev()
+ public Block Goto(BlockNavigationDirection direction)
{
- if (Blocks.Count == 0)
+ if (_blocks.Count == 0)
return null;
- if (_current == -1)
- Current = 0;
- else if (_current > 0)
- Current = _current - 1;
- return Blocks[_current];
+ _current = direction switch
+ {
+ BlockNavigationDirection.First => 0,
+ BlockNavigationDirection.Prev => _current <= 0 ? 0 : _current - 1,
+ BlockNavigationDirection.Next => _current >= _blocks.Count - 1 ? _blocks.Count - 1 : _current + 1,
+ BlockNavigationDirection.Last => _blocks.Count - 1,
+ _ => _current
+ };
+
+ OnPropertyChanged(nameof(Indicator));
+ return _blocks[_current];
}
- public Block GotoNext()
+ public void UpdateByCaretPosition(int caretLine)
{
- if (Blocks.Count == 0)
- return null;
+ if (_current >= 0 && _current < _blocks.Count)
+ {
+ var block = _blocks[_current];
+ if (block.Contains(caretLine))
+ return;
+ }
- if (_current < Blocks.Count - 1)
- Current = _current + 1;
- return Blocks[_current];
- }
+ _current = -1;
- public Block GotoLast()
- {
- if (Blocks.Count == 0)
- return null;
+ for (var i = 0; i < _blocks.Count; i++)
+ {
+ var block = _blocks[i];
+ if (block.Start > caretLine)
+ break;
+
+ _current = i;
+ if (block.End >= caretLine)
+ break;
+ }
- Current = Blocks.Count - 1;
- return Blocks[_current];
+ OnPropertyChanged(nameof(Indicator));
}
- private int _current = -1;
+ private int _current;
+ private readonly List _blocks = [];
}
}
diff --git a/src/ViewModels/BranchCompare.cs b/src/ViewModels/BranchCompare.cs
index f88bc32ab..7c6a484d4 100644
--- a/src/ViewModels/BranchCompare.cs
+++ b/src/ViewModels/BranchCompare.cs
@@ -1,17 +1,18 @@
using System;
using System.Collections.Generic;
-using System.IO;
using System.Threading.Tasks;
-
-using Avalonia.Controls;
using Avalonia.Threading;
-
using CommunityToolkit.Mvvm.ComponentModel;
namespace SourceGit.ViewModels
{
public class BranchCompare : ObservableObject
{
+ public string RepositoryPath
+ {
+ get => _repo;
+ }
+
public bool IsLoading
{
get => _isLoading;
@@ -42,6 +43,12 @@ public Models.Commit ToHead
private set => SetProperty(ref _toHead, value);
}
+ public int TotalChanges
+ {
+ get => _totalChanges;
+ private set => SetProperty(ref _totalChanges, value);
+ }
+
public List VisibleChanges
{
get => _visibleChanges;
@@ -127,68 +134,11 @@ public string GetAbsPath(string path)
return Native.OS.GetAbsPath(_repo, path);
}
- public ContextMenu CreateChangeContextMenu()
+ public async Task SaveChangesAsPatchAsync(List changes, string saveTo)
{
- if (_selectedChanges is not { Count: 1 })
- return null;
-
- var change = _selectedChanges[0];
- var menu = new ContextMenu();
-
- var openWithMerger = new MenuItem();
- openWithMerger.Header = App.Text("OpenInExternalMergeTool");
- openWithMerger.Icon = App.CreateMenuIcon("Icons.OpenWith");
- openWithMerger.Tag = OperatingSystem.IsMacOS() ? "⌘+⇧+D" : "Ctrl+Shift+D";
- openWithMerger.Click += (_, ev) =>
- {
- var toolType = Preferences.Instance.ExternalMergeToolType;
- var toolPath = Preferences.Instance.ExternalMergeToolPath;
- var opt = new Models.DiffOption(_based.Head, _to.Head, change);
-
- new Commands.DiffTool(_repo, toolType, toolPath, opt).Open();
- ev.Handled = true;
- };
- menu.Items.Add(openWithMerger);
-
- if (change.Index != Models.ChangeState.Deleted)
- {
- var full = Path.GetFullPath(Path.Combine(_repo, change.Path));
- var explore = new MenuItem();
- explore.Header = App.Text("RevealFile");
- explore.Icon = App.CreateMenuIcon("Icons.Explore");
- explore.IsEnabled = File.Exists(full);
- explore.Click += (_, ev) =>
- {
- Native.OS.OpenInFileManager(full, true);
- ev.Handled = true;
- };
- menu.Items.Add(explore);
- }
-
- var copyPath = new MenuItem();
- copyPath.Header = App.Text("CopyPath");
- copyPath.Icon = App.CreateMenuIcon("Icons.Copy");
- copyPath.Tag = OperatingSystem.IsMacOS() ? "⌘+C" : "Ctrl+C";
- copyPath.Click += async (_, ev) =>
- {
- await App.CopyTextAsync(change.Path);
- ev.Handled = true;
- };
- menu.Items.Add(new MenuItem() { Header = "-" });
- menu.Items.Add(copyPath);
-
- var copyFullPath = new MenuItem();
- copyFullPath.Header = App.Text("CopyFullPath");
- copyFullPath.Icon = App.CreateMenuIcon("Icons.Copy");
- copyFullPath.Tag = OperatingSystem.IsMacOS() ? "⌘+⇧+C" : "Ctrl+Shift+C";
- copyFullPath.Click += async (_, e) =>
- {
- await App.CopyTextAsync(Native.OS.GetAbsPath(_repo, change.Path));
- e.Handled = true;
- };
- menu.Items.Add(copyFullPath);
-
- return menu;
+ var succ = await Commands.SaveChangesAsPatch.ProcessRevisionCompareChangesAsync(_repo, changes, _based.Head, _to.Head, saveTo);
+ if (succ)
+ App.SendNotification(_repo, App.Text("SaveAsPatchSuccess"));
}
private void Refresh()
@@ -231,6 +181,7 @@ private void Refresh()
Dispatcher.UIThread.Post(() =>
{
+ TotalChanges = _changes.Count;
VisibleChanges = visible;
IsLoading = false;
@@ -270,6 +221,7 @@ private void RefreshVisible()
private Models.Branch _to = null;
private Models.Commit _baseHead = null;
private Models.Commit _toHead = null;
+ private int _totalChanges = 0;
private List _changes = null;
private List _visibleChanges = null;
private List _selectedChanges = null;
diff --git a/src/ViewModels/BranchCompareCommandPalette.cs b/src/ViewModels/BranchCompareCommandPalette.cs
new file mode 100644
index 000000000..bf2f2fc15
--- /dev/null
+++ b/src/ViewModels/BranchCompareCommandPalette.cs
@@ -0,0 +1,98 @@
+using System;
+using System.Collections.Generic;
+
+namespace SourceGit.ViewModels
+{
+ public class BranchCompareCommandPalette : ICommandPalette
+ {
+ public List