diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b3dd9d5edb..c52adeacc3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,31 +1,42 @@ name: Build on: workflow_call: + inputs: + ref: + description: Commit to check out. Defaults to the commit that triggered the workflow. + required: false + type: string + runtimes: + description: Comma-separated runtimes to build. Falls back to the BUILD_RUNTIMES repository variable, then osx-arm64. + required: false + type: string jobs: + select: + name: Select runtimes + runs-on: ubuntu-latest + outputs: + include: ${{ steps.select.outputs.include }} + steps: + - name: Select runtimes + id: select + env: + RUNTIMES: ${{ inputs.runtimes || vars.BUILD_RUNTIMES || 'osx-arm64' }} + run: | + ALL='[ + {"name": "Windows x64", "os": "windows-2022", "runtime": "win-x64"}, + {"name": "Windows ARM64", "os": "windows-2022", "runtime": "win-arm64"}, + {"name": "macOS (Intel)", "os": "macos-15-intel", "runtime": "osx-x64"}, + {"name": "macOS (Apple Silicon)", "os": "macos-latest", "runtime": "osx-arm64"}, + {"name": "Linux", "os": "ubuntu-latest", "runtime": "linux-x64", "container": "ubuntu:20.04"}, + {"name": "Linux (arm64)", "os": "ubuntu-latest", "runtime": "linux-arm64", "container": "ubuntu:20.04"} + ]' + echo "include=$(jq -c --arg want "$RUNTIMES" '($want | split(",") | map(gsub("\\s"; ""))) as $w | map(select(.runtime as $r | $w | index($r)))' <<< "$ALL")" >> "$GITHUB_OUTPUT" build: + needs: select + if: needs.select.outputs.include != '[]' strategy: matrix: - include: - - name: Windows x64 - os: windows-2022 - runtime: win-x64 - - name: Windows ARM64 - os: windows-2022 - runtime: win-arm64 - - name: macOS (Intel) - os: macos-15-intel - runtime: osx-x64 - - name: macOS (Apple Silicon) - os: macos-latest - runtime: osx-arm64 - - name: Linux - os: ubuntu-latest - runtime: linux-x64 - container: ubuntu:20.04 - - name: Linux (arm64) - os: ubuntu-latest - runtime: linux-arm64 - container: ubuntu:20.04 + include: ${{ fromJSON(needs.select.outputs.include) }} name: Build ${{ matrix.name }} runs-on: ${{ matrix.os }} container: ${{ matrix.container || '' }} @@ -41,6 +52,7 @@ jobs: - name: Checkout sources uses: actions/checkout@v6 with: + ref: ${{ inputs.ref }} submodules: true - name: Setup .NET uses: actions/setup-dotnet@v5 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3204df528a..3d29b99ba8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,6 +2,8 @@ name: Continuous Integration on: push: branches: [develop] + # A release commit only bumps VERSION, and the Release workflow builds it anyway. + paths-ignore: [VERSION] pull_request: branches: [develop] workflow_dispatch: diff --git a/.github/workflows/format-check.yml b/.github/workflows/format-check.yml index 0640d19e9b..d6fb799d38 100644 --- a/.github/workflows/format-check.yml +++ b/.github/workflows/format-check.yml @@ -2,6 +2,8 @@ name: Format Check on: push: branches: [develop] + # A release commit only bumps VERSION, and the Release workflow builds it anyway. + paths-ignore: [VERSION] pull_request: branches: [develop] workflow_dispatch: diff --git a/.github/workflows/homebrew-notify.yml b/.github/workflows/homebrew-notify.yml deleted file mode 100644 index d0538b37a6..0000000000 --- a/.github/workflows/homebrew-notify.yml +++ /dev/null @@ -1,22 +0,0 @@ -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/localization-check.yml b/.github/workflows/localization-check.yml deleted file mode 100644 index 76d7be77f4..0000000000 --- a/.github/workflows/localization-check.yml +++ /dev/null @@ -1,41 +0,0 @@ -name: Localization Check -on: - push: - branches: [develop] - paths: - - 'src/Resources/Locales/**' - workflow_dispatch: - workflow_call: - -jobs: - localization-check: - runs-on: ubuntu-latest - - steps: - - name: Checkout repository - uses: actions/checkout@v6 - - - name: Set up Node.js - uses: actions/setup-node@v6 - with: - node-version: '24.x' - - - name: Install dependencies - run: npm install fs-extra@11.2.0 path@0.12.7 xml2js@0.6.2 - - - name: Run localization check - run: node build/scripts/localization-check.js - - - name: Commit changes - run: | - git config --global user.name 'github-actions[bot]' - git config --global user.email 'github-actions[bot]@users.noreply.github.com' - if [ -n "$(git status --porcelain)" ]; then - git add TRANSLATION.md src/Resources/Locales/*.axaml - git commit -m 'doc: Update translation status and sort locale files' - git push - else - echo "No changes to commit" - fi - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/package.yml b/.github/workflows/package.yml index 0845774fb3..1d6af9910f 100644 --- a/.github/workflows/package.yml +++ b/.github/workflows/package.yml @@ -6,16 +6,47 @@ on: description: SourceGit package version required: true type: string + ref: + description: Commit to check out. Defaults to the commit that triggered the workflow. + required: false + type: string + runtimes: + description: Comma-separated runtimes to package. Falls back to the BUILD_RUNTIMES repository variable, then osx-arm64. + required: false + type: string jobs: + select: + name: Select runtimes + runs-on: ubuntu-latest + outputs: + windows: ${{ steps.select.outputs.windows }} + osx: ${{ steps.select.outputs.osx }} + linux: ${{ steps.select.outputs.linux }} + steps: + - name: Select runtimes + id: select + env: + RUNTIMES: ${{ inputs.runtimes || vars.BUILD_RUNTIMES || 'osx-arm64' }} + run: | + pick() { + jq -cn --arg want "$RUNTIMES" --arg prefix "$1" '$want | split(",") | map(gsub("\\s"; "")) | map(select(startswith($prefix)))' + } + echo "windows=$(pick win-)" >> "$GITHUB_OUTPUT" + echo "osx=$(pick osx-)" >> "$GITHUB_OUTPUT" + echo "linux=$(pick linux-)" >> "$GITHUB_OUTPUT" windows: name: Package Windows + needs: select + if: needs.select.outputs.windows != '[]' runs-on: windows-2022 strategy: matrix: - runtime: [win-x64, win-arm64] + runtime: ${{ fromJSON(needs.select.outputs.windows) }} steps: - name: Checkout sources uses: actions/checkout@v6 + with: + ref: ${{ inputs.ref }} - name: Download build uses: actions/download-artifact@v8 with: @@ -38,13 +69,17 @@ jobs: name: sourcegit.${{ matrix.runtime }} osx-app: name: Package macOS + needs: select + if: needs.select.outputs.osx != '[]' runs-on: macos-latest strategy: matrix: - runtime: [osx-x64, osx-arm64] + runtime: ${{ fromJSON(needs.select.outputs.osx) }} steps: - name: Checkout sources uses: actions/checkout@v6 + with: + ref: ${{ inputs.ref }} - name: Download build uses: actions/download-artifact@v8 with: @@ -54,6 +89,11 @@ jobs: env: VERSION: ${{ inputs.version }} RUNTIME: ${{ matrix.runtime }} + MACOS_CERTIFICATE: ${{ secrets.MACOS_CERTIFICATE }} + MACOS_CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PASSWORD }} + APPLE_API_KEY: ${{ secrets.APPLE_API_KEY }} + APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }} + APPLE_API_ISSUER_ID: ${{ secrets.APPLE_API_ISSUER_ID }} run: | mkdir build/SourceGit tar -xf "build/sourcegit.${{ matrix.runtime }}.tar" -C build/SourceGit @@ -62,21 +102,27 @@ jobs: uses: actions/upload-artifact@v7 with: name: package.${{ matrix.runtime }} - path: build/sourcegit_*.zip + path: | + build/sourcegit_*.zip + build/SourceGit-mac-*.dmg - name: Delete temp artifacts uses: geekyeggo/delete-artifact@v6 with: name: sourcegit.${{ matrix.runtime }} linux: name: Package Linux + needs: select + if: needs.select.outputs.linux != '[]' runs-on: ubuntu-latest container: ubuntu:20.04 strategy: matrix: - runtime: [linux-x64, linux-arm64] + runtime: ${{ fromJSON(needs.select.outputs.linux) }} steps: - name: Checkout sources uses: actions/checkout@v6 + with: + ref: ${{ inputs.ref }} - name: Download package dependencies run: | export DEBIAN_FRONTEND=noninteractive diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 816870a021..1928fe6800 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,29 +1,84 @@ name: Release on: push: - tags: - - v* + branches: [master] + workflow_dispatch: + inputs: + runtimes: + description: Comma-separated runtimes, e.g. osx-arm64,osx-x64,win-x64 + required: false + type: string +# Each run bumps VERSION on master, so runs must not overlap. +concurrency: + group: release + cancel-in-progress: false jobs: - build: - name: Build - uses: ./.github/workflows/build.yml version: - name: Prepare version string + name: Bump version runs-on: ubuntu-latest + permissions: + contents: write outputs: version: ${{ steps.version.outputs.version }} + tag: ${{ steps.version.outputs.tag }} + sha: ${{ steps.version.outputs.sha }} steps: - - name: Output version string + - name: Checkout sources + uses: actions/checkout@v6 + with: + ref: master + fetch-depth: 0 + - name: Bump, commit and tag id: version env: - TAG: ${{ github.ref_name }} - run: echo "version=${TAG#v}" >> "$GITHUB_OUTPUT" + EVENT: ${{ github.event_name }} + run: | + # A queued run can find master already released by the run before it. + if [ "$EVENT" = push ] && git tag --points-at HEAD | grep -q '^v'; then + echo "master is already released as $(git tag --points-at HEAD | grep '^v' | head -1)" + exit 0 + fi + + # VERSION keeps its value until it has been released, e.g. 2026.22.1 after an upstream merge. + version=$(cat VERSION) + [[ "$version" =~ ^[0-9]{4}\.[0-9]{1,2}$ ]] && version="$version.1" + while git rev-parse -q --verify "refs/tags/v$version" > /dev/null; do + version=$(echo "$version" | awk -F. -v OFS=. '{ $NF += 1; print }') + done + + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + if [ "$version" != "$(cat VERSION)" ]; then + printf '%s' "$version" > VERSION + git commit --quiet -m "version: Release $version" VERSION + fi + git tag -a "v$version" -m "v$version" + git push --atomic origin HEAD:master "v$version" + + # Hand the VERSION commit to develop too, so the next release fast-forwards master. + # A plain push only succeeds when develop has not moved on since this release. + git push origin HEAD:develop || echo "::notice::develop has moved on; release.sh merges the VERSION commit into it." + + echo "version=$version" >> "$GITHUB_OUTPUT" + echo "tag=v$version" >> "$GITHUB_OUTPUT" + echo "sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT" + build: + needs: version + if: needs.version.outputs.version + name: Build + uses: ./.github/workflows/build.yml + with: + ref: ${{ needs.version.outputs.sha }} + runtimes: ${{ inputs.runtimes }} package: needs: [build, version] name: Package uses: ./.github/workflows/package.yml + secrets: inherit with: + ref: ${{ needs.version.outputs.sha }} version: ${{ needs.version.outputs.version }} + runtimes: ${{ inputs.runtimes }} release: needs: [package, version] name: Release @@ -33,12 +88,16 @@ jobs: steps: - name: Checkout sources uses: actions/checkout@v6 + with: + ref: ${{ needs.version.outputs.sha }} - name: Create release env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - TAG: ${{ github.ref_name }} + TAG: ${{ needs.version.outputs.tag }} VERSION: ${{ needs.version.outputs.version }} - run: gh release create "$TAG" -t "$VERSION" --notes-from-tag + run: | + git fetch --quiet origin "refs/tags/$TAG:refs/tags/$TAG" + gh release create "$TAG" -t "$VERSION" --notes-from-tag - name: Download artifacts uses: actions/download-artifact@v8 with: @@ -48,5 +107,10 @@ jobs: - name: Upload assets env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - TAG: ${{ github.ref_name }} + TAG: ${{ needs.version.outputs.tag }} run: gh release upload "$TAG" packages/* + - name: Update Homebrew cask + env: + GH_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }} + VERSION: ${{ needs.version.outputs.version }} + run: ./build/scripts/update-homebrew-cask.sh diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000000..6c681ed21f --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,13 @@ +# Holion fork of SourceGit + +Fork-specific setup (install, release process, secrets) is documented in the "Holion fork" section of README.md. Read it before changing anything around versions, releases or updates. + +- Every push to `master` is a release. Release with `./release.sh`, which pushes `develop` to `master`; never tag or bump `VERSION` for a release by hand. `.github/workflows/release.yml` bumps `VERSION` on `master`, tags `v*` and builds. +- When asked to release, do it without asking again: from a clean `develop`, run `echo y | ./release.sh` (it merges `origin/master` into `develop` when the workflow could not push its `VERSION` commit there, and pushes `develop` to `master`), then follow the run with `gh run watch` and report the version and assets. +- Stage only the files you changed, never `git add -A`; unrelated uncommitted work may be in the tree. +- `VERSION` carries a fork patch number on top of upstream (`2026.21.3`). Upstream merges conflict on it; keep the fork's value and set it to `.1`, which the workflow then releases as is because it has no tag yet. +- The update check and links point at `holion/sourcegit`, not `sourcegit-scm`. Keep it that way when merging upstream changes to `src/App.axaml.cs`, `src/Views/About.axaml.cs` and `src/Views/SelfUpdate.axaml.cs`. +- macOS auto-update lives in `src/Models/AutoUpdate.cs`: it stages the release zip in the cache dir and swaps the app bundle when the app exits. +- Built runtimes come from the `runtimes` workflow input, then the `BUILD_RUNTIMES` repository variable, then `osx-arm64`. +- `build/resources/` is gitignored; new files there need `git add -f`. +- The fork is English only: `src/Resources/Locales/en_US.axaml` is merged directly in `src/App.axaml`, and there is no language setting. When merging upstream, `git rm` the other locale files (modify/delete conflicts), drop their entries in `src/App.axaml`, `src/Models/Locales.cs`, `TRANSLATION.md` and `.github/workflows/localization-check.yml`, and keep only the `en_US` text of new keys. diff --git a/README.md b/README.md index 53baa34274..32dccbdaca 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,58 @@ [![latest](https://img.shields.io/github/v/release/sourcegit-scm/sourcegit.svg)](https://github.com/sourcegit-scm/sourcegit/releases/latest) [![downloads](https://img.shields.io/github/downloads/sourcegit-scm/sourcegit/total)](https://github.com/sourcegit-scm/sourcegit/releases) +## Holion fork + +This is Holion's fork of SourceGit. It adds our own features and ships its own releases with automatic updates on macOS. + +### Install + +* Download: [SourceGit for Mac (Apple Silicon)](https://github.com/holion/sourcegit/releases/latest/download/SourceGit-mac-apple-silicon.dmg) +* Or with Homebrew: `brew trust --cask holion/tap/sourcegit-holion && brew install --cask holion/tap/sourcegit-holion` + +The app checks for new releases on startup and every 6 hours, downloads them in the background and installs them when it quits. + +### GitHub + +Sign in under `Preferences > GitHub` (or from the GitHub button in the clone dialog). After that: + +* The clone dialog's GitHub button lists every repository you can access, grouped by owner. Picked repositories go into `/`. +* Typing in the tab switcher (`Ctrl/⌘+P`) also lists GitHub repositories that are not cloned yet; picking one opens the clone dialog with it filled in. +* Fetch, pull and push to `https://github.com/...` use the account automatically, so no SSH key or credential manager is needed (this can be turned off in the same tab). The token lives in the system keychain (Keychain, Windows Credential Manager or libsecret). + +The sign-in uses the device flow of the Holion OAuth app, whose client id is `Models.GitHub.ClientId` in `src/Models/GitHub.cs` (the integration is hidden while it is empty). The app is registered under [holion's OAuth apps](https://github.com/organizations/holion/settings/applications) with "Enable Device Flow" checked. Organizations that restrict third-party access have to approve it once; until then their private repositories are missing from the list. + +### Azure DevOps + +Sign in under `Preferences > Azure DevOps` (or from the Azure DevOps button in the clone dialog) with your Microsoft work account. After that: + +* The clone dialog's Azure DevOps button lists the repositories of every organization you are a member of, filtered by project. Picked repositories go into `/`. +* The tab switcher (`Ctrl/⌘+P`) lists Azure DevOps repositories that are not cloned yet, next to the GitHub ones. +* Fetch, pull and push to `https://dev.azure.com/...` and `https://.visualstudio.com/...` use the account automatically (this can be turned off in the same tab). Remotes over SSH keep using SSH keys; switch a remote to its HTTPS URL to use the account instead. The refresh token lives in the system keychain; git gets a fresh access token from it through `--azure-devops-credential`. + +The sign-in uses the Microsoft Entra ID device code flow of a Holion app registration, whose application (client) id is `Models.AzureDevOps.ClientId` in `src/Models/AzureDevOps.cs` (the integration is hidden while it is empty). To set up the app registration in the [Entra admin center](https://entra.microsoft.com/#view/Microsoft_AAD_RegisteredApps/ApplicationsListBlade): + +1. New registration, "Accounts in any organizational directory (Multitenant)", no redirect URI. +2. Under Authentication, set "Allow public client flows" to Yes. +3. Under API permissions, add Azure DevOps > Delegated > `user_impersonation`. + +Only organizations connected to the tenant you sign in with are listed. Tenants that do not let users consent to apps need an admin to consent once. + +### Release + +Every push to `master` makes a release. From a clean `develop`, run: + +```shell +./release.sh +``` + +The script shows the commits that are not on `master` yet and pushes `develop` to `master`. The [Release workflow](https://github.com/holion/sourcegit/actions/workflows/release.yml) then bumps `VERSION` on `master` (e.g. 2026.21.3 -> 2026.21.4), tags it and does the rest: build, sign and notarize, publish the release and update the [Homebrew tap](https://github.com/holion/homebrew-tap). The workflow also pushes that `VERSION` commit to `develop` when `develop` has not moved on since the release; otherwise the next `./release.sh` merges it in. + +* Only `osx-arm64` is built by default. Set the `BUILD_RUNTIMES` repository variable to build more, e.g. `gh variable set BUILD_RUNTIMES -b "osx-arm64,osx-x64,win-x64"`. +* Versions use a third number on top of upstream's, e.g. `2026.21.3`. After merging a new upstream version, set `VERSION` to e.g. `2026.22.1` on `develop`; the workflow releases a `VERSION` that has no tag yet as it is. +* Running the Release workflow by hand releases the tip of `master` as the next version, e.g. to build other runtimes. +* Signing needs the `MACOS_CERTIFICATE`, `MACOS_CERTIFICATE_PASSWORD`, `APPLE_API_KEY`, `APPLE_API_KEY_ID` and `APPLE_API_ISSUER_ID` secrets, and the Homebrew tap needs `HOMEBREW_TAP_TOKEN`. + ## Screenshots * Dark Theme @@ -24,7 +76,6 @@ * Supports Windows/macOS/Linux * Opensource/Free -* Fast * Deutsch/English/Español/Bahasa Indonesia/Français/Italiano/Português/Русский/Українська/简体中文/繁體中文/日本語/தமிழ் (Tamil)/한국어 * Built-in light/dark themes * Customize theme @@ -281,27 +332,6 @@ Thanks to all the people who contribute. [![Contributors](https://contrib.rocks/image?repo=sourcegit-scm/sourcegit&columns=20)](https://github.com/sourcegit-scm/sourcegit/graphs/contributors) -## Translation Status - -You can find the current translation status in [TRANSLATION.md](https://github.com/sourcegit-scm/sourcegit/blob/develop/TRANSLATION.md) - -### Translate Utility Script - -A script that assists with translations by reading the target language, comparing it with the base language, and going through missing keys one by one, so the translator can provide the translations interactively without needing to check each key manually. - -#### Usage - -Check for a given language (e.g., `pt_BR`) and optionally check for missing translations: - -```bash -python translate_helper.py pt_BR [--check] -``` - -- `pt_BR` is the target language code (change as needed), it should correspond to a file named `pt_BR.axaml` in the `src/Resources/Locales/` directory, so you can replace it with any other language code you want to translate, e.g., `de_DE`, `es_ES`, etc. -- `--check` is an optional flag used to only check for missing keys without prompting for translations, useful for getting a list of missing translations. - -The script will read the base language file (`en_US.axaml`) and the target language file (e.g., `pt_BR.axaml`), identify missing keys, and prompt you to provide translations for those keys. If the `--check` flag is used, it will only list the missing keys without prompting for translations. - ## Third-Party Components For detailed license information, see [THIRD-PARTY-LICENSES.md](THIRD-PARTY-LICENSES.md). diff --git a/TRANSLATION.md b/TRANSLATION.md deleted file mode 100644 index 67becad004..0000000000 --- a/TRANSLATION.md +++ /dev/null @@ -1,1932 +0,0 @@ -# Translation Status - -This document shows the translation status of each locale file in the repository. - -## Details - -### ![en_US](https://img.shields.io/badge/en__US-%E2%88%9A-brightgreen) - -### ![de__DE](https://img.shields.io/badge/de__DE-95.66%25-yellow) - -
-Missing keys in de_DE.axaml - -- Text.Blame.Tips -- Text.BranchTree.PushURL -- Text.CommitDetail.Files.Tips -- Text.Dashboard -- Text.Diff.Binary.ViewContentOfNew -- Text.File.Binary -- Text.File.HexViewer -- Text.File.HexViewer.GotoAddress -- Text.Histories.AdvancedOptions -- Text.Histories.HighlightsInGraph.SelectedCommitsOnlyFirstParent -- Text.Hotkeys.Repo.ToggleCommitDetailPanel -- Text.Hotkeys.Repo.ToggleSearchCommits -- Text.Hotkeys.Repo.ViewDashboard -- Text.OpenAppDataDir.Cache -- Text.OpenAppDataDir.Config -- Text.Preferences.AI.ExtraHeaders -- Text.Preferences.AI.ReasoningEffortLevel -- Text.Remote.ResetPushURL -- Text.RemoteCM.SetPushURL -- Text.Repository.Search.Method -- Text.Repository.Search.ToolTip -- Text.SetPushUrl -- Text.SetPushUrl.PushURL -- Text.SetPushUrl.Remote -- Text.SetPushUrl.URL -- Text.SSHKeyHelper -- Text.SSHKeyHelper.ConfirmDeletion -- Text.SSHKeyHelper.Fingerprint -- Text.SSHKeyHelper.Generator -- Text.SSHKeyHelper.Generator.ConfirmPassphrase -- Text.SSHKeyHelper.Generator.Email -- Text.SSHKeyHelper.Generator.Email.Placeholder -- Text.SSHKeyHelper.Generator.Name -- Text.SSHKeyHelper.Generator.Name.Placeholder -- Text.SSHKeyHelper.Generator.Passphrase -- Text.SSHKeyHelper.Generator.Start -- Text.SSHKeyHelper.Generator.Type -- Text.SSHKeyHelper.Generator.UsePassphrase -- Text.SSHKeyHelper.Path -- Text.SSHKeyHelper.PublicKey -- Text.SSHKeyHelper.Title -- Text.Statistics.Tips -- Text.Terminate -- Text.WorkingCopy.CollapseSidebar -- Text.WorkingCopy.DiscardAll -- Text.WorkingCopy.ExpandSidebar - -
- -### ![el__GR](https://img.shields.io/badge/el__GR-95.19%25-yellow) - -
-Missing keys in el_GR.axaml - -- Text.Blame.Tips -- Text.BranchTree.PushURL -- Text.CommitDetail.Files.Tips -- Text.Dashboard -- Text.Diff.Binary.ViewContentOfNew -- Text.File.Binary -- Text.File.HexViewer -- Text.File.HexViewer.GotoAddress -- Text.Histories.AdvancedOptions -- Text.Histories.HighlightsInGraph.SelectedCommitsOnlyFirstParent -- Text.Hotkeys.Repo.ToggleCommitDetailPanel -- Text.Hotkeys.Repo.ToggleSearchCommits -- Text.Hotkeys.Repo.ViewDashboard -- Text.Launcher.NewVersion -- Text.OpenAppDataDir.Cache -- Text.OpenAppDataDir.Config -- Text.Preferences.AI.ExtraHeaders -- Text.Preferences.AI.ReasoningEffortLevel -- Text.Remote.ResetPushURL -- Text.RemoteCM.SetPushURL -- Text.Repository.FilterCommits.Collapse -- Text.Repository.FilterCommits.Expand -- Text.Repository.FilterCommits.Summary -- Text.Repository.Search.Method -- Text.Repository.Search.ToolTip -- Text.SetPushUrl -- Text.SetPushUrl.PushURL -- Text.SetPushUrl.Remote -- Text.SetPushUrl.URL -- Text.SSHKeyHelper -- Text.SSHKeyHelper.ConfirmDeletion -- Text.SSHKeyHelper.Fingerprint -- Text.SSHKeyHelper.Generator -- Text.SSHKeyHelper.Generator.ConfirmPassphrase -- Text.SSHKeyHelper.Generator.Email -- Text.SSHKeyHelper.Generator.Email.Placeholder -- Text.SSHKeyHelper.Generator.Name -- Text.SSHKeyHelper.Generator.Name.Placeholder -- Text.SSHKeyHelper.Generator.Passphrase -- Text.SSHKeyHelper.Generator.Start -- Text.SSHKeyHelper.Generator.Type -- Text.SSHKeyHelper.Generator.UsePassphrase -- Text.SSHKeyHelper.Path -- Text.SSHKeyHelper.PublicKey -- Text.SSHKeyHelper.Title -- Text.Statistics.Tips -- Text.Terminate -- Text.WorkingCopy.CollapseSidebar -- Text.WorkingCopy.DiscardAll -- Text.WorkingCopy.ExpandSidebar -- Text.WorkingCopy.FilterChanges - -
- -### ![es__ES](https://img.shields.io/badge/es__ES-99.72%25-yellow) - -
-Missing keys in es_ES.axaml - -- Text.CommitDetail.Files.Tips -- Text.WorkingCopy.CollapseSidebar -- Text.WorkingCopy.ExpandSidebar - -
- -### ![fr__FR](https://img.shields.io/badge/fr__FR-91.42%25-yellow) - -
-Missing keys in fr_FR.axaml - -- Text.Apply.Source -- Text.Apply.Source.File -- Text.Apply.Source.Clipboard -- Text.Bisect.WaitingForCheckoutAnother -- Text.Bisect.WaitingForFirstBad -- Text.Blame.Tips -- Text.BranchTree.PushURL -- Text.CheckoutDetached -- Text.CheckoutDetached.Target -- Text.CheckoutDetached.Warning -- Text.CommitCM.CopyAuthorTime -- Text.CommitCM.CopyCommitterTime -- Text.CommitDetail.Files.Tips -- Text.Configure.Git.EnableRecursiveWhenAutoUpdatingSubmodules -- Text.CopyAsPatch -- Text.Dashboard -- Text.DeleteBranch.Force -- Text.Diff.Binary.ViewContentOfNew -- Text.Diff.EmptyFile -- Text.File.Binary -- Text.File.HexViewer -- Text.File.HexViewer.GotoAddress -- Text.FileModeChange -- Text.FileModeChange.Deleted -- Text.FileModeChange.Directory -- Text.FileModeChange.Executable -- Text.FileModeChange.New -- Text.FileModeChange.Normal -- Text.FileModeChange.Submodule -- Text.FileModeChange.Symlink -- Text.FileModeChange.Unknown -- Text.GitFlow.Finish -- Text.GitFlow.FinishWithRebase -- Text.GitFlow.StartAt -- Text.GitFlow.StartName -- Text.Histories.AdvancedOptions -- Text.Histories.HighlightsInGraph.SelectedCommitsOnlyFirstParent -- Text.Hotkeys.Repo.ToggleCommitDetailPanel -- Text.Hotkeys.Repo.ToggleSearchCommits -- Text.Hotkeys.Repo.ViewDashboard -- Text.Launcher.NewVersion -- Text.Merge.Test -- Text.Merge.Test.NoConflicts -- Text.Merge.Test.UnknownError -- Text.Merge.Test.WillCauseConflicts -- Text.OpenAppDataDir.Cache -- Text.OpenAppDataDir.Config -- Text.Preferences.AI.ExtraHeaders -- Text.Preferences.AI.ReasoningEffortLevel -- Text.Preferences.General.UseCompactBranchNames -- Text.Rebase.Test -- Text.Rebase.Test.OK -- Text.Rebase.Test.UnknownError -- Text.Rebase.Test.WillCauseConflicts -- Text.Remote.ResetPushURL -- Text.RemoteCM.SetPushURL -- Text.Repository.FilterCommits.Collapse -- Text.Repository.FilterCommits.Expand -- Text.Repository.FilterCommits.Summary -- Text.Repository.Search.Method -- Text.Repository.Search.ToolTip -- Text.SetPushUrl -- Text.SetPushUrl.PushURL -- Text.SetPushUrl.Remote -- Text.SetPushUrl.URL -- Text.SSHKeyHelper -- Text.SSHKeyHelper.ConfirmDeletion -- Text.SSHKeyHelper.Fingerprint -- Text.SSHKeyHelper.Generator -- Text.SSHKeyHelper.Generator.ConfirmPassphrase -- Text.SSHKeyHelper.Generator.Email -- Text.SSHKeyHelper.Generator.Email.Placeholder -- Text.SSHKeyHelper.Generator.Name -- Text.SSHKeyHelper.Generator.Name.Placeholder -- Text.SSHKeyHelper.Generator.Passphrase -- Text.SSHKeyHelper.Generator.Start -- Text.SSHKeyHelper.Generator.Type -- Text.SSHKeyHelper.Generator.UsePassphrase -- Text.SSHKeyHelper.Path -- Text.SSHKeyHelper.PublicKey -- Text.SSHKeyHelper.Title -- Text.Statistics.Tips -- Text.TagCM.Checkout -- Text.TagCM.Merge -- Text.Terminate -- Text.UpdateSubmodules.Recursive -- Text.WorkingCopy.AddToGitIgnore.UntrackedInSameFolder -- Text.WorkingCopy.CollapseSidebar -- Text.WorkingCopy.DiscardAll -- Text.WorkingCopy.ExpandSidebar -- Text.WorkingCopy.FilterChanges - -
- -### ![he__IL](https://img.shields.io/badge/he__IL-91.42%25-yellow) - -
-Missing keys in he_IL.axaml - -- Text.Apply.Source -- Text.Apply.Source.File -- Text.Apply.Source.Clipboard -- Text.Bisect.WaitingForCheckoutAnother -- Text.Bisect.WaitingForFirstBad -- Text.Blame.Tips -- Text.BranchTree.PushURL -- Text.CheckoutDetached -- Text.CheckoutDetached.Target -- Text.CheckoutDetached.Warning -- Text.CommitCM.CopyAuthorTime -- Text.CommitCM.CopyCommitterTime -- Text.CommitDetail.Files.Tips -- Text.Configure.Git.EnableRecursiveWhenAutoUpdatingSubmodules -- Text.CopyAsPatch -- Text.Dashboard -- Text.DeleteBranch.Force -- Text.Diff.Binary.ViewContentOfNew -- Text.Diff.EmptyFile -- Text.File.Binary -- Text.File.HexViewer -- Text.File.HexViewer.GotoAddress -- Text.FileModeChange -- Text.FileModeChange.Deleted -- Text.FileModeChange.Directory -- Text.FileModeChange.Executable -- Text.FileModeChange.New -- Text.FileModeChange.Normal -- Text.FileModeChange.Submodule -- Text.FileModeChange.Symlink -- Text.FileModeChange.Unknown -- Text.GitFlow.Finish -- Text.GitFlow.FinishWithRebase -- Text.GitFlow.StartAt -- Text.GitFlow.StartName -- Text.Histories.AdvancedOptions -- Text.Histories.HighlightsInGraph.SelectedCommitsOnlyFirstParent -- Text.Hotkeys.Repo.ToggleCommitDetailPanel -- Text.Hotkeys.Repo.ToggleSearchCommits -- Text.Hotkeys.Repo.ViewDashboard -- Text.Launcher.NewVersion -- Text.Merge.Test -- Text.Merge.Test.NoConflicts -- Text.Merge.Test.UnknownError -- Text.Merge.Test.WillCauseConflicts -- Text.OpenAppDataDir.Cache -- Text.OpenAppDataDir.Config -- Text.Preferences.AI.ExtraHeaders -- Text.Preferences.AI.ReasoningEffortLevel -- Text.Preferences.General.UseCompactBranchNames -- Text.Rebase.Test -- Text.Rebase.Test.OK -- Text.Rebase.Test.UnknownError -- Text.Rebase.Test.WillCauseConflicts -- Text.Remote.ResetPushURL -- Text.RemoteCM.SetPushURL -- Text.Repository.FilterCommits.Collapse -- Text.Repository.FilterCommits.Expand -- Text.Repository.FilterCommits.Summary -- Text.Repository.Search.Method -- Text.Repository.Search.ToolTip -- Text.SetPushUrl -- Text.SetPushUrl.PushURL -- Text.SetPushUrl.Remote -- Text.SetPushUrl.URL -- Text.SSHKeyHelper -- Text.SSHKeyHelper.ConfirmDeletion -- Text.SSHKeyHelper.Fingerprint -- Text.SSHKeyHelper.Generator -- Text.SSHKeyHelper.Generator.ConfirmPassphrase -- Text.SSHKeyHelper.Generator.Email -- Text.SSHKeyHelper.Generator.Email.Placeholder -- Text.SSHKeyHelper.Generator.Name -- Text.SSHKeyHelper.Generator.Name.Placeholder -- Text.SSHKeyHelper.Generator.Passphrase -- Text.SSHKeyHelper.Generator.Start -- Text.SSHKeyHelper.Generator.Type -- Text.SSHKeyHelper.Generator.UsePassphrase -- Text.SSHKeyHelper.Path -- Text.SSHKeyHelper.PublicKey -- Text.SSHKeyHelper.Title -- Text.Statistics.Tips -- Text.TagCM.Checkout -- Text.TagCM.Merge -- Text.Terminate -- Text.UpdateSubmodules.Recursive -- Text.WorkingCopy.AddToGitIgnore.UntrackedInSameFolder -- Text.WorkingCopy.CollapseSidebar -- Text.WorkingCopy.DiscardAll -- Text.WorkingCopy.ExpandSidebar -- Text.WorkingCopy.FilterChanges - -
- -### ![id__ID](https://img.shields.io/badge/id__ID-95.66%25-yellow) - -
-Missing keys in id_ID.axaml - -- Text.Blame.Tips -- Text.BranchTree.PushURL -- Text.CommitDetail.Files.Tips -- Text.Dashboard -- Text.Diff.Binary.ViewContentOfNew -- Text.File.Binary -- Text.File.HexViewer -- Text.File.HexViewer.GotoAddress -- Text.Histories.AdvancedOptions -- Text.Histories.HighlightsInGraph.SelectedCommitsOnlyFirstParent -- Text.Hotkeys.Repo.ToggleCommitDetailPanel -- Text.Hotkeys.Repo.ToggleSearchCommits -- Text.Hotkeys.Repo.ViewDashboard -- Text.OpenAppDataDir.Cache -- Text.OpenAppDataDir.Config -- Text.Preferences.AI.ReasoningEffortLevel -- Text.Remote.ResetPushURL -- Text.RemoteCM.SetPushURL -- Text.Repository.Search.Method -- Text.Repository.Search.ToolTip -- Text.SetPushUrl -- Text.SetPushUrl.PushURL -- Text.SetPushUrl.Remote -- Text.SetPushUrl.URL -- Text.SSHKeyHelper -- Text.SSHKeyHelper.ConfirmDeletion -- Text.SSHKeyHelper.Fingerprint -- Text.SSHKeyHelper.Generator -- Text.SSHKeyHelper.Generator.ConfirmPassphrase -- Text.SSHKeyHelper.Generator.Email -- Text.SSHKeyHelper.Generator.Email.Placeholder -- Text.SSHKeyHelper.Generator.Name -- Text.SSHKeyHelper.Generator.Name.Placeholder -- Text.SSHKeyHelper.Generator.Passphrase -- Text.SSHKeyHelper.Generator.Start -- Text.SSHKeyHelper.Generator.Type -- Text.SSHKeyHelper.Generator.UsePassphrase -- Text.SSHKeyHelper.Path -- Text.SSHKeyHelper.PublicKey -- Text.SSHKeyHelper.Title -- Text.Statistics.Tips -- Text.Terminate -- Text.WorkingCopy.CollapseSidebar -- Text.WorkingCopy.DiscardAll -- Text.WorkingCopy.ExpandSidebar -- Text.WorkingCopy.FilterChanges - -
- -### ![it__IT](https://img.shields.io/badge/it__IT-85.28%25-yellow) - -
-Missing keys in it_IT.axaml - -- Text.AIAssistant.Use -- Text.App.HideOthers -- Text.Apply.3Way -- Text.Apply.Source -- Text.Apply.Source.File -- Text.Apply.Source.Clipboard -- Text.Bisect.WaitingForCheckoutAnother -- Text.Bisect.WaitingForFirstBad -- Text.Blame.Tips -- Text.BranchCM.CompareWithSpecial -- Text.BranchTree.PushURL -- Text.ChangeCM.ResetFileTo -- Text.CheckoutBranchFromStash -- Text.CheckoutBranchFromStash.Branch -- Text.CheckoutBranchFromStash.Stash -- Text.CheckoutDetached -- Text.CheckoutDetached.Target -- Text.CheckoutDetached.Warning -- Text.Clone.Bookmark -- Text.Clone.Group -- Text.CommandPalette.Branches -- Text.CommandPalette.BranchesAndTags -- Text.CommandPalette.RepositoryActions -- Text.CommandPalette.RevisionFiles -- Text.CommitCM.CopyAuthorTime -- Text.CommitCM.CopyCommitterTime -- Text.CommitDetail.CollapseToBottom -- Text.CommitDetail.Files.Tips -- Text.CommitMessageTextBox.Column -- Text.Compare.Changes -- Text.Compare.Commits -- Text.Compare.Commits.LeftOnly -- Text.Compare.Commits.RightOnly -- Text.Compare.Commits.Tips -- Text.Configure.Git.EnableRecursiveWhenAutoUpdatingSubmodules -- Text.ConfigureCustomActionControls.StringFormatter -- Text.ConfigureCustomActionControls.StringFormatter.Tip -- Text.ConfigureCustomActionControls.UseFriendlyName -- Text.ConfirmEmptyCommit.StageSelectedThenCommit -- Text.CopyAsPatch -- Text.Dashboard -- Text.DeleteBranch.Force -- Text.Diff.Binary.ViewContentOfNew -- Text.Diff.EmptyFile -- Text.Diff.Submodule.UncommittedChanges -- Text.Discard.IncludeModified -- Text.File.Binary -- Text.File.HexViewer -- Text.File.HexViewer.GotoAddress -- Text.FileModeChange -- Text.FileModeChange.Deleted -- Text.FileModeChange.Directory -- Text.FileModeChange.Executable -- Text.FileModeChange.New -- Text.FileModeChange.Normal -- Text.FileModeChange.Submodule -- Text.FileModeChange.Symlink -- Text.FileModeChange.Unknown -- Text.GitFlow.Finish -- Text.GitFlow.FinishWithRebase -- Text.GitFlow.StartAt -- Text.GitFlow.StartName -- Text.GotoRevisionSelector -- Text.Histories.AdvancedOptions -- Text.Histories.HighlightsInGraph -- Text.Histories.HighlightsInGraph.All -- Text.Histories.HighlightsInGraph.CurrentBranchOnly -- Text.Histories.HighlightsInGraph.CurrentBranchAndSelectedCommits -- Text.Histories.HighlightsInGraph.SelectedCommitsOnly -- Text.Histories.HighlightsInGraph.SelectedCommitsOnlyFirstParent -- Text.Histories.ShowColumns -- Text.HistoriesDetailsStandalone -- Text.HistoriesDetailsStandalone.CommitDetail -- Text.HistoriesDetailsStandalone.RevisionCompare -- Text.Hotkeys.Global.OpenLocalRepository -- Text.Hotkeys.Repo.CreateBranch -- Text.Hotkeys.Repo.GoToChild -- Text.Hotkeys.Repo.GoToParent -- Text.Hotkeys.Repo.ToggleCommitDetailPanel -- Text.Hotkeys.Repo.ToggleSearchCommits -- Text.Hotkeys.Repo.ViewDashboard -- Text.Init.CommandTip -- Text.Init.ErrorMessageTip -- Text.InteractiveRebase.NoVerify -- Text.Launcher.NewVersion -- Text.Merge.Test -- Text.Merge.Test.NoConflicts -- Text.Merge.Test.UnknownError -- Text.Merge.Test.WillCauseConflicts -- Text.OpenAppDataDir.Cache -- Text.OpenAppDataDir.Config -- Text.OpenLocalRepository -- Text.OpenLocalRepository.Bookmark -- Text.OpenLocalRepository.Group -- Text.OpenLocalRepository.Path -- Text.Preferences.AI.AdditionalPrompt -- Text.Preferences.AI.ExtraHeaders -- Text.Preferences.AI.Model -- Text.Preferences.AI.Model.AutoFetchAvailableModels -- Text.Preferences.AI.ReasoningEffortLevel -- Text.Preferences.General.ShowRelativeTimeInGraph -- Text.Preferences.General.Use24Hours -- Text.Preferences.General.UseCompactBranchNames -- Text.Preferences.Git.UseStashAndReapplyByDefault -- Text.Rebase.NoVerify -- Text.Rebase.Test -- Text.Rebase.Test.OK -- Text.Rebase.Test.UnknownError -- Text.Rebase.Test.WillCauseConflicts -- Text.Remote.ResetPushURL -- Text.RemoteCM.EnableAutoFetch -- Text.RemoteCM.SetPushURL -- Text.Repository.FilterCommits.Collapse -- Text.Repository.FilterCommits.Expand -- Text.Repository.FilterCommits.Summary -- Text.Repository.Search.Method -- Text.Repository.Search.ToolTip -- Text.SelfUpdate.CurrentVersion -- Text.SelfUpdate.ReleaseDate -- Text.SetPushUrl -- Text.SetPushUrl.PushURL -- Text.SetPushUrl.Remote -- Text.SetPushUrl.URL -- Text.SSHKeyHelper -- Text.SSHKeyHelper.ConfirmDeletion -- Text.SSHKeyHelper.Fingerprint -- Text.SSHKeyHelper.Generator -- Text.SSHKeyHelper.Generator.ConfirmPassphrase -- Text.SSHKeyHelper.Generator.Email -- Text.SSHKeyHelper.Generator.Email.Placeholder -- Text.SSHKeyHelper.Generator.Name -- Text.SSHKeyHelper.Generator.Name.Placeholder -- Text.SSHKeyHelper.Generator.Passphrase -- Text.SSHKeyHelper.Generator.Start -- Text.SSHKeyHelper.Generator.Type -- Text.SSHKeyHelper.Generator.UsePassphrase -- Text.SSHKeyHelper.Path -- Text.SSHKeyHelper.PublicKey -- Text.SSHKeyHelper.Title -- Text.StashCM.ApplyFileChanges -- Text.StashCM.Branch -- Text.Statistics.Tips -- Text.SubmoduleRevisionCompare -- Text.SubmoduleRevisionCompare.OpenDetails -- Text.TagCM.Checkout -- Text.TagCM.Merge -- Text.Terminate -- Text.UpdateSubmodules.Recursive -- Text.WorkingCopy.AddToGitIgnore.UntrackedInSameFolder -- Text.WorkingCopy.CollapseSidebar -- Text.WorkingCopy.DiscardAll -- Text.WorkingCopy.ExpandSidebar -- Text.WorkingCopy.FilterChanges -- Text.Worktree.Branch -- Text.Worktree.Head -- Text.Worktree.Path - -
- -### ![ja__JP](https://img.shields.io/badge/ja__JP-99.72%25-yellow) - -
-Missing keys in ja_JP.axaml - -- Text.CommitDetail.Files.Tips -- Text.WorkingCopy.CollapseSidebar -- Text.WorkingCopy.ExpandSidebar - -
- -### ![ko__KR](https://img.shields.io/badge/ko__KR-92.83%25-yellow) - -
-Missing keys in ko_KR.axaml - -- Text.Bisect.WaitingForCheckoutAnother -- Text.Bisect.WaitingForFirstBad -- Text.Blame.Tips -- Text.BranchTree.PushURL -- Text.CheckoutDetached -- Text.CheckoutDetached.Target -- Text.CheckoutDetached.Warning -- Text.CommitDetail.Files.Tips -- Text.Configure.Git.EnableRecursiveWhenAutoUpdatingSubmodules -- Text.Dashboard -- Text.DeleteBranch.Force -- Text.Diff.Binary.ViewContentOfNew -- Text.Diff.EmptyFile -- Text.File.Binary -- Text.File.HexViewer -- Text.File.HexViewer.GotoAddress -- Text.FileModeChange -- Text.FileModeChange.Deleted -- Text.FileModeChange.Directory -- Text.FileModeChange.Executable -- Text.FileModeChange.New -- Text.FileModeChange.Normal -- Text.FileModeChange.Submodule -- Text.FileModeChange.Symlink -- Text.FileModeChange.Unknown -- Text.GitFlow.Finish -- Text.GitFlow.FinishWithRebase -- Text.GitFlow.StartAt -- Text.GitFlow.StartName -- Text.Histories.AdvancedOptions -- Text.Histories.HighlightsInGraph.SelectedCommitsOnlyFirstParent -- Text.Hotkeys.Repo.ToggleCommitDetailPanel -- Text.Hotkeys.Repo.ToggleSearchCommits -- Text.Hotkeys.Repo.ViewDashboard -- Text.Launcher.NewVersion -- Text.OpenAppDataDir.Cache -- Text.OpenAppDataDir.Config -- Text.Preferences.AI.ExtraHeaders -- Text.Preferences.AI.ReasoningEffortLevel -- Text.Remote.ResetPushURL -- Text.RemoteCM.SetPushURL -- Text.Repository.FilterCommits.Collapse -- Text.Repository.FilterCommits.Expand -- Text.Repository.FilterCommits.Summary -- Text.Repository.Search.Method -- Text.Repository.Search.ToolTip -- Text.SetPushUrl -- Text.SetPushUrl.PushURL -- Text.SetPushUrl.Remote -- Text.SetPushUrl.URL -- Text.SSHKeyHelper -- Text.SSHKeyHelper.ConfirmDeletion -- Text.SSHKeyHelper.Fingerprint -- Text.SSHKeyHelper.Generator -- Text.SSHKeyHelper.Generator.ConfirmPassphrase -- Text.SSHKeyHelper.Generator.Email -- Text.SSHKeyHelper.Generator.Email.Placeholder -- Text.SSHKeyHelper.Generator.Name -- Text.SSHKeyHelper.Generator.Name.Placeholder -- Text.SSHKeyHelper.Generator.Passphrase -- Text.SSHKeyHelper.Generator.Start -- Text.SSHKeyHelper.Generator.Type -- Text.SSHKeyHelper.Generator.UsePassphrase -- Text.SSHKeyHelper.Path -- Text.SSHKeyHelper.PublicKey -- Text.SSHKeyHelper.Title -- Text.Statistics.Tips -- Text.TagCM.Checkout -- Text.TagCM.Merge -- Text.Terminate -- Text.UpdateSubmodules.Recursive -- Text.WorkingCopy.AddToGitIgnore.UntrackedInSameFolder -- Text.WorkingCopy.CollapseSidebar -- Text.WorkingCopy.DiscardAll -- Text.WorkingCopy.ExpandSidebar -- Text.WorkingCopy.FilterChanges - -
- -### ![pt__BR](https://img.shields.io/badge/pt__BR-60.19%25-red) - -
-Missing keys in pt_BR.axaml - -- Text.AIAssistant.Use -- Text.App.HideOthers -- Text.Apply.3Way -- Text.Apply.Source -- Text.Apply.Source.File -- Text.Apply.Source.Clipboard -- Text.Bisect.WaitingForCheckoutAnother -- Text.Bisect.WaitingForFirstBad -- Text.Blame.BlameOnPreviousRevision -- Text.Blame.Tips -- Text.BranchCM.CompareWithSpecial -- Text.BranchCM.InteractiveRebase.Manually -- Text.BranchTree.AheadBehind -- Text.BranchTree.Behind -- Text.BranchTree.PushURL -- Text.BranchTree.Tracking -- Text.BranchTree.URL -- Text.BranchTree.Worktree -- Text.ChangeCM.Merge -- Text.ChangeCM.MergeExternal -- Text.ChangeCM.ResetFileTo -- Text.ChangeSubmoduleUrl -- Text.ChangeSubmoduleUrl.Submodule -- Text.ChangeSubmoduleUrl.URL -- Text.Checkout.WarnLostCommits -- Text.Checkout.WarnUpdatingSubmodules -- Text.Checkout.WithFastForward -- Text.Checkout.WithFastForward.Upstream -- Text.CheckoutBranchFromStash -- Text.CheckoutBranchFromStash.Branch -- Text.CheckoutBranchFromStash.Stash -- Text.CheckoutDetached -- Text.CheckoutDetached.Target -- Text.CheckoutDetached.Warning -- Text.Clone.Bookmark -- Text.Clone.Group -- Text.Clone.RecurseSubmodules -- Text.CommandPalette.Branches -- Text.CommandPalette.BranchesAndTags -- Text.CommandPalette.RepositoryActions -- Text.CommandPalette.RevisionFiles -- Text.CommitCM.CopyAuthor -- Text.CommitCM.CopyAuthorTime -- Text.CommitCM.CopyCommitMessage -- Text.CommitCM.CopyCommitter -- Text.CommitCM.CopyCommitterTime -- 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.MergeMultiple -- Text.CommitCM.PushRevision -- Text.CommitCM.Rebase -- Text.CommitCM.Reset -- Text.CommitDetail.Changes.Count -- Text.CommitDetail.CollapseToBottom -- Text.CommitDetail.Files.Search -- Text.CommitDetail.Files.Tips -- Text.CommitDetail.Info.CopyEmail -- Text.CommitDetail.Info.CopyName -- Text.CommitDetail.Info.CopyNameAndEmail -- Text.CommitDetail.Info.Key -- Text.CommitDetail.Info.Signer -- Text.CommitMessageTextBox.Column -- Text.CommitMessageTextBox.Placeholder -- Text.CommitMessageTextBox.SubjectCount -- Text.Compare.Changes -- Text.Compare.Commits -- Text.Compare.Commits.LeftOnly -- Text.Compare.Commits.RightOnly -- Text.Compare.Commits.Tips -- Text.Configure.CommitMessageTemplate.BuiltinVars -- Text.Configure.CustomAction.Arguments.Tip -- Text.Configure.CustomAction.InputControls -- Text.Configure.CustomAction.InputControls.Edit -- 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.AskBeforeAutoUpdatingSubmodules -- Text.Configure.Git.ConventionalTypesOverride -- Text.Configure.Git.EnableRecursiveWhenAutoUpdatingSubmodules -- Text.Configure.Git.PreferredMergeMode -- Text.Configure.IssueTracker.AddSampleGerritChangeIdCommit -- Text.Configure.IssueTracker.AddSampleGiteeIssue -- Text.Configure.IssueTracker.AddSampleGiteePullRequest -- 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.StringFormatter -- Text.ConfigureCustomActionControls.StringFormatter.Tip -- Text.ConfigureCustomActionControls.StringValue.Tip -- Text.ConfigureCustomActionControls.Type -- Text.ConfigureCustomActionControls.UseFriendlyName -- Text.ConfirmEmptyCommit.Continue -- Text.ConfirmEmptyCommit.NoLocalChanges -- Text.ConfirmEmptyCommit.StageAllThenCommit -- Text.ConfirmEmptyCommit.StageSelectedThenCommit -- Text.ConfirmEmptyCommit.WithLocalChanges -- Text.ConfirmRestart.Title -- Text.ConfirmRestart.Message -- Text.CopyAsPatch -- Text.CopyFullPath -- Text.CreateBranch.OverwriteExisting -- Text.Dashboard -- Text.DeinitSubmodule -- Text.DeinitSubmodule.Force -- Text.DeinitSubmodule.Path -- Text.DeleteBranch.Force -- Text.DeleteMultiTags -- Text.DeleteMultiTags.DeleteFromRemotes -- Text.DeleteMultiTags.Tip -- Text.DeleteRepositoryNode.Path -- Text.DeleteRepositoryNode.TipForGroup -- Text.DeleteRepositoryNode.TipForRepository -- Text.Diff.Binary.ViewContentOfNew -- Text.Diff.EmptyFile -- 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.Submodule.UncommittedChanges -- Text.DirHistories -- Text.DirtyState.HasLocalChanges -- Text.DirtyState.HasPendingPullOrPush -- Text.DirtyState.UpToDate -- Text.Discard.IncludeModified -- Text.Discard.IncludeUntracked -- Text.EditBranchDescription -- Text.EditBranchDescription.Target -- Text.ExecuteCustomAction.Target -- Text.ExecuteCustomAction.Repository -- Text.Fetch.Force -- Text.File.Binary -- Text.File.HexViewer -- Text.File.HexViewer.GotoAddress -- Text.FileCM.CustomAction -- Text.FileCM.ResolveUsing -- Text.FileModeChange -- Text.FileModeChange.Deleted -- Text.FileModeChange.Directory -- Text.FileModeChange.Executable -- Text.FileModeChange.New -- Text.FileModeChange.Normal -- Text.FileModeChange.Submodule -- Text.FileModeChange.Symlink -- Text.FileModeChange.Unknown -- Text.GitFlow.Finish -- Text.GitFlow.FinishWithRebase -- Text.GitFlow.FinishWithSquash -- Text.GitFlow.StartAt -- Text.GitFlow.StartName -- Text.GitLFS.Locks.UnlockAllMyLocks -- Text.GitLFS.Locks.UnlockAllMyLocks.Confirm -- Text.GotoRevisionSelector -- Text.Histories.AdvancedOptions -- Text.Histories.HighlightsInGraph -- Text.Histories.HighlightsInGraph.All -- Text.Histories.HighlightsInGraph.CurrentBranchOnly -- Text.Histories.HighlightsInGraph.CurrentBranchAndSelectedCommits -- Text.Histories.HighlightsInGraph.SelectedCommitsOnly -- Text.Histories.HighlightsInGraph.SelectedCommitsOnlyFirstParent -- Text.Histories.ShowColumns -- Text.HistoriesDetailsStandalone -- Text.HistoriesDetailsStandalone.CommitDetail -- Text.HistoriesDetailsStandalone.RevisionCompare -- Text.Hotkeys.Global.Clone -- Text.Hotkeys.Global.OpenLocalRepository -- Text.Hotkeys.Global.ShowWorkspaceDropdownMenu -- Text.Hotkeys.Global.SwitchTab -- Text.Hotkeys.Global.Zoom -- Text.Hotkeys.Repo.CreateBranch -- Text.Hotkeys.Repo.GoToChild -- Text.Hotkeys.Repo.GoToParent -- Text.Hotkeys.Repo.OpenCommandPalette -- Text.Hotkeys.Repo.ToggleCommitDetailPanel -- Text.Hotkeys.Repo.ToggleSearchCommits -- Text.Hotkeys.Repo.ViewDashboard -- Text.Init.CommandTip -- Text.Init.ErrorMessageTip -- Text.InProgress.CherryPick.Head -- Text.InProgress.Merge.Operating -- Text.InProgress.Rebase.StoppedAt -- Text.InProgress.Revert.Head -- Text.InteractiveRebase.NoVerify -- Text.InteractiveRebase.ReorderTip -- Text.Launcher.Commands -- Text.Launcher.NewVersion -- Text.Launcher.OpenRepository -- Text.Launcher.Pages -- Text.Launcher.Workspaces -- Text.Merge.Edit -- Text.Merge.Source -- Text.Merge.Test -- Text.Merge.Test.NoConflicts -- Text.Merge.Test.UnknownError -- Text.Merge.Test.WillCauseConflicts -- Text.MergeConflictEditor.AcceptBoth.MineFirst -- Text.MergeConflictEditor.AcceptBoth.TheirsFirst -- Text.MergeConflictEditor.UseBoth -- Text.MergeConflictEditor.AllResolved -- Text.MergeConflictEditor.ConflictsRemaining -- Text.MergeConflictEditor.Mine -- Text.MergeConflictEditor.NextConflict -- Text.MergeConflictEditor.PrevConflict -- Text.MergeConflictEditor.Result -- Text.MergeConflictEditor.SaveAndStage -- Text.MergeConflictEditor.Theirs -- Text.MergeConflictEditor.Title -- Text.MergeConflictEditor.UnsavedChanges -- Text.MergeConflictEditor.UseMine -- Text.MergeConflictEditor.UseTheirs -- Text.MergeConflictEditor.Undo -- Text.MergeMultiple -- Text.MergeMultiple.CommitChanges -- Text.MergeMultiple.Strategy -- Text.MergeMultiple.Targets -- Text.MoveSubmodule -- Text.MoveSubmodule.MoveTo -- Text.MoveSubmodule.Submodule -- Text.No -- Text.Open -- Text.Open.SystemDefaultEditor -- Text.OpenAppDataDir.Cache -- Text.OpenAppDataDir.Config -- Text.OpenFile -- Text.OpenLocalRepository -- Text.OpenLocalRepository.Bookmark -- Text.OpenLocalRepository.Group -- Text.OpenLocalRepository.Path -- Text.PageTabBar.Tab.MoveToWorkspace -- Text.PageTabBar.Tab.Refresh -- Text.Preferences.AI.AdditionalPrompt -- Text.Preferences.AI.ExtraHeaders -- Text.Preferences.AI.Model -- Text.Preferences.AI.Model.AutoFetchAvailableModels -- Text.Preferences.AI.ReadApiKeyFromEnv -- Text.Preferences.AI.ReasoningEffortLevel -- 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.ShowRelativeTimeInGraph -- Text.Preferences.General.ShowTagsInGraph -- Text.Preferences.General.Use24Hours -- Text.Preferences.General.UseCompactBranchNames -- Text.Preferences.General.UseGitHubStyleAvatar -- Text.Preferences.Git.IgnoreCRAtEOLInDiff -- Text.Preferences.Git.SSLVerify -- Text.Preferences.Git.UseLibsecret -- Text.Preferences.Git.UseStashAndReapplyByDefault -- 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.Rebase.NoVerify -- Text.Rebase.Test -- Text.Rebase.Test.OK -- Text.Rebase.Test.UnknownError -- Text.Rebase.Test.WillCauseConflicts -- Text.Remote.ResetPushURL -- Text.RemoteCM.CustomAction -- Text.RemoteCM.EnableAutoFetch -- Text.RemoteCM.SetPushURL -- Text.Repository.BranchSort -- Text.Repository.BranchSort.ByCommitterDate -- Text.Repository.BranchSort.ByName -- Text.Repository.ClearStashes -- Text.Repository.FilterCommits -- Text.Repository.FilterCommits.Collapse -- Text.Repository.FilterCommits.Expand -- Text.Repository.FilterCommits.Summary -- Text.Repository.HistoriesLayout -- Text.Repository.HistoriesLayout.Horizontal -- Text.Repository.HistoriesLayout.Vertical -- Text.Repository.HistoriesOrder -- Text.Repository.Notifications.Clear -- Text.Repository.OpenAsFolder -- Text.Repository.Resolve -- Text.Repository.Search.ByContent -- Text.Repository.Search.ByPath -- Text.Repository.Search.Method -- Text.Repository.Search.ToolTip -- Text.Repository.ShowDecoratedCommitsOnly -- Text.Repository.ShowFirstParentOnly -- Text.Repository.ShowFlags -- Text.Repository.ShowLostCommits -- Text.Repository.ShowSubmodulesAsTree -- Text.Repository.Skip -- Text.Repository.Tags.OrderByCreatorDate -- Text.Repository.Tags.OrderByName -- Text.Repository.Tags.Sort -- Text.Repository.ViewLogs -- Text.Repository.Visit -- Text.ResetWithoutCheckout -- Text.ResetWithoutCheckout.MoveTo -- Text.ResetWithoutCheckout.Target -- Text.ScanRepositories.UseCustomDir -- Text.SelfUpdate.CurrentVersion -- Text.SelfUpdate.ReleaseDate -- Text.SetPushUrl -- Text.SetPushUrl.PushURL -- Text.SetPushUrl.Remote -- Text.SetPushUrl.URL -- Text.SetSubmoduleBranch -- Text.SetSubmoduleBranch.Submodule -- Text.SetSubmoduleBranch.Current -- Text.SetSubmoduleBranch.New -- Text.SetSubmoduleBranch.New.Tip -- Text.SetUpstream -- Text.SetUpstream.Local -- Text.SetUpstream.Unset -- Text.SetUpstream.Upstream -- Text.SHALinkCM.NavigateTo -- Text.SSHKeyHelper -- Text.SSHKeyHelper.ConfirmDeletion -- Text.SSHKeyHelper.Fingerprint -- Text.SSHKeyHelper.Generator -- Text.SSHKeyHelper.Generator.ConfirmPassphrase -- Text.SSHKeyHelper.Generator.Email -- Text.SSHKeyHelper.Generator.Email.Placeholder -- Text.SSHKeyHelper.Generator.Name -- Text.SSHKeyHelper.Generator.Name.Placeholder -- Text.SSHKeyHelper.Generator.Passphrase -- Text.SSHKeyHelper.Generator.Start -- Text.SSHKeyHelper.Generator.Type -- Text.SSHKeyHelper.Generator.UsePassphrase -- Text.SSHKeyHelper.Path -- Text.SSHKeyHelper.PublicKey -- Text.SSHKeyHelper.Title -- Text.Stash.Mode -- Text.StashCM.ApplyFileChanges -- Text.StashCM.Branch -- Text.StashCM.CopyMessage -- Text.StashCM.SaveAsPatch -- Text.Statistics.Tips -- Text.Submodule.Branch -- Text.Submodule.CopyBranch -- Text.Submodule.Deinit -- Text.Submodule.Histories -- Text.Submodule.Move -- 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.SubmoduleRevisionCompare -- Text.SubmoduleRevisionCompare.OpenDetails -- Text.Tag.Tagger -- Text.Tag.Time -- Text.TagCM.Checkout -- Text.TagCM.CompareTwo -- Text.TagCM.CompareWith -- Text.TagCM.CompareWithHead -- Text.TagCM.Copy.Message -- Text.TagCM.Copy.Name -- Text.TagCM.Copy.Tagger -- Text.TagCM.CopyName -- Text.TagCM.CustomAction -- Text.TagCM.DeleteMultiple -- Text.TagCM.Merge -- Text.Terminate -- Text.UpdateSubmodules.Recursive -- Text.UpdateSubmodules.UpdateToRemoteTrackingBranch -- Text.ViewLogs -- Text.ViewLogs.Clear -- Text.ViewLogs.CopyLog -- Text.ViewLogs.Delete -- Text.WorkingCopy.AddToGitIgnore.InFolder -- Text.WorkingCopy.AddToGitIgnore.UntrackedInSameFolder -- Text.WorkingCopy.ClearCommitHistories -- Text.WorkingCopy.ClearCommitHistories.Confirm -- Text.WorkingCopy.CollapseSidebar -- Text.WorkingCopy.CommitToEdit -- Text.WorkingCopy.ConfirmCommitWithDetachedHead -- Text.WorkingCopy.ConfirmCommitWithFilter -- Text.WorkingCopy.Conflicts.Merge -- Text.WorkingCopy.Conflicts.MergeExternal -- Text.WorkingCopy.Conflicts.OpenExternalMergeToolAllConflicts -- Text.WorkingCopy.Conflicts.UseMine -- Text.WorkingCopy.Conflicts.UseTheirs -- Text.WorkingCopy.DiscardAll -- Text.WorkingCopy.ExpandSidebar -- Text.WorkingCopy.FilterChanges -- Text.WorkingCopy.NoVerify -- Text.WorkingCopy.ResetAuthor -- Text.WorkingCopy.SignOff -- Text.Worktree.Branch -- Text.Worktree.Head -- Text.Worktree.Open -- Text.Worktree.Path -- Text.Yes - -
- -### ![ru__RU](https://img.shields.io/badge/ru__RU-98.02%25-yellow) - -
-Missing keys in ru_RU.axaml - -- Text.Blame.Tips -- Text.BranchTree.PushURL -- Text.CommitDetail.Files.Tips -- Text.Dashboard -- Text.Histories.AdvancedOptions -- Text.Hotkeys.Repo.ToggleCommitDetailPanel -- Text.Hotkeys.Repo.ToggleSearchCommits -- Text.Hotkeys.Repo.ViewDashboard -- Text.Preferences.AI.ExtraHeaders -- Text.Remote.ResetPushURL -- Text.RemoteCM.SetPushURL -- Text.Repository.Search.Method -- Text.Repository.Search.ToolTip -- Text.SetPushUrl -- Text.SetPushUrl.PushURL -- Text.SetPushUrl.Remote -- Text.SetPushUrl.URL -- Text.Statistics.Tips -- Text.WorkingCopy.CollapseSidebar -- Text.WorkingCopy.DiscardAll -- Text.WorkingCopy.ExpandSidebar - -
- -### ![ta__IN](https://img.shields.io/badge/ta__IN-61.79%25-red) - -
-Missing keys in ta_IN.axaml - -- Text.About.ReleaseDate -- Text.About.ReleaseNotes -- Text.AddToIgnore -- Text.AddToIgnore.Pattern -- Text.AddToIgnore.Storage -- Text.AIAssistant.Use -- Text.App.Hide -- Text.App.HideOthers -- Text.App.ShowAll -- Text.Apply.3Way -- Text.Apply.Source -- Text.Apply.Source.File -- Text.Apply.Source.Clipboard -- Text.Askpass.Passphrase -- Text.Avatar.Load -- Text.Bisect -- Text.Bisect.Abort -- Text.Bisect.Bad -- Text.Bisect.Good -- Text.Bisect.Skip -- Text.Bisect.WaitingForCheckoutAnother -- Text.Bisect.WaitingForFirstBad -- Text.Bisect.WaitingForFirstGood -- Text.Bisect.WaitingForMark -- Text.Blame.BlameOnPreviousRevision -- Text.Blame.IgnoreWhitespace -- Text.Blame.Tips -- Text.BranchCM.CompareTwo -- Text.BranchCM.CompareWith -- Text.BranchCM.CompareWithHead -- Text.BranchCM.CompareWithSpecial -- Text.BranchCM.CreatePR -- Text.BranchCM.CreatePRForUpstream -- Text.BranchCM.EditDescription -- Text.BranchCM.InteractiveRebase.Manually -- Text.BranchCM.ResetToSelectedCommit -- Text.BranchCM.SwitchToWorktree -- Text.BranchTree.Ahead -- Text.BranchTree.AheadBehind -- Text.BranchTree.Behind -- Text.BranchTree.InvalidUpstream -- Text.BranchTree.PushURL -- Text.BranchTree.Remote -- Text.BranchTree.Status -- Text.BranchTree.Tracking -- Text.BranchTree.URL -- Text.BranchTree.Worktree -- Text.ChangeCM.Merge -- Text.ChangeCM.MergeExternal -- Text.ChangeCM.ResetFileTo -- Text.ChangeSubmoduleUrl -- Text.ChangeSubmoduleUrl.Submodule -- Text.ChangeSubmoduleUrl.URL -- Text.Checkout.WarnLostCommits -- Text.Checkout.WarnUpdatingSubmodules -- Text.Checkout.WithFastForward -- Text.Checkout.WithFastForward.Upstream -- Text.CheckoutBranchFromStash -- Text.CheckoutBranchFromStash.Branch -- Text.CheckoutBranchFromStash.Stash -- Text.CheckoutDetached -- Text.CheckoutDetached.Target -- Text.CheckoutDetached.Warning -- Text.Clone.Bookmark -- Text.Clone.Group -- Text.CommandPalette.Branches -- Text.CommandPalette.BranchesAndTags -- Text.CommandPalette.RepositoryActions -- Text.CommandPalette.RevisionFiles -- Text.CommitCM.CopyAuthor -- Text.CommitCM.CopyAuthorTime -- Text.CommitCM.CopyCommitMessage -- Text.CommitCM.CopyCommitter -- Text.CommitCM.CopyCommitterTime -- 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.CollapseToBottom -- Text.CommitDetail.Files.Tips -- Text.CommitDetail.Info.CopyEmail -- Text.CommitDetail.Info.CopyName -- Text.CommitDetail.Info.CopyNameAndEmail -- Text.CommitDetail.Info.Key -- Text.CommitDetail.Info.Signer -- Text.CommitMessageTextBox.Column -- Text.CommitMessageTextBox.Placeholder -- Text.CommitMessageTextBox.SubjectCount -- Text.Compare.Changes -- Text.Compare.Commits -- Text.Compare.Commits.LeftOnly -- Text.Compare.Commits.RightOnly -- Text.Compare.Commits.Tips -- Text.Configure.CommitMessageTemplate.BuiltinVars -- Text.Configure.CustomAction.Arguments.Tip -- Text.Configure.CustomAction.InputControls -- Text.Configure.CustomAction.InputControls.Edit -- Text.Configure.CustomAction.Scope.File -- Text.Configure.CustomAction.Scope.Remote -- Text.Configure.CustomAction.Scope.Tag -- Text.Configure.Git.AskBeforeAutoUpdatingSubmodules -- Text.Configure.Git.ConventionalTypesOverride -- Text.Configure.Git.EnableRecursiveWhenAutoUpdatingSubmodules -- Text.Configure.Git.PreferredMergeMode -- Text.Configure.IssueTracker.AddSampleGerritChangeIdCommit -- 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.StringFormatter -- Text.ConfigureCustomActionControls.StringFormatter.Tip -- Text.ConfigureCustomActionControls.StringValue.Tip -- Text.ConfigureCustomActionControls.Type -- Text.ConfigureCustomActionControls.UseFriendlyName -- Text.ConfirmEmptyCommit.Continue -- Text.ConfirmEmptyCommit.NoLocalChanges -- Text.ConfirmEmptyCommit.StageAllThenCommit -- Text.ConfirmEmptyCommit.StageSelectedThenCommit -- Text.ConfirmEmptyCommit.WithLocalChanges -- Text.ConfirmRestart.Title -- Text.ConfirmRestart.Message -- Text.CopyAsPatch -- Text.CreateBranch.OverwriteExisting -- Text.Dashboard -- Text.DealWithLocalChanges.DoNothing -- Text.DeinitSubmodule -- Text.DeinitSubmodule.Force -- Text.DeinitSubmodule.Path -- Text.DeleteBranch.Force -- Text.DeleteMultiTags -- Text.DeleteMultiTags.DeleteFromRemotes -- Text.DeleteMultiTags.Tip -- Text.Diff.Binary.ViewContentOfNew -- Text.Diff.EmptyFile -- 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.Diff.Submodule.UncommittedChanges -- Text.DirHistories -- Text.DirtyState.HasLocalChanges -- Text.DirtyState.HasPendingPullOrPush -- Text.DirtyState.UpToDate -- Text.Discard.IncludeModified -- Text.Discard.IncludeUntracked -- Text.EditBranchDescription -- Text.EditBranchDescription.Target -- Text.ExecuteCustomAction.Target -- Text.ExecuteCustomAction.Repository -- Text.File.Binary -- Text.File.HexViewer -- Text.File.HexViewer.GotoAddress -- Text.FileCM.CustomAction -- Text.FileModeChange -- Text.FileModeChange.Deleted -- Text.FileModeChange.Directory -- Text.FileModeChange.Executable -- Text.FileModeChange.New -- Text.FileModeChange.Normal -- Text.FileModeChange.Submodule -- Text.FileModeChange.Symlink -- Text.FileModeChange.Unknown -- Text.GitFlow.Finish -- Text.GitFlow.FinishWithRebase -- Text.GitFlow.FinishWithSquash -- Text.GitFlow.StartAt -- Text.GitFlow.StartName -- Text.GitLFS.Locks.UnlockAllMyLocks -- Text.GitLFS.Locks.UnlockAllMyLocks.Confirm -- Text.GotoRevisionSelector -- Text.Histories.AdvancedOptions -- Text.Histories.HighlightsInGraph -- Text.Histories.HighlightsInGraph.All -- Text.Histories.HighlightsInGraph.CurrentBranchOnly -- Text.Histories.HighlightsInGraph.CurrentBranchAndSelectedCommits -- Text.Histories.HighlightsInGraph.SelectedCommitsOnly -- Text.Histories.HighlightsInGraph.SelectedCommitsOnlyFirstParent -- Text.Histories.ShowColumns -- Text.HistoriesDetailsStandalone -- Text.HistoriesDetailsStandalone.CommitDetail -- Text.HistoriesDetailsStandalone.RevisionCompare -- Text.Hotkeys.Global.OpenLocalRepository -- Text.Hotkeys.Global.ShowWorkspaceDropdownMenu -- Text.Hotkeys.Global.SwitchTab -- Text.Hotkeys.Global.Zoom -- Text.Hotkeys.Repo.CreateBranch -- Text.Hotkeys.Repo.GoToChild -- Text.Hotkeys.Repo.GoToParent -- Text.Hotkeys.Repo.OpenCommandPalette -- Text.Hotkeys.Repo.ToggleCommitDetailPanel -- Text.Hotkeys.Repo.ToggleSearchCommits -- Text.Hotkeys.Repo.ViewDashboard -- Text.Init.CommandTip -- Text.Init.ErrorMessageTip -- Text.InteractiveRebase.NoVerify -- Text.InteractiveRebase.ReorderTip -- Text.Launcher.Commands -- Text.Launcher.NewVersion -- Text.Launcher.OpenRepository -- Text.Launcher.Pages -- Text.Launcher.Workspaces -- Text.Merge.Edit -- Text.Merge.Test -- Text.Merge.Test.NoConflicts -- Text.Merge.Test.UnknownError -- Text.Merge.Test.WillCauseConflicts -- Text.MergeConflictEditor.AcceptBoth.MineFirst -- Text.MergeConflictEditor.AcceptBoth.TheirsFirst -- Text.MergeConflictEditor.UseBoth -- Text.MergeConflictEditor.AllResolved -- Text.MergeConflictEditor.ConflictsRemaining -- Text.MergeConflictEditor.Mine -- Text.MergeConflictEditor.NextConflict -- Text.MergeConflictEditor.PrevConflict -- Text.MergeConflictEditor.Result -- Text.MergeConflictEditor.SaveAndStage -- Text.MergeConflictEditor.Theirs -- Text.MergeConflictEditor.Title -- Text.MergeConflictEditor.UnsavedChanges -- Text.MergeConflictEditor.UseMine -- Text.MergeConflictEditor.UseTheirs -- Text.MergeConflictEditor.Undo -- Text.MoveSubmodule -- Text.MoveSubmodule.MoveTo -- Text.MoveSubmodule.Submodule -- Text.No -- Text.Open -- Text.Open.SystemDefaultEditor -- Text.OpenAppDataDir.Cache -- Text.OpenAppDataDir.Config -- Text.OpenFile -- Text.OpenLocalRepository -- Text.OpenLocalRepository.Bookmark -- Text.OpenLocalRepository.Group -- Text.OpenLocalRepository.Path -- Text.PageTabBar.Tab.MoveToWorkspace -- Text.PageTabBar.Tab.Refresh -- Text.Preferences.AI.AdditionalPrompt -- Text.Preferences.AI.ExtraHeaders -- Text.Preferences.AI.Model -- Text.Preferences.AI.Model.AutoFetchAvailableModels -- Text.Preferences.AI.ReadApiKeyFromEnv -- Text.Preferences.AI.ReasoningEffortLevel -- 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.ShowRelativeTimeInGraph -- Text.Preferences.General.Use24Hours -- Text.Preferences.General.UseCompactBranchNames -- Text.Preferences.General.UseGitHubStyleAvatar -- Text.Preferences.Git.IgnoreCRAtEOLInDiff -- Text.Preferences.Git.UseLibsecret -- Text.Preferences.Git.UseStashAndReapplyByDefault -- 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.Rebase.NoVerify -- Text.Rebase.Test -- Text.Rebase.Test.OK -- Text.Rebase.Test.UnknownError -- Text.Rebase.Test.WillCauseConflicts -- Text.Remote.ResetPushURL -- Text.RemoteCM.CustomAction -- Text.RemoteCM.EnableAutoFetch -- Text.RemoteCM.SetPushURL -- Text.Repository.BranchSort -- Text.Repository.BranchSort.ByCommitterDate -- Text.Repository.BranchSort.ByName -- Text.Repository.ClearStashes -- Text.Repository.FilterCommits.Collapse -- Text.Repository.FilterCommits.Expand -- Text.Repository.FilterCommits.Summary -- Text.Repository.OpenAsFolder -- Text.Repository.Resolve -- Text.Repository.Search.ByContent -- Text.Repository.Search.ByPath -- Text.Repository.Search.Method -- Text.Repository.Search.ToolTip -- Text.Repository.ShowDecoratedCommitsOnly -- Text.Repository.ShowFirstParentOnly -- Text.Repository.ShowFlags -- Text.Repository.ShowLostCommits -- Text.Repository.ShowSubmodulesAsTree -- Text.Repository.ViewLogs -- Text.Repository.Visit -- Text.ResetWithoutCheckout -- Text.ResetWithoutCheckout.MoveTo -- Text.ResetWithoutCheckout.Target -- Text.ScanRepositories.UseCustomDir -- Text.SelfUpdate.CurrentVersion -- Text.SelfUpdate.ReleaseDate -- Text.SetPushUrl -- Text.SetPushUrl.PushURL -- Text.SetPushUrl.Remote -- Text.SetPushUrl.URL -- Text.SetSubmoduleBranch -- Text.SetSubmoduleBranch.Submodule -- Text.SetSubmoduleBranch.Current -- Text.SetSubmoduleBranch.New -- Text.SetSubmoduleBranch.New.Tip -- Text.SSHKeyHelper -- Text.SSHKeyHelper.ConfirmDeletion -- Text.SSHKeyHelper.Fingerprint -- Text.SSHKeyHelper.Generator -- Text.SSHKeyHelper.Generator.ConfirmPassphrase -- Text.SSHKeyHelper.Generator.Email -- Text.SSHKeyHelper.Generator.Email.Placeholder -- Text.SSHKeyHelper.Generator.Name -- Text.SSHKeyHelper.Generator.Name.Placeholder -- Text.SSHKeyHelper.Generator.Passphrase -- Text.SSHKeyHelper.Generator.Start -- Text.SSHKeyHelper.Generator.Type -- Text.SSHKeyHelper.Generator.UsePassphrase -- Text.SSHKeyHelper.Path -- Text.SSHKeyHelper.PublicKey -- Text.SSHKeyHelper.Title -- Text.Stash.Mode -- Text.StashCM.ApplyFileChanges -- Text.StashCM.Branch -- Text.StashCM.CopyMessage -- Text.Statistics.Tips -- Text.Submodule.Branch -- Text.Submodule.CopyBranch -- Text.Submodule.Deinit -- Text.Submodule.Histories -- Text.Submodule.Move -- 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.SubmoduleRevisionCompare -- Text.SubmoduleRevisionCompare.OpenDetails -- Text.Tag.Tagger -- Text.Tag.Time -- Text.TagCM.Checkout -- Text.TagCM.CompareTwo -- Text.TagCM.CompareWith -- Text.TagCM.CompareWithHead -- Text.TagCM.Copy.Message -- Text.TagCM.Copy.Name -- Text.TagCM.Copy.Tagger -- Text.TagCM.CopyName -- Text.TagCM.CustomAction -- Text.TagCM.DeleteMultiple -- Text.TagCM.Merge -- Text.Terminate -- Text.UpdateSubmodules.Target -- Text.UpdateSubmodules.Recursive -- Text.UpdateSubmodules.UpdateToRemoteTrackingBranch -- Text.ViewLogs -- Text.ViewLogs.Clear -- Text.ViewLogs.CopyLog -- Text.ViewLogs.Delete -- Text.WorkingCopy.AddToGitIgnore.InFolder -- Text.WorkingCopy.AddToGitIgnore.UntrackedInSameFolder -- Text.WorkingCopy.ClearCommitHistories -- Text.WorkingCopy.ClearCommitHistories.Confirm -- Text.WorkingCopy.CollapseSidebar -- Text.WorkingCopy.ConfirmCommitWithDetachedHead -- Text.WorkingCopy.Conflicts.Merge -- Text.WorkingCopy.Conflicts.MergeExternal -- Text.WorkingCopy.Conflicts.OpenExternalMergeToolAllConflicts -- Text.WorkingCopy.Conflicts.UseMine -- Text.WorkingCopy.Conflicts.UseTheirs -- Text.WorkingCopy.DiscardAll -- Text.WorkingCopy.ExpandSidebar -- Text.WorkingCopy.FilterChanges -- Text.WorkingCopy.NoVerify -- Text.WorkingCopy.ResetAuthor -- Text.Worktree.Branch -- Text.Worktree.Head -- Text.Worktree.Open -- Text.Worktree.Path -- Text.Yes - -
- -### ![uk__UA](https://img.shields.io/badge/uk__UA-62.55%25-red) - -
-Missing keys in uk_UA.axaml - -- Text.About.ReleaseDate -- Text.About.ReleaseNotes -- Text.AddToIgnore -- Text.AddToIgnore.Pattern -- Text.AddToIgnore.Storage -- Text.AIAssistant.Use -- Text.App.Hide -- Text.App.HideOthers -- Text.App.ShowAll -- Text.Apply.3Way -- Text.Apply.Source -- Text.Apply.Source.File -- Text.Apply.Source.Clipboard -- Text.Askpass.Passphrase -- Text.Avatar.Load -- Text.Bisect -- Text.Bisect.Abort -- Text.Bisect.Bad -- Text.Bisect.Good -- Text.Bisect.Skip -- Text.Bisect.WaitingForCheckoutAnother -- Text.Bisect.WaitingForFirstBad -- Text.Bisect.WaitingForFirstGood -- Text.Bisect.WaitingForMark -- Text.Blame.BlameOnPreviousRevision -- Text.Blame.IgnoreWhitespace -- Text.Blame.Tips -- Text.BranchCM.CompareTwo -- Text.BranchCM.CompareWith -- Text.BranchCM.CompareWithHead -- Text.BranchCM.CompareWithSpecial -- Text.BranchCM.CreatePR -- Text.BranchCM.CreatePRForUpstream -- Text.BranchCM.EditDescription -- Text.BranchCM.InteractiveRebase.Manually -- Text.BranchCM.ResetToSelectedCommit -- Text.BranchCM.SwitchToWorktree -- Text.BranchTree.Ahead -- Text.BranchTree.AheadBehind -- Text.BranchTree.Behind -- Text.BranchTree.InvalidUpstream -- Text.BranchTree.PushURL -- Text.BranchTree.Remote -- Text.BranchTree.Status -- Text.BranchTree.Tracking -- Text.BranchTree.URL -- Text.BranchTree.Worktree -- Text.ChangeCM.Merge -- Text.ChangeCM.MergeExternal -- Text.ChangeCM.ResetFileTo -- Text.ChangeSubmoduleUrl -- Text.ChangeSubmoduleUrl.Submodule -- Text.ChangeSubmoduleUrl.URL -- Text.Checkout.WarnLostCommits -- Text.Checkout.WarnUpdatingSubmodules -- Text.Checkout.WithFastForward -- Text.Checkout.WithFastForward.Upstream -- Text.CheckoutBranchFromStash -- Text.CheckoutBranchFromStash.Branch -- Text.CheckoutBranchFromStash.Stash -- Text.CheckoutDetached -- Text.CheckoutDetached.Target -- Text.CheckoutDetached.Warning -- Text.Clone.Bookmark -- Text.Clone.Group -- Text.CommandPalette.Branches -- Text.CommandPalette.BranchesAndTags -- Text.CommandPalette.RepositoryActions -- Text.CommandPalette.RevisionFiles -- Text.CommitCM.CopyAuthor -- Text.CommitCM.CopyAuthorTime -- Text.CommitCM.CopyCommitMessage -- Text.CommitCM.CopyCommitter -- Text.CommitCM.CopyCommitterTime -- 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.CollapseToBottom -- Text.CommitDetail.Files.Tips -- Text.CommitDetail.Info.CopyEmail -- Text.CommitDetail.Info.CopyName -- Text.CommitDetail.Info.CopyNameAndEmail -- Text.CommitDetail.Info.Key -- Text.CommitDetail.Info.Signer -- Text.CommitMessageTextBox.Column -- Text.CommitMessageTextBox.Placeholder -- Text.CommitMessageTextBox.SubjectCount -- Text.Compare.Changes -- Text.Compare.Commits -- Text.Compare.Commits.LeftOnly -- Text.Compare.Commits.RightOnly -- Text.Compare.Commits.Tips -- Text.Configure.CommitMessageTemplate.BuiltinVars -- Text.Configure.CustomAction.Arguments.Tip -- Text.Configure.CustomAction.InputControls -- Text.Configure.CustomAction.InputControls.Edit -- Text.Configure.CustomAction.Scope.File -- Text.Configure.CustomAction.Scope.Remote -- Text.Configure.CustomAction.Scope.Tag -- Text.Configure.Git.AskBeforeAutoUpdatingSubmodules -- Text.Configure.Git.ConventionalTypesOverride -- Text.Configure.Git.EnableRecursiveWhenAutoUpdatingSubmodules -- Text.Configure.IssueTracker.AddSampleGerritChangeIdCommit -- 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.StringFormatter -- Text.ConfigureCustomActionControls.StringFormatter.Tip -- Text.ConfigureCustomActionControls.StringValue.Tip -- Text.ConfigureCustomActionControls.Type -- Text.ConfigureCustomActionControls.UseFriendlyName -- Text.ConfigureWorkspace.Name -- Text.ConfirmEmptyCommit.StageSelectedThenCommit -- Text.ConfirmRestart.Title -- Text.ConfirmRestart.Message -- Text.CopyAsPatch -- Text.CreateBranch.OverwriteExisting -- Text.Dashboard -- Text.DealWithLocalChanges.DoNothing -- Text.DeinitSubmodule -- Text.DeinitSubmodule.Force -- Text.DeinitSubmodule.Path -- Text.DeleteBranch.Force -- Text.DeleteMultiTags -- Text.DeleteMultiTags.DeleteFromRemotes -- Text.DeleteMultiTags.Tip -- Text.Diff.Binary.ViewContentOfNew -- Text.Diff.EmptyFile -- 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.Diff.Submodule.UncommittedChanges -- Text.DirHistories -- Text.DirtyState.HasLocalChanges -- Text.DirtyState.HasPendingPullOrPush -- Text.DirtyState.UpToDate -- Text.Discard.IncludeModified -- Text.Discard.IncludeUntracked -- Text.EditBranchDescription -- Text.EditBranchDescription.Target -- Text.ExecuteCustomAction.Target -- Text.ExecuteCustomAction.Repository -- Text.File.Binary -- Text.File.HexViewer -- Text.File.HexViewer.GotoAddress -- Text.FileCM.CustomAction -- Text.FileModeChange -- Text.FileModeChange.Deleted -- Text.FileModeChange.Directory -- Text.FileModeChange.Executable -- Text.FileModeChange.New -- Text.FileModeChange.Normal -- Text.FileModeChange.Submodule -- Text.FileModeChange.Symlink -- Text.FileModeChange.Unknown -- Text.GitFlow.Finish -- Text.GitFlow.FinishWithRebase -- Text.GitFlow.FinishWithSquash -- Text.GitFlow.StartAt -- Text.GitFlow.StartName -- Text.GitLFS.Locks.UnlockAllMyLocks -- Text.GitLFS.Locks.UnlockAllMyLocks.Confirm -- Text.GotoRevisionSelector -- Text.Histories.AdvancedOptions -- Text.Histories.HighlightsInGraph -- Text.Histories.HighlightsInGraph.All -- Text.Histories.HighlightsInGraph.CurrentBranchOnly -- Text.Histories.HighlightsInGraph.CurrentBranchAndSelectedCommits -- Text.Histories.HighlightsInGraph.SelectedCommitsOnly -- Text.Histories.HighlightsInGraph.SelectedCommitsOnlyFirstParent -- Text.Histories.ShowColumns -- Text.HistoriesDetailsStandalone -- Text.HistoriesDetailsStandalone.CommitDetail -- Text.HistoriesDetailsStandalone.RevisionCompare -- Text.Hotkeys.Global.OpenLocalRepository -- Text.Hotkeys.Global.ShowWorkspaceDropdownMenu -- Text.Hotkeys.Global.SwitchTab -- Text.Hotkeys.Global.Zoom -- Text.Hotkeys.Repo.CreateBranch -- Text.Hotkeys.Repo.GoToChild -- Text.Hotkeys.Repo.GoToParent -- Text.Hotkeys.Repo.OpenCommandPalette -- Text.Hotkeys.Repo.ToggleCommitDetailPanel -- Text.Hotkeys.Repo.ToggleSearchCommits -- Text.Hotkeys.Repo.ViewDashboard -- Text.Init.CommandTip -- Text.Init.ErrorMessageTip -- Text.InteractiveRebase.NoVerify -- Text.InteractiveRebase.ReorderTip -- Text.Launcher.Commands -- Text.Launcher.NewVersion -- Text.Launcher.OpenRepository -- Text.Launcher.Pages -- Text.Launcher.Workspaces -- Text.Merge.Edit -- Text.Merge.Test -- Text.Merge.Test.NoConflicts -- Text.Merge.Test.UnknownError -- Text.Merge.Test.WillCauseConflicts -- Text.MergeConflictEditor.AcceptBoth.MineFirst -- Text.MergeConflictEditor.AcceptBoth.TheirsFirst -- Text.MergeConflictEditor.UseBoth -- Text.MergeConflictEditor.AllResolved -- Text.MergeConflictEditor.ConflictsRemaining -- Text.MergeConflictEditor.Mine -- Text.MergeConflictEditor.NextConflict -- Text.MergeConflictEditor.PrevConflict -- Text.MergeConflictEditor.Result -- Text.MergeConflictEditor.SaveAndStage -- Text.MergeConflictEditor.Theirs -- Text.MergeConflictEditor.Title -- Text.MergeConflictEditor.UnsavedChanges -- Text.MergeConflictEditor.UseMine -- Text.MergeConflictEditor.UseTheirs -- Text.MergeConflictEditor.Undo -- Text.MoveSubmodule -- Text.MoveSubmodule.MoveTo -- Text.MoveSubmodule.Submodule -- Text.No -- Text.Open -- Text.Open.SystemDefaultEditor -- Text.OpenAppDataDir.Cache -- Text.OpenAppDataDir.Config -- Text.OpenFile -- Text.OpenLocalRepository -- Text.OpenLocalRepository.Bookmark -- Text.OpenLocalRepository.Group -- Text.OpenLocalRepository.Path -- Text.PageTabBar.Tab.MoveToWorkspace -- Text.PageTabBar.Tab.Refresh -- Text.Preferences.AI.AdditionalPrompt -- Text.Preferences.AI.ExtraHeaders -- Text.Preferences.AI.Model -- Text.Preferences.AI.Model.AutoFetchAvailableModels -- Text.Preferences.AI.ReadApiKeyFromEnv -- Text.Preferences.AI.ReasoningEffortLevel -- 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.ShowRelativeTimeInGraph -- Text.Preferences.General.Use24Hours -- Text.Preferences.General.UseCompactBranchNames -- Text.Preferences.General.UseGitHubStyleAvatar -- Text.Preferences.Git.IgnoreCRAtEOLInDiff -- Text.Preferences.Git.UseLibsecret -- Text.Preferences.Git.UseStashAndReapplyByDefault -- 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.Rebase.NoVerify -- Text.Rebase.Test -- Text.Rebase.Test.OK -- Text.Rebase.Test.UnknownError -- Text.Rebase.Test.WillCauseConflicts -- Text.Remote.ResetPushURL -- Text.RemoteCM.CustomAction -- Text.RemoteCM.EnableAutoFetch -- Text.RemoteCM.SetPushURL -- Text.Repository.BranchSort -- Text.Repository.BranchSort.ByCommitterDate -- Text.Repository.BranchSort.ByName -- Text.Repository.ClearStashes -- Text.Repository.FilterCommits.Collapse -- Text.Repository.FilterCommits.Expand -- Text.Repository.FilterCommits.Summary -- Text.Repository.OpenAsFolder -- Text.Repository.Resolve -- Text.Repository.Search.ByContent -- Text.Repository.Search.ByPath -- Text.Repository.Search.Method -- Text.Repository.Search.ToolTip -- Text.Repository.ShowDecoratedCommitsOnly -- Text.Repository.ShowFirstParentOnly -- Text.Repository.ShowFlags -- Text.Repository.ShowLostCommits -- Text.Repository.ShowSubmodulesAsTree -- Text.Repository.ViewLogs -- Text.Repository.Visit -- Text.ResetWithoutCheckout -- Text.ResetWithoutCheckout.MoveTo -- Text.ResetWithoutCheckout.Target -- Text.ScanRepositories.UseCustomDir -- Text.SelfUpdate.CurrentVersion -- Text.SelfUpdate.ReleaseDate -- Text.SetPushUrl -- Text.SetPushUrl.PushURL -- Text.SetPushUrl.Remote -- Text.SetPushUrl.URL -- Text.SetSubmoduleBranch -- Text.SetSubmoduleBranch.Submodule -- Text.SetSubmoduleBranch.Current -- Text.SetSubmoduleBranch.New -- Text.SetSubmoduleBranch.New.Tip -- Text.SSHKeyHelper -- Text.SSHKeyHelper.ConfirmDeletion -- Text.SSHKeyHelper.Fingerprint -- Text.SSHKeyHelper.Generator -- Text.SSHKeyHelper.Generator.ConfirmPassphrase -- Text.SSHKeyHelper.Generator.Email -- Text.SSHKeyHelper.Generator.Email.Placeholder -- Text.SSHKeyHelper.Generator.Name -- Text.SSHKeyHelper.Generator.Name.Placeholder -- Text.SSHKeyHelper.Generator.Passphrase -- Text.SSHKeyHelper.Generator.Start -- Text.SSHKeyHelper.Generator.Type -- Text.SSHKeyHelper.Generator.UsePassphrase -- Text.SSHKeyHelper.Path -- Text.SSHKeyHelper.PublicKey -- Text.SSHKeyHelper.Title -- Text.Stash.Mode -- Text.StashCM.ApplyFileChanges -- Text.StashCM.Branch -- Text.StashCM.CopyMessage -- Text.Statistics.Tips -- Text.Submodule.Branch -- Text.Submodule.CopyBranch -- Text.Submodule.Deinit -- Text.Submodule.Histories -- Text.Submodule.Move -- 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.SubmoduleRevisionCompare -- Text.SubmoduleRevisionCompare.OpenDetails -- Text.Tag.Tagger -- Text.Tag.Time -- Text.TagCM.Checkout -- Text.TagCM.CompareTwo -- Text.TagCM.CompareWith -- Text.TagCM.CompareWithHead -- Text.TagCM.Copy.Message -- Text.TagCM.Copy.Name -- Text.TagCM.Copy.Tagger -- Text.TagCM.CopyName -- Text.TagCM.CustomAction -- Text.TagCM.DeleteMultiple -- Text.TagCM.Merge -- Text.Terminate -- Text.UpdateSubmodules.Recursive -- Text.UpdateSubmodules.UpdateToRemoteTrackingBranch -- Text.ViewLogs -- Text.ViewLogs.Clear -- Text.ViewLogs.CopyLog -- Text.ViewLogs.Delete -- Text.WorkingCopy.AddToGitIgnore.InFolder -- Text.WorkingCopy.AddToGitIgnore.UntrackedInSameFolder -- Text.WorkingCopy.ClearCommitHistories -- Text.WorkingCopy.ClearCommitHistories.Confirm -- Text.WorkingCopy.CollapseSidebar -- Text.WorkingCopy.ConfirmCommitWithDetachedHead -- Text.WorkingCopy.Conflicts.Merge -- Text.WorkingCopy.Conflicts.MergeExternal -- Text.WorkingCopy.DiscardAll -- Text.WorkingCopy.ExpandSidebar -- Text.WorkingCopy.FilterChanges -- Text.WorkingCopy.NoVerify -- Text.WorkingCopy.ResetAuthor -- Text.Worktree.Branch -- Text.Worktree.Head -- Text.Worktree.Open -- Text.Worktree.Path -- Text.Yes - -
- -### ![zh__CN](https://img.shields.io/badge/zh__CN-%E2%88%9A-brightgreen) - -### ![zh__TW](https://img.shields.io/badge/zh__TW-99.72%25-yellow) - -
-Missing keys in zh_TW.axaml - -- Text.CommitDetail.Files.Tips -- Text.WorkingCopy.CollapseSidebar -- Text.WorkingCopy.ExpandSidebar - -
\ No newline at end of file diff --git a/VERSION b/VERSION index 88005f0e1c..dafcf91559 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2026.21 \ No newline at end of file +2026.21.13 \ No newline at end of file diff --git a/build/resources/app/App.plist b/build/resources/app/App.plist index d20efa5e29..4ece0ac25d 100644 --- a/build/resources/app/App.plist +++ b/build/resources/app/App.plist @@ -9,7 +9,7 @@ CFBundleName SourceGit CFBundleVersion - SOURCE_GIT_VERSION.0 + SOURCE_GIT_VERSION LSMinimumSystemVersion 11.0 CFBundleExecutable diff --git a/build/resources/homebrew/sourcegit-holion.rb b/build/resources/homebrew/sourcegit-holion.rb new file mode 100644 index 0000000000..d87d86c38c --- /dev/null +++ b/build/resources/homebrew/sourcegit-holion.rb @@ -0,0 +1,28 @@ +cask "sourcegit-holion" do + arch arm: "arm64", intel: "x64" + + version "SOURCE_GIT_VERSION" + sha256 arm: "SOURCE_GIT_SHA256_ARM64", + intel: "SOURCE_GIT_SHA256_X64" + + url "https://github.com/holion/sourcegit/releases/download/v#{version}/sourcegit_#{version}.osx-#{arch}.zip" + name "SourceGit (Holion)" + desc "Holion fork of the SourceGit Git GUI client" + homepage "https://github.com/holion/sourcegit" + + livecheck do + url :url + strategy :github_latest + end + + auto_updates true + conflicts_with cask: "sourcegit" + depends_on macos: ">= :ventura" + + app "SourceGit.app" + + # Builds made without the signing secrets are not notarized, so strip the quarantine flag for those. + postflight do + system_command "/usr/bin/xattr", args: ["-cr", "#{appdir}/SourceGit.app"] + end +end diff --git a/build/scripts/localization-check.js b/build/scripts/localization-check.js deleted file mode 100644 index 8d636b5bb2..0000000000 --- a/build/scripts/localization-check.js +++ /dev/null @@ -1,83 +0,0 @@ -const fs = require('fs-extra'); -const path = require('path'); -const xml2js = require('xml2js'); - -const repoRoot = path.join(__dirname, '../../'); -const localesDir = path.join(repoRoot, 'src/Resources/Locales'); -const enUSFile = path.join(localesDir, 'en_US.axaml'); -const outputFile = path.join(repoRoot, 'TRANSLATION.md'); - -const parser = new xml2js.Parser(); - -async function parseXml(filePath) { - const data = await fs.readFile(filePath); - return parser.parseStringPromise(data); -} - -async function filterAndSortTranslations(localeData, enUSKeys, enUSData) { - const strings = localeData.ResourceDictionary['x:String']; - // Remove keys that don't exist in English file - const filtered = strings.filter(item => enUSKeys.has(item.$['x:Key'])); - - // Sort based on the key order in English file - const enUSKeysArray = enUSData.ResourceDictionary['x:String'].map(item => item.$['x:Key']); - filtered.sort((a, b) => { - const aIndex = enUSKeysArray.indexOf(a.$['x:Key']); - const bIndex = enUSKeysArray.indexOf(b.$['x:Key']); - return aIndex - bIndex; - }); - - return filtered; -} - -async function calculateTranslationRate() { - const enUSData = await parseXml(enUSFile); - const enUSKeys = new Set(enUSData.ResourceDictionary['x:String'].map(item => item.$['x:Key'])); - const files = (await fs.readdir(localesDir)).filter(file => file !== 'en_US.axaml' && file.endsWith('.axaml')); - - const lines = []; - - lines.push('# Translation Status'); - lines.push('This document shows the translation status of each locale file in the repository.'); - lines.push(`## Details`); - lines.push(`### ![en_US](https://img.shields.io/badge/en__US-%E2%88%9A-brightgreen)`); - - for (const file of files) { - const locale = file.replace('.axaml', '').replace('_', '__'); - const filePath = path.join(localesDir, file); - const localeData = await parseXml(filePath); - const localeKeys = new Set(localeData.ResourceDictionary['x:String'].map(item => item.$['x:Key'])); - const missingKeys = [...enUSKeys].filter(key => !localeKeys.has(key)); - - // Sort and clean up extra translations - const sortedAndCleaned = await filterAndSortTranslations(localeData, enUSKeys, enUSData); - localeData.ResourceDictionary['x:String'] = sortedAndCleaned; - - // Save the updated file - const builder = new xml2js.Builder({ - headless: true, - renderOpts: { pretty: true, indent: ' ' } - }); - let xmlStr = builder.buildObject(localeData); - - // Add an empty line before the first x:String - xmlStr = xmlStr.replace(' 0) { - const progress = ((enUSKeys.size - missingKeys.length) / enUSKeys.size) * 100; - const badgeColor = progress >= 75 ? 'yellow' : 'red'; - - lines.push(`### ![${locale}](https://img.shields.io/badge/${locale}-${progress.toFixed(2)}%25-${badgeColor})`); - lines.push(`
\nMissing keys in ${file}\n\n${missingKeys.map(key => `- ${key}`).join('\n')}\n\n
`) - } else { - lines.push(`### ![${locale}](https://img.shields.io/badge/${locale}-%E2%88%9A-brightgreen)`); - } - } - - const content = lines.join('\n\n'); - console.log(content); - await fs.writeFile(outputFile, content, 'utf8'); -} - -calculateTranslationRate().catch(err => console.error(err)); diff --git a/build/scripts/package.osx-app.sh b/build/scripts/package.osx-app.sh index 62e9184f66..5da3ec533d 100755 --- a/build/scripts/package.osx-app.sh +++ b/build/scripts/package.osx-app.sh @@ -15,11 +15,68 @@ rm -rf SourceGit.app/Contents/MacOS/SourceGit.dsym rm -f SourceGit.app/Contents/MacOS/*.pdb case "$RUNTIME" in - osx-arm64) ARCH=arm64 ;; - osx-x64) ARCH=x86_64 ;; + osx-arm64) ARCH=arm64; DMG=SourceGit-mac-apple-silicon.dmg ;; + osx-x64) ARCH=x86_64; DMG=SourceGit-mac-intel.dmg ;; *) echo "Unsupported RUNTIME: $RUNTIME" >&2; exit 1 ;; esac clang -arch "$ARCH" ../tools/setsid-macos/setsid.c -o SourceGit.app/Contents/MacOS/setsid -mmacosx-version-min=13.0 -zip "sourcegit_$VERSION.$RUNTIME.zip" -r SourceGit.app +# Sign with the Developer ID certificate when it is available (release builds only). +SIGN=0 +if [ -n "${MACOS_CERTIFICATE:-}" ]; then + SIGN=1 + KEYCHAIN="$RUNNER_TEMP/signing.keychain-db" + KEYCHAIN_PASSWORD=$(uuidgen) + + security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN" + security set-keychain-settings -lut 21600 "$KEYCHAIN" + security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN" + echo "$MACOS_CERTIFICATE" | base64 --decode > "$RUNNER_TEMP/certificate.p12" + security import "$RUNNER_TEMP/certificate.p12" -P "$MACOS_CERTIFICATE_PASSWORD" -A -t cert -f pkcs12 -k "$KEYCHAIN" + security set-key-partition-list -S apple-tool:,apple: -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN" > /dev/null + security list-keychains -d user -s "$KEYCHAIN" login.keychain + IDENTITY=$(security find-identity -v -p codesigning "$KEYCHAIN" | grep "Developer ID Application" | head -n 1 | awk '{print $2}') + + # Nested binaries first, then the bundle itself. + find SourceGit.app/Contents/MacOS -type f ! -name SourceGit | while read -r f; do + if file -b "$f" | grep -q Mach-O; then + codesign --force --timestamp --options runtime --sign "$IDENTITY" "$f" + fi + done + codesign --force --timestamp --options runtime --sign "$IDENTITY" SourceGit.app + codesign --verify --deep --strict --verbose=2 SourceGit.app +fi + +mkdir dmg +cp -R SourceGit.app dmg/ +ln -s /Applications dmg/Applications +hdiutil create -volname SourceGit -srcfolder dmg -ov -format UDZO "$DMG" +rm -rf dmg + +if [ "$SIGN" = "1" ]; then + codesign --force --timestamp --sign "$IDENTITY" "$DMG" + + echo "$APPLE_API_KEY" | base64 --decode > "$RUNNER_TEMP/api_key.p8" + RESULT=$(xcrun notarytool submit "$DMG" \ + --key "$RUNNER_TEMP/api_key.p8" \ + --key-id "$APPLE_API_KEY_ID" \ + --issuer "$APPLE_API_ISSUER_ID" \ + --wait --output-format json) + echo "$RESULT" + + if ! echo "$RESULT" | grep -q '"status":"Accepted"'; then + SUBMISSION_ID=$(echo "$RESULT" | sed -n 's/.*"id":"\([^"]*\)".*/\1/p') + xcrun notarytool log "$SUBMISSION_ID" --key "$RUNNER_TEMP/api_key.p8" --key-id "$APPLE_API_KEY_ID" --issuer "$APPLE_API_ISSUER_ID" || true + exit 1 + fi + + # The notarization of the DMG also covers the app inside it. + xcrun stapler staple "$DMG" + xcrun stapler staple SourceGit.app + + security delete-keychain "$KEYCHAIN" + rm -f "$RUNNER_TEMP/certificate.p12" "$RUNNER_TEMP/api_key.p8" +fi + +ditto -c -k --keepParent SourceGit.app "sourcegit_$VERSION.$RUNTIME.zip" diff --git a/build/scripts/update-homebrew-cask.sh b/build/scripts/update-homebrew-cask.sh new file mode 100755 index 0000000000..2578d6adaa --- /dev/null +++ b/build/scripts/update-homebrew-cask.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash + +set -euo pipefail + +if [ -z "${GH_TOKEN:-}" ]; then + echo "::warning::HOMEBREW_TAP_TOKEN is not set, skipping Homebrew cask update" + exit 0 +fi + +ZIP_ARM64="packages/sourcegit_$VERSION.osx-arm64.zip" +ZIP_X64="packages/sourcegit_$VERSION.osx-x64.zip" +if [ ! -f "$ZIP_ARM64" ]; then + echo "::warning::No Apple Silicon package in this release, skipping Homebrew cask update" + exit 0 +fi + +git clone "https://x-access-token:$GH_TOKEN@github.com/holion/homebrew-tap.git" tap +mkdir -p tap/Casks +CASK=tap/Casks/sourcegit-holion.rb +sed -e "s/SOURCE_GIT_VERSION/$VERSION/g" \ + -e "s/SOURCE_GIT_SHA256_ARM64/$(sha256sum "$ZIP_ARM64" | cut -d' ' -f1)/g" \ + build/resources/homebrew/sourcegit-holion.rb > "$CASK" + +if [ -f "$ZIP_X64" ]; then + sed -i -e "s/SOURCE_GIT_SHA256_X64/$(sha256sum "$ZIP_X64" | cut -d' ' -f1)/g" "$CASK" +else + # Apple Silicon only release. + sed -i -e 's/^ arch arm: "arm64", intel: "x64"$/ arch arm: "arm64"/' \ + -e 's/^ sha256 arm: \("[0-9a-f]*"\),$/ sha256 \1/' \ + -e '/SOURCE_GIT_SHA256_X64/d' \ + -e 's/^ depends_on macos: ">= :ventura"$/ depends_on arch: :arm64\n depends_on macos: ">= :ventura"/' \ + "$CASK" +fi + +cd tap +git config user.name "github-actions[bot]" +git config user.email "41898282+github-actions[bot]@users.noreply.github.com" +git add Casks/sourcegit-holion.rb +git commit -m "sourcegit-holion $VERSION" +git push diff --git a/release.sh b/release.sh new file mode 100755 index 0000000000..f0dca2a8a5 --- /dev/null +++ b/release.sh @@ -0,0 +1,46 @@ +#!/usr/bin/env bash +# +# Releases develop by pushing it to master, which starts the Release workflow. +# The workflow bumps VERSION, tags the release and builds it. +# +# ./release.sh +# +# The platforms that get built come from the BUILD_RUNTIMES repository variable (default: osx-arm64). + +set -euo pipefail +cd "$(dirname "$0")" + +fail() { + echo "$1" >&2 + exit 1 +} + +branch=$(git rev-parse --abbrev-ref HEAD) +[ "$branch" = "develop" ] || fail "Releases are made from develop, but you are on $branch." +[ -z "$(git status --porcelain)" ] || fail "Commit or stash your changes first." + +git pull --ff-only --quiet origin develop +git fetch --quiet --tags origin master + +[ -n "$(git rev-list origin/master..HEAD)" ] || fail "Nothing to release: master already has everything on develop." + +# The same rule as the Release workflow, to show what the next version will be. +version=$(cat VERSION) +[[ "$version" =~ ^[0-9]{4}\.[0-9]{1,2}$ ]] && version="$version.1" +while git rev-parse -q --verify "refs/tags/v$version" > /dev/null; do + version=$(echo "$version" | awk -F. -v OFS=. '{ $NF += 1; print }') +done + +git log --oneline origin/master..HEAD +read -r -p "Release these commits as v$version? [y/N] " answer +[[ "$answer" =~ ^[yY]$ ]] || fail "Aborted." + +# Pick up the VERSION commits the Release workflow made on master, so master fast-forwards. +if ! git merge-base --is-ancestor origin/master HEAD; then + git merge --quiet --no-edit origin/master +fi + +git push --quiet origin develop develop:master + +echo "Pushed to master. Follow the release of v$version at:" +echo "https://github.com/holion/sourcegit/actions/workflows/release.yml" diff --git a/src/App.JsonCodeGen.cs b/src/App.JsonCodeGen.cs index 8eef67ae72..5aaa24a45d 100644 --- a/src/App.JsonCodeGen.cs +++ b/src/App.JsonCodeGen.cs @@ -61,7 +61,16 @@ public override void Write(Utf8JsonWriter writer, GridLength value, JsonSerializ typeof(GridLengthConverter), ] )] + [JsonSerializable(typeof(Models.AzureDevOpsDeviceCode))] + [JsonSerializable(typeof(Models.AzureDevOpsOrganizationList))] + [JsonSerializable(typeof(Models.AzureDevOpsProfile))] + [JsonSerializable(typeof(Models.AzureDevOpsRepositoryList))] + [JsonSerializable(typeof(Models.AzureDevOpsTokens))] [JsonSerializable(typeof(Models.ExternalToolCustomization))] + [JsonSerializable(typeof(Models.GitHubAccessToken))] + [JsonSerializable(typeof(Models.GitHubDeviceCode))] + [JsonSerializable(typeof(Models.GitHubUser))] + [JsonSerializable(typeof(List))] [JsonSerializable(typeof(Models.InteractiveRebaseJobCollection))] [JsonSerializable(typeof(Models.JetBrainsState))] [JsonSerializable(typeof(Models.ThemeOverrides))] diff --git a/src/App.axaml b/src/App.axaml index 2663e44ad4..8b1479aa52 100644 --- a/src/App.axaml +++ b/src/App.axaml @@ -1,6 +1,7 @@ @@ -10,24 +11,8 @@ + - - - - - - - - - - - - - - - - - @@ -41,10 +26,10 @@ - + - + @@ -52,7 +37,7 @@ - + diff --git a/src/App.axaml.cs b/src/App.axaml.cs index eef4684cee..8e5403e3b8 100644 --- a/src/App.axaml.cs +++ b/src/App.axaml.cs @@ -1,7 +1,9 @@ using System; +using System.Collections.Generic; using System.IO; using System.Net.Http; using System.Text.Json; +using System.Threading; using System.Threading.Tasks; using Avalonia; @@ -37,7 +39,9 @@ public static void Main(string[] args) try { - if (TryLaunchAsRebaseTodoEditor(args, out int exitTodo)) + if (TryLaunchAsCredentialHelper(args)) + Environment.Exit(0); + else if (TryLaunchAsRebaseTodoEditor(args, out int exitTodo)) Environment.Exit(exitTodo); else if (TryLaunchAsRebaseMessageEditor(args, out int exitMessage)) Environment.Exit(exitMessage); @@ -47,6 +51,11 @@ public static void Main(string[] args) catch (Exception ex) { Native.OS.LogException(ex); + + // When Avalonia.Native fails to start (e.g. askpass launched by SSH in the background), its static + // destructors abort the process on a normal exit, which macOS reports as a crash of the whole app. + if (OperatingSystem.IsMacOS()) + Native.MacOS.ExitWithoutCleanup(-1); } } @@ -100,23 +109,6 @@ public static async Task AskConfirmAsync(string message, Models.ConfirmBut return Models.ConfirmEmptyCommitResult.Cancel; } - public static void SetLocale(string localeKey) - { - var locale = Models.Locale.Supported.Find(x => x.Key.Equals(localeKey, StringComparison.OrdinalIgnoreCase)); - var finalLocaleKey = locale?.Key ?? "en_US"; - - if (Current is not App app || - app.Resources[finalLocaleKey] is not ResourceDictionary targetLocale || - targetLocale == app._activeLocale) - return; - - if (app._activeLocale != null) - app.Resources.MergedDictionaries.Remove(app._activeLocale); - - app.Resources.MergedDictionaries.Add(targetLocale); - app._activeLocale = targetLocale; - } - public static void SetTheme(string theme, string themeOverridesFile) { if (Current is not App app) @@ -227,6 +219,14 @@ public static ViewModels.Launcher GetLauncher() return Current is App app ? app._launcher : null; } + public static void RestartToInstallUpdate() + { + if (Current is App app) + app._relaunchAfterUpdate = true; + + Quit(0); + } + public static void Quit(int exitCode) { if (Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) @@ -242,7 +242,6 @@ public override void Initialize() AvaloniaXamlLoader.Load(this); var pref = ViewModels.Preferences.Instance; - SetLocale(pref.Locale); SetTheme(pref.Theme, pref.ThemeOverrides); SetFonts(pref.DefaultFontFamily, pref.MonospaceFontFamily); } @@ -279,6 +278,58 @@ public override void OnFrameworkInitializationCompleted() #endregion #region Launch Ways + /// + /// Git credential helper protocol (`git help credential`) for github.com (`--github-credential`) and Azure + /// DevOps (`--azure-devops-credential`): `get` answers with the token of the signed-in account. `store` and + /// `erase` are ignored, since the token is managed by this app. + /// + private static bool TryLaunchAsCredentialHelper(string[] args) + { + if (args.Length != 2) + return false; + + var isGitHub = args[0].Equals("--github-credential", StringComparison.Ordinal); + var isAzureDevOps = args[0].Equals("--azure-devops-credential", StringComparison.Ordinal); + if (!isGitHub && !isAzureDevOps) + return false; + + var attributes = new Dictionary(); + string line; + while (!string.IsNullOrEmpty(line = Console.In.ReadLine())) + { + var idx = line.IndexOf('='); + if (idx > 0) + attributes[line.Substring(0, idx)] = line.Substring(idx + 1); + } + + if (!args[1].Equals("get", StringComparison.Ordinal) || + !attributes.TryGetValue("protocol", out var protocol) || protocol != "https" || + !attributes.TryGetValue("host", out var host)) + return true; + + string userName = null, token = null; + if (isGitHub && host.Equals(Models.GitHub.Host, StringComparison.OrdinalIgnoreCase)) + { + userName = Models.GitHub.TokenUserName; + token = Native.SecretStore.Get(ViewModels.GitHubAccount.SecretKey); + } + else if (isAzureDevOps && Models.AzureDevOps.IsHost(host)) + { + // Azure DevOps ignores the user name, so keep the one from the remote URL (`https://@dev.azure.com/...`). + userName = attributes.GetValueOrDefault("username", Models.AzureDevOps.TokenUserName); + using var cancellation = new CancellationTokenSource(TimeSpan.FromSeconds(30)); + token = ViewModels.AzureDevOpsAccount.GetAccessTokenForGitAsync(cancellation.Token).GetAwaiter().GetResult(); + } + + if (!string.IsNullOrEmpty(token)) + { + Console.Out.Write($"username={userName}\npassword={token}\n"); + Console.Out.Flush(); + } + + return true; + } + private static bool TryLaunchAsRebaseTodoEditor(string[] args, out int exitCode) { exitCode = -1; @@ -515,6 +566,9 @@ private void TryLaunchAsNormal(IClassicDesktopStyleApplicationLifetime desktop) { _ipcChannel?.Dispose(); _ipcChannel = null; + + if (OperatingSystem.IsMacOS()) + Models.AutoUpdate.InstallOnExit(_relaunchAfterUpdate); }; _ipcChannel.MessageReceived += repo => @@ -528,8 +582,22 @@ private void TryLaunchAsNormal(IClassicDesktopStyleApplicationLifetime desktop) }; #if !DISABLE_UPDATE_DETECTION - if (pref.ShouldCheck4UpdateOnStartup()) + if (OperatingSystem.IsMacOS()) + { + Models.AutoUpdate.Restore(); + _launcher.NewVersion = Models.AutoUpdate.Staged; + } + + if (pref.Check4UpdatesOnStartup) Check4Update(); + + // Keep looking for updates while the app stays open for days. + DispatcherTimer.Run(() => + { + if (pref.Check4UpdatesOnStartup) + Check4Update(); + return true; + }, TimeSpan.FromHours(6)); #endif } #endregion @@ -537,7 +605,7 @@ private void TryLaunchAsNormal(IClassicDesktopStyleApplicationLifetime desktop) #region Check for Updates private void Check4Update(bool manually = false) { - if (_launcher != null) + if (_launcher is { NewVersion.IsReadyToInstall: false }) _launcher.NewVersion = null; Task.Run(async () => @@ -547,26 +615,30 @@ private void Check4Update(bool manually = false) // Fetch latest release information. using var client = new HttpClient(); client.Timeout = TimeSpan.FromSeconds(5); + client.DefaultRequestHeaders.UserAgent.ParseAdd("SourceGit"); - var data = await client.GetStringAsync("https://sourcegit-scm.github.io/data/version.json"); + var data = await client.GetStringAsync("https://api.github.com/repos/holion/sourcegit/releases/latest"); var ver = JsonSerializer.Deserialize(data, JsonCodeGen.Default.Version); if (ver == null) return; - if (manually) + if (!ver.IsNewVersion) { - if (ver.IsNewVersion) - ShowSelfUpdateResult(ver); - else + if (manually) ShowSelfUpdateResult(new Models.AlreadyUpToDate()); + return; } - else if (_launcher != null) - { - if (!ver.IsNewVersion || ver.TagName == ViewModels.Preferences.Instance.IgnoreUpdateTag) - return; - _launcher.NewVersion = ver; - } + if (!manually && ver.TagName == ViewModels.Preferences.Instance.IgnoreUpdateTag) + return; + + if (OperatingSystem.IsMacOS() && await Models.AutoUpdate.StageAsync(ver)) + ver = Models.AutoUpdate.Staged; + + if (manually) + ShowSelfUpdateResult(ver); + else if (_launcher != null) + Dispatcher.UIThread.Post(() => _launcher.NewVersion = ver); } catch (Exception e) { @@ -598,8 +670,8 @@ private void ShowSelfUpdateResult(object data) #endregion private Models.IpcChannel _ipcChannel = null; + private bool _relaunchAfterUpdate = false; private ViewModels.Launcher _launcher = null; - private ResourceDictionary _activeLocale = null; private ResourceDictionary _themeOverrides = null; private ResourceDictionary _fontsOverrides = null; } diff --git a/src/Commands/Command.cs b/src/Commands/Command.cs index ba68bb90da..4fdb217819 100644 --- a/src/Commands/Command.cs +++ b/src/Commands/Command.cs @@ -170,6 +170,18 @@ protected ProcessStartInfo CreateGitStartInfo(bool redirect) .Append(Native.OS.CredentialHelper) .Append(' '); + // While signed in to GitHub, answer github.com credential requests with that account's token. The empty + // value first clears the helpers configured so far (`manager` above, `osxkeychain`, ...) for github.com. + if (ViewModels.GitHubAccount.Instance is { IsSignedIn: true, UseForGit: true }) + builder.Append($"""-c credential.https://github.com.helper= -c credential.https://github.com.helper="!\"{selfExecFile}\" --github-credential" """); + + // Same for Azure DevOps, at dev.azure.com and the older .visualstudio.com. + if (ViewModels.AzureDevOpsAccount.Instance is { IsSignedIn: true, UseForGit: true }) + { + foreach (var host in new[] { "dev.azure.com", "*.visualstudio.com" }) + builder.Append($"""-c credential.https://{host}.helper= -c credential.https://{host}.helper="!\"{selfExecFile}\" --azure-devops-credential" """); + } + switch (Editor) { case EditorType.CoreEditor: diff --git a/src/Converters/ListConverters.cs b/src/Converters/ListConverters.cs index e0c5967e81..afc738375b 100644 --- a/src/Converters/ListConverters.cs +++ b/src/Converters/ListConverters.cs @@ -1,5 +1,4 @@ using System.Collections; -using System.Collections.Generic; using Avalonia.Data.Converters; @@ -15,11 +14,5 @@ public static class ListConverters public static readonly FuncValueConverter IsNotNullOrEmpty = new FuncValueConverter(v => v != null && v.Count > 0); - - public static readonly FuncValueConverter, List> Top100Changes = - new FuncValueConverter, List>(v => (v == null || v.Count < 100) ? v : v.GetRange(0, 100)); - - public static readonly FuncValueConverter IsOnlyTop100Shows = - new FuncValueConverter(v => v != null && v.Count > 100); } } diff --git a/src/Converters/StringConverters.cs b/src/Converters/StringConverters.cs index 4a6fd33d33..2b5b4a59fe 100644 --- a/src/Converters/StringConverters.cs +++ b/src/Converters/StringConverters.cs @@ -9,21 +9,6 @@ namespace SourceGit.Converters { public static class StringConverters { - public class ToLocaleConverter : IValueConverter - { - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) - { - return Models.Locale.Supported.Find(x => x.Key == value as string); - } - - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) - { - return (value as Models.Locale)?.Key; - } - } - - public static readonly ToLocaleConverter ToLocale = new ToLocaleConverter(); - public class ToThemeConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) diff --git a/src/Models/AutoUpdate.cs b/src/Models/AutoUpdate.cs new file mode 100644 index 0000000000..2ff2334b8e --- /dev/null +++ b/src/Models/AutoUpdate.cs @@ -0,0 +1,264 @@ +using System; +using System.Diagnostics; +using System.IO; +using System.Net.Http; +using System.Runtime.InteropServices; +using System.Runtime.Versioning; +using System.Security.Cryptography; +using System.Text.RegularExpressions; +using System.Threading; +using System.Threading.Tasks; + +namespace SourceGit.Models +{ + /// + /// Downloads new releases in the background on macOS and swaps the app bundle once SourceGit exits. + /// + [SupportedOSPlatform("macOS")] + public static partial class AutoUpdate + { + [DllImport("/usr/lib/libSystem.B.dylib", SetLastError = true)] + private static extern int access(string path, int mode); + + public static bool IsSupported + { + get + { + var bundle = AppBundle; + return bundle != null && + access(bundle, 2 /* W_OK */) == 0 && + access(Path.GetDirectoryName(bundle), 2 /* W_OK */) == 0; + } + } + + public static Version Staged + { + get; + private set; + } + + /// + /// Picks up an update downloaded by a previous session that was never installed, or cleans it up. + /// + public static void Restore() + { + try + { + var tagFile = Path.Combine(UpdateDir, "tag"); + if (File.Exists(tagFile) && Directory.Exists(StagedBundle)) + { + var ver = new Version() { TagName = File.ReadAllText(tagFile).Trim(), IsReadyToInstall = true }; + if (ver.IsNewVersion) + { + Staged = ver; + return; + } + } + + if (Directory.Exists(UpdateDir)) + Directory.Delete(UpdateDir, true); + } + catch + { + // Ignore errors, the update will simply be downloaded again. + } + } + + /// + /// Downloads and verifies the given release so it can be installed when the app exits. + /// + public static async Task StageAsync(Version ver) + { + if (!IsSupported) + return false; + + await _lock.WaitAsync(); + try + { + if (Staged?.TagName == ver.TagName) + { + ver.IsReadyToInstall = true; + Staged = ver; + return true; + } + + var rid = RuntimeInformation.ProcessArchitecture == Architecture.Arm64 ? "osx-arm64" : "osx-x64"; + var assetName = $"sourcegit_{ver.TagName.Substring(1)}.{rid}.zip"; + var asset = ver.Assets.Find(x => x.Name == assetName); + if (asset == null) + return false; + + // Without a digest to check the download against, only accept it if we can compare code signatures. + var teamId = GetTeamIdentifier(AppBundle); + var expectedHash = asset.Digest?.StartsWith("sha256:", StringComparison.Ordinal) == true ? asset.Digest.Substring(7) : null; + if (teamId == null && expectedHash == null) + return false; + + if (Directory.Exists(UpdateDir)) + Directory.Delete(UpdateDir, true); + Directory.CreateDirectory(UpdateDir); + + var zip = Path.Combine(UpdateDir, assetName); + using (var client = new HttpClient()) + { + client.Timeout = TimeSpan.FromMinutes(10); + client.DefaultRequestHeaders.UserAgent.ParseAdd("SourceGit"); + + await using var input = await client.GetStreamAsync(asset.DownloadUrl); + await using var output = File.Create(zip); + await input.CopyToAsync(output); + } + + if (expectedHash != null) + { + await using var stream = File.OpenRead(zip); + var hash = Convert.ToHexStringLower(await SHA256.HashDataAsync(stream)); + if (!hash.Equals(expectedHash, StringComparison.OrdinalIgnoreCase)) + return false; + } + + var extractDir = Path.Combine(UpdateDir, "staged"); + if (Run("/usr/bin/ditto", "-x", "-k", zip, extractDir) != 0 || !Directory.Exists(StagedBundle)) + return false; + + File.Delete(zip); + + // A signed app only accepts updates signed by the same team. + if (teamId != null) + { + if (Run("/usr/bin/codesign", "--verify", "--deep", "--strict", StagedBundle) != 0 || + GetTeamIdentifier(StagedBundle) != teamId) + return false; + } + + await File.WriteAllTextAsync(Path.Combine(UpdateDir, "tag"), ver.TagName); + ver.IsReadyToInstall = true; + Staged = ver; + return true; + } + catch (Exception e) + { + Native.OS.LogException(e); + return false; + } + finally + { + _lock.Release(); + } + } + + /// + /// Replaces the running app bundle with the staged one after this process has exited. + /// + public static void InstallOnExit(bool relaunch) + { + if (Staged == null || !Directory.Exists(StagedBundle) || !IsSupported) + return; + + var script = Path.Combine(UpdateDir, "install.sh"); + File.WriteAllText(script, INSTALL_SCRIPT); + + var args = new[] + { + script, + Environment.ProcessId.ToString(), + AppBundle, + StagedBundle, + Path.Combine(UpdateDir, "previous.app"), + UpdateDir, + relaunch ? "1" : "0", + }; + + var start = new ProcessStartInfo(); + if (Native.OS.SupportSetSid()) + { + start.FileName = Native.OS.GetSetSidExecutable(); + start.ArgumentList.Add("/bin/sh"); + } + else + { + start.FileName = "/bin/sh"; + } + + foreach (var arg in args) + start.ArgumentList.Add(arg); + + start.UseShellExecute = false; + Process.Start(start); + } + + private static string AppBundle + { + get + { + // .app/Contents/MacOS/SourceGit + var macOSDir = Path.GetDirectoryName(Environment.ProcessPath); + var bundle = Path.GetDirectoryName(Path.GetDirectoryName(macOSDir)); + return bundle != null && bundle.EndsWith(".app", StringComparison.Ordinal) ? bundle : null; + } + } + + private static string UpdateDir => Path.Combine(Native.OS.BasicDirectories.CacheDir, "update"); + + private static string StagedBundle => Path.Combine(UpdateDir, "staged", "SourceGit.app"); + + private static string GetTeamIdentifier(string bundle) + { + var start = new ProcessStartInfo("/usr/bin/codesign", ["-dv", "--verbose=2", bundle]) + { + UseShellExecute = false, + RedirectStandardError = true, + RedirectStandardOutput = true, + }; + + using var proc = Process.Start(start); + var info = proc.StandardError.ReadToEnd(); + proc.WaitForExit(); + + var match = REG_TEAM_ID().Match(info); + return proc.ExitCode == 0 && match.Success ? match.Groups[1].Value : null; + } + + private static int Run(string file, params string[] args) + { + var start = new ProcessStartInfo(file, args) + { + UseShellExecute = false, + RedirectStandardError = true, + RedirectStandardOutput = true, + }; + + using var proc = Process.Start(start); + proc.StandardOutput.ReadToEnd(); + proc.StandardError.ReadToEnd(); + proc.WaitForExit(); + return proc.ExitCode; + } + + [GeneratedRegex(@"^TeamIdentifier=([A-Z0-9]{10})$", RegexOptions.Multiline)] + private static partial Regex REG_TEAM_ID(); + + // Arguments: + private const string INSTALL_SCRIPT = """ + #!/bin/sh + PID="$1"; APP="$2"; NEW="$3"; OLD="$4"; DIR="$5"; RELAUNCH="$6" + + while kill -0 "$PID" 2>/dev/null; do sleep 0.2; done + + rm -rf "$OLD" + if mv "$APP" "$OLD"; then + if mv "$NEW" "$APP"; then + rm -rf "$DIR" + else + mv "$OLD" "$APP" + fi + fi + + if [ "$RELAUNCH" = "1" ]; then + open "$APP" + fi + """; + + private static readonly SemaphoreSlim _lock = new(1, 1); + } +} diff --git a/src/Models/AzureDevOps.cs b/src/Models/AzureDevOps.cs new file mode 100644 index 0000000000..26d18890d1 --- /dev/null +++ b/src/Models/AzureDevOps.cs @@ -0,0 +1,426 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Text.Json.Serialization; +using System.Text.RegularExpressions; +using System.Threading; +using System.Threading.Tasks; + +namespace SourceGit.Models +{ + public class AzureDevOpsProject + { + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + [JsonPropertyName("visibility")] + public string Visibility { get; set; } = string.Empty; + } + + public class AzureDevOpsRepository + { + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + [JsonPropertyName("project")] + public AzureDevOpsProject Project { get; set; } = new(); + + [JsonPropertyName("remoteUrl")] + public string RemoteUrl { get; set; } = string.Empty; + + [JsonPropertyName("sshUrl")] + public string SshUrl { get; set; } = string.Empty; + + [JsonPropertyName("isDisabled")] + public bool IsDisabled { get; set; } = false; + + [JsonIgnore] + public string Organization { get; set; } = string.Empty; + + /// + /// `organization/project/name`, the same key `AzureDevOps.ParseFullName` returns for a remote URL. + /// + [JsonIgnore] + public string FullName => $"{Organization}/{Project.Name}/{Name}"; + + [JsonIgnore] + public bool IsPrivate => !Project.Visibility.Equals("public", StringComparison.OrdinalIgnoreCase); + + [JsonIgnore] + public bool IsCloned { get; set; } = false; + } + + public class AzureDevOpsRepositoryList + { + [JsonPropertyName("value")] + public List Value { get; set; } = []; + } + + public class AzureDevOpsProfile + { + [JsonPropertyName("id")] + public string Id { get; set; } = string.Empty; + + [JsonPropertyName("displayName")] + public string DisplayName { get; set; } = string.Empty; + + [JsonPropertyName("emailAddress")] + public string EmailAddress { get; set; } = string.Empty; + } + + public class AzureDevOpsOrganization + { + [JsonPropertyName("accountName")] + public string AccountName { get; set; } = string.Empty; + } + + public class AzureDevOpsOrganizationList + { + [JsonPropertyName("value")] + public List Value { get; set; } = []; + } + + public class AzureDevOpsDeviceCode + { + [JsonPropertyName("device_code")] + public string DeviceCode { get; set; } = string.Empty; + + [JsonPropertyName("user_code")] + public string UserCode { get; set; } = string.Empty; + + [JsonPropertyName("verification_uri")] + public string VerificationUri { get; set; } = string.Empty; + + [JsonPropertyName("expires_in")] + public int ExpiresIn { get; set; } = 900; + + [JsonPropertyName("interval")] + public int Interval { get; set; } = 5; + } + + public class AzureDevOpsTokens + { + [JsonPropertyName("access_token")] + public string AccessToken { get; set; } = string.Empty; + + [JsonPropertyName("refresh_token")] + public string RefreshToken { get; set; } = string.Empty; + + [JsonPropertyName("expires_in")] + public int ExpiresIn { get; set; } = 0; + + [JsonPropertyName("error")] + public string Error { get; set; } = string.Empty; + + [JsonPropertyName("error_description")] + public string ErrorDescription { get; set; } = string.Empty; + } + + public class AzureDevOpsException : Exception + { + public bool IsUnauthorized { get; } + + public AzureDevOpsException(string message, bool isUnauthorized = false) : base(message) + { + IsUnauthorized = isUnauthorized; + } + } + + /// + /// Minimal Azure DevOps client: Microsoft Entra ID device code sign-in, and listing the repositories of every + /// organization the signed-in user is a member of. + /// + public static partial class AzureDevOps + { + /// + /// Application (client) id of the Holion app registration in Microsoft Entra ID: a multitenant public client + /// with the delegated Azure DevOps `user_impersonation` permission. It is public by design; the device code + /// flow needs no client secret. + /// + public const string ClientId = "a87d6f69-c057-4782-8ce7-d6b5d64b021b"; + + public const string TokenUserName = "AzureDevOps"; + public const string OrganizationsUrl = "https://aex.dev.azure.com/me"; + + public static bool IsConfigured => !string.IsNullOrEmpty(ClientId); + + /// + /// Whether git talks to Azure DevOps when using this host: `dev.azure.com` or `.visualstudio.com`. + /// + public static bool IsHost(string host) + { + return host.Equals("dev.azure.com", StringComparison.OrdinalIgnoreCase) || + host.EndsWith(".visualstudio.com", StringComparison.OrdinalIgnoreCase); + } + + public static async Task RequestDeviceCodeAsync(CancellationToken token) + { + var form = new FormUrlEncodedContent(new Dictionary() + { + ["client_id"] = ClientId, + ["scope"] = Scopes, + }); + + using var rsp = await s_client.PostAsync($"{Authority}/devicecode", form, token).ConfigureAwait(false); + await EnsureSuccessAsync(rsp, token).ConfigureAwait(false); + + await using var stream = await rsp.Content.ReadAsStreamAsync(token).ConfigureAwait(false); + return await System.Text.Json.JsonSerializer.DeserializeAsync(stream, JsonCodeGen.Default.AzureDevOpsDeviceCode, token).ConfigureAwait(false); + } + + /// + /// Polls until the user has entered the code at microsoft.com/devicelogin. Returns the tokens, or throws when + /// the code expires or the user declines. + /// + public static async Task WaitForTokensAsync(AzureDevOpsDeviceCode code, CancellationToken token) + { + var interval = Math.Max(code.Interval, 1); + var deadline = DateTime.UtcNow.AddSeconds(code.ExpiresIn); + + while (DateTime.UtcNow < deadline) + { + await Task.Delay(TimeSpan.FromSeconds(interval), token).ConfigureAwait(false); + + var result = await RequestTokensAsync(new Dictionary() + { + ["client_id"] = ClientId, + ["device_code"] = code.DeviceCode, + ["grant_type"] = "urn:ietf:params:oauth:grant-type:device_code", + }, token).ConfigureAwait(false); + + if (!string.IsNullOrEmpty(result.AccessToken)) + return result; + + switch (result.Error) + { + case "authorization_pending": + break; + case "slow_down": + interval += 5; + break; + case "expired_token": + throw new AzureDevOpsException(App.Text("AzureDevOps.SignIn.Expired")); + case "authorization_declined": + case "access_denied": + throw new AzureDevOpsException(App.Text("AzureDevOps.SignIn.Denied")); + default: + throw new AzureDevOpsException(string.IsNullOrEmpty(result.ErrorDescription) ? result.Error : result.ErrorDescription); + } + } + + throw new AzureDevOpsException(App.Text("AzureDevOps.SignIn.Expired")); + } + + /// + /// Trades a refresh token for a new access token (and usually a new refresh token). Throws an unauthorized + /// exception when the refresh token is no longer valid, so the user has to sign in again. + /// + public static async Task RefreshTokensAsync(string refreshToken, CancellationToken token) + { + var result = await RequestTokensAsync(new Dictionary() + { + ["client_id"] = ClientId, + ["refresh_token"] = refreshToken, + ["grant_type"] = "refresh_token", + ["scope"] = Scopes, + }, token).ConfigureAwait(false); + + if (!string.IsNullOrEmpty(result.AccessToken)) + return result; + + var message = string.IsNullOrEmpty(result.ErrorDescription) ? result.Error : result.ErrorDescription; + throw new AzureDevOpsException($"Azure DevOps: {message}", result.Error is "invalid_grant" or "interaction_required"); + } + + public static async Task GetProfileAsync(string accessToken, CancellationToken token) + { + using var req = CreateApiRequest("https://app.vssps.visualstudio.com/_apis/profile/profiles/me?api-version=7.1-preview.3", accessToken); + using var rsp = await s_client.SendAsync(req, token).ConfigureAwait(false); + await EnsureSuccessAsync(rsp, token).ConfigureAwait(false); + + await using var stream = await rsp.Content.ReadAsStreamAsync(token).ConfigureAwait(false); + return await System.Text.Json.JsonSerializer.DeserializeAsync(stream, JsonCodeGen.Default.AzureDevOpsProfile, token).ConfigureAwait(false); + } + + /// + /// Names of the organizations the user is a member of. + /// + public static async Task> GetOrganizationsAsync(string accessToken, string memberId, CancellationToken token) + { + var url = $"https://app.vssps.visualstudio.com/_apis/accounts?memberId={Uri.EscapeDataString(memberId)}&api-version=7.1-preview.1"; + using var req = CreateApiRequest(url, accessToken); + using var rsp = await s_client.SendAsync(req, token).ConfigureAwait(false); + await EnsureSuccessAsync(rsp, token).ConfigureAwait(false); + + await using var stream = await rsp.Content.ReadAsStreamAsync(token).ConfigureAwait(false); + var list = await System.Text.Json.JsonSerializer.DeserializeAsync(stream, JsonCodeGen.Default.AzureDevOpsOrganizationList, token).ConfigureAwait(false); + + var outs = new List(); + foreach (var account in list?.Value ?? []) + { + if (!string.IsNullOrEmpty(account.AccountName)) + outs.Add(account.AccountName); + } + + return outs; + } + + /// + /// Lists the repositories of every project in the organization that the user can access. + /// + public static async Task> GetRepositoriesAsync(string accessToken, string organization, CancellationToken token) + { + var url = $"https://dev.azure.com/{Uri.EscapeDataString(organization)}/_apis/git/repositories?api-version=7.1"; + using var req = CreateApiRequest(url, accessToken); + using var rsp = await s_client.SendAsync(req, token).ConfigureAwait(false); + await EnsureSuccessAsync(rsp, token).ConfigureAwait(false); + + await using var stream = await rsp.Content.ReadAsStreamAsync(token).ConfigureAwait(false); + var list = await System.Text.Json.JsonSerializer.DeserializeAsync(stream, JsonCodeGen.Default.AzureDevOpsRepositoryList, token).ConfigureAwait(false); + + var repos = list?.Value ?? []; + foreach (var repo in repos) + repo.Organization = organization; + + return repos; + } + + /// + /// Returns `organization/project/name` (lower case) when the given remote URL points at a repository on + /// Azure DevOps, over HTTPS (`dev.azure.com` or `.visualstudio.com`) or SSH. + /// + public static string ParseFullName(string url) + { + if (string.IsNullOrEmpty(url)) + return null; + + url = url.Trim(); + foreach (var regex in new[] { REG_DEV_AZURE_URL(), REG_VISUALSTUDIO_URL(), REG_SSH_URL() }) + { + var match = regex.Match(url); + if (!match.Success) + continue; + + // A URL without a project points at the repository named after its project. + var repo = match.Groups["repo"].Value; + var project = match.Groups["project"].Success ? match.Groups["project"].Value : repo; + return Uri.UnescapeDataString($"{match.Groups["org"].Value}/{project}/{repo}").ToLowerInvariant(); + } + + return null; + } + + /// + /// Collects the Azure DevOps repositories (`organization/project/name`, lower case) that the given local + /// repositories use as remotes. + /// + public static HashSet CollectClonedFullNames(IEnumerable repoPaths) + { + var outs = new HashSet(); + foreach (var path in repoPaths) + { + var config = Path.Combine(path, ".git", "config"); + if (!File.Exists(config)) + config = Path.Combine(path, "config"); + + try + { + if (!File.Exists(config)) + continue; + + foreach (var line in File.ReadLines(config)) + { + var trimmed = line.Trim(); + if (!trimmed.StartsWith("url", StringComparison.Ordinal)) + continue; + + var idx = trimmed.IndexOf('='); + if (idx < 0) + continue; + + var fullName = ParseFullName(trimmed.Substring(idx + 1)); + if (fullName != null) + outs.Add(fullName); + } + } + catch + { + // Ignore unreadable repositories. + } + } + + return outs; + } + + /// + /// The token endpoint answers pending and failed requests with 400 and an error in the body, so the body + /// is read whatever the status. + /// + private static async Task RequestTokensAsync(Dictionary fields, CancellationToken token) + { + using var form = new FormUrlEncodedContent(fields); + using var rsp = await s_client.PostAsync($"{Authority}/token", form, token).ConfigureAwait(false); + var body = await rsp.Content.ReadAsStringAsync(token).ConfigureAwait(false); + + try + { + return System.Text.Json.JsonSerializer.Deserialize(body, JsonCodeGen.Default.AzureDevOpsTokens); + } + catch (System.Text.Json.JsonException) + { + throw new AzureDevOpsException($"Azure DevOps: {(int)rsp.StatusCode} {rsp.ReasonPhrase} {body}".Trim()); + } + } + + private static HttpRequestMessage CreateApiRequest(string url, string accessToken) + { + var req = new HttpRequestMessage(HttpMethod.Get, url); + req.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken); + + // Without it, failed authentication redirects to a sign-in page instead of answering 401. + req.Headers.Add("X-TFS-FedAuthRedirect", "Suppress"); + return req; + } + + private static async Task EnsureSuccessAsync(HttpResponseMessage rsp, CancellationToken token) + { + // Azure DevOps answers 203 with an HTML sign-in page when it does not accept the token. + if (rsp.IsSuccessStatusCode && rsp.StatusCode != HttpStatusCode.NonAuthoritativeInformation) + return; + + var body = await rsp.Content.ReadAsStringAsync(token).ConfigureAwait(false); + if (body.Length > 500) + body = body.Substring(0, 500); + + var unauthorized = rsp.StatusCode is HttpStatusCode.Unauthorized or HttpStatusCode.NonAuthoritativeInformation; + throw new AzureDevOpsException($"Azure DevOps: {(int)rsp.StatusCode} {rsp.ReasonPhrase} {body}".Trim(), unauthorized); + } + + private static HttpClient CreateClient() + { + var client = new HttpClient(new HttpClientHandler() { AllowAutoRedirect = false }) { Timeout = TimeSpan.FromSeconds(30) }; + client.DefaultRequestHeaders.UserAgent.ParseAdd("SourceGit"); + client.DefaultRequestHeaders.Accept.ParseAdd("application/json"); + return client; + } + + [GeneratedRegex(@"^https?://(?:[^@/]+@)?dev\.azure\.com/(?[^/]+)/(?:(?[^/]+)/)?_git/(?[^/?#]+?)(?:\.git)?/?$", RegexOptions.IgnoreCase)] + private static partial Regex REG_DEV_AZURE_URL(); + + [GeneratedRegex(@"^https?://(?:[^@/]+@)?(?[\w-]+)\.visualstudio\.com/(?:DefaultCollection/)?(?:(?[^/]+)/)?_git/(?[^/?#]+?)(?:\.git)?/?$", RegexOptions.IgnoreCase)] + private static partial Regex REG_VISUALSTUDIO_URL(); + + [GeneratedRegex(@"^(?:ssh://)?(?:[^@/]+@)?(?:ssh\.dev\.azure\.com|vs-ssh\.visualstudio\.com)(?::22)?[:/]v3/(?[^/]+)/(?[^/]+)/(?[^/]+?)(?:\.git)?/?$", RegexOptions.IgnoreCase)] + private static partial Regex REG_SSH_URL(); + + private const string Authority = "https://login.microsoftonline.com/organizations/oauth2/v2.0"; + + // The resource id of Azure DevOps, plus a refresh token so git keeps working without signing in again. + private const string Scopes = "499b84ac-1321-427f-aa17-267ca6975798/.default offline_access"; + + private static readonly HttpClient s_client = CreateClient(); + } +} diff --git a/src/Models/GitHub.cs b/src/Models/GitHub.cs new file mode 100644 index 0000000000..d36f25aa2f --- /dev/null +++ b/src/Models/GitHub.cs @@ -0,0 +1,327 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Text.Json.Serialization; +using System.Text.RegularExpressions; +using System.Threading; +using System.Threading.Tasks; + +namespace SourceGit.Models +{ + public class GitHubOwner + { + [JsonPropertyName("login")] + public string Login { get; set; } = string.Empty; + } + + public class GitHubRepository + { + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + [JsonPropertyName("full_name")] + public string FullName { get; set; } = string.Empty; + + [JsonPropertyName("owner")] + public GitHubOwner Owner { get; set; } = new(); + + [JsonPropertyName("description")] + public string Description { get; set; } = string.Empty; + + [JsonPropertyName("private")] + public bool IsPrivate { get; set; } = false; + + [JsonPropertyName("archived")] + public bool IsArchived { get; set; } = false; + + [JsonPropertyName("fork")] + public bool IsFork { get; set; } = false; + + [JsonPropertyName("clone_url")] + public string CloneUrl { get; set; } = string.Empty; + + [JsonPropertyName("ssh_url")] + public string SshUrl { get; set; } = string.Empty; + + [JsonPropertyName("pushed_at")] + public string PushedAt { get; set; } = string.Empty; + + [JsonIgnore] + public bool IsCloned { get; set; } = false; + } + + public class GitHubUser + { + [JsonPropertyName("login")] + public string Login { get; set; } = string.Empty; + } + + public class GitHubDeviceCode + { + [JsonPropertyName("device_code")] + public string DeviceCode { get; set; } = string.Empty; + + [JsonPropertyName("user_code")] + public string UserCode { get; set; } = string.Empty; + + [JsonPropertyName("verification_uri")] + public string VerificationUri { get; set; } = string.Empty; + + [JsonPropertyName("expires_in")] + public int ExpiresIn { get; set; } = 900; + + [JsonPropertyName("interval")] + public int Interval { get; set; } = 5; + } + + public class GitHubAccessToken + { + [JsonPropertyName("access_token")] + public string AccessToken { get; set; } = string.Empty; + + [JsonPropertyName("error")] + public string Error { get; set; } = string.Empty; + + [JsonPropertyName("error_description")] + public string ErrorDescription { get; set; } = string.Empty; + + [JsonPropertyName("interval")] + public int Interval { get; set; } = 0; + } + + public class GitHubException : Exception + { + public bool IsUnauthorized { get; } + + public GitHubException(string message, bool isUnauthorized = false) : base(message) + { + IsUnauthorized = isUnauthorized; + } + } + + /// + /// Minimal GitHub client: OAuth device flow sign-in and listing the repositories the signed-in user can access. + /// + public static partial class GitHub + { + /// + /// Client id of the Holion OAuth app (github.com/organizations/holion/settings/applications) with device flow + /// enabled. It is public by design; the device flow needs no client secret. + /// + public const string ClientId = "Ov23liyFBsWP7an8gjv0"; + + public const string Host = "github.com"; + public const string Scopes = "repo read:org workflow"; + public const string TokenUserName = "x-access-token"; + + public static bool IsConfigured => !string.IsNullOrEmpty(ClientId); + + public static string ApplicationSettingsUrl => $"https://github.com/settings/connections/applications/{ClientId}"; + + public static async Task RequestDeviceCodeAsync(CancellationToken token) + { + var form = new FormUrlEncodedContent(new Dictionary() + { + ["client_id"] = ClientId, + ["scope"] = Scopes, + }); + + using var rsp = await s_client.PostAsync("https://github.com/login/device/code", form, token).ConfigureAwait(false); + await EnsureSuccessAsync(rsp, token).ConfigureAwait(false); + + await using var stream = await rsp.Content.ReadAsStreamAsync(token).ConfigureAwait(false); + return await System.Text.Json.JsonSerializer.DeserializeAsync(stream, JsonCodeGen.Default.GitHubDeviceCode, token).ConfigureAwait(false); + } + + /// + /// Polls until the user has entered the code on github.com. Returns the access token, or throws when the + /// code expires or the user denies access. + /// + public static async Task WaitForAccessTokenAsync(GitHubDeviceCode code, CancellationToken token) + { + var interval = Math.Max(code.Interval, 1); + var deadline = DateTime.UtcNow.AddSeconds(code.ExpiresIn); + + while (DateTime.UtcNow < deadline) + { + await Task.Delay(TimeSpan.FromSeconds(interval), token).ConfigureAwait(false); + + var form = new FormUrlEncodedContent(new Dictionary() + { + ["client_id"] = ClientId, + ["device_code"] = code.DeviceCode, + ["grant_type"] = "urn:ietf:params:oauth:grant-type:device_code", + }); + + using var rsp = await s_client.PostAsync("https://github.com/login/oauth/access_token", form, token).ConfigureAwait(false); + await EnsureSuccessAsync(rsp, token).ConfigureAwait(false); + + await using var stream = await rsp.Content.ReadAsStreamAsync(token).ConfigureAwait(false); + var result = await System.Text.Json.JsonSerializer.DeserializeAsync(stream, JsonCodeGen.Default.GitHubAccessToken, token).ConfigureAwait(false); + if (!string.IsNullOrEmpty(result.AccessToken)) + return result.AccessToken; + + switch (result.Error) + { + case "authorization_pending": + break; + case "slow_down": + interval = result.Interval > 0 ? result.Interval : interval + 5; + break; + case "expired_token": + throw new GitHubException(App.Text("GitHub.SignIn.Expired")); + case "access_denied": + throw new GitHubException(App.Text("GitHub.SignIn.Denied")); + default: + throw new GitHubException(string.IsNullOrEmpty(result.ErrorDescription) ? result.Error : result.ErrorDescription); + } + } + + throw new GitHubException(App.Text("GitHub.SignIn.Expired")); + } + + public static async Task GetUserAsync(string accessToken, CancellationToken token) + { + using var req = CreateApiRequest("https://api.github.com/user", accessToken); + using var rsp = await s_client.SendAsync(req, token).ConfigureAwait(false); + await EnsureSuccessAsync(rsp, token).ConfigureAwait(false); + + await using var stream = await rsp.Content.ReadAsStreamAsync(token).ConfigureAwait(false); + return await System.Text.Json.JsonSerializer.DeserializeAsync(stream, JsonCodeGen.Default.GitHubUser, token).ConfigureAwait(false); + } + + /// + /// Lists every repository the user owns, collaborates on or can access through an organization. + /// + public static async Task> GetRepositoriesAsync(string accessToken, CancellationToken token) + { + var repos = new List(); + var url = "https://api.github.com/user/repos?per_page=100&affiliation=owner,collaborator,organization_member"; + + while (!string.IsNullOrEmpty(url)) + { + using var req = CreateApiRequest(url, accessToken); + using var rsp = await s_client.SendAsync(req, token).ConfigureAwait(false); + await EnsureSuccessAsync(rsp, token).ConfigureAwait(false); + + await using var stream = await rsp.Content.ReadAsStreamAsync(token).ConfigureAwait(false); + var page = await System.Text.Json.JsonSerializer.DeserializeAsync(stream, JsonCodeGen.Default.ListGitHubRepository, token).ConfigureAwait(false); + if (page != null) + repos.AddRange(page); + + url = GetNextPageUrl(rsp); + } + + return repos; + } + + /// + /// Returns `owner/name` (lower case) when the given remote URL points at a repository on github.com. + /// + public static string ParseFullName(string url) + { + if (string.IsNullOrEmpty(url)) + return null; + + var match = REG_GITHUB_URL().Match(url.Trim()); + if (!match.Success) + return null; + + return $"{match.Groups[1].Value}/{match.Groups[2].Value}".ToLowerInvariant(); + } + + /// + /// Collects the github.com repositories (`owner/name`, lower case) that the given local repositories + /// use as remotes. Reads the config files directly so it is cheap enough for hundreds of repositories. + /// + public static HashSet CollectClonedFullNames(IEnumerable repoPaths) + { + var outs = new HashSet(); + foreach (var path in repoPaths) + { + var config = Path.Combine(path, ".git", "config"); + if (!File.Exists(config)) + config = Path.Combine(path, "config"); + + try + { + if (!File.Exists(config)) + continue; + + foreach (var line in File.ReadLines(config)) + { + var trimmed = line.Trim(); + if (!trimmed.StartsWith("url", StringComparison.Ordinal)) + continue; + + var idx = trimmed.IndexOf('='); + if (idx < 0) + continue; + + var fullName = ParseFullName(trimmed.Substring(idx + 1)); + if (fullName != null) + outs.Add(fullName); + } + } + catch + { + // Ignore unreadable repositories. + } + } + + return outs; + } + + private static HttpRequestMessage CreateApiRequest(string url, string accessToken) + { + var req = new HttpRequestMessage(HttpMethod.Get, url); + req.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken); + req.Headers.Accept.ParseAdd("application/vnd.github+json"); + req.Headers.Add("X-GitHub-Api-Version", "2022-11-28"); + return req; + } + + private static async Task EnsureSuccessAsync(HttpResponseMessage rsp, CancellationToken token) + { + if (rsp.IsSuccessStatusCode) + return; + + var body = await rsp.Content.ReadAsStringAsync(token).ConfigureAwait(false); + var unauthorized = rsp.StatusCode == System.Net.HttpStatusCode.Unauthorized; + throw new GitHubException($"GitHub: {(int)rsp.StatusCode} {rsp.ReasonPhrase} {body}".Trim(), unauthorized); + } + + private static string GetNextPageUrl(HttpResponseMessage rsp) + { + if (!rsp.Headers.TryGetValues("Link", out var values)) + return null; + + foreach (var value in values) + { + var match = REG_NEXT_LINK().Match(value); + if (match.Success) + return match.Groups[1].Value; + } + + return null; + } + + private static HttpClient CreateClient() + { + var client = new HttpClient() { Timeout = TimeSpan.FromSeconds(30) }; + client.DefaultRequestHeaders.UserAgent.ParseAdd("SourceGit"); + client.DefaultRequestHeaders.Accept.ParseAdd("application/json"); + return client; + } + + [GeneratedRegex(@"^(?:https?://(?:[^@/]+@)?|ssh://(?:[^@/]+@)?|git@)github\.com[:/]([\w.-]+)/([\w.-]+?)(?:\.git)?/?$", RegexOptions.IgnoreCase)] + private static partial Regex REG_GITHUB_URL(); + + [GeneratedRegex(@"<([^>]+)>;\s*rel=""next""")] + private static partial Regex REG_NEXT_LINK(); + + private static readonly HttpClient s_client = CreateClient(); + } +} diff --git a/src/Models/Locales.cs b/src/Models/Locales.cs deleted file mode 100644 index 5bdb2431bc..0000000000 --- a/src/Models/Locales.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Collections.Generic; - -namespace SourceGit.Models -{ - public class Locale - { - public string Name { get; set; } - public string Key { get; set; } - - public static readonly List Supported = new List() { - new Locale("Deutsch", "de_DE"), - new Locale("Ελληνικά", "el_GR"), - new Locale("English", "en_US"), - new Locale("Español", "es_ES"), - new Locale("Français", "fr_FR"), - new Locale("עברית", "he_IL"), - new Locale("Bahasa Indonesia", "id_ID"), - new Locale("Italiano", "it_IT"), - new Locale("Português (Brasil)", "pt_BR"), - new Locale("Українська", "uk_UA"), - new Locale("Русский", "ru_RU"), - new Locale("简体中文", "zh_CN"), - new Locale("繁體中文", "zh_TW"), - new Locale("日本語", "ja_JP"), - new Locale("தமிழ் (Tamil)", "ta_IN"), - new Locale("한국어", "ko_KR"), - }; - - public Locale(string name, string key) - { - Name = name; - Key = key; - } - } -} diff --git a/src/Models/RepositoryUIStates.cs b/src/Models/RepositoryUIStates.cs index 0b35f8d618..195850d7c3 100644 --- a/src/Models/RepositoryUIStates.cs +++ b/src/Models/RepositoryUIStates.cs @@ -225,6 +225,18 @@ public string LastCommitMessage set; } = string.Empty; + public string SelectedNestedRepository + { + get; + set; + } = string.Empty; + + public string SelectedNestedWorktree + { + get; + set; + } = string.Empty; + public AvaloniaList HistoryFilters { get; diff --git a/src/Models/SelfUpdate.cs b/src/Models/SelfUpdate.cs index 9cf95a1489..d19532253a 100644 --- a/src/Models/SelfUpdate.cs +++ b/src/Models/SelfUpdate.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Reflection; using System.Text.Json.Serialization; @@ -18,11 +19,19 @@ public class Version [JsonPropertyName("body")] public string Body { get; set; } + [JsonPropertyName("assets")] + public List Assets { get; set; } = []; + + [JsonIgnore] + public bool IsReadyToInstall { get; set; } + [JsonIgnore] public System.Version CurrentVersion { get; } [JsonIgnore] - public string CurrentVersionStr => $"v{CurrentVersion.Major}.{CurrentVersion.Minor:D2}"; + public string CurrentVersionStr => CurrentVersion.Build > 0 + ? $"v{CurrentVersion.Major}.{CurrentVersion.Minor:D2}.{CurrentVersion.Build}" + : $"v{CurrentVersion.Major}.{CurrentVersion.Minor:D2}"; [JsonIgnore] public bool IsNewVersion => CurrentVersion.CompareTo(new System.Version(TagName.Substring(1))) < 0; @@ -37,6 +46,18 @@ public Version() } } + public class VersionAsset + { + [JsonPropertyName("name")] + public string Name { get; set; } + + [JsonPropertyName("browser_download_url")] + public string DownloadUrl { get; set; } + + [JsonPropertyName("digest")] + public string Digest { get; set; } + } + public class AlreadyUpToDate; public class SelfUpdateFailed diff --git a/src/Models/Shortcut.cs b/src/Models/Shortcut.cs new file mode 100644 index 0000000000..f2bc645ae5 --- /dev/null +++ b/src/Models/Shortcut.cs @@ -0,0 +1,415 @@ +using System; +using System.Collections.Generic; +using System.Text; + +using Avalonia.Input; +using CommunityToolkit.Mvvm.ComponentModel; + +namespace SourceGit.Models +{ + public enum ShortcutCategory + { + Global, + Repository, + NestedRepositories, + Diff, + MergeConflict, + InteractiveRebase, + } + + public class ShortcutGroup(string header, List items) + { + public string Header { get; } = header; + public List Items { get; } = items; + } + + public class Shortcut : ObservableObject + { + public string Id { get; } + public ShortcutCategory Category { get; } + public string DescriptionKey { get; } + public KeyGesture Default { get; } + + public string Description => App.Text(DescriptionKey); + public string DefaultDisplayText => Format(Default); + public string DisplayText => Format(_gesture); + public bool IsCustomized => !Equals(_gesture, Default); + + public KeyGesture Gesture + { + get => _gesture; + set + { + if (SetProperty(ref _gesture, value)) + { + OnPropertyChanged(nameof(DisplayText)); + OnPropertyChanged(nameof(IsCustomized)); + } + } + } + + public bool HasConflict + { + get => _hasConflict; + set => SetProperty(ref _hasConflict, value); + } + + public Shortcut(string id, ShortcutCategory category, string descriptionKey, KeyGesture defaultGesture) + { + Id = id; + Category = category; + DescriptionKey = descriptionKey; + Default = defaultGesture; + _gesture = defaultGesture; + } + + public bool Matches(KeyEventArgs e) + { + return _gesture != null && + e.KeyModifiers == _gesture.KeyModifiers && + NormalizeKey(e.Key) == NormalizeKey(_gesture.Key); + } + + /// + /// Matches the gesture with `extra` modifiers held down as well. Never matches when the gesture already + /// uses them. + /// + public bool Matches(KeyEventArgs e, KeyModifiers extra) + { + return _gesture != null && + (_gesture.KeyModifiers & extra) == 0 && + e.KeyModifiers == (_gesture.KeyModifiers | extra) && + NormalizeKey(e.Key) == NormalizeKey(_gesture.Key); + } + + public void Reset() + { + Gesture = Default; + } + + public static string Format(KeyGesture gesture) + { + if (gesture == null) + return string.Empty; + + var builder = new StringBuilder(); + var mods = gesture.KeyModifiers; + if (OperatingSystem.IsMacOS()) + { + if (mods.HasFlag(KeyModifiers.Meta)) + builder.Append("⌘+"); + if (mods.HasFlag(KeyModifiers.Control)) + builder.Append("⌃+"); + if (mods.HasFlag(KeyModifiers.Alt)) + builder.Append("⌥+"); + if (mods.HasFlag(KeyModifiers.Shift)) + builder.Append("⇧+"); + } + else + { + if (mods.HasFlag(KeyModifiers.Control)) + builder.Append("Ctrl+"); + if (mods.HasFlag(KeyModifiers.Alt)) + builder.Append("Alt+"); + if (mods.HasFlag(KeyModifiers.Shift)) + builder.Append("Shift+"); + if (mods.HasFlag(KeyModifiers.Meta)) + builder.Append(OperatingSystem.IsWindows() ? "Win+" : "Super+"); + } + + builder.Append(FormatKey(gesture.Key)); + return builder.ToString(); + } + + public static string Serialize(KeyGesture gesture) + { + if (gesture == null) + return string.Empty; + + var builder = new StringBuilder(); + if (gesture.KeyModifiers.HasFlag(KeyModifiers.Control)) + builder.Append("Ctrl+"); + if (gesture.KeyModifiers.HasFlag(KeyModifiers.Alt)) + builder.Append("Alt+"); + if (gesture.KeyModifiers.HasFlag(KeyModifiers.Shift)) + builder.Append("Shift+"); + if (gesture.KeyModifiers.HasFlag(KeyModifiers.Meta)) + builder.Append("Meta+"); + + builder.Append(gesture.Key.ToString()); + return builder.ToString(); + } + + public static bool TryDeserialize(string data, out KeyGesture gesture) + { + gesture = null; + if (string.IsNullOrEmpty(data)) + return true; + + var parts = data.Split('+', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries); + if (parts.Length == 0 || !Enum.TryParse(parts[^1], out var key) || key == Key.None) + return false; + + var mods = KeyModifiers.None; + for (int i = 0; i < parts.Length - 1; i++) + { + switch (parts[i]) + { + case "Ctrl": + mods |= KeyModifiers.Control; + break; + case "Alt": + mods |= KeyModifiers.Alt; + break; + case "Shift": + mods |= KeyModifiers.Shift; + break; + case "Meta": + mods |= KeyModifiers.Meta; + break; + default: + return false; + } + } + + gesture = new KeyGesture(key, mods); + return true; + } + + public static bool IsModifierKey(Key key) + { + return key is Key.LeftCtrl or Key.RightCtrl + or Key.LeftAlt or Key.RightAlt + or Key.LeftShift or Key.RightShift + or Key.LWin or Key.RWin + or Key.None; + } + + private static Key NormalizeKey(Key key) + { + if (key >= Key.NumPad0 && key <= Key.NumPad9) + return Key.D0 + (key - Key.NumPad0); + + return key; + } + + private static string FormatKey(Key key) + { + if (key >= Key.D0 && key <= Key.D9) + return ((char)('0' + (key - Key.D0))).ToString(); + + return key switch + { + Key.Enter => "Enter", + Key.Escape => "Esc", + Key.Back => "Backspace", + Key.PageUp => "PageUp", + Key.PageDown => "PageDown", + Key.OemComma => ",", + Key.OemPeriod => ".", + Key.OemPlus => "=", + Key.OemMinus => "-", + Key.OemTilde => "`", + Key.OemQuestion => "/", + Key.OemSemicolon => ";", + Key.OemQuotes => "'", + Key.OemOpenBrackets => "[", + Key.OemCloseBrackets => "]", + Key.OemPipe => "\\", + _ => key.ToString(), + }; + } + + private KeyGesture _gesture; + private bool _hasConflict = false; + } + + public static class Shortcuts + { + private static readonly bool s_isMacOS = OperatingSystem.IsMacOS(); + private static readonly KeyModifiers s_cmd = s_isMacOS ? KeyModifiers.Meta : KeyModifiers.Control; + + public static List All { get; } = []; + + public static event Action Changed; + + // Global + public static readonly Shortcut OpenPreferences = Add("OpenPreferences", ShortcutCategory.Global, "Hotkeys.Global.OpenPreferences", Key.OemComma, s_cmd); + public static readonly Shortcut OpenHotkeys = Add("OpenHotkeys", ShortcutCategory.Global, "Hotkeys", Key.F1); + public static readonly Shortcut NewTab = Add("NewTab", ShortcutCategory.Global, "Hotkeys.Global.NewTab", Key.T, s_cmd); + public static readonly Shortcut CloseTab = Add("CloseTab", ShortcutCategory.Global, "Hotkeys.Global.CloseTab", Key.W, s_cmd); + public static readonly Shortcut GotoPrevTab = s_isMacOS + ? Add("GotoPrevTab", ShortcutCategory.Global, "Hotkeys.Global.GotoPrevTab", Key.Left, s_cmd | KeyModifiers.Alt) + : Add("GotoPrevTab", ShortcutCategory.Global, "Hotkeys.Global.GotoPrevTab", Key.Tab, s_cmd | KeyModifiers.Shift); + public static readonly Shortcut GotoNextTab = s_isMacOS + ? Add("GotoNextTab", ShortcutCategory.Global, "Hotkeys.Global.GotoNextTab", Key.Right, s_cmd | KeyModifiers.Alt) + : Add("GotoNextTab", ShortcutCategory.Global, "Hotkeys.Global.GotoNextTab", Key.Tab, s_cmd); + public static readonly Shortcut Clone = Add("Clone", ShortcutCategory.Global, "Hotkeys.Global.Clone", Key.R, s_cmd); + public static readonly Shortcut OpenLocalRepository = Add("OpenLocalRepository", ShortcutCategory.Global, "Hotkeys.Global.OpenLocalRepository", Key.L, s_cmd); + public static readonly Shortcut ShowWorkspaceMenu = Add("ShowWorkspaceMenu", ShortcutCategory.Global, "Hotkeys.Global.ShowWorkspaceDropdownMenu", Key.P, s_cmd | KeyModifiers.Alt); + public static readonly Shortcut SwitchTab = Add("SwitchTab", ShortcutCategory.Global, "Hotkeys.Global.SwitchTab", Key.P, s_cmd); + public static readonly Shortcut ZoomIn = Add("ZoomIn", ShortcutCategory.Global, "Hotkeys.Global.ZoomIn", Key.OemPlus, s_cmd); + public static readonly Shortcut ZoomOut = Add("ZoomOut", ShortcutCategory.Global, "Hotkeys.Global.ZoomOut", Key.OemMinus, s_cmd); + public static readonly Shortcut OpenTerminal = Add("OpenTerminal", ShortcutCategory.Global, "Welcome.OpenTerminal", Key.OemTilde, KeyModifiers.Control); + public static readonly Shortcut Search = Add("Search", ShortcutCategory.Global, "Hotkeys.Global.Search", Key.F, s_cmd); + public static readonly Shortcut Quit = Add("Quit", ShortcutCategory.Global, "Quit", Key.Q, s_cmd); + + // Repository + public static readonly Shortcut ViewHistories = Add("ViewHistories", ShortcutCategory.Repository, "Hotkeys.Repo.ViewDashboard", Key.D1, s_cmd); + public static readonly Shortcut ViewChanges = Add("ViewChanges", ShortcutCategory.Repository, "Hotkeys.Repo.ViewChanges", Key.D2, s_cmd); + public static readonly Shortcut ViewStashes = Add("ViewStashes", ShortcutCategory.Repository, "Hotkeys.Repo.ViewStashes", Key.D3, s_cmd); + public static readonly Shortcut ToggleSearchCommits = Add("ToggleSearchCommits", ShortcutCategory.Repository, "Hotkeys.Repo.ToggleSearchCommits", Key.F, s_cmd | KeyModifiers.Shift); + public static readonly Shortcut OpenCommandPalette = Add("OpenCommandPalette", ShortcutCategory.Repository, "Hotkeys.Repo.OpenCommandPalette", Key.P, s_cmd | KeyModifiers.Shift); + public static readonly Shortcut Commit = Add("Commit", ShortcutCategory.Repository, "Hotkeys.Repo.Commit", Key.Enter, s_cmd); + public static readonly Shortcut CommitWithAutoStage = Add("CommitWithAutoStage", ShortcutCategory.Repository, "Hotkeys.Repo.CommitWithAutoStage", Key.Enter, s_cmd | KeyModifiers.Shift); + public static readonly Shortcut CommitAndPush = Add("CommitAndPush", ShortcutCategory.Repository, "Hotkeys.Repo.CommitAndPush", Key.Enter, s_cmd | KeyModifiers.Alt); + public static readonly Shortcut CreateBranch = Add("CreateBranch", ShortcutCategory.Repository, "Hotkeys.Repo.CreateBranch", Key.B, s_cmd); + public static readonly Shortcut CreateBranchFromCommit = Add("CreateBranchFromCommit", ShortcutCategory.Repository, "Hotkeys.Repo.CreateBranchFromCommit", Key.B, s_cmd | KeyModifiers.Shift); + public static readonly Shortcut CreateTagFromCommit = Add("CreateTagFromCommit", ShortcutCategory.Repository, "Hotkeys.Repo.CreateTagFromCommit", Key.T, s_cmd | KeyModifiers.Shift); + public static readonly Shortcut Fetch = Add("Fetch", ShortcutCategory.Repository, "Hotkeys.Repo.Fetch", Key.Down, s_cmd); + public static readonly Shortcut Pull = Add("Pull", ShortcutCategory.Repository, "Hotkeys.Repo.Pull", Key.Down, s_cmd | KeyModifiers.Shift); + public static readonly Shortcut Push = Add("Push", ShortcutCategory.Repository, "Hotkeys.Repo.Push", Key.Up, s_cmd | KeyModifiers.Shift); + public static readonly Shortcut OpenInFileManager = Add("OpenInFileManager", ShortcutCategory.Repository, "Repository.Explore", Key.E, s_cmd); + public static readonly Shortcut OpenInVSCode = Add("OpenInVSCode", ShortcutCategory.Repository, "Hotkeys.Repo.OpenInVSCode", Key.E, s_cmd | KeyModifiers.Shift); + public static readonly Shortcut CopyRepositoryPath = Add("CopyRepositoryPath", ShortcutCategory.Repository, "Hotkeys.Repo.CopyPath", Key.C, s_isMacOS ? s_cmd | KeyModifiers.Control : s_cmd | KeyModifiers.Alt); + public static readonly Shortcut ToggleCommitDetailPanel = Add("ToggleCommitDetailPanel", ShortcutCategory.Repository, "Hotkeys.Repo.ToggleCommitDetailPanel", Key.J, s_cmd); + public static readonly Shortcut OpenCommitDetailStandalone = Add("OpenCommitDetailStandalone", ShortcutCategory.Repository, "HistoriesDetailsStandalone", Key.N, s_cmd); + public static readonly Shortcut GoToParent = Add("GoToParent", ShortcutCategory.Repository, "Hotkeys.Repo.GoToParent", Key.Down, KeyModifiers.Alt); + public static readonly Shortcut GoToChild = Add("GoToChild", ShortcutCategory.Repository, "Hotkeys.Repo.GoToChild", Key.Up, KeyModifiers.Alt); + public static readonly Shortcut OpenFileWithDefaultEditor = Add("OpenFileWithDefaultEditor", ShortcutCategory.Repository, "Hotkeys.Repo.OpenFileWithDefaultEditor", Key.O, s_cmd); + public static readonly Shortcut Refresh = Add("Refresh", ShortcutCategory.Repository, "Hotkeys.Repo.Refresh", Key.F5); + + // Nested repositories + public static readonly Shortcut FetchAllRepositories = Add("FetchAllRepositories", ShortcutCategory.NestedRepositories, "NestedRepos.FetchAll", Key.F, s_cmd | KeyModifiers.Alt | KeyModifiers.Shift); + public static readonly Shortcut PullAllRepositories = Add("PullAllRepositories", ShortcutCategory.NestedRepositories, "NestedRepos.PullAll", Key.Down, s_cmd | KeyModifiers.Alt | KeyModifiers.Shift); + public static readonly Shortcut PushAllRepositories = Add("PushAllRepositories", ShortcutCategory.NestedRepositories, "NestedRepos.PushAll", Key.Up, s_cmd | KeyModifiers.Alt | KeyModifiers.Shift); + public static readonly Shortcut RefreshAllRepositories = Add("RefreshAllRepositories", ShortcutCategory.NestedRepositories, "NestedRepos.Refresh", Key.F5, KeyModifiers.Shift); + public static readonly Shortcut SelectPrevRepository = Add("SelectPrevRepository", ShortcutCategory.NestedRepositories, "Hotkeys.NestedRepos.SelectPrev", Key.Up, KeyModifiers.Alt | KeyModifiers.Shift); + public static readonly Shortcut SelectNextRepository = Add("SelectNextRepository", ShortcutCategory.NestedRepositories, "Hotkeys.NestedRepos.SelectNext", Key.Down, KeyModifiers.Alt | KeyModifiers.Shift); + + // Diff + public static readonly Shortcut GotoFirstChange = Add("GotoFirstChange", ShortcutCategory.Diff, "Diff.First", Key.Home, s_cmd | KeyModifiers.Alt); + public static readonly Shortcut GotoPrevChange = Add("GotoPrevChange", ShortcutCategory.Diff, "Diff.Prev", Key.Up, s_cmd | KeyModifiers.Alt); + public static readonly Shortcut GotoNextChange = Add("GotoNextChange", ShortcutCategory.Diff, "Diff.Next", Key.Down, s_cmd | KeyModifiers.Alt); + public static readonly Shortcut GotoLastChange = Add("GotoLastChange", ShortcutCategory.Diff, "Diff.Last", Key.End, s_cmd | KeyModifiers.Alt); + public static readonly Shortcut OpenExternalMergeTool = Add("OpenExternalMergeTool", ShortcutCategory.Diff, "Diff.UseMerger", Key.D, s_cmd | KeyModifiers.Shift); + public static readonly Shortcut StageChunk = Add("StageChunk", ShortcutCategory.Diff, "Hunk.Stage", Key.S, s_cmd); + public static readonly Shortcut UnstageChunk = Add("UnstageChunk", ShortcutCategory.Diff, "Hunk.Unstage", Key.U, s_cmd); + public static readonly Shortcut DiscardChunk = Add("DiscardChunk", ShortcutCategory.Diff, "Hunk.Discard", Key.D, s_cmd); + + // Merge conflict editor + public static readonly Shortcut PrevConflict = Add("PrevConflict", ShortcutCategory.MergeConflict, "MergeConflictEditor.PrevConflict", Key.Up, s_cmd); + public static readonly Shortcut NextConflict = Add("NextConflict", ShortcutCategory.MergeConflict, "MergeConflictEditor.NextConflict", Key.Down, s_cmd); + public static readonly Shortcut SaveAndStageConflict = Add("SaveAndStageConflict", ShortcutCategory.MergeConflict, "MergeConflictEditor.SaveAndStage", Key.S, s_cmd); + + // Interactive rebase + public static readonly Shortcut RebaseMoveUp = Add("RebaseMoveUp", ShortcutCategory.InteractiveRebase, "Hotkeys.InteractiveRebase.MoveUp", Key.Up, s_cmd); + public static readonly Shortcut RebaseMoveDown = Add("RebaseMoveDown", ShortcutCategory.InteractiveRebase, "Hotkeys.InteractiveRebase.MoveDown", Key.Down, s_cmd); + public static readonly Shortcut RebasePick = Add("RebasePick", ShortcutCategory.InteractiveRebase, "Hotkeys.InteractiveRebase.Pick", Key.P); + public static readonly Shortcut RebaseEdit = Add("RebaseEdit", ShortcutCategory.InteractiveRebase, "Hotkeys.InteractiveRebase.Edit", Key.E); + public static readonly Shortcut RebaseReword = Add("RebaseReword", ShortcutCategory.InteractiveRebase, "Hotkeys.InteractiveRebase.Reword", Key.R); + public static readonly Shortcut RebaseSquash = Add("RebaseSquash", ShortcutCategory.InteractiveRebase, "Hotkeys.InteractiveRebase.Squash", Key.S); + public static readonly Shortcut RebaseFixup = Add("RebaseFixup", ShortcutCategory.InteractiveRebase, "Hotkeys.InteractiveRebase.Fixup", Key.F); + public static readonly Shortcut RebaseDrop = Add("RebaseDrop", ShortcutCategory.InteractiveRebase, "Hotkeys.InteractiveRebase.Drop", Key.D); + + public static List GetGroups() + { + var groups = new List(); + foreach (var category in Enum.GetValues()) + { + var items = All.FindAll(x => x.Category == category); + var header = category switch + { + ShortcutCategory.Global => "Hotkeys.Global", + ShortcutCategory.Repository => "Hotkeys.Repo", + ShortcutCategory.NestedRepositories => "NestedRepos", + ShortcutCategory.Diff => "Hotkeys.Diff", + ShortcutCategory.MergeConflict => "Hotkeys.MergeConflict", + _ => "Hotkeys.InteractiveRebase", + }; + + groups.Add(new ShortcutGroup(App.Text(header), items)); + } + + return groups; + } + + public static void ResetAll() + { + foreach (var shortcut in All) + shortcut.Reset(); + + NotifyChanged(); + } + + public static void Load(Dictionary custom) + { + foreach (var shortcut in All) + { + if (custom != null && custom.TryGetValue(shortcut.Id, out var data) && Shortcut.TryDeserialize(data, out var gesture)) + shortcut.Gesture = gesture; + else + shortcut.Reset(); + } + + NotifyChanged(); + } + + public static Dictionary Export() + { + var custom = new Dictionary(); + foreach (var shortcut in All) + { + if (shortcut.IsCustomized) + custom[shortcut.Id] = Shortcut.Serialize(shortcut.Gesture); + } + + return custom; + } + + public static void NotifyChanged() + { + UpdateConflicts(); + Changed?.Invoke(); + } + + private static void UpdateConflicts() + { + foreach (var shortcut in All) + { + var conflict = false; + if (shortcut.Gesture != null) + { + foreach (var other in All) + { + if (other != shortcut && CanConflict(shortcut.Category, other.Category) && shortcut.Gesture.Equals(other.Gesture)) + { + conflict = true; + break; + } + } + } + + shortcut.HasConflict = conflict; + } + } + + private static bool CanConflict(ShortcutCategory a, ShortcutCategory b) + { + // Merge conflict editor and interactive rebase run in their own windows, so they only + // share their window with global shortcuts. + if (a == b || a == ShortcutCategory.Global || b == ShortcutCategory.Global) + return true; + + return a is ShortcutCategory.Repository or ShortcutCategory.NestedRepositories or ShortcutCategory.Diff && + b is ShortcutCategory.Repository or ShortcutCategory.NestedRepositories or ShortcutCategory.Diff; + } + + private static Shortcut Add(string id, ShortcutCategory category, string descriptionKey, Key key, KeyModifiers modifiers = KeyModifiers.None) + { + var shortcut = new Shortcut(id, category, descriptionKey, new KeyGesture(key, modifiers)); + All.Add(shortcut); + return shortcut; + } + } +} diff --git a/src/Native/MacOS.cs b/src/Native/MacOS.cs index 06d09e8fa3..41c8039e32 100644 --- a/src/Native/MacOS.cs +++ b/src/Native/MacOS.cs @@ -18,11 +18,19 @@ internal class MacOS : OS.IBackend [DllImport("/usr/lib/libSystem.B.dylib", SetLastError = true)] private static extern int kill(int pid, int sig); + [DllImport("/usr/lib/libSystem.B.dylib")] + private static extern void _exit(int status); + public MacOS() { _setsidExecutable = Path.Combine(Path.GetDirectoryName(Environment.ProcessPath), "setsid"); } + public static void ExitWithoutCleanup(int code) + { + _exit(code); + } + public void SetupApp(AppBuilder builder) { builder.With(new MacOSPlatformOptions() diff --git a/src/Native/SecretStore.cs b/src/Native/SecretStore.cs new file mode 100644 index 0000000000..03cf86251d --- /dev/null +++ b/src/Native/SecretStore.cs @@ -0,0 +1,223 @@ +using System; +using System.Diagnostics; +using System.IO; +using System.Runtime.InteropServices; +using System.Text; + +namespace SourceGit.Native +{ + /// + /// Stores small secrets (access tokens) in the OS credential store: the login keychain on macOS, the Windows + /// Credential Manager, and libsecret on Linux (falling back to a file only readable by the user). + /// + public static class SecretStore + { + public static string Get(string key) + { + try + { + if (OperatingSystem.IsMacOS()) + return Run("/usr/bin/security", $"find-generic-password -s {Service} -a {key} -w", null); + + if (OperatingSystem.IsWindows()) + return WindowsRead($"{Service}:{key}"); + + var secret = Run("secret-tool", $"lookup service {Service} account {key}", null); + if (secret != null) + return secret; + + var file = GetFallbackFile(key); + return File.Exists(file) ? File.ReadAllText(file).Trim() : null; + } + catch (Exception e) + { + OS.LogException(e); + return null; + } + } + + public static bool Set(string key, string secret) + { + try + { + if (OperatingSystem.IsMacOS()) + { + // Interactive mode reads the command from stdin, so the secret never shows up in the process list. + return Run("/usr/bin/security", "-i", $"add-generic-password -U -s {Service} -a {key} -w \"{secret}\"\n") != null; + } + + if (OperatingSystem.IsWindows()) + return WindowsWrite($"{Service}:{key}", secret); + + if (Run("secret-tool", $"store --label=\"SourceGit ({key})\" service {Service} account {key}", secret) != null) + return true; + + var file = GetFallbackFile(key); + File.WriteAllText(file, string.Empty); + File.SetUnixFileMode(file, UnixFileMode.UserRead | UnixFileMode.UserWrite); + File.WriteAllText(file, secret); + return true; + } + catch (Exception e) + { + OS.LogException(e); + return false; + } + } + + public static void Delete(string key) + { + try + { + if (OperatingSystem.IsMacOS()) + { + Run("/usr/bin/security", $"delete-generic-password -s {Service} -a {key}", null); + } + else if (OperatingSystem.IsWindows()) + { + CredDeleteW($"{Service}:{key}", CRED_TYPE_GENERIC, 0); + } + else + { + Run("secret-tool", $"clear service {Service} account {key}", null); + + var file = GetFallbackFile(key); + if (File.Exists(file)) + File.Delete(file); + } + } + catch (Exception e) + { + OS.LogException(e); + } + } + + /// + /// Runs a tool and returns its trimmed stdout, or null when it can not be started or fails. + /// + private static string Run(string file, string args, string stdin) + { + var start = new ProcessStartInfo(file, args) + { + UseShellExecute = false, + CreateNoWindow = true, + RedirectStandardInput = true, + RedirectStandardOutput = true, + RedirectStandardError = true, + }; + + Process proc; + try + { + proc = Process.Start(start); + } + catch + { + return null; + } + + if (proc == null) + return null; + + using (proc) + { + if (stdin != null) + proc.StandardInput.Write(stdin); + proc.StandardInput.Close(); + + var output = proc.StandardOutput.ReadToEnd(); + proc.StandardError.ReadToEnd(); + proc.WaitForExit(); + return proc.ExitCode == 0 ? output.Trim() : null; + } + } + + private static string GetFallbackFile(string key) + { + return Path.Combine(OS.BasicDirectories.ConfigDir, $"{key}.secret"); + } + + private static string WindowsRead(string target) + { + if (!CredReadW(target, CRED_TYPE_GENERIC, 0, out var ptr)) + return null; + + try + { + var cred = Marshal.PtrToStructure(ptr); + if (cred.CredentialBlob == IntPtr.Zero || cred.CredentialBlobSize == 0) + return null; + + return Marshal.PtrToStringUni(cred.CredentialBlob, (int)cred.CredentialBlobSize / 2); + } + finally + { + CredFree(ptr); + } + } + + private static bool WindowsWrite(string target, string secret) + { + var blob = Encoding.Unicode.GetBytes(secret); + var blobPtr = Marshal.AllocHGlobal(blob.Length); + var targetPtr = Marshal.StringToHGlobalUni(target); + var userPtr = Marshal.StringToHGlobalUni(Environment.UserName); + + try + { + Marshal.Copy(blob, 0, blobPtr, blob.Length); + + var cred = new CREDENTIAL() + { + Type = CRED_TYPE_GENERIC, + TargetName = targetPtr, + CredentialBlobSize = (uint)blob.Length, + CredentialBlob = blobPtr, + Persist = CRED_PERSIST_LOCAL_MACHINE, + UserName = userPtr, + }; + + return CredWriteW(ref cred, 0); + } + finally + { + Marshal.FreeHGlobal(blobPtr); + Marshal.FreeHGlobal(targetPtr); + Marshal.FreeHGlobal(userPtr); + } + } + + [StructLayout(LayoutKind.Sequential)] + private struct CREDENTIAL + { + public uint Flags; + public uint Type; + public IntPtr TargetName; + public IntPtr Comment; + public long LastWritten; + public uint CredentialBlobSize; + public IntPtr CredentialBlob; + public uint Persist; + public uint AttributeCount; + public IntPtr Attributes; + public IntPtr TargetAlias; + public IntPtr UserName; + } + + [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)] + private static extern bool CredReadW(string target, uint type, uint flags, out IntPtr credential); + + [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)] + private static extern bool CredWriteW(ref CREDENTIAL credential, uint flags); + + [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)] + private static extern bool CredDeleteW(string target, uint type, uint flags); + + [DllImport("advapi32.dll")] + private static extern void CredFree(IntPtr buffer); + + private const string Service = "SourceGit"; + private const uint CRED_TYPE_GENERIC = 1; + private const uint CRED_PERSIST_LOCAL_MACHINE = 2; + } +} diff --git a/src/Resources/Icons.axaml b/src/Resources/Icons.axaml index a410aef45f..9354975552 100644 --- a/src/Resources/Icons.axaml +++ b/src/Resources/Icons.axaml @@ -5,6 +5,7 @@ M233 163h560c11 0 20-9 20-20V63h-226c-6-36-37-63-74-63s-68 27-74 63h-226v80c0 11 9 20 20 20zM883 63h-10v112c0 33-27 60-60 60h-600c-33 0-60-27-60-60V63h-10c-44 0-80 36-80 80v801c0 44 36 80 80 80h740c44 0 80-36 80-80V143c0-44-36-80-80-80zm-720 469c0-24 20-44 44-44h62v-72c0-24 20-44 44-44s44 20 44 44v72h62c24 0 44 20 44 44s-20 44-44 44h-62v72c0 24-20 44-44 44s-44-20-44-44v-72h-62c-24 0-44-20-44-44zm700 307c0 24-20 44-44 44h-612c-24 0-44-20-44-44s20-44 44-44h612c24 0 44 20 44 44zm0-191c0 24-20 44-44 44h-232c-24 0-44-20-44-44s20-44 44-44h232c24 0 44 20 44 44zm0-191c0 24-20 44-44 44h-162c-24 0-44-20-44-44s20-44 44-44h162c24 0 44 20 44 44z M366 146l293 0 0-73-293 0 0 73zm658 366 0 274q0 38-27 65t-65 27l-841 0q-38 0-65-27t-27-65l0-274 384 0 0 91q0 15 11 26t26 11l183 0q15 0 26-11t11-26l0-91 384 0zm-439 0 0 73-146 0 0-73 146 0zm439-274 0 219-1024 0 0-219q0-38 27-65t65-27l201 0 0-91q0-23 16-39t39-16l329 0q23 0 39 16t16 39l0 91 201 0q38 0 65 27t27 65z M567 192C385 192 238 335 238 512H128l142 138 3 5L421 512H311c0-138 114-249 256-249s256 111 256 249c0 138-114 249-256 249a258 258 0 01-181-73l-52 51A332 332 0 00567 832C749 832 896 689 896 512S749 192 567 192zm-37 178v178l155 90 28-46-129-74v-148H530z + M0 8.877L2.247 5.91l8.405-3.416V.022l7.37 5.393L2.966 8.338v8.225L0 15.707zm24-4.45v14.651l-5.753 4.9-9.303-3.057v3.056l-5.978-7.416 15.057 1.798V5.415z M851 755q0 23-16 39l-78 78q-16 16-39 16t-39-16l-168-168-168 168q-16 16-39 16t-39-16l-78-78q-16-16-16-39t16-39l168-168-168-168q-16-16-16-39t16-39l78-78q16-16 39-16t39 16l168 168 168-168q16-16 39-16t39 16l78 78q16 16 16 39t-16 39l-168 168 168 168q16 16 16 39z M71 1024V0h661L953 219V1024H71zm808-731-220-219H145V951h735V293zM439 512h-220V219h220V512zm-74-219H292v146h74v-146zm0 512h74v73h-220v-73H292v-146H218V585h147v219zm294-366h74V512H512v-73h74v-146H512V219h147v219zm74 439H512V585h220v293zm-74-219h-74v146h74v-146z M128 384a43 43 0 0043-43V213a43 43 0 0143-43h128a43 43 0 000-85H213a128 128 0 00-128 128v128a43 43 0 0043 43zm213 469H213a43 43 0 01-43-43v-128a43 43 0 00-85 0v128a128 128 0 00128 128h128a43 43 0 000-85zm384-299a43 43 0 000-85h-49A171 171 0 00555 347V299a43 43 0 00-85 0v49A171 171 0 00347 469H299a43 43 0 000 85h49A171 171 0 00469 677V725a43 43 0 0085 0v-49A171 171 0 00677 555zm-213 43a85 85 0 1185-85 85 85 0 01-85 85zm384 43a43 43 0 00-43 43v128a43 43 0 01-43 43h-128a43 43 0 000 85h128a128 128 0 00128-128v-128a43 43 0 00-43-43zM811 85h-128a43 43 0 000 85h128a43 43 0 0143 43v128a43 43 0 0085 0V213a128 128 0 00-128-128z diff --git a/src/Resources/Locales/de_DE.axaml b/src/Resources/Locales/de_DE.axaml deleted file mode 100644 index fee376aad9..0000000000 --- a/src/Resources/Locales/de_DE.axaml +++ /dev/null @@ -1,1036 +0,0 @@ - - - - - - Info - Über SourceGit - Veröffentlichungsdatum: {0} - Versionshinweise - Open Source & freier Git GUI-Client - Zu ignorierende Datei(en) hinzufügen - Muster: - Speichern in Datei: - Worktree hinzufügen - Ordner: - Pfad für diesen Worktree. Relative Pfade werden unterstützt. - Branch-Name: - Optional. Standard ist der Name des Zielordners. - Branch verfolgen: - Remote-Branch verfolgen - Was auschecken: - Neuen Branch erstellen - Existierender Branch - AI-Assistent - Modell - NEU GENERIEREN - Verwende AI, um Commit-Nachrichten zu generieren - Übernehmen - SourceGit minimieren - Andere ausblenden - Alles anzeigen - 3-Way Merge - Wähle die anzuwendende patch-Datei - Ignoriere Leerzeichen-Änderungen - Quelle: - Datei - Zwischenablage - Patch anwenden - Leerzeichen: - Stash anwenden - Nach dem Anwenden löschen - Änderungen des Index wiederherstellen - Stash: - Archivieren… - Speichere Archiv in: - Wähle einen Archivpfad aus - Revision: - Archiv erstellen - SourceGit-Askpass - Passphrase eingeben: - ALS UNVERÄNDERT ANGENOMMENE DATEIEN - KEINE ALS UNVERÄNDERT ANGENOMMENEN DATEIEN - Bild laden… - Aktualisieren - Bisect - Abbrechen - Schlecht - Gut - Überspringen - Bisecting. Einen anderen Commit auschecken und als gut oder schlecht markieren. - Bisecting. Aktuellen Commit als schlecht markieren oder einen anderen auschecken und als schlecht markieren. - Bisecting. Aktuellen Commit als gut oder schlecht markieren und einen anderen auschecken. - Bisecting. Ist der aktuelle HEAD gut oder schlecht? - Blame - Blame auf vorheriger Revision - Leerzeichen-Änderungen ignorieren - BLAME WIRD BEI DIESER DATEI NICHT UNTERSTÜTZT!!! - Auschecken von ${0}$… - Ausgewählte 2 Branches vergleichen - Vergleichen mit… - Vergleichen mit HEAD - Vergleichen mit ${0}$ - Branch-Namen kopieren - PR erstellen… - PR für Upstream ${0}$ erstellen… - Benutzerdefinierte Aktion - Lösche ${0}$… - Lösche ausgewählte {0} Branches - Beschreibung für ${0}$ bearbeiten… - Fast-Forward zu ${0}$ - Fetche ${0}$ in ${1}$ hinein… - Git Flow – Abschließen ${0}$ - Interaktives Rebase von ${0}$ auf ${1}$ - Merge ${0}$ in ${1}$ hinein… - Merge ausgewählte {0} Branches in aktuellen hinein - Pull ${0}$ - Pull ${0}$ in ${1}$ hinein… - Push ${0}$ - Rebase ${0}$ auf ${1}$… - Benenne ${0}$ um… - Setze ${0}$ zurück auf ${1}$… - Zu ${0}$ wechseln (Worktree) - Setze verfolgten Branch… - {0} Commit(s) voraus - {0} Commit(s) voraus, {1} Commit(s) zurück - {0} Commit(s) zurück - Ungültig - REMOTE - STATUS - VERFOLGT - URL - WORKTREE - ABBRECHEN - Auf Vorgänger-Revision zurücksetzen - Auf diese Revision zurücksetzen - Generiere Commit-Nachricht - Merge (integriert) - Merge (extern) - Datei(en) auf ${0}$ zurücksetzen - ANZEIGEMODUS ÄNDERN - Zeige als Datei- und Ordnerliste - Zeige als Pfadliste - Zeige als Dateisystem-Baumstruktur - Ändere URL des Submoduls - Submodul: - URL: - Branch auschecken - Lokale Änderungen: - Branch: - Dein aktueller HEAD enthält Commit(s) ohne Verbindung zu einem Branch / Tag. Möchtest du trotzdem fortfahren? - Die folgenden Submodule müssen aktualisiert werden:{0}Möchtest du sie aktualisieren? - Auschecken & Fast Forward - Fast Forward zu: - Branch aus Stash auschecken - Neuer Branch: - Stash: - Commit oder Tag auschecken - Ziel: - Achtung: Danach ist HEAD losgelöst (‚detached‘) - Cherry Pick - Quelle an Commit-Nachricht anhängen - Commit(s): - Alle Änderungen committen - Hauptlinie: - Normalerweise ist es nicht möglich, einen Merge zu cherry-picken, da unklar ist, welche Seite des Merges als Hauptlinie anzusehen 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? - Remote-Repository klonen - Extra-Parameter: - Zusätzliche Argumente für das Klonen des Repositorys. Optional. - Lesezeichen: - Gruppe: - Lokaler Name: - Repository-Name. Optional. - Übergeordnetes Verzeichnis: - Submodule initialisieren und aktualisieren - Repository-URL: - SCHLIESSEN - Editor - Branches - Branches & Tags - Benutzerdefinierte Repository-Aktionen - Dateien der Revision - Commit auschecken - Diesen Commit cherry-picken - Mehrere cherry-picken… - Vergleiche mit HEAD - Vergleiche mit Worktree - Autor - Autor-Zeitpunkt - Commit-Nachricht - Committer - Committer-Zeitpunkt - SHA - Betreff - Benutzerdefinierte Aktion - Interaktives Rebase - Entfernen… - Bearbeiten… - Fixup in den Vorgänger… - Interaktives Rebase von ${0}$ auf ${1}$ - Umformulieren… - Squash in den Vorgänger… - Merge… - Push ${0}$ zu ${1}$ - Rebase ${0}$ auf ${1}$ - Setze ${0}$ auf ${1}$ zurück - Commit rückgängig machen - Als Patch speichern… - ÄNDERUNGEN - geänderte Datei(en) - Änderungen durchsuchen… - Details einklappen - DATEIEN - LFS-DATEI - Dateien durchsuchen… - Submodul - INFORMATION - AUTOR - COMMITTER - Prüfe Refs, die diesen Commit enthalten - COMMIT ENTHALTEN IN - E-Mail-Adresse kopieren - Namen kopieren - Namen & E-Mail-Adresse kopieren - Zeigt nur die ersten 100 Änderungen. Alle Änderungen siehe Registerkarte ‚ÄNDERUNGEN‘. - Schlüssel: - COMMIT-NACHRICHT - VORGÄNGER - REFS - SHA - Unterzeichner: - Im Browser öffnen - SPALTE - Commit-Nachricht eingeben. Leerzeile zum Trennen von Betreff und Beschreibung verwenden! - BETREFF - Vergleichen - ÄNDERUNGEN - COMMITS - NUR LINKS VORHANDENE COMMITS - NUR RECHTS VORHANDENE COMMITS - Tipp: Wenn die andere Seite HEAD ist, kannst du ausgewählte Commits über das Kontextmenü cherry-picken. - Repository-Einstellungen - COMMIT-VORLAGE - 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 - Vorlageninhalt: - Vorlagenname: - BENUTZERDEFINIERTE AKTION - Argumente: - 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} Benutzerfreundlicher Name des selektierten Branches, enthält ${REMOTE}-Teil für Remote-Branches -${SHA} Hash des selektierten Commits -${TAG} Ausgewählter Tag -${FILE} Ausgewählte Datei, relativ zum Stammverzeichnis des Repositorys -$1, $2, … Werte der Eingabe-Steuerelemente - Ausführbare Datei: - Eingabe-Steuerelemente: - Bearbeiten - Name: - Geltungsbereich: - Branch - Commit - Datei - Remote - Repository - Tag - Auf Beenden der Aktion warten - E-Mail-Adresse - E-Mail-Adresse - GIT - Vor dem Auto-Aktualisieren von Submodulen fragen - Remotes automatisch fetchen - Minute(n) - Konventionelle Commit-Typen - Standard-Remote - `--recursive` beim Auto-Aktualisieren von Submodulen verwenden - 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 - Beispiel für Gitlab-Issue-Regel hinzufügen - Beispiel für Gitlab-Merge-Request-Regel hinzufügen - Beispiel für Jira-Regel hinzufügen - Neue Regel - Regulärer Ausdruck für Ticket-ID: - Name: - Diese Regel per .issuetracker-Datei teilen - Ergebnis-URL: - Verwende bitte $1, $2, um auf Regex-Gruppenwerte zuzugreifen. - OPEN AI - Bevorzugter Dienst: - Der ausgewählte ‚Bevorzugte Dienst‘ wird nur in diesem Repository gesetzt und verwendet. Wenn keiner gesetzt ist und mehrere Dienste verfügbar sind, wird ein Kontextmenü zur Auswahl angezeigt. - HTTP-Proxy - HTTP-Proxy für dieses Repository - Benutzername - Benutzername für dieses Repository - Bearbeite Steuerelemente für benutzerdefinierte Aktionen - Wert bei Markierung: - Falls ausgewählt, wird dieser Wert in Kommandozeilen-Argumenten benutzt - Beschreibung: - Standardwert: - Auf Ordner einschränken - Bezeichnung: - Einträge: - Nutze ‚|‘, um Einträge zu trennen - String-Formatierung: - Optional. Formatiert die Ausgabe. Wird ignoriert, wenn die Eingabe leer ist. Verwende bitte `${VALUE}` als Platzhalter für die Eingabe. - Die vordefinierten Parameter ${REPO}, ${REMOTE}, ${BRANCH}, ${BRANCH_FRIENDLY_NAME}, ${SHA}, ${FILE} und ${TAG} bleiben hier verwendbar - Typ: - Kurznamen verwenden: - Arbeitsumgebungen - Farbe - Name - Offene Registerkarten beim Programmstart wiederherstellen - WEITER - Leerer Commit erkannt! Möchtest du trotzdem fortfahren (--allow-empty)? - ALLES STAGEN & COMMITTEN - AUSGEWÄHLTE STAGEN & COMMITTEN - Leerer Commit erkannt! Möchtest du trotzdem fortfahren (--allow-empty) oder alle Änderungen stagen und dann committen? - Neustart erforderlich - Du musst dieses Programm neustarten, um die Änderungen zu übernehmen. - Konventionelle Commit-Hilfe - Breaking Change: - Geschlossenes Ticket: - Änderungen im Detail: - Geltungsbereich: - Kurzbeschreibung: - Typ der Änderung: - Kopieren - Gesamten Text kopieren - Als Patch kopieren - Ganzen Pfad kopieren - Pfad kopieren - Branch erstellen… - Basierend auf: - Erstellten Branch auschecken - Lokale Änderungen: - Neuer Branch-Name: - Einen Branch-Namen eingeben - Lokalen Branch erstellen - Überschreibe existierenden Branch - Tag erstellen… - Neuer Tag auf: - Mit GPG signieren - Anmerkung: - Optional. - Tag-Name: - Empfohlenes Format: v1.0.0-alpha - Nach Erstellung auf alle Remotes pushen - Neuen Tag anlegen - Art: - Mit Anmerkung - Ohne Anmerkung - Halte ‚Strg‘ gedrückt, um direkt auszuführen - Ausschneiden - Verwerfen - Nichts tun - Stashen & wieder anwenden - Deinitialisiere Submodul - Erzwinge Deinitialisierung, selbst wenn lokale Änderungen enthalten sind. - Submodul: - Branch löschen - Branch: - Löschen erzwingen, auch bei nicht gemergten Commits - Du bist dabei, einen Remote-Branch zu löschen!!! - Auch Remote-Branch ${0}$ löschen - Mehrere Branches löschen - Du versuchst, mehrere Branches auf einmal zu löschen. Kontrolliere dies sorgfältig, bevor du fortfährst! - Mehrere Tags löschen - Von Remotes löschen - Du versuchst, mehrere Tags auf einmal zu löschen. Kontrolliere dies sorgfältig, bevor du fortfährst! - Remote löschen - Remote: - Pfad: - Ziel: - Alle Nachfolger werden aus der Liste entfernt. - Dadurch wird es nur aus der Liste entfernt, nicht von der Festplatte! - Bestätige Löschen von Gruppe - Bestätige Löschen von Repository - Lösche Submodul - Submodul-Pfad: - Tag löschen - Tag: - Von Remote-Repositorys löschen - BINÄRER VERGLEICH - LEERE DATEI - Erster Unterschied - Ignoriere Leerzeichen-Änderungen - ÜBEREINANDER - DIFFERENZ - NEBENEINANDER - WISCHEN - Letzter Unterschied - LFS-OBJEKT-ÄNDERUNG - NEU - Nächster Unterschied - KEINE ÄNDERUNG ODER NUR ZEILENENDE-ÄNDERUNGEN - ALT - Vorheriger Unterschied - Als Patch speichern - Zeige versteckte Symbole - Nebeneinander - SUBMODUL - GELÖSCHT - NEU - + {0} nicht committete Änderungen - Seiten tauschen - Syntax-Hervorhebung - Zeilenumbruch - Ö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 - Bereits aktuell - Änderungen verwerfen - Alle Änderungen in der Arbeitskopie. - Änderungen: - Ignorierte Dateien einbeziehen - Geänderte/gelöschte Dateien einbeziehen - Nicht-verfolgte Dateien einbeziehen - {0} Änderungen werden verworfen - Du kannst das nicht rückgängig machen!!! - Beschreibung des Branches bearbeiten - Ziel-Branch: - Lesezeichen: - Neuer Name: - Ziel: - Ausgewählte Gruppe bearbeiten - Ausgewähltes Repository bearbeiten - Ziel: - Dieses Repository - Fetch - Alle Remotes fetchen - Überschreiben lokaler Refs erzwingen - Ohne Tags fetchen - Remote: - Remote-Änderungen fetchen - Als unverändert betrachten - Benutzerdefinierte Aktion - Verwerfen… - Verwerfe {0} Dateien… - Löse mit ${0}$ - Als Patch speichern… - Stagen - Stage {0} Dateien - Stashen… - Stashe {0} Dateien… - Unstagen - {0} Dateien unstagen - Meine verwenden (checkout --ours) - Deren verwenden (checkout --theirs) - Dateiverlauf - ÄNDERUNG - INHALT - Dateimodus-Änderung: - Gelöschter Dateimodus: - Verzeichnis - Ausführbar - Neuer Dateimodus: - Normal - Submodul - Symlink - Unbekannt - Git Flow - Development-Branch: - Feature: - Feature-Präfix: - Abschließen ${0}$ - FLOW – Feature fertigstellen - FLOW – Hotfix fertigstellen - FLOW – Release fertigstellen - Ziel: - Vor dem Mergen rebasen - Squash beim Merge - Hotfix: - Hotfix-Präfix: - Git Flow initialisieren - Branch behalten - Production-Branch: - Release: - Release-Präfix: - Beginnen bei: - Feature beginnen… - FLOW – Feature beginnen - Hotfix beginnen… - FLOW – Hotfix beginnen - Name: - Namen eingeben - Release beginnen… - FLOW – Release beginnen - Versions-Tag-Präfix: - Git LFS - Verfolgungsmuster hinzufügen… - Muster ist ein Dateiname - Eigenes Muster: - Verfolgungsmuster zu Git LFS hinzufügen - Fetch - Führt `git lfs fetch` aus, um Git-LFS-Objekte herunterzuladen. Dies aktualisiert nicht die Arbeitskopie. - LFS-Objekte fetchen - Installiere Git-LFS-Hooks - Sperren anzeigen - Keine gesperrten Dateien - Sperre - Zeige nur meine Sperren - LFS-Sperren - Entsperren - Alle meine Sperrungen aufheben - Sollen alle deine Dateien entsperrt werden? - Erzwinge entsperren - Prune - Führt `git lfs prune` aus, um alte LFS-Dateien aus dem lokalen Speicher zu löschen - Pull - 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 - LFS-Objekte pushen - Remote: - Verfolge alle ‚{0}‘ Dateien - Verfolge alle *{0} Dateien - Commit auswählen - AUTOR - AUTOR-ZEITPUNKT - COMMIT-ZEITPUNKT - VERLAUF & COMMIT-NACHRICHT - SHA - HERVORHEBUNGEN IM GRAPHEN - Alle - Nur aktueller Branch - Aktueller Branch & ausgewählte Commits - Nur ausgewählte Commits - {0} COMMITS AUSGEWÄHLT - SPALTEN ANZEIGEN - Halte ‚Strg‘ oder ‚Umschalt‘, um mehrere Commits auszuwählen. - Halte ⌘ oder ⇧, um mehrere Commits auszuwählen - TIPPS: - In separatem Fenster öffnen - Commit-Details - Revisionsvergleich - Tastaturkürzel-Referenz - GLOBAL - Klone neues Repository - Aktuelle Registerkarte schließen - Zur nächsten Registerkarte wechseln - Zur vorherigen Registerkarte wechseln - Neue Registerkarte erstellen - Lokales Repository öffnen - Einstellungen öffnen - Auswahlmenü für Arbeitsumgebungen anzeigen - Aktive Registerkarte wechseln - Herein- / herauszoomen - REPOSITORY - Gestagte Änderungen committen - Gestagte Änderungen committen und pushen - Alle Änderungen stagen und committen - Neuen Branch erstellen - Fetch, wird direkt ausgeführt - Springe zum Nachfolger des ausgewählten Commits - Springe zum Vorgänger des ausgewählten Commits - Befehlspalette öffnen - Pull, wird direkt ausgeführt - Push, wird direkt ausgeführt - Erzwinge Neuladen des Repositorys - Wechsle zu ‚Änderungen‘ - Wechsle zu ‚Stashes‘ - Verwerfen - Stagen - Unstagen - Initialisiere Repository - Möchtest du `git init` in diesem Pfad ausführen? - Öffnen des Repositorys fehlgeschlagen. Grund: - Pfad: - Cherry-Pick wird durchgeführt. - Verarbeite Commit - Merge Request wird durchgeführt. - Verarbeite - Rebase wird durchgeführt. - Angehalten bei - Revert wird durchgeführt. - Reverte Commit - Interaktiver Rebase - Lokale Änderungen stashen & wieder anwenden - pre-rebase Hook überspringen - Auf: - Drag & Drop zum Anordnen der Commits - Ziel-Branch: - Link kopieren - Im Browser öffnen - Befehle - FEHLER - INFO - Neue Version verfügbar - Repositorys öffnen - Registerkarten - Arbeitsumgebungen - Branch mergen - Merge-Nachricht anpassen - Ziel-Branch: - Merge-Option: - Quelle: - Merge wird geprüft… - Merge ist ohne Konflikte möglich - Unbekannter Fehler bei der Merge-Prüfung - Merge wird Konflikte verursachen - Zuerst meine, dann deren - Zuerst deren, dann meine - BEIDE VERWENDEN - Alle Konflikte gelöst - {0} Konflikt(e) verbleibend - MEINE - Nächster Konflikt - Vorheriger Konflikt - ERGEBNIS - SPEICHERN & STAGEN - DEREN - Merge-Konflikte - Ungespeicherte Änderungen verwerfen? - MEINE VERWENDEN - DEREN VERWENDEN - RÜCKGÄNGIG MACHEN - Merge (mehrere) - Alle Änderungen committen - Strategie: - Ziele: - Submodul verschieben - Verschieben zu: - Submodul: - Verschiebe Repository-Knoten - Wähle Vorgänger-Knoten für: - Name: - NEIN - Git wurde NICHT konfiguriert. Gehe bitte zunächst in die [Einstellungen] und konfiguriere es. - Öffnen - Standard-Texteditor (System) - Programmdaten-Ordner öffnen - Datei öffnen - Öffnen in externem Merge-Tool - Lokales Repository öffnen - Lesezeichen: - Gruppe: - Ordner: - Optional. - Neue Registerkarte erstellen - Registerkarte schließen - Andere Registerkarten schließen - Registerkarten zur Rechten schließen - Kopiere Repository-Pfad - Bearbeiten - In Arbeitsumgebung verschieben - Aktualisieren - Repositorys - Einfügen - Vor {0} Tagen - Vor 1 Stunde - Vor {0} Stunden - Gerade eben - Letzter Monat - Letztes Jahr - Vor {0} Minuten - Vor {0} Monaten - Vor {0} Jahren - Gestern - Einstellungen - AI - Zusätzlicher Prompt (Verwende `-`, um deine Anforderungen aufzulisten) - API-Schlüssel - Modell - Verfügbare Modell-IDs automatisch abrufen - Name - Der eingegebene Wert ist der Name der Umgebungsvariable, aus der der API-Schlüssel gelesen wird - Server - DARSTELLUNG - Standardschriftart - Editor-Tab-Breite - Schriftgröße - Standard - Texteditor - Festbreiten-Schriftart - Design - Design-Anpassungen - Bildlaufleisten automatisch ausblenden - Fixe Tab-Breite in Titelleiste verwenden - Nativen Fensterrahmen verwenden - DIFF- / MERGE-TOOL - Argumente für Diff - Verfügbare Variablen: $LOCAL, $REMOTE - Argumente für Merge - Verfügbare Variablen: $BASE, $LOCAL, $REMOTE, $MERGED - Installationspfad - Pfad zum Diff- / Merge-Tool - Tool - ALLGEMEIN - Beim Programmstart nach Aktualisierungen suchen - Datumsformat - Aktiviere kompakte Ordner im Änderungsbaum - Sprache - Commit-Historie - Standardmäßig ‚ÄNDERUNGEN‘-Ansicht anzeigen - Standardmäßig Registerkarte ‚ÄNDERUNGEN‘ in Commit-Details anzeigen - Relative Zeitangaben im Commit-Graphen anzeigen - Zeige Tags im Commit-Verlauf - Längenvorgabe für Commit-Nachrichten - 24-Stunden-Format - Kompakte Branch-Namen im Commit-Graphen verwenden - Standard-Avatar im GitHub-Stil generieren - GIT - Aktiviere Auto-CRLF - Standard Klon-Ordner - Benutzer-E-Mail - Globale Git Benutzer-E-Mail - Aktiviere --prune beim Fetchen - Aktiviere --ignore-cr-at-eol für Text-Diff - Dieses Programm setzt Git (>= 2.25.1) voraus - Installationspfad - Aktiviere HTTP-SSL-Verifizierung - git-credential-libsecret statt git-credential-manager verwenden - Benutzername - Globaler Git-Benutzername - Änderungen beim Auschecken oder Mergen von Branches standardmäßig stashen & wieder anwenden - Git-Version - GPG-SIGNIERUNG - Commit-Signierung - GPG-Format - GPG-Installationspfad - Pfad zum GPG-Programm - Tag-Signierung - Benutzer-Signierungsschlüssel - GPG-Signierungsschlüssel des Benutzers - INTEGRATIONEN - SHELL / TERMINAL - Argumente - Bitte verwende ‚.‘ für das aktuelle Verzeichnis - Pfad - Shell / Terminal - Remote bereinigen - Ziel: - Worktrees bereinigen - Worktree-Informationen in `$GIT_COMMON_DIR/worktrees` bereinigen - Pull - Remote-Branch: - Lokaler Branch: - Lokale Änderungen: - Remote: - Pull (Fetch & Merge) - Rebase anstatt Merge verwenden - Push - Sicherstellen, dass Submodule gepusht wurden - Erzwinge Push - Lokaler Branch: - NEU - pre-push Hook überspringen - Remote: - Revision: - Revision zu Remote-Branch pushen - Push - Remote-Branch: - Remote-Branch verfolgen - Alle Tags pushen - Tag zum Remote pushen - Zu allen Remotes pushen - Remote: - Tag: - Push zu einem NEUEN Branch - Name des neuen Remote-Branches: - Schließen - Aktuellen Branch rebasen - Lokale Änderungen stashen & wieder anwenden - pre-rebase Hook überspringen - Auf: - Rebase wird geprüft… - Rebase ist ohne Konflikte möglich - Unbekannter Fehler bei der Rebase-Prüfung - Rebase wird Konflikte verursachen - Remote hinzufügen - Remote bearbeiten - Name: - Remote-Name - Repository-URL: - Remote Git-Repository-URL - URL kopieren - Benutzerdefinierte Aktion - Löschen… - Bearbeiten… - Auto-Fetch aktivieren - Fetch - Im Browser öffnen - Prune - Bestätige das Entfernen des Worktrees - Aktiviere `--force` Option - Ziel: - Branch umbenennen - Neuer Name: - Eindeutiger Name für diesen Branch - Branch: - ABBRECHEN - Änderungen automatisch von Remote fetchen… - Sortieren - Nach Commit-Datum - Nach Name - Aufräumen (GC & Prune) - Führt `git gc` in diesem Repository aus. - Filter aufheben - Löschen - Repository-Einstellungen - WEITER - Benutzerdefinierte Aktionen - Keine benutzerdefinierten Aktionen - Alle Änderungen verwerfen - Öffne im Datei-Browser - Suche Branches / Tags / Submodule - Sichtbarkeit im Verlauf - Filter einklappen - Aufheben - Im Verlauf ausblenden - Filter ausklappen - Im Verlauf filtern - Filter aktiv - LAYOUT - Horizontal - Vertikal - COMMIT-SORTIERUNG - Commit-Zeitpunkt - Topologisch - LOKALE BRANCHES - Zum HEAD wechseln - Erstelle Branch - BENACHRICHTIGUNGEN LÖSCHEN - Als Ordner öffnen - Öffne in {0} - Öffne in externen Tools - REMOTES - Remote hinzufügen - AUFLÖSEN - Commit suchen - Autor - Inhalt - Commit-Nachricht - Pfad - SHA - Aktueller Branch - Nur dekorierte Commits - Nur ersten Vorgänger anzeigen - ANZEIGE-FLAGS - Verlorene Commits anzeigen - Zeige Submodule als Baumstruktur - Zeige Tags als Baumstruktur - ÜBERSPRINGEN - Statistiken - SUBMODULE - Submodul hinzufügen - Submodul aktualisieren - TAGS - Neuer Tag - Nach Erstelldatum - Nach Name - Sortieren - Öffne im Terminal - Logs ansehen - Öffne ‚{0}‘ im Browser - WORKTREES - Worktree hinzufügen - Prune - Git-Repository-URL - Aktuellen Branch auf Revision zurücksetzen - Rücksetzmodus: - Verschiebe zu: - Aktueller Branch: - Branch zurücksetzen (ohne Checkout) - Auf: - Branch: - Zeigen im Datei-Explorer - Commit rückgängig machen - Commit: - Commit-Änderungen rückgängig machen - In Bearbeitung. Bitte warten… - SPEICHERN - Speichern als… - Patch wurde erfolgreich gespeichert! - Durchsuche Repositorys - Stammverzeichnis: - Anderes benutzerdefiniertes Verzeichnis durchsuchen - Suche nach Aktualisierungen… - Eine neue Version dieses Programms ist verfügbar: - Derzeitige Version: - Suche nach Aktualisierungen fehlgeschlagen! - Herunterladen - Diese Version überspringen - Veröffentlichungsdatum neue Version: - Software-Update - Momentan sind keine Aktualisierungen verfügbar. - Branch des Submoduls setzen - Submodul: - Aktueller: - Ändern zu: - Optional. Leer lassen für Standardwert. - Setze verfolgten Branch - Branch: - Upstream-Verfolgung aufheben - Upstream: - SHA kopieren - Zum Commit wechseln - Privater SSH-Schlüssel: - Pfad zum privaten SSH-Schlüssel - START - Stash - Nicht-verfolgte Dateien einbeziehen - Name: - Optional. Name des Stashes. - Modus: - Nur gestagte Änderungen - Gestagte und ungestagte Änderungen der ausgewählten Datei(en) werden gestasht!!! - Lokale Änderungen stashen - Anwenden - Änderungen anwenden - Neuen Branch auschecken - Kopiere Nachricht - Entfernen - Als Patch speichern… - Stash entfernen - Entfernen: - STASHES - ÄNDERUNGEN - STASHES - Statistiken - ÜBERSICHT - MONAT - WOCHE - AUTOREN: - COMMITS: - SUBMODULE - Submodul hinzufügen - BRANCH - Branch - Relativer Pfad - Deinitialisiere Submodul - Untergeordnete Submodule fetchen - Verlauf - Verschieben nach - Öffne Submodul-Repository - Relativer Pfad: - Relativer Pfad, um dieses Submodul zu speichern. - Submodul löschen - Branch setzen - URL ändern - STATUS - geändert - nicht initialisiert - Revision geändert - nicht gemerged - Aktualisieren - URL - Details der Submodul-Änderung - DETAILS ÖFFNEN - OK - TAGGER - ZEIT - Tag auschecken… - Vergleiche 2 Tags - Vergleichen mit… - Vergleichen mit HEAD - Nachricht - Name - Tagger - Namen des Tags kopieren - Benutzerdefinierte Aktion - Lösche ${0}$… - Lösche ausgewählte {0} Tags… - Merge ${0}$ in ${1}$ hinein… - Pushe ${0}$… - Submodule aktualisieren - Alle Submodule - Bei Bedarf initialisieren - Submodul: - Verschachtelte Submodule aktualisieren - Auf verfolgten Remote-Branch des Submoduls aktualisieren - URL: - Logs - ALLES LÖSCHEN - Kopieren - Löschen - Warnung - Willkommensseite - Erstelle Gruppe - Erstelle Untergruppe - Klone Repository - Lösche - DRAG & DROP VON ORDNER UNTERSTÜTZT. BENUTZERDEFINIERTE GRUPPIERUNG UNTERSTÜTZT. - Bearbeiten - Verschiebe in eine andere Gruppe - Öffne alle Repositorys - Öffne Repository - Öffne Terminal - Standard Klon-Ordner erneut nach Repositorys durchsuchen - Suche Repositorys… - ÄNDERUNGEN - Git Ignore - Ignoriere alle *{0} Dateien - Ignoriere *{0} Dateien im selben Ordner - Ignoriere nicht-verfolgte Dateien in diesem Ordner - Ignoriere nur diese Datei - Ignoriere alle nicht-verfolgten Dateien im selben Ordner - Nachbesserung - Du kannst diese Datei jetzt stagen. - Verlauf löschen - Soll wirklich der Verlauf aller Commit-Nachrichten gelöscht werden? Dies kann nicht rückgängig gemacht werden. - COMMIT - COMMIT & PUSH - Vorlage / Historie - Klick-Ereignis auslösen - Commit (Bearbeitung) - Alle Änderungen stagen und committen - Du erzeugst einen Commit auf einem losgelösten (‚detached‘) HEAD. Möchtest du trotzdem fortfahren? - Du hast {0} Datei(en) gestaged, aber nur {1} werden angezeigt ({2} sind herausgefiltert). Möchtest du trotzdem fortfahren? - KONFLIKTE ERKANNT - MERGE - Merge mit externem Tool - ALLE KONFLIKTE IN EXTERNEM MERGE-TOOL ÖFFNEN - DATEI-KONFLIKTE SIND GELÖST - MEINE VERSION VERWENDEN - DEREN VERSION VERWENDEN - Änderungen filtern… - NICHT-VERFOLGTE DATEIEN EINBEZIEHEN - KEINE BISHERIGEN COMMIT-NACHRICHTEN - KEINE COMMIT-VORLAGEN - Ohne Überprüfung - Autor zurücksetzen - Abzeichnen - GESTAGED - UNSTAGEN - ALLES UNSTAGEN - UNGESTAGED - STAGEN - ALLES STAGEN - ALS UNVERÄNDERT BETRACHTETE ANZEIGEN - Vorlage: ${0}$ - ARBEITSUMGEBUNG: - Arbeitsumgebungen konfigurieren… - WORKTREE - BRANCH - Pfad kopieren - HEAD - Sperren - Öffnen - PFAD - Entfernen - Entsperren - JA - diff --git a/src/Resources/Locales/el_GR.axaml b/src/Resources/Locales/el_GR.axaml deleted file mode 100644 index 6c6996121a..0000000000 --- a/src/Resources/Locales/el_GR.axaml +++ /dev/null @@ -1,1031 +0,0 @@ - - - - - - Σχετικά - Σχετικά με το SourceGit - Ημερομηνία έκδοσης: {0} - Σημειώσεις έκδοσης - Ελεύθερο & ανοιχτού κώδικα γραφικό περιβάλλον για το Git - Προσθήκη αρχείου(-ων) στα αγνοούμενα - Μοτίβο: - Αρχείο αποθήκευσης: - Προσθήκη Worktree - Τοποθεσία: - Διαδρομή για αυτό το worktree. Υποστηρίζεται σχετική διαδρομή. - Όνομα κλάδου: - Προαιρετικό. Προεπιλογή είναι το όνομα του φακέλου προορισμού. - Παρακολούθηση κλάδου: - Παρακολούθηση απομακρυσμένου κλάδου - Τι να γίνει checkout: - Δημιουργία νέου κλάδου - Υπάρχων κλάδος - Βοηθός AI - ΜΟΝΤΕΛΟ - ΕΠΑΝΑΔΗΜΙΟΥΡΓΙΑ - Χρήση AI για δημιουργία μηνύματος commit - Χρήση - Απόκρυψη SourceGit - Απόκρυψη άλλων - Εμφάνιση όλων - Τριμερής συγχώνευση (3-Way) - Επιλέξτε αρχείο patch για εφαρμογή - Αγνόηση αλλαγών κενών χαρακτήρων - Πηγή: - Αρχείο - Πρόχειρο - Εφαρμογή Patch - Κενά: - Εφαρμογή Stash - Διαγραφή μετά την εφαρμογή - Επαναφορά των αλλαγών του index - Stash: - Αρχειοθέτηση... - Αποθήκευση αρχείου σε: - Επιλέξτε διαδρομή για το αρχείο - Αναθεώρηση: - Αρχειοθέτηση - SourceGit Askpass - Εισαγωγή κωδικής φράσης: - ΑΡΧΕΙΑ ΠΟΥ ΘΕΩΡΟΥΝΤΑΙ ΑΜΕΤΑΒΛΗΤΑ - ΚΑΝΕΝΑ ΑΡΧΕΙΟ ΔΕΝ ΘΕΩΡΕΙΤΑΙ ΑΜΕΤΑΒΛΗΤΟ - Φόρτωση εικόνας... - Ανανέωση - Bisect - Ματαίωση - Κακό - Καλό - Παράλειψη - Εκτέλεση bisect. Κάντε checkout σε άλλο και μετά σημειώστε το ως καλό ή κακό. - Εκτέλεση bisect. Σημειώστε το τρέχον commit ως κακό ή κάντε checkout σε άλλο και μετά σημειώστε το ως κακό. - Εκτέλεση bisect. Σημειώστε το τρέχον commit ως καλό ή κακό και κάντε checkout σε άλλο. - Εκτέλεση bisect. Το τρέχον HEAD είναι καλό ή κακό; - Blame - Blame στην προηγούμενη αναθεώρηση - Αγνόηση αλλαγών κενών χαρακτήρων - ΤΟ BLAME ΣΕ ΑΥΤΟ ΤΟ ΑΡΧΕΙΟ ΔΕΝ ΥΠΟΣΤΗΡΙΖΕΤΑΙ!!! - Checkout ${0}$... - Σύγκριση των 2 επιλεγμένων κλάδων - Σύγκριση με... - Σύγκριση με το HEAD - Σύγκριση με ${0}$ - Αντιγραφή ονόματος κλάδου - Δημιουργία PR... - Δημιουργία PR για το upstream ${0}$... - Προσαρμοσμένη ενέργεια - Διαγραφή ${0}$... - Διαγραφή {0} επιλεγμένων κλάδων - Επεξεργασία περιγραφής για ${0}$... - Fast-Forward στο ${0}$ - Fetch ${0}$ στο ${1}$... - Git Flow - Ολοκλήρωση ${0}$ - Διαδραστικό rebase του ${0}$ πάνω στο ${1}$ - Συγχώνευση ${0}$ στο ${1}$... - Συγχώνευση {0} επιλεγμένων κλάδων στον τρέχοντα - Pull ${0}$ - Pull ${0}$ στο ${1}$... - Push ${0}$ - Rebase του ${0}$ πάνω στο ${1}$... - Μετονομασία ${0}$... - Επαναφορά ${0}$ στο ${1}$... - Μετάβαση στο ${0}$ (worktree) - Ορισμός κλάδου παρακολούθησης... - {0} commit μπροστά - {0} commit μπροστά, {1} commit πίσω - {0} commit πίσω - Μη έγκυρο - ΑΠΟΜΑΚΡΥΣΜΕΝΟ - ΚΑΤΑΣΤΑΣΗ - ΠΑΡΑΚΟΛΟΥΘΗΣΗ - URL - WORKTREE - ΑΚΥΡΟ - Επαναφορά στη γονική αναθεώρηση - Επαναφορά σε αυτή την αναθεώρηση - Δημιουργία μηνύματος commit - Συγχώνευση (ενσωματωμένη) - Συγχώνευση (εξωτερική) - Επαναφορά αρχείου(-ων) στο ${0}$ - ΑΛΛΑΓΗ ΤΡΟΠΟΥ ΕΜΦΑΝΙΣΗΣ - Εμφάνιση ως λίστα αρχείων και φακέλων - Εμφάνιση ως λίστα διαδρομών - Εμφάνιση ως δέντρο αρχείων - Αλλαγή URL της υπομονάδας - Υπομονάδα: - URL: - Checkout κλάδου - Τοπικές αλλαγές: - Κλάδος: - Το τρέχον HEAD περιέχει commit που δεν συνδέονται με κανέναν κλάδο/ετικέτα! Θέλετε να συνεχίσετε; - Οι ακόλουθες υπομονάδες πρέπει να ενημερωθούν:{0}Θέλετε να τις ενημερώσετε; - Checkout & Fast-Forward - Fast-Forward στο: - Checkout κλάδου από Stash - Νέος κλάδος: - Stash: - Checkout commit ή ετικέτας - Στόχος: - Προσοχή: Μετά από αυτό, το HEAD θα αποσυνδεθεί (detached) - Cherry-Pick - Προσθήκη πηγής στο μήνυμα commit - Commit: - Commit όλων των αλλαγών - Κύρια γραμμή: - Συνήθως δεν μπορείτε να κάνετε cherry-pick μια συγχώνευση, επειδή δεν γνωρίζετε ποια πλευρά της συγχώνευσης πρέπει να θεωρηθεί η κύρια γραμμή. Αυτή η επιλογή επιτρέπει στο cherry-pick να αναπαράγει την αλλαγή σε σχέση με τον καθορισμένο γονέα. - Εκκαθάριση Stashes - Πρόκειται να εκκαθαρίσετε όλα τα stashes. Είστε σίγουροι ότι θέλετε να συνεχίσετε; - Κλωνοποίηση απομακρυσμένου αποθετηρίου - Επιπλέον παράμετροι: - Πρόσθετα ορίσματα για την κλωνοποίηση του αποθετηρίου. Προαιρετικό. - Σελιδοδείκτης: - Ομάδα: - Τοπικό όνομα: - Όνομα αποθετηρίου. Προαιρετικό. - Γονικός φάκελος: - Αρχικοποίηση & ενημέρωση υπομονάδων - URL αποθετηρίου: - ΚΛΕΙΣΙΜΟ - Επεξεργαστής - Κλάδοι - Κλάδοι & Ετικέτες - Προσαρμοσμένες ενέργειες αποθετηρίου - Αρχεία αναθεώρησης - Checkout commit - Cherry-Pick commit - Cherry-Pick ... - Σύγκριση με το HEAD - Σύγκριση με το Worktree - Συγγραφέας - Ώρα συγγραφέα - Μήνυμα - Committer - Ώρα committer - SHA - Θέμα - Προσαρμοσμένη ενέργεια - Διαδραστικό rebase - Απόρριψη (Drop)... - Επεξεργασία... - Fixup στον γονέα... - Διαδραστικό rebase του ${0}$ πάνω στο ${1}$ - Επαναδιατύπωση... - Squash στον γονέα... - Συγχώνευση ... - Push ${0}$ στο ${1}$ - Rebase του ${0}$ πάνω στο ${1}$ - Επαναφορά ${0}$ στο ${1}$ - Αναίρεση commit - Αποθήκευση ως Patch... - ΑΛΛΑΓΕΣ - αλλαγμένο(-α) αρχείο(-α) - Αναζήτηση αλλαγών... - Σύμπτυξη λεπτομερειών - ΑΡΧΕΙΑ - Αρχείο LFS - Αναζήτηση αρχείων... - Υπομονάδα - ΠΛΗΡΟΦΟΡΙΕΣ - ΣΥΓΓΡΑΦΕΑΣ - COMMITTER - Έλεγχος refs που περιέχουν αυτό το commit - ΤΟ COMMIT ΠΕΡΙΕΧΕΤΑΙ ΣΕ - Αντιγραφή email - Αντιγραφή ονόματος - Αντιγραφή ονόματος & email - Εμφανίζονται μόνο οι πρώτες 100 αλλαγές. Δείτε όλες τις αλλαγές στην καρτέλα ΑΛΛΑΓΕΣ. - Κλειδί: - ΜΗΝΥΜΑ - ΓΟΝΕΙΣ - REFS - SHA - Υπογράφων: - Άνοιγμα στον περιηγητή - ΣΤΗΛΗ - Εισαγάγετε το μήνυμα commit. Χρησιμοποιήστε μια κενή γραμμή για να διαχωρίσετε το θέμα από την περιγραφή! - ΘΕΜΑ - Σύγκριση - ΑΛΛΑΓΕΣ - COMMITS - COMMITS ΜΟΝΟ ΑΡΙΣΤΕΡΑ - COMMITS ΜΟΝΟ ΔΕΞΙΑ - Συμβουλή: Μπορείτε να κάνετε cherry-pick τα επιλεγμένα commits αν η άλλη πλευρά είναι το HEAD (μέσω του μενού περιβάλλοντος). - Ρύθμιση αποθετηρίου - ΠΡΟΤΥΠΟ COMMIT - Ενσωματωμένες παράμετροι: - - ${branch_name} Όνομα τρέχοντος τοπικού κλάδου. - ${files_num} Πλήθος αλλαγμένων αρχείων - ${files} Διαδρομές αλλαγμένων αρχείων - ${files:N} Έως N διαδρομές αλλαγμένων αρχείων - ${pure_files} Όπως το ${files}, αλλά μόνο καθαρά ονόματα αρχείων - ${pure_files:N} Όπως το ${files:N}, αλλά χωρίς φακέλους - Περιεχόμενο προτύπου: - Όνομα προτύπου: - ΠΡΟΣΑΡΜΟΣΜΕΝΗ ΕΝΕΡΓΕΙΑ - Ορίσματα: - Ενσωματωμένες παράμετροι: - - ${REPO} Διαδρομή του αποθετηρίου - ${REMOTE} Επιλεγμένο remote ή το remote του επιλεγμένου κλάδου - ${BRANCH} Επιλεγμένος κλάδος, χωρίς το τμήμα ${REMOTE} για απομακρυσμένους κλάδους - ${BRANCH_FRIENDLY_NAME} Φιλικό όνομα του επιλεγμένου κλάδου, περιέχει το τμήμα ${REMOTE} για απομακρυσμένους κλάδους - ${SHA} Hash του επιλεγμένου commit - ${TAG} Επιλεγμένη ετικέτα - ${FILE} Επιλεγμένο αρχείο, σε σχέση με τη ρίζα του αποθετηρίου - $1, $2 ... Τιμές των στοιχείων εισόδου - Εκτελέσιμο αρχείο: - Στοιχεία εισόδου: - Επεξεργασία - Όνομα: - Εμβέλεια: - Κλάδος - Commit - Αρχείο - Απομακρυσμένο - Αποθετήριο - Ετικέτα - Αναμονή για έξοδο της ενέργειας - Διεύθυνση email - Διεύθυνση email - GIT - Ερώτηση πριν την αυτόματη ενημέρωση υπομονάδων - Αυτόματο fetch από τα απομακρυσμένα - Λεπτό(-ά) - Τύποι Conventional Commit - Προεπιλεγμένο απομακρυσμένο - Ενεργοποίηση `--recursive` κατά την αυτόματη ενημέρωση υπομονάδων - Προτιμώμενος τρόπος συγχώνευσης - ΣΥΣΤΗΜΑ ΠΑΡΑΚΟΛΟΥΘΗΣΗΣ ΖΗΤΗΜΑΤΩΝ - Προσθήκη κανόνα Azure DevOps - Προσθήκη κανόνα Gerrit Change-Id Commit - Προσθήκη κανόνα Gitee Issue - Προσθήκη κανόνα Gitee Pull Request - Προσθήκη κανόνα GitHub - Προσθήκη κανόνα GitLab Issue - Προσθήκη κανόνα GitLab Merge Request - Προσθήκη κανόνα Jira - Νέος κανόνας - Κανονική έκφραση ζητήματος: - Όνομα κανόνα: - Κοινή χρήση αυτού του κανόνα στο αρχείο .issuetracker - URL αποτελέσματος: - Χρησιμοποιήστε $1, $2 για πρόσβαση στις τιμές των ομάδων της κανονικής έκφρασης. - AI - Προτιμώμενη υπηρεσία: - Αν οριστεί η «Προτιμώμενη υπηρεσία», το SourceGit θα τη χρησιμοποιεί μόνο σε αυτό το αποθετήριο. Διαφορετικά, αν υπάρχουν περισσότερες από μία διαθέσιμες υπηρεσίες, θα εμφανίζεται μενού για να επιλέξετε μία. - HTTP Proxy - HTTP proxy που χρησιμοποιεί αυτό το αποθετήριο - Όνομα χρήστη - Όνομα χρήστη για αυτό το αποθετήριο - Επεξεργασία στοιχείων προσαρμοσμένης ενέργειας - Τιμή όταν επιλεγεί: - Όταν είναι επιλεγμένο, αυτή η τιμή θα χρησιμοποιείται στα ορίσματα της γραμμής εντολών - Περιγραφή: - Προεπιλογή: - Είναι φάκελος: - Ετικέτα: - Επιλογές: - Χρησιμοποιήστε το '|' ως διαχωριστικό για τις επιλογές - Μορφοποιητής συμβολοσειράς: - Προαιρετικό. Χρησιμοποιείται για μορφοποίηση της συμβολοσειράς εξόδου. Αγνοείται όταν η είσοδος είναι κενή. Χρησιμοποιήστε το `${VALUE}` για να αναπαραστήσετε τη συμβολοσειρά εισόδου. - Οι ενσωματωμένες μεταβλητές ${REPO}, ${REMOTE}, ${BRANCH}, ${BRANCH_FRIENDLY_NAME}, ${SHA}, ${FILE}, και ${TAG} παραμένουν διαθέσιμες εδώ - Τύπος: - Χρήση φιλικού ονόματος: - Χώροι εργασίας - Χρώμα - Όνομα - Επαναφορά καρτελών κατά την εκκίνηση - ΣΥΝΕΧΕΙΑ - Εντοπίστηκε κενό commit! Θέλετε να συνεχίσετε (--allow-empty); - ΠΡΟΣΘΗΚΗ ΟΛΩΝ & COMMIT - ΠΡΟΣΘΗΚΗ ΕΠΙΛΕΓΜΕΝΩΝ & COMMIT - Εντοπίστηκε κενό commit! Θέλετε να συνεχίσετε (--allow-empty) ή να γίνει αυτόματη προσθήκη στο ευρετήριο και μετά commit; - Απαιτείται επανεκκίνηση - Πρέπει να επανεκκινήσετε την εφαρμογή για να εφαρμοστούν οι αλλαγές. - Βοηθός Conventional Commit - Breaking Change: - Ζήτημα που κλείνει: - Λεπτομέρειες αλλαγών: - Εμβέλεια: - Σύντομη περιγραφή: - Τύπος αλλαγής: - Αντιγραφή - Αντιγραφή όλου του κειμένου - Αντιγραφή ως Patch - Αντιγραφή πλήρους διαδρομής - Αντιγραφή διαδρομής - Δημιουργία κλάδου... - Με βάση: - Checkout του κλάδου που δημιουργήθηκε - Τοπικές αλλαγές: - Όνομα νέου κλάδου: - Εισαγάγετε όνομα κλάδου. - Δημιουργία τοπικού κλάδου - Αντικατάσταση υπάρχοντος κλάδου - Δημιουργία ετικέτας... - Νέα ετικέτα στο: - Υπογραφή GPG - Μήνυμα ετικέτας: - Προαιρετικό. - Όνομα ετικέτας: - Προτεινόμενη μορφή: v1.0.0-alpha - Push σε όλα τα απομακρυσμένα μετά τη δημιουργία - Δημιουργία ετικέτας - Είδος: - επισημειωμένη - ελαφριά - Κρατήστε Ctrl για άμεση εκκίνηση - Αποκοπή - Απόρριψη - Καμία ενέργεια - Stash & επανεφαρμογή - Απο-αρχικοποίηση υπομονάδας - Εξαναγκασμός απο-αρχικοποίησης ακόμη κι αν περιέχει τοπικές αλλαγές. - Υπομονάδα: - Διαγραφή κλάδου - Κλάδος: - Εξαναγκασμένη διαγραφή ακόμη κι αν περιέχει μη συγχωνευμένα commit - Πρόκειται να διαγράψετε έναν απομακρυσμένο κλάδο!!! - Διαγραφή και του απομακρυσμένου κλάδου ${0}$ - Διαγραφή πολλαπλών κλάδων - Προσπαθείτε να διαγράψετε πολλούς κλάδους ταυτόχρονα. Βεβαιωθείτε ότι ελέγξατε ξανά πριν προχωρήσετε! - Διαγραφή πολλαπλών ετικετών - Διαγραφή τους από τα απομακρυσμένα - Προσπαθείτε να διαγράψετε πολλές ετικέτες ταυτόχρονα. Βεβαιωθείτε ότι ελέγξατε ξανά πριν προχωρήσετε! - Διαγραφή απομακρυσμένου - Απομακρυσμένο: - Διαδρομή: - Στόχος: - Όλα τα παιδιά θα αφαιρεθούν από τη λίστα. - Αυτό θα το αφαιρέσει μόνο από τη λίστα, όχι από τον δίσκο! - Επιβεβαίωση διαγραφής ομάδας - Επιβεβαίωση διαγραφής αποθετηρίου - Διαγραφή υπομονάδας - Διαδρομή υπομονάδας: - Διαγραφή ετικέτας - Ετικέτα: - Διαγραφή από τα απομακρυσμένα αποθετήρια - ΔΥΑΔΙΚΟ DIFF - ΚΕΝΟ ΑΡΧΕΙΟ - Πρώτη διαφορά - Αγνόηση αλλαγών κενών χαρακτήρων - ΑΝΑΜΕΙΞΗ - ΔΙΑΦΟΡΑ - ΔΙΠΛΑ-ΔΙΠΛΑ - ΣΑΡΩΣΗ - Τελευταία διαφορά - ΑΛΛΑΓΗ ΑΝΤΙΚΕΙΜΕΝΟΥ LFS - ΝΕΟ - Επόμενη διαφορά - ΚΑΜΙΑ ΑΛΛΑΓΗ Ή ΜΟΝΟ ΑΛΛΑΓΕΣ EOL - ΠΑΛΙΟ - Προηγούμενη διαφορά - Αποθήκευση ως Patch - Εμφάνιση κρυφών συμβόλων - Diff δίπλα-δίπλα - ΥΠΟΜΟΝΑΔΑ - ΔΙΑΓΡΑΦΗΚΕ - ΝΕΟ - + {0} μη υποβληθείσες αλλαγές - Εναλλαγή - Επισήμανση σύνταξης - Αναδίπλωση γραμμών - Άνοιγμα στο εργαλείο συγχώνευσης - Εμφάνιση όλων των γραμμών - Μείωση αριθμού ορατών γραμμών - Αύξηση αριθμού ορατών γραμμών - ΕΠΙΛΕΞΤΕ ΑΡΧΕΙΟ ΓΙΑ ΠΡΟΒΟΛΗ ΑΛΛΑΓΩΝ - Ιστορικό φακέλου - Έχει τοπικές αλλαγές - Αναντιστοιχία με το upstream - Ήδη ενημερωμένο - Απόρριψη αλλαγών - Όλες οι τοπικές αλλαγές στο αντίγραφο εργασίας. - Αλλαγές: - Συμπερίληψη αγνοούμενων αρχείων - Συμπερίληψη τροποποιημένων/διαγραμμένων αρχείων - Συμπερίληψη μη παρακολουθούμενων αρχείων - {0} αλλαγές θα απορριφθούν - Δεν μπορείτε να αναιρέσετε αυτή την ενέργεια!!! - Επεξεργασία περιγραφής κλάδου - Στόχος: - Σελιδοδείκτης: - Νέο όνομα: - Στόχος: - Επεξεργασία επιλεγμένης ομάδας - Επεξεργασία επιλεγμένου αποθετηρίου - Στόχος: - Αυτό το αποθετήριο - Fetch - Fetch από όλα τα απομακρυσμένα - Εξαναγκασμός αντικατάστασης τοπικών refs - Fetch χωρίς ετικέτες - Απομακρυσμένο: - Fetch απομακρυσμένων αλλαγών - Θεώρηση ως αμετάβλητο - Προσαρμοσμένη ενέργεια - Απόρριψη... - Απόρριψη {0} αρχείων... - Επίλυση με χρήση ${0}$ - Αποθήκευση ως Patch... - Προσθήκη στο ευρετήριο - Προσθήκη {0} αρχείων στο ευρετήριο - Stash... - Stash {0} αρχείων... - Αφαίρεση από το ευρετήριο - Αφαίρεση {0} αρχείων από το ευρετήριο - Χρήση δικού μου (checkout --ours) - Χρήση δικού τους (checkout --theirs) - Ιστορικό αρχείου - ΑΛΛΑΓΗ - ΠΕΡΙΕΧΟΜΕΝΟ - Αλλαγή mode αρχείου: - mode διαγραμμένου αρχείου: - Κατάλογος - Εκτελέσιμο - mode νέου αρχείου: - Κανονικό - Υπομονάδα - Συμβολικός σύνδεσμος - Άγνωστο - Git-Flow - Κλάδος ανάπτυξης: - Feature: - Πρόθεμα Feature: - Ολοκλήρωση ${0}$ - FLOW - Ολοκλήρωση Feature - FLOW - Ολοκλήρωση Hotfix - FLOW - Ολοκλήρωση Release - Στόχος: - Rebase πριν τη συγχώνευση - Squash κατά τη συγχώνευση - Hotfix: - Πρόθεμα Hotfix: - Αρχικοποίηση Git-Flow - Διατήρηση κλάδου - Κλάδος παραγωγής: - Release: - Πρόθεμα Release: - Έναρξη στο: - Έναρξη Feature... - FLOW - Έναρξη Feature - Έναρξη Hotfix... - FLOW - Έναρξη Hotfix - Όνομα: - Εισαγάγετε όνομα - Έναρξη Release... - FLOW - Έναρξη Release - Πρόθεμα ετικέτας έκδοσης: - Git LFS - Προσθήκη μοτίβου παρακολούθησης... - Το μοτίβο είναι όνομα αρχείου - Προσαρμοσμένο μοτίβο: - Προσθήκη μοτίβου παρακολούθησης στο Git LFS - Fetch - Εκτελέστε `git lfs fetch` για να κατεβάσετε αντικείμενα Git LFS. Αυτό δεν ενημερώνει το αντίγραφο εργασίας. - Fetch αντικειμένων LFS - Εγκατάσταση hooks του Git LFS - Εμφάνιση κλειδωμάτων - Δεν υπάρχουν κλειδωμένα αρχεία - Κλείδωμα - Εμφάνιση μόνο των δικών μου κλειδωμάτων - Κλειδώματα LFS - Ξεκλείδωμα - Ξεκλείδωμα όλων των δικών μου κλειδωμάτων - Είστε σίγουροι ότι θέλετε να ξεκλειδώσετε όλα τα κλειδωμένα σας αρχεία; - Εξαναγκασμός ξεκλειδώματος - Εκκαθάριση - Εκτελέστε `git lfs prune` για να διαγράψετε παλιά αρχεία LFS από την τοπική αποθήκευση - Pull - Εκτελέστε `git lfs pull` για να κατεβάσετε όλα τα αρχεία Git LFS για το τρέχον ref & checkout - Pull αντικειμένων LFS - Push - Push των μεγάλων αρχείων που βρίσκονται σε αναμονή προς το endpoint του Git LFS - Push αντικειμένων LFS - Απομακρυσμένο: - Παρακολούθηση αρχείων με όνομα '{0}' - Παρακολούθηση όλων των αρχείων *{0} - Επιλογή commit - ΣΥΓΓΡΑΦΕΑΣ - ΩΡΑ ΣΥΓΓΡΑΦΕΑ - ΩΡΑ COMMIT - ΓΡΑΦΗΜΑ & ΘΕΜΑ - SHA - ΕΠΙΣΗΜΑΝΣΕΙΣ ΣΤΟ ΓΡΑΦΗΜΑ - Όλα - Μόνο ο τρέχων κλάδος - Τρέχων κλάδος & επιλεγμένα commits - Μόνο τα επιλεγμένα commits - ΕΠΙΛΕΓΜΕΝΑ {0} COMMITS - ΕΜΦΑΝΙΣΗ ΣΤΗΛΩΝ - Κρατήστε 'Ctrl' ή 'Shift' για να επιλέξετε πολλαπλά commits. - Κρατήστε ⌘ ή ⇧ για να επιλέξετε πολλαπλά commits. - ΣΥΜΒΟΥΛΕΣ: - Άνοιγμα σε ξεχωριστό παράθυρο - Λεπτομέρειες commit - Σύγκριση αναθεωρήσεων - Αναφορά συντομεύσεων πληκτρολογίου - ΚΑΘΟΛΙΚΑ - Κλωνοποίηση νέου αποθετηρίου - Κλείσιμο τρέχουσας καρτέλας - Μετάβαση στην επόμενη καρτέλα - Μετάβαση στην προηγούμενη καρτέλα - Δημιουργία νέας καρτέλας - Άνοιγμα τοπικού αποθετηρίου - Άνοιγμα διαλόγου Προτιμήσεων - Εμφάνιση αναπτυσσόμενου μενού χώρων εργασίας - Εναλλαγή ενεργής καρτέλας - Μεγέθυνση/σμίκρυνση - ΑΠΟΘΕΤΗΡΙΟ - Commit των αλλαγών στο ευρετήριο - Commit και push των αλλαγών στο ευρετήριο - Προσθήκη όλων των αλλαγών στο ευρετήριο και commit - Δημιουργία νέου κλάδου - Fetch, ξεκινά άμεσα - Μετάβαση στον απόγονο του επιλεγμένου commit - Μετάβαση στον γονέα του επιλεγμένου commit - Άνοιγμα παλέτας εντολών - Pull, ξεκινά άμεσα - Push, ξεκινά άμεσα - Εξαναγκασμός επαναφόρτωσης αυτού του αποθετηρίου - Μετάβαση στις 'ΤΟΠΙΚΕΣ ΑΛΛΑΓΕΣ' - Μετάβαση στα 'STASHES' - Απόρριψη - Προσθήκη στο ευρετήριο - Αφαίρεση από το ευρετήριο - Αρχικοποίηση αποθετηρίου - Θέλετε να εκτελέσετε την εντολή `git init` σε αυτή τη διαδρομή; - Το άνοιγμα του αποθετηρίου απέτυχε. Αιτία: - Διαδρομή: - Cherry-Pick σε εξέλιξη. - Επεξεργασία commit - Συγχώνευση σε εξέλιξη. - Συγχώνευση - Rebase σε εξέλιξη. - Σταμάτησε στο - Αναίρεση σε εξέλιξη. - Αναίρεση commit - Διαδραστικό rebase - Stash & επανεφαρμογή τοπικών αλλαγών - Παράκαμψη του pre-rebase hook - Πάνω στο: - Σύρετε και αφήστε για αναδιάταξη των commits - Κλάδος-στόχος: - Αντιγραφή συνδέσμου - Άνοιγμα στον περιηγητή - Εντολές - ΣΦΑΛΜΑ - ΕΙΔΟΠΟΙΗΣΗ - Άνοιγμα αποθετηρίων - Καρτέλες - Χώροι εργασίας - Συγχώνευση κλάδου - Προσαρμογή μηνύματος συγχώνευσης - Στο: - Τρόπος συγχώνευσης: - Πηγή: - Έλεγχος για συγχώνευση... - Η συγχώνευση μπορεί να γίνει χωρίς συγκρούσεις - Παρουσιάστηκε άγνωστο σφάλμα κατά τον έλεγχο για συγχώνευση - Η συγχώνευση θα προκαλέσει συγκρούσεις - Πρώτα το δικό μου, μετά το δικό τους - Πρώτα το δικό τους, μετά το δικό μου - ΧΡΗΣΗ ΚΑΙ ΤΩΝ ΔΥΟ - Όλες οι συγκρούσεις επιλύθηκαν - Απομένουν {0} συγκρούσεις - ΔΙΚΟ ΜΟΥ - Επόμενη σύγκρουση - Προηγούμενη σύγκρουση - ΑΠΟΤΕΛΕΣΜΑ - ΑΠΟΘΗΚΕΥΣΗ & ΠΡΟΣΘΗΚΗ - ΔΙΚΟ ΤΟΥΣ - Συγκρούσεις συγχώνευσης - Απόρριψη μη αποθηκευμένων αλλαγών; - ΧΡΗΣΗ ΔΙΚΟΥ ΜΟΥ - ΧΡΗΣΗ ΔΙΚΟΥ ΤΟΥΣ - ΑΝΑΙΡΕΣΗ - Συγχώνευση (πολλαπλή) - Commit όλων των αλλαγών - Στρατηγική: - Στόχοι: - Μετακίνηση υπομονάδας - Μετακίνηση σε: - Υπομονάδα: - Μετακίνηση κόμβου αποθετηρίου - Επιλέξτε γονικό κόμβο για: - Όνομα: - ΟΧΙ - Το Git ΔΕΝ έχει ρυθμιστεί. Μεταβείτε στις [Προτιμήσεις] και ρυθμίστε το πρώτα. - Άνοιγμα - Προεπιλεγμένος επεξεργαστής (συστήματος) - Άνοιγμα φακέλου αποθήκευσης δεδομένων - Άνοιγμα αρχείου - Άνοιγμα σε εξωτερικό εργαλείο συγχώνευσης - Άνοιγμα τοπικού αποθετηρίου - Σελιδοδείκτης: - Ομάδα: - Φάκελος: - Προαιρετικό. - Δημιουργία νέας καρτέλας - Κλείσιμο καρτέλας - Κλείσιμο άλλων καρτελών - Κλείσιμο καρτελών στα δεξιά - Αντιγραφή διαδρομής αποθετηρίου - Επεξεργασία - Μετακίνηση σε χώρο εργασίας - Ανανέωση - Αποθετήρια - Επικόλληση - {0} ημέρες πριν - 1 ώρα πριν - {0} ώρες πριν - Μόλις τώρα - Τον προηγούμενο μήνα - Πέρυσι - {0} λεπτά πριν - {0} μήνες πριν - {0} χρόνια πριν - Χθες - Προτιμήσεις - AI - Επιπλέον prompt (χρησιμοποιήστε `-` για να απαριθμήσετε τις απαιτήσεις σας) - Κλειδί API - Μοντέλο - Αυτόματη ανάκτηση διαθέσιμων model-ids - Όνομα - Η τιμή που εισήχθη είναι το όνομα για φόρτωση του κλειδιού API από το ENV - Διακομιστής - ΕΜΦΑΝΙΣΗ - Προεπιλεγμένη γραμματοσειρά - Πλάτος tab επεξεργαστή - Μέγεθος γραμματοσειράς - Προεπιλογή - Επεξεργαστής - Γραμματοσειρά σταθερού πλάτους - Θέμα - Παρακάμψεις θέματος - Χρήση μπαρών κύλισης αυτόματης απόκρυψης - Χρήση σταθερού πλάτους καρτελών στη γραμμή τίτλου - Χρήση εγγενούς πλαισίου παραθύρου - ΕΡΓΑΛΕΙΟ DIFF/MERGE - Ορίσματα Diff - Διαθέσιμες μεταβλητές: $LOCAL, $REMOTE - Ορίσματα Merge - Διαθέσιμες μεταβλητές: $BASE, $LOCAL, $REMOTE, $MERGED - Διαδρομή εγκατάστασης - Εισαγάγετε τη διαδρομή του εργαλείου diff/merge - Εργαλείο - ΓΕΝΙΚΑ - Έλεγχος για ενημερώσεις κατά την εκκίνηση - Μορφή ημερομηνίας - Ενεργοποίηση συμπαγών φακέλων στο δέντρο αλλαγών - Γλώσσα - Commits ιστορικού - Εμφάνιση της σελίδας `ΤΟΠΙΚΕΣ ΑΛΛΑΓΕΣ` από προεπιλογή - Εμφάνιση της καρτέλας `ΑΛΛΑΓΕΣ` στις λεπτομέρειες commit από προεπιλογή - Εμφάνιση σχετικού χρόνου στο γράφημα commit - Εμφάνιση ετικετών στο γράφημα commit - Μήκος οδηγού θέματος - 24ωρη μορφή - Χρήση συμπαγών ονομάτων κλάδων στο γράφημα commit - Δημιουργία προεπιλεγμένου avatar τύπου Github - GIT - Ενεργοποίηση αυτόματου CRLF - Προεπιλεγμένος φάκελος κλωνοποίησης - Email χρήστη - Καθολικό email χρήστη git - Εκκαθάριση νεκρών κλάδων μετά το fetch - Αγνόηση CR στο τέλος γραμμής στο diff κειμένου - Απαιτείται Git (>= 2.25.1) από αυτή την εφαρμογή - Διαδρομή εγκατάστασης - Ενεργοποίηση επαλήθευσης HTTP SSL - Χρήση git-credential-libsecret αντί για git-credential-manager - Όνομα χρήστη - Καθολικό όνομα χρήστη git - Stash & επανεφαρμογή αλλαγών από προεπιλογή κατά το checkout ή τη συγχώνευση κλάδων - Έκδοση Git - ΥΠΟΓΡΑΦΗ GPG - Υπογραφή GPG στα commit - Μορφή GPG - Διαδρομή εγκατάστασης προγράμματος - Εισαγάγετε τη διαδρομή του εγκατεστημένου προγράμματος gpg - Υπογραφή GPG στις ετικέτες - Κλειδί υπογραφής χρήστη - Κλειδί υπογραφής gpg του χρήστη - ΕΝΣΩΜΑΤΩΣΗ - SHELL/ΤΕΡΜΑΤΙΚΟ - Ορίσματα - Χρησιμοποιήστε το '.' για να υποδείξετε τον φάκελο εργασίας - Διαδρομή - Shell/Τερματικό - Εκκαθάριση απομακρυσμένου - Στόχος: - Εκκαθάριση Worktrees - Εκκαθάριση πληροφοριών worktree στο `$GIT_COMMON_DIR/worktrees` - Pull - Απομακρυσμένος κλάδος: - Στο: - Τοπικές αλλαγές: - Απομακρυσμένο: - Pull (Fetch & Merge) - Χρήση rebase αντί για συγχώνευση - Push - Βεβαιωθείτε ότι έχει γίνει push στις υπομονάδες - Εξαναγκασμένο push - Τοπικός κλάδος: - ΝΕΟ - Παράκαμψη του pre-push hook - Απομακρυσμένο: - Αναθεώρηση: - Push αναθεώρησης σε απομακρυσμένο - Push αλλαγών σε απομακρυσμένο - Απομακρυσμένος κλάδος: - Ορισμός ως κλάδου παρακολούθησης - Push όλων των ετικετών - Push ετικέτας σε απομακρυσμένο - Push σε όλα τα απομακρυσμένα - Απομακρυσμένο: - Ετικέτα: - Push σε ΝΕΟ κλάδο - Εισαγάγετε το όνομα του νέου απομακρυσμένου κλάδου: - Έξοδος - Rebase τρέχοντος κλάδου - Stash & επανεφαρμογή τοπικών αλλαγών - Παράκαμψη του pre-rebase hook - Πάνω στο: - Έλεγχος για rebase ... - Το rebase μπορεί να γίνει χωρίς συγκρούσεις - Παρουσιάστηκε άγνωστο σφάλμα κατά τον έλεγχο για rebase - Το rebase θα προκαλέσει συγκρούσεις - Προσθήκη απομακρυσμένου - Επεξεργασία απομακρυσμένου - Όνομα: - Όνομα απομακρυσμένου - URL αποθετηρίου: - URL απομακρυσμένου αποθετηρίου git - Αντιγραφή URL - Προσαρμοσμένη ενέργεια - Διαγραφή... - Επεξεργασία... - Ενεργοποίηση αυτόματου Fetch - Fetch - Άνοιγμα στον περιηγητή - Εκκαθάριση - Επιβεβαίωση αφαίρεσης Worktree - Ενεργοποίηση της επιλογής `--force` - Στόχος: - Μετονομασία κλάδου - Νέο όνομα: - Μοναδικό όνομα για αυτόν τον κλάδο - Κλάδος: - ΜΑΤΑΙΩΣΗ - Αυτόματο fetch αλλαγών από τα απομακρυσμένα... - Ταξινόμηση - Κατά ημερομηνία committer - Κατά όνομα - Εκκαθάριση (GC & Prune) - Εκτέλεση της εντολής `git gc` για αυτό το αποθετήριο. - Εκκαθάριση όλων - Εκκαθάριση - Ρύθμιση αυτού του αποθετηρίου - ΣΥΝΕΧΕΙΑ - Προσαρμοσμένες ενέργειες - Καμία προσαρμοσμένη ενέργεια - Απόρριψη όλων των αλλαγών - Άνοιγμα στον περιηγητή αρχείων - Αναζήτηση κλάδων/ετικετών/υπομονάδων - Ορατότητα στο γράφημα - Μη ορισμένο - Απόκρυψη στο γράφημα commit - Φιλτράρισμα στο γράφημα commit - ΔΙΑΤΑΞΗ - Οριζόντια - Κάθετη - ΣΕΙΡΑ COMMITS - Ημερομηνία commit - Τοπολογικά - ΤΟΠΙΚΟΙ ΚΛΑΔΟΙ - Μετάβαση στο HEAD - Δημιουργία κλάδου - ΕΚΚΑΘΑΡΙΣΗ ΕΙΔΟΠΟΙΗΣΕΩΝ - Άνοιγμα ως φάκελος - Άνοιγμα σε {0} - Άνοιγμα σε εξωτερικά εργαλεία - ΑΠΟΜΑΚΡΥΣΜΕΝΑ - Προσθήκη απομακρυσμένου - ΕΠΙΛΥΣΗ - Αναζήτηση commit - Συγγραφέας - Περιεχόμενο - Μήνυμα - Διαδρομή - SHA - Τρέχων κλάδος - Μόνο commits με αναφορές - Μόνο πρώτος γονέας - ΕΜΦΑΝΙΣΗ ΣΗΜΑΙΩΝ - Εμφάνιση χαμένων commits - Εμφάνιση υπομονάδων ως δέντρο - Εμφάνιση ετικετών ως δέντρο - ΠΑΡΑΛΕΙΨΗ - Στατιστικά - ΥΠΟΜΟΝΑΔΕΣ - Προσθήκη υπομονάδας - Ενημέρωση υπομονάδας - ΕΤΙΚΕΤΕΣ - Νέα ετικέτα - Κατά ημερομηνία δημιουργίας - Κατά όνομα - Ταξινόμηση - Άνοιγμα στο τερματικό - Προβολή καταγραφών - Επίσκεψη '{0}' στον περιηγητή - WORKTREES - Προσθήκη Worktree - Εκκαθάριση - URL αποθετηρίου Git - Επαναφορά τρέχοντος κλάδου σε αναθεώρηση - Τρόπος επαναφοράς: - Μετακίνηση σε: - Τρέχων κλάδος: - Επαναφορά κλάδου (χωρίς checkout) - Μετακίνηση σε: - Κλάδος: - Εμφάνιση στον περιηγητή αρχείων - Αναίρεση commit - Commit: - Commit των αλλαγών αναίρεσης - Εκτελείται. Παρακαλώ περιμένετε... - ΑΠΟΘΗΚΕΥΣΗ - Αποθήκευση ως... - Το patch αποθηκεύτηκε με επιτυχία! - Σάρωση αποθετηρίων - Ριζικός φάκελος: - Σάρωση άλλου προσαρμοσμένου φακέλου - Έλεγχος για ενημερώσεις... - Είναι διαθέσιμη νέα έκδοση αυτού του λογισμικού: - Τρέχουσα έκδοση: - Ο έλεγχος για ενημερώσεις απέτυχε! - Λήψη - Παράλειψη αυτής της έκδοσης - Ημερομηνία έκδοσης νέας έκδοσης: - Ενημέρωση λογισμικού - Δεν υπάρχουν διαθέσιμες ενημερώσεις αυτή τη στιγμή. - Ορισμός κλάδου υπομονάδας - Υπομονάδα: - Τρέχων: - Αλλαγή σε: - Προαιρετικό. Όταν είναι κενό, ορίζεται στην προεπιλογή. - Ορισμός κλάδου παρακολούθησης - Κλάδος: - Κατάργηση upstream - Upstream: - Αντιγραφή SHA - Μετάβαση σε - Ιδιωτικό κλειδί SSH: - Διαδρομή αποθήκευσης ιδιωτικού κλειδιού SSH - ΕΝΑΡΞΗ - Stash - Συμπερίληψη μη παρακολουθούμενων αρχείων - Μήνυμα: - Προαιρετικό. Μήνυμα αυτού του stash - Λειτουργία: - Μόνο τα αρχεία στο ευρετήριο - Θα γίνουν stash τόσο οι αλλαγές στο ευρετήριο όσο και αυτές εκτός ευρετηρίου των επιλεγμένων αρχείων!!! - Stash τοπικών αλλαγών - Εφαρμογή - Εφαρμογή αλλαγών - Checkout νέου κλάδου - Αντιγραφή μηνύματος - Απόρριψη - Αποθήκευση ως Patch... - Απόρριψη Stash - Απόρριψη: - STASHES - ΑΛΛΑΓΕΣ - STASHES - Στατιστικά - ΕΠΙΣΚΟΠΗΣΗ - ΜΗΝΑΣ - ΕΒΔΟΜΑΔΑ - ΣΥΓΓΡΑΦΕΙΣ: - COMMITS: - ΥΠΟΜΟΝΑΔΕΣ - Προσθήκη υπομονάδας - ΚΛΑΔΟΣ - Κλάδος - Σχετική διαδρομή - Απο-αρχικοποίηση - Fetch ένθετων υπομονάδων - Ιστορικό - Μετακίνηση... - Άνοιγμα αποθετηρίου - Σχετική διαδρομή: - Σχετικός φάκελος για την αποθήκευση αυτής της υπομονάδας. - Διαγραφή - Ορισμός κλάδου - Αλλαγή URL - ΚΑΤΑΣΤΑΣΗ - τροποποιημένη - μη αρχικοποιημένη - η αναθεώρηση άλλαξε - μη συγχωνευμένη - Ενημέρωση - URL - Λεπτομέρειες αλλαγής υπομονάδας - ΑΝΟΙΓΜΑ ΛΕΠΤΟΜΕΡΕΙΩΝ - ΟΚ - ΔΗΜΙΟΥΡΓΟΣ ΕΤΙΚΕΤΑΣ - ΩΡΑ - Checkout ετικέτας... - Σύγκριση 2 ετικετών - Σύγκριση με... - Σύγκριση με το HEAD - Μήνυμα - Όνομα - Δημιουργός ετικέτας - Αντιγραφή ονόματος ετικέτας - Προσαρμοσμένη ενέργεια - Διαγραφή ${0}$... - Διαγραφή {0} επιλεγμένων ετικετών... - Συγχώνευση ${0}$ στο ${1}$... - Push ${0}$... - Ενημέρωση υπομονάδων - Όλες οι υπομονάδες - Αρχικοποίηση όπου χρειάζεται - Υπομονάδα: - Ενημέρωση ένθετων υπομονάδων - Ενημέρωση στον απομακρυσμένο κλάδο παρακολούθησης της υπομονάδας - URL: - Καταγραφές - ΕΚΚΑΘΑΡΙΣΗ ΟΛΩΝ - Αντιγραφή - Διαγραφή - Προειδοποίηση - Σελίδα υποδοχής - Δημιουργία ομάδας - Δημιουργία υπο-ομάδας - Κλωνοποίηση αποθετηρίου - Διαγραφή - ΥΠΟΣΤΗΡΙΖΕΤΑΙ ΜΕΤΑΦΟΡΑ & ΑΠΟΘΕΣΗ ΦΑΚΕΛΟΥ. ΥΠΟΣΤΗΡΙΖΕΤΑΙ ΠΡΟΣΑΡΜΟΣΜΕΝΗ ΟΜΑΔΟΠΟΙΗΣΗ. - Επεξεργασία - Μετακίνηση σε άλλη ομάδα - Άνοιγμα όλων των αποθετηρίων - Άνοιγμα αποθετηρίου - Άνοιγμα τερματικού - Επανασάρωση αποθετηρίων στον προεπιλεγμένο φάκελο κλωνοποίησης - Αναζήτηση αποθετηρίων... - ΤΟΠΙΚΕΣ ΑΛΛΑΓΕΣ - Git Ignore - Αγνόηση όλων των αρχείων *{0} - Αγνόηση αρχείων *{0} στον ίδιο φάκελο - Αγνόηση μη παρακολουθούμενων αρχείων σε αυτόν τον φάκελο - Αγνόηση μόνο αυτού του αρχείου - Αγνόηση όλων των μη παρακολουθούμενων αρχείων στον ίδιο φάκελο - Τροποποίηση - Μπορείτε να προσθέσετε αυτό το αρχείο στο ευρετήριο τώρα. - Εκκαθάριση ιστορικού - Είστε σίγουροι ότι θέλετε να εκκαθαρίσετε όλο το ιστορικό μηνυμάτων commit; Αυτή η ενέργεια δεν μπορεί να αναιρεθεί. - COMMIT - COMMIT & PUSH - Πρότυπο/Ιστορικό - Ενεργοποίηση συμβάντος κλικ - Commit (Επεξεργασία) - Προσθήκη όλων των αλλαγών στο ευρετήριο και commit - Δημιουργείτε commit σε αποσυνδεδεμένο (detached) HEAD. Θέλετε να συνεχίσετε; - Έχετε προσθέσει στο ευρετήριο {0} αρχείο(-α) αλλά εμφανίζονται μόνο {1} αρχείο(-α) ({2} αρχεία είναι φιλτραρισμένα). Θέλετε να συνεχίσετε; - ΕΝΤΟΠΙΣΤΗΚΑΝ ΣΥΓΚΡΟΥΣΕΙΣ - ΣΥΓΧΩΝΕΥΣΗ - Συγχώνευση με εξωτερικό εργαλείο - ΑΝΟΙΓΜΑ ΟΛΩΝ ΤΩΝ ΣΥΓΚΡΟΥΣΕΩΝ ΣΕ ΕΞΩΤΕΡΙΚΟ ΕΡΓΑΛΕΙΟ ΣΥΓΧΩΝΕΥΣΗΣ - ΟΙ ΣΥΓΚΡΟΥΣΕΙΣ ΑΡΧΕΙΩΝ ΕΠΙΛΥΘΗΚΑΝ - ΧΡΗΣΗ ΔΙΚΟΥ ΜΟΥ - ΧΡΗΣΗ ΔΙΚΟΥ ΤΟΥΣ - ΣΥΜΠΕΡΙΛΗΨΗ ΜΗ ΠΑΡΑΚΟΛΟΥΘΟΥΜΕΝΩΝ ΑΡΧΕΙΩΝ - ΔΕΝ ΥΠΑΡΧΟΥΝ ΠΡΟΣΦΑΤΑ ΜΗΝΥΜΑΤΑ ΕΙΣΟΔΟΥ - ΔΕΝ ΥΠΑΡΧΟΥΝ ΠΡΟΤΥΠΑ COMMIT - Χωρίς έλεγχο - Επαναφορά συγγραφέα - Προσυπογραφή - ΣΤΟ ΕΥΡΕΤΗΡΙΟ - ΑΦΑΙΡΕΣΗ - ΑΦΑΙΡΕΣΗ ΟΛΩΝ - ΕΚΤΟΣ ΕΥΡΕΤΗΡΙΟΥ - ΠΡΟΣΘΗΚΗ - ΠΡΟΣΘΗΚΗ ΟΛΩΝ - ΠΡΟΒΟΛΗ ΑΡΧΕΙΩΝ ΠΟΥ ΘΕΩΡΟΥΝΤΑΙ ΑΜΕΤΑΒΛΗΤΑ - Πρότυπο: ${0}$ - ΧΩΡΟΣ ΕΡΓΑΣΙΑΣ: - Ρύθμιση χώρων εργασίας... - WORKTREE - ΚΛΑΔΟΣ - Αντιγραφή διαδρομής - HEAD - Κλείδωμα - Άνοιγμα - ΔΙΑΔΡΟΜΗ - Αφαίρεση - Ξεκλείδωμα - ΝΑΙ - diff --git a/src/Resources/Locales/en_US.axaml b/src/Resources/Locales/en_US.axaml index eb8ff1ca7e..190d4e949d 100644 --- a/src/Resources/Locales/en_US.axaml +++ b/src/Resources/Locales/en_US.axaml @@ -48,6 +48,25 @@ NO FILES ASSUMED AS UNCHANGED Load Image... Refresh + Clone from Azure DevOps + All projects + Clone + cloned + Missing an organization? Only organizations connected to the Microsoft Entra tenant you signed in with are listed. + This account is not a member of any Azure DevOps organization. + Show your organizations on Azure DevOps + Refresh + Search repositories + Sign in with Azure DevOps + The code is copied to your clipboard + The sign-in was declined. + The Azure DevOps sign-in has expired. Please sign in again. + Paste this code on the Microsoft page that just opened in your browser and sign in with your work account. + No Azure DevOps token found. Please sign in again. + Open Microsoft Sign-in + Try Again + Could not save the Azure DevOps token in the system credential store. + Waiting for Microsoft ... Bisect Abort Bad @@ -137,10 +156,13 @@ Extra Parameters: Additional arguments to clone repository. Optional. Bookmark: + Pick a repository from Azure DevOps + Pick a repository from GitHub Group: Local Name: Repository name. Optional. Parent Folder: + Folder does not exist and will be created Initialize & update submodules Repository URL: CLOSE @@ -184,7 +206,6 @@ Search Files... Submodule SELECT FILE TO VIEW CONTENT - INFORMATION AUTHOR COMMITTER Check refs that contains this commit @@ -192,7 +213,6 @@ Copy Email Copy Name Copy Name & Email - Shows only the first 100 changes. See all changes on the CHANGES tab. Key: MESSAGE PARENTS @@ -481,6 +501,25 @@ Start Release... Start Release Version Tag Prefix: + Clone from GitHub + All organizations + archived + Clone + cloned + Grant access to organizations on GitHub + Missing repositories from an organization? The organization may have to approve SourceGit first. + Refresh + Search repositories + Sign in with GitHub + The code is copied to your clipboard + Access was denied on GitHub. + The GitHub sign-in has expired. Please sign in again. + Paste this code on the GitHub page that just opened in your browser and approve SourceGit. + No GitHub token found. Please sign in again. + Open GitHub + Try Again + Could not save the GitHub token in the system credential store. + Waiting for GitHub ... Git LFS Add Track Pattern... Pattern is file name @@ -532,6 +571,8 @@ Commit Detail Revision Compare Keyboard Shortcuts Reference + Shortcuts can be changed in Preferences › Shortcuts + DIFF GLOBAL Clone remote repository Close current tab @@ -540,17 +581,36 @@ Create new tab Open local repository Open Preferences dialog + Search/filter in current panel Show workspace dropdown menu Switch active tab - Zoom in/out + Zoom in + Zoom out + INTERACTIVE REBASE + Set action of selected commits to 'Drop' + Set action of selected commits to 'Edit' + Set action of selected commits to 'Fixup' + Move selected commits down + Move selected commits up + Set action of selected commits to 'Pick' + Set action of selected commits to 'Reword' + Set action of selected commits to 'Squash' + MERGE CONFLICT EDITOR + Switch to next repository + Switch to previous repository REPOSITORY Commit staged changes Commit and push staged changes Stage all changes and commit + Copy repository path Create new branch + Create new branch from selected commit + Create new tag on selected commit Fetch, starts directly Goto child of selected commit Goto parent of selected commit + Open selected file with default editor + Open repository in Visual Studio Code Open command palette Pull, starts directly Push, starts directly @@ -583,6 +643,7 @@ Target Branch: Copy Link Open in Browser + Clone Commands ERROR NOTICE @@ -625,6 +686,13 @@ Move Repository Node Select parent node for: Name: + REPOSITORIES + All Repositories + Fetch All Repositories + Pull All Repositories + Push All Repositories (with outgoing commits) + Rescan & Refresh All Repositories + {0} all repositories: {1} succeeded, {2} failed, {3} skipped NO Git has NOT been configured. Please to go [Preferences] and configure it first. Open @@ -682,6 +750,12 @@ Use auto-hide scrollbars Use fixed tab width in titlebar Use native window frame + AZURE DEVOPS + Sign in to clone repositories from your Azure DevOps organizations without copying URLs. SourceGit then also uses this account for fetching and pushing over HTTPS, so no extra credentials or SSH keys are needed. + The Azure DevOps integration is not configured in this build. + Clone with SSH instead of HTTPS (requires an SSH key on Azure DevOps) + Use this account for fetch, pull and push over HTTPS + Replaces other credential helpers (Keychain, Git Credential Manager, ...) for https://dev.azure.com and *.visualstudio.com while signed in DIFF/MERGE TOOL Diff Arguments Available variables: $LOCAL, $REMOTE @@ -694,10 +768,8 @@ Check for updates on startup Date Format Enable compact folders in changes tree - Language History Commits Show `LOCAL CHANGES` page by default - Show `CHANGES` tab in commit detail by default Show relative time in commit graph Show tags in commit graph Subject Guide Length @@ -727,7 +799,23 @@ Tag GPG signing User Signing Key User's gpg signing key + GITHUB + Sign in to clone repositories from your organizations without copying URLs. SourceGit then also uses this account for fetching and pushing over HTTPS, so no extra credentials or SSH keys are needed. + The GitHub integration is not configured in this build. + Clone with SSH instead of HTTPS (requires an SSH key on GitHub) + Sign Out + Signed in as + Not signed in + Use this account for fetch, pull and push over HTTPS + Replaces other credential helpers (Keychain, Git Credential Manager, ...) for https://github.com while signed in INTEGRATION + SHORTCUTS + This shortcut is also used by another action + Press new shortcut... + Reset to default + Reset All + Search by action or key combination... + Click a shortcut and press the new key combination. Backspace removes the shortcut, Esc cancels. SHELL/TERMINAL Arguments Please use '.' to indicate working directory @@ -890,7 +978,10 @@ Check for updates failed! Download Skip This Version + Later + The update has been downloaded and will be installed when SourceGit quits. New Version Release Date: + Restart Now Software Update There are currently no updates available. Set Push URL for Remote @@ -994,6 +1085,13 @@ Merge ${0}$ into ${1}$... Push ${0}$... TERMINATE + Actions + Branch + Cleanup + LFS + Open + Patch + Stats Update Submodules All submodules Initialize as needed diff --git a/src/Resources/Locales/es_ES.axaml b/src/Resources/Locales/es_ES.axaml deleted file mode 100644 index 856153ea2f..0000000000 --- a/src/Resources/Locales/es_ES.axaml +++ /dev/null @@ -1,1079 +0,0 @@ - - - - - - Acerca de - Acerca de SourceGit - Fecha de Release: {0} - Notas de la versión (Release) - Cliente Git GUI de código abierto y gratuito - Agregar Archivo(s) Para Ignorar - Patrón: - Almacenar Archivo: - Agregar Worktree - Ubicación: - Ruta para este worktree. Se admite ruta relativa. - Nombre de la Rama: - Opcional. Por defecto es el nombre de la carpeta de destino. - Rama de Seguimiento: - Seguimiento de rama remota - Qué Checkout: - Crear Nueva Rama - Rama Existente - Asistente OpenAI - Modelo - RE-GENERAR - Usar OpenAI para generar mensaje de commit - Usar - Ocultar SourceGit - Ocultar Otros - Mostrar Todo - Merge a 3 vías (3-Way) - Seleccionar archivo parche para aplicar - Ignorar cambios de espacios en blanco - Fuente: - Archivo - Portapapeles - Aplicar Parche - Espacios en Blanco: - Aplicar Stash - Borrar después de aplicar - Restaurar los cambios del índice - Stash: - Archivar... - Guardar Archivo en: - Seleccionar ruta del archivo - Revisión: - Archivar - SourceGit Askpass - Introduce la frase de contraseña: - ARCHIVOS ASUMIDOS COMO SIN CAMBIOS - NO HAY ARCHIVOS ASUMIDOS COMO SIN CAMBIOS - Cargar Imagen... - Refrescar - Bisect - Abortar - Malo - Bueno - Saltar - Bisecting. Por favor revisa otro y márcalo como bueno o malo. - Bisecting. Marca el commit actual como malo o revisa otro y márcalo como malo. - Bisecting. Marcar el commit actual como bueno o malo y revisar otro. - Bisecting. ¿Es el HEAD actual bueno o malo? - Blame - Blame sobre la Revisión Previa - Ignorar cambios de espacios en blanco - Mantener presionado Ctrl (en Windows/Linux) o ⌘ (en macOS) cuando se hace click en el SHA del commit reconstruirá lo datos del blame basados en esa revisión. - ¡BLAME EN ESTE ARCHIVO NO SOPORTADO! - Checkout ${0}$... - Comparar las 2 ramas seleccionadas - Comparar con... - Comparar con HEAD - Comparar con ${0}$ - 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}$ - Hacer Rebase interactivamente ${0}$ en ${1}$ - Merge ${0}$ en ${1}$... - Hacer merge de las ramas {0} seleccionadas hacia la rama actual - Pull ${0}$ - Pull ${0}$ en ${1}$... - Push ${0}$ - Rebase ${0}$ en ${1}$... - Renombrar ${0}$... - Resetear ${0}$ a ${1}$... - Cambiar a ${0}$ (worktree) - Establecer Rama de Seguimiento... - {0} commit(s) adelante - {0} commit(s) adelante, {1} commit(s) detrás - {0} commit(s) detrás - Inválido - PUSH URL - REMOTO - ESTADO - SEGUIMIENTO - URL - WORKTREE - CANCELAR - Resetear a Revisión Padre - Resetear a Esta Revisión - Generar mensaje de commit - Merge (Incorporado) - Merge (Externa) - Resetear Archivo(s) a ${0}$ - CAMBIAR MODO DE VISUALIZACIÓN - Mostrar como Lista de Archivos y Directorios - Mostrar como Lista de Rutas - Mostrar como Árbol de Sistema de Archivos - Cambiar la URL del Submódulo - Submódulo: - URL: - Checkout Rama - Cambios Locales: - Rama: - ¡Tu HEAD actual contiene commit(s) que no están conectados a ningunas ramas/etiquetas! ¿Quieres continuar? - Los siguientes submódulos necesitan ser actualizados:{0} ¿Quieres actualizarlos? - Checkout y Fast-Forward - Fast-Forward a: - Checkout a la Rama desde el Stash - Nueva Rama: - Stash: - Hacer checkout a Commit o Etiqueta - Destino: - Advertencia: Después de hacer esto, se deprenderá/separará de HEAD - Cherry Pick - Añadir fuente al mensaje de commit - Commit(s): - Commit todos los cambios - Mainline: - Normalmente no puedes cherry-pick un merge porque no sabes qué lado del merge debe considerarse la línea principal. Esta opción permite que cherry-pick reproduzca el cambio en relación con el padre especificado. - Limpiar Stashes - Estás intentando limpiar todos los stashes. ¿Estás seguro de continuar? - Clonar Repositorio Remoto - Parámetros Adicionales: - Argumentos adicionales para clonar el repositorio. Opcional. - Marcador: - Grupo: - Nombre Local: - Nombre del repositorio. Opcional. - Carpeta Padre: - Inicializar y actualizar submódulos - URL del Repositorio: - CERRAR - Editor - Ramas - Ramas y Etiquetas - Acciones Personalizadas del Repositorio - Archivos de Revisión - Checkout Commit - Cherry-Pick Este Commit - Cherry-Pick ... - Comparar con HEAD - Comparar con Worktree - Autor - Fecha/Hora del Autor - Mensaje - Committer - Fecha/Hora del Committer - SHA - Asunto - Acción personalizada - Rebase interactivo - Eliminar... - Editar... - Arreglar en el Padre... - Hacer Rebase interactivamente ${0}$ en ${1}$ - Reescribir... - Squash en el Padre... - Merge ... - Push ${0}$ a ${1}$ - Rebase ${0}$ en ${1}$ - Resetear ${0}$ a ${1}$ - Revertir Commit - Guardar como Parche... - CAMBIOS - archivo(s) modificado(s) - Buscar Cambios... - Colapsar detalles - ARCHIVOS - Archivo LFS - Buscar Archivos... - Submódulo - INFORMACIÓN - AUTOR - COMMITTER - Ver refs que contienen este commit - COMMIT ESTÁ CONTENIDO EN - Copiar Email - Copiar Nombre - Copiar Nombre y Email - Muestra solo los primeros 100 cambios. Ver todos los cambios en la pestaña CAMBIOS. - Clave: - MENSAJE - PADRES - REFS - SHA - Firmante: - Abrir en Navegador - COL - Ingresa el mensaje de commit. ¡Por favor usa una línea en blanco para separar el título y la descripción! - ASUNTO - Comparar - CAMBIOS - COMMITS - SOLO COMMITS A LA IZQUIERDA - SOLO COMMITS A LA DERECHA - Tips: Puedes hacer cherry-pick a los commits seleccionados si el otro lado está en HEAD (usando el menú contextual). - Configurar Repositorio - PLANTILLA DE COMMIT - 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 - ${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 - Nombre: - Alcance: - Rama - Commit - Archivo - Remoto - Repositorio - Etiqueta - Esperar la acción de salida - Dirección de Email - Dirección de email - GIT - Preguntar antes de actualizar automáticamente los submódulos - Fetch remotos automáticamente - Minuto(s) - Tipos de Commit Convencionales - Remoto por Defecto - Habilitar `--recursive` cuando se actualicen automáticamente los submódulos - 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 - Añadir Regla de Ejemplo para Incidencias de GitLab - Añadir Regla de Ejemplo para Merge Requests de GitLab - Añadir Regla de Ejemplo para Jira - Nueva Regla - Expresión Regex para Incidencias: - Nombre de la Regla: - Compartir esta regla en el archivo .issuetracker - URL Resultante: - Por favor, use $1, $2 para acceder a los valores de los grupos regex. - OPEN AI - Servicio Preferido: - 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 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 - Descripción: - Por defecto: - Es Carpeta: - Etiqueta: - Opciones: - Usar '|' como delimitador para las opciones - Formateador de Cadenas de texto: - Opcional. Utilizado para formatear la cadena de salida. Ignorado cuando la entrada está vacía. Por favor utiliza `${VALUE}` para representar la cadena de entrada. - La variables incorporadas ${REPO}, ${REMOTE}, ${BRANCH}, ${BRANCH_FRIENDLY_NAME}, ${SHA}, ${FILE}, y ${TAG} permanecen disponibles aquí - Tipo: - Utilizar Nombre Amigable: - Espacios de Trabajo - Color - Nombre - Restaurar pestañas al iniciar - CONTINUAR - ¡Commit vacío detectado! ¿Quieres continuar (--allow-empty)? - HACER STAGE A TODO y COMMIT - STAGE LO SELECCIONADO y COMMIT - ¡Commit vacío detectado! ¿Quieres continuar (--allow-empty) o hacer stage a todo y después commit? - Reinicio Requerido - Necesita reiniciar esta aplicación para aplicar los cambios. - Asistente de Commit Convencional - Cambio Importante: - Incidencia Cerrada: - Detalles del Cambio: - Alcance: - Descripción Corta: - Tipo de Cambio: - Copiar - Copiar Todo el Texto - Copiar como Parche - Copiar Ruta Completa - Copiar Ruta - Crear Rama... - Basado En: - Checkout de la rama creada - Cambios Locales: - Nombre de la Nueva Rama: - Introduzca el nombre de la rama. - Crear Rama Local - Sobrescribir la rama existente - Crear Etiqueta... - Nueva Etiqueta En: - Firma GPG - Mensaje de la Etiqueta: - Opcional. - Nombre de la Etiqueta: - Formato recomendado: v1.0.0-alpha - Push a todos los remotos después de crear - Crear Nueva Etiqueta - Tipo: - anotada - ligera - Mantenga Ctrl para iniciar directamente - Cortar - Tablero - Descartar - No Hacer Nada - Stash y Volver a aplicar - Desinicializar Submódulo - Forzar desinicialización incluso si contiene cambios locales. - Submódulo: - Eliminar Rama - Rama: - Forzar la eliminación incluso si contiene commit(s) sin fusionar - ¡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 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: - Destino: - Todos los hijos serán removidos de la lista. - ¡Esto solo lo removera de la lista, no del disco! - Confirmar Eliminación de Grupo - Confirmar Eliminación de Repositorio - Eliminar Submódulo - Ruta del Submódulo: - Eliminar Etiqueta - Etiqueta: - Eliminar de los repositorios remotos - DIFERENCIA BINARIA - VER CONTENIDO NUEVO - ARCHIVO VACÍO - Primera Diferencia - Ignorar Cambio de Espacios en Blanco - MEZCLAR - DIFERENCIA - LADO-A-LADO - DESLIZAR - Última Diferencia - CAMBIO DE OBJETO LFS - NUEVO - Siguiente Diferencia - SIN CAMBIOS O SOLO CAMBIOS DE EOL - VIEJO - Diferencia Anterior - Guardar como Parche - Mostrar símbolos ocultos - Diferencia Lado a Lado - SUBMÓDULO - BORRADO - NUEVO - + {0} Cambios Sin confirmar - Intercambiar - Resaltado de Sintaxis - Ajuste de Línea - 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: - Incluir archivos ignorados - Incluir archivos modificados/eliminados - Incluir archivos sin rastrear - Total {0} cambios serán descartados - ¡No puedes deshacer esta acción! - Editar la descripción de la rama - Destino: - Marcador: - Nuevo Nombre: - Destino: - Editar Grupo Seleccionado - Editar Repositorio Seleccionado - Destino: - Este repositorio - Fetch - Fetch todos los remotos - Utilizar opción '--force' - Fetch sin etiquetas - Remoto: - Fetch Cambios Remotos - ARCHIVO BINARIO - VISOR HEXADECIMAL - Ir a la dirección... - Asumir como sin cambios - Acción Personalizada - Descartar... - Descartar {0} archivos... - Resolver usando ${0}$ - Guardar como Parche... - Stage - Stage {0} archivos - Stash... - Stash {0} archivos... - Unstage - Unstage {0} archivos - Usar Míos (checkout --ours) - Usar Suyos (checkout --theirs) - Historial de Archivos - CAMBIO - CONTENIDO - Cambiar modo archivo: - Modo archivo eliminado: - Directorio - Ejecutable - Modo archivo nuevo: - Normal - Submódulo - Enlace simbólico (Symlink) - Desconocido - Git-Flow - Rama de Desarrollo: - Feature: - Prefijo de Feature: - Finalizar ${0}$ - FLOW - Finalizar Feature - FLOW - Finalizar Hotfix - FLOW - Finalizar Release - Destino: - Hacer rebase antes de fusionar - Squash durante el merge - Hotfix: - Prefijo de Hotfix: - Inicializar Git-Flow - Mantener rama - Rama de Producción: - Release: - Prefijo de Release: - Iniciar en: - Iniciar Feature... - FLOW - Iniciar Feature - Iniciar Hotfix... - FLOW - Iniciar Hotfix - Nombre: - Introducir nombre - Iniciar Release... - FLOW - Iniciar Release - Prefijo de Etiqueta de Versión: - Git LFS - Añadir Patrón de Seguimiento... - El patrón es el nombre del archivo - Patrón Personalizado: - Añadir Patrón de Seguimiento a Git LFS - Fetch - Ejecuta `git lfs fetch` para descargar objetos Git LFS. Esto no actualiza la copia de trabajo. - Fetch Objetos LFS - Instalar hooks de Git LFS - Mostrar Bloqueos - No hay archivos bloqueados - Bloquear - 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 - Pull - Ejecuta `git lfs pull` para descargar todos los archivos Git LFS para la referencia actual y hacer checkout - Pull Objetos LFS - Push - Push archivos grandes en cola al endpoint de Git LFS - Push Objetos LFS - Remoto: - Seguir archivos llamados '{0}' - Seguir todos los archivos *{0} - Seleccionar Commit - Opciones Avanzadas - AUTOR - HORA DEL AUTOR - FECHA DE COMMIT - GRÁFICO y ASUNTO - SHA - DESTACADOS EN EL GRÁFICO - Todos - Solo la Rama Actual - Rama Actual y los Commits Seleccionados - Solo los Commits Seleccionados - Commits seleccionados (Solamente el primer padre) - {0} COMMITS SELECCIONADOS - MOSTRAR COLUMNAS - Mantén 'Ctrl' o 'Shift' para seleccionar múltiples commits. - Mantén ⌘ o ⇧ para seleccionar múltiples commits. - CONSEJOS: - Abrir en una ventana separada - Detalles del Commit - Comparación de Revisiones - Referencia de Atajos de Teclado - GLOBAL - Clonar repositorio nuevo - Cerrar página actual - Ir a la siguiente página - Ir a la página anterior - Crear nueva página - Abrir repositorio local - Abrir diálogo de preferencias - Mostrar menú desplegable del espacio de trabajo - Cambiar página activa - Acercar/Alejar - REPOSITORIO - Commit cambios staged - Commit y push cambios staged - Stage todos los cambios y commit - Crear nueva rama - Fetch, empieza directamente - Ir al hijo del commit seleccionado - Ir al padre del commit seleccionado - Abrir paleta de comandos - Pull, empieza directamente - Push, empieza directamente - Forzar a recargar este repositorio - Expandir/Colapsar panel detallado del commit - Alternar panel de búsqueda del commit - Cambiar a 'Cambios' - Cambiar a 'Tablero' - Cambiar a 'Stashes' - Descartar - Stage - Unstage - Inicializar Repositorio - ¿Quieres correr el comando `git init` en esta ruta? - Falló la apertura del repositorio. Razón: - Ruta: - Cherry-Pick en progreso. - Procesando commit - Merge en progreso. - Haciendo merge - Rebase en progreso. - Pausado en - Revert en progreso. - Haciendo revert del commit - Rebase Interactivo - Stash y volver a aplicar cambios locales - Saltar el hook de pre-rebase - En: - Arrastrar y soltar para reordenar commits - Rama Destino: - Copiar Enlace - Abrir en el Navegador - Comandos - ERROR - AVISO - Nueva Versión Disponible - Abrir Repositorios - Páginas - Espacios de trabajo - Merge Rama - Personalizar mensaje de merge - En: - Opción de Merge: - Rama Fuente: - Pruebas para hacer merge... - El merge se puede realizar sin conflictos - Error desconocido ocurrido al probar el merge - Hacer merge causará conflictos - Primero Míos, después Suyos - Primero Suyos, después Míos - USAR AMBOS - Todos los conflictos resueltos - {0} conflicto(s) restantes - MÍOS - Conflicto Siguiente - Conflicto Previo - RESULTADO - GUARDAR y hacer STAGE - SUYOS - Conflictos de Merge - ¿Descartar cambios sin guardar? - USAR MÍOS - USAR SUYOS - DESHACER - Merge (Multiple) - Commit todos los cambios - Estrategia: - Destino: - Mover Submódulo - Mover A: - Submódulo: - Mover Nodo del Repositorio - Seleccionar nodo padre para: - Nombre: - NO - 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 - Cache - Configuración - Abrir Archivo - Abrir en Herramienta de Merge - Abrir Repositorio Local - Marcador: - Grupo: - Carpeta: - Opcional. - Crear Nueva Página - Cerrar Pestaña - Cerrar Otras Pestañas - Cerrar Pestañas a la Derecha - Copiar Ruta del Repositorio - Editar - Mover al Espacio de trabajo - Actualizar - Repositorios - Pegar - Hace {0} días - Hace 1 hora - Hace {0} horas - Justo ahora - Último mes - Último año - Hace {0} minutos - Hace {0} meses - Hace {0} años - Ayer - Preferencias - OPEN AI - Prompt adicional (Usa `-` para listar tus requerimientos) - Clave API - Encabezados adicionales (un `Nombre: Valor` por línea) - Modelo - Traer automáticamente los model-ids disponibles - Nombre - El valor ingresado es el nombre de la clave API a cargar desde ENV - Nivel de Esfuerzo de Razonamiento - Servidor - APARIENCIA - Fuente por defecto - Ancho de la Pestaña del Editor - Tamaño de fuente - Por defecto - Editor - Fuente Monospace - 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 la página `CAMBIOS LOCALES` por defecto - Mostrar pestaña de `CAMBIOS` en los detalles del commit por defecto - Mostrar hora relativa en el gráfico de commits - Mostrar etiquetas en el gráfico de commit - Longitud de la guía del asunto - 24-Horas - Utilizar nombres de ramas compactos en el gráfico de commits - Generar avatar con estilo por defecto de Github - GIT - Habilitar Auto CRLF - Directorio de clonado por defecto - Email del usuario - Email global del usuario git - Habilitar --prune para fetch - Habilitar --ignore-cr-at-eol en diff - Se requiere Git (>= 2.25.1) para esta aplicación - Ruta de instalación - Habilitar verificación HTTP SSL - Usar git-credential-libsecret en lugar de git-credential-manager - Nombre del usuario - Nombre global del usuario git - Hacer Stash y volver a aplicar cambios por defecto cuando se haga checkout o fusionen las ramas - Versión de Git - FIRMA GPG - Firma GPG en commit - Formato GPG - Ruta de instalación del programa - Introducir ruta para el programa gpg instalado - Firma GPG en etiqueta - Clave de firma del usuario - Clave de firma gpg del usuario - INTEGRACIÓN - SHELL/TERMINAL - Argumentos - Por favor utiliza '.' para indicar el directorio de trabajo - Ruta - Shell/Terminal - Podar Remoto - Destino: - Podar Worktrees - Podar información de worktree en `$GIT_COMMON_DIR/worktrees` - Pull - Rama Remota: - En: - Cambios Locales: - Remoto: - Pull (Fetch & Merge) - Usar rebase en lugar de merge - Push - Asegurarse de que los submódulos se hayan hecho push - Forzar push - Rama Local: - NUEVO - Saltar el hook de pre-push - Remoto: - Revisión: - Push Revisión al Remoto - Push Cambios al Remoto - Rama Remota: - Establecer como rama de seguimiento - Push todas las etiquetas - Push Etiqueta al Remoto - 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 y volver a aplicar cambios locales - Saltar el hook de pre-rebase - En: - Pruebas para hacer rebase ... - El rebase se puede realizar sin conflictos - Error desconocido ocurrido al probar el rebase - Hacer rebase causará conflictos - Añadir Remoto - Editar Remoto - Nombre: - Nombre remoto - Resetear la "push URL" a la URL de este repositorio - URL del Repositorio: - URL del repositorio git remoto - Copiar URL - Acción Personalizada - Borrar... - Editar... - Habilitar Auto-Fetch - Fetch - Abrir En Navegador - Podar (Prune) - Establecer Push URL... - Confirmar para Eliminar Worktree - Utilizar Opción `--force` - Destino: - Renombrar Rama - Nuevo Nombre: - Nombre único para esta rama - Rama: - ABORTAR - Auto fetching cambios desde remotos... - Ordenar - Por Fecha de Committer - Por Nombre - Limpiar (GC & Prune) - Ejecutar comando `git gc` para este repositorio. - Limpiar todo - Limpiar - Configurar este repositorio - CONTINUAR - Acciones Personalizadas - No hay ninguna Acción Personalizada - Descartar todos los cambios - Abrir en el Explorador - Buscar Ramas/Etiquetas/Submódulos - Visibilidad en el Gráfico - Colapsar Filtros - Desestablecer - Ocultar en el Gráfico de Commits - Expandir Filtros - Filtrar en el Gráfico de Commits - filtro(s) activado(s) - DISPOSICIÓN - Horizontal - Vertical - ORDEN DE COMMITS - Fecha de Commit - Topológicamente - RAMAS LOCALES - Navegar a HEAD - Crear Rama - LIMPIAR NOTIFICACIONES - Abrir como Carpeta - Abrir en {0} - Abrir en Herramientas Externas - REMOTOS - AÑADIR REMOTO - RESOLVER - Buscar Commit - Autor - Contenido - Mensaje - Ruta - SHA - Rama Actual - BUSCAR POR - Buscar Commits - Sólo los commits decorados - Mostrar sólo el primer padre - MOSTRAR FLAGS - Mostrar commits perdidos - Mostrar Submódulos como Árbol - Mostrar Etiquetas como Árbol - OMITIR - Estadísticas - SUBMÓDULOS - AÑADIR SUBMÓDULO - ACTUALIZAR SUBMÓDULO - ETIQUETAS - NUEVA ETIQUETA - Por Fecha de Creación - Por Nombre - Ordenar - Abrir en Terminal - Ver Logs - Visitar '{0}' en el Navegador - WORKTREES - AÑADIR WORKTREE - PRUNE - URL del Repositorio Git - Resetear Rama Actual a Revisión - Modo de Reset: - Mover a: - Rama Actual: - Resetear Rama (Sin hacer Checkout) - Mover A: - Rama: - Revelar en el Explorador de Archivos - Revertir Commit - Commit: - Commit revertir cambios - Ejecutando. Por favor espera... - GUARDAR - Guardar Como... - ¡El parche se ha guardado exitosamente! - Escanear Repositorios - Directorio Raíz: - Escanear otro directorio personalizado - Buscar Actualizaciones... - Nueva versión de este software disponible: - Versión Actual: - ¡Error al buscar actualizaciones! - Descargar - Omitir Esta Versión - Fecha de Release de la Nueva Versión: - Actualización de Software - Actualmente no hay actualizaciones disponibles. - Establecer Push URL para el Remoto - Push URL: - Remoto: - URL: - Establecer Rama del Submódulo - Submódulo: - Actual: - Cambiar A: - Opcional. Establecer por defecto cuando este vacío. - Establecer Rama de Seguimiento - Rama: - Desestablecer upstream - Upstream: - Copiar SHA - Ir a - Clave Privada SSH: - Ruta de almacenamiento de la clave privada SSH - Abrir el Asistente para Claves SSH - ¿De verdad deseas borrar las siguientes claves? - Fingerprint - Generar Clave SSH - Confirmar Contraseña: - Email: - Requerido. - Nombre de la Clave: - Requerido. Por ejemplo: id_github - Contraseña: - GENERAR - Tipo: - Usar contraseña para la clave privada - Ruta - Clave Pública - Asistente para Claves SSH - INICIAR - Stash - Incluir archivos sin rastrear - Mensaje: - Opcional. Información de este stash - Modo: - Solo cambios staged - ¡Tanto los cambios staged como los no staged de los archivos seleccionados serán stashed! - Stash Cambios Locales - Aplicar - Aplicar Cambios - Checkout a Nueva Rama - Copiar Mensaje - Eliminar - Guardar como Parche... - Eliminar Stash - Eliminar: - Stashes - CAMBIOS - STASHES - Estadísticas - GENERAL - MES - SEMANA - SourceGit solamente obtendrá un máximo de 200,000 commits de acuerdo a la rama destino para su análisis. - AUTORES: - COMMITS: - SUBMÓDULOS - Añadir Submódulo - RAMA - Rama - Ruta Relativa - Desinicializar Submódulo - Fetch submódulos anidados - Historial - Mover A - Abrir Repositorio del Submódulo - Ruta Relativa: - Carpeta relativa para almacenar este módulo. - Eliminar Submódulo - Establecer Rama - Cambiar URL - ESTADO - modificado - no inicializado - revisión cambiada - unmerged - Actualizar - URL - Cambiar Detalles del Submódulo - ABRIR DETALLES - OK - ETIQUETADOR - HORA - Hacer checkout a Etiqueta... - Comparar 2 etiquetas - Comparar con... - Comparar con HEAD - Mensaje - Nombre - Etiquetador - Copiar Nombre de la Etiqueta - Acción Personalizada - Eliminar ${0}$... - Eliminar {0} etiquetas seleccionadas... - Hacer merge de ${0}$ a ${1}$... - Hacer push a ${0}$... - FINALIZAR - Actualizar Submódulos - Todos los submódulos - Inicializar según sea necesario - Submódulo: - Actualizar submódulos anidados - Actualizar la rama de seguimiento remota del submódulo - URL: - Logs - LIMPIAR TODO - Copiar - Borrar - Advertencia - Página de Bienvenida - Crear Grupo - Crear Sub-Grupo - Clonar Repositorio - Eliminar - SOPORTA ARRASTRAR Y SOLTAR CARPETAS. SOPORTA AGRUPACIÓN PERSONALIZADA. - Editar - Mover a Otro Grupo - Abrir Todos Los Repositorios - Abrir Repositorio - Abrir Terminal - Reescanear Repositorios en el Directorio de Clonado por Defecto - Buscar Repositorios... - Cambios - Git Ignore - Ignorar todos los archivos *{0} - Ignorar archivos *{0} en la misma carpeta - Ignorar archivos sin rastrear en esta carpeta - Ignorar solo este archivo - Ignorar todos los archivos sin rastrear en la misma carpeta - 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 y PUSH - Plantilla/Historias - Activar evento de clic - Commit (Editar) - Hacer stage a todos los cambios y commit - Estas creando un commit en una HEAD separada. ¿Quieres continuar? - Tienes {0} archivo(s) en stage, pero solo {1} archivo(s) mostrado(s) ({2} archivo(s) están filtrados). ¿Quieres continuar? - CONFLICTOS DETECTADOS - MERGE - Merge con Herramienta Externa - ABRIR TODOS LOS CONFLICTOS EN HERRAMIENTA DE MERGE EXTERNA - LOS CONFLICTOS DE ARCHIVOS ESTÁN RESUELTOS - USAR MÍOS - USAR SUYOS - DESCARTAR TODO - Cambios de Filtro... - INCLUIR ARCHIVOS SIN RASTREAR - NO HAY MENSAJES DE ENTRADA RECIENTES - NO HAY PLANTILLAS DE COMMIT - Sin verificar - Restablecer Autor - Firmar - STAGED - UNSTAGE - UNSTAGE TODO - UNSTAGED - STAGE - STAGE TODO - VER ASUMIR COMO SIN CAMBIOS - Plantilla: ${0}$ - ESPACIO DE TRABAJO: - Configura Espacios de Trabajo... - WORKTREE - RAMA - Copiar Ruta - HEAD - Bloquear - Abrir - RUTA - Eliminar - Desbloquear - SÍ - diff --git a/src/Resources/Locales/fr_FR.axaml b/src/Resources/Locales/fr_FR.axaml deleted file mode 100644 index 823b851bae..0000000000 --- a/src/Resources/Locales/fr_FR.axaml +++ /dev/null @@ -1,991 +0,0 @@ - - - - - - À propos - À propos de SourceGit - Date de publication : {0} - 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é. - Nom de branche: - Optionnel. Nom du dossier de destination par défaut. - Suivre la branche : - Suivi de la branche distante - Que récupérer : - Créer une nouvelle branche - Branche existante - Assistant IA - Modèle - RE-GÉNÉRER - Utiliser l'IA pour générer un message de commit - Utiliser - Masquer SourceGit - Masquer les autres - Tout Afficher - Fusion à 3 voies - Selectionner le fichier patch à appliquer - Ignorer les changements d'espaces blancs - Appliquer le patch - Espaces blancs : - Appliquer le Stash - Supprimer après application - Rétablir les changements de l'index - Stash: - Archiver... - Enregistrer l'archive sous : - Sélectionnez le chemin du fichier d'archive - 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 - Bisect - Annuler - Mauvais - Bon - Passer - Bisect en cours. Marquer le commit actuel comme bon ou mauvais et en récupérer un autre. - Bisect en cours. Le HEAD actuel est-il bon ou mauvais ? - Blâme - Blâmer sur la révision précédente - Ignorer les changements d'espaces - LE BLÂME SUR CE FICHIER N'EST PAS SUPPORTÉ!!! - Récupérer ${0}$... - Comparer les 2 branches sélectionnées - Comparer avec... - Comparer avec HEAD - Comparer avec ${0}$ - 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 - Modifier la description de ${0}$... - Fast-Forward vers ${0}$ - Fetch ${0}$ vers ${1}$... - Git Flow - Terminer ${0}$ - Rebaser Interactivement ${0}$ sur ${1}$ - Fusionner ${0}$ dans ${1}$... - Fusionner les {0} branches sélectionnées dans celle en cours - Tirer ${0}$ - Tirer ${0}$ dans ${1}$... - Pousser ${0}$ - Rebaser ${0}$ sur ${1}$... - Renommer ${0}$... - Réinitialiser ${0}$ sur ${1}$... - Basculer vers ${0}$ (worktree) - Définir la branche de suivi... - {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 - Générer un message de commit - Fusion (intégré) - Fusion (externe) - Réinitialiser le(s) fichier(s) à ${0}$ - CHANGER LE MODE D'AFFICHAGE - 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 - Changements locaux : - Branche : - Votre HEAD actuel contient un ou plusieurs commits non connectés à une branche/tag ! Voulez-vous continuer ? - Les sous-modules suivants doivent être mis à jour :{0}Voulez-vous les mettre à jour ? - Récupérer & Fast-Forward - Fast-Forward vers : - Créer une branche depuis le stash - Nouvelle branche : - Stash : - Cherry-Pick de ce commit - Ajouter la source au message de commit - Commit : - Commit tous les changements - Ligne principale : - Habituellement, on ne peut pas cherry-pick un commit car on ne sait pas quel côté devrait être considéré comme principal. Cette option permet de rejouer les changements relatifs au parent spécifié. - Supprimer les stashes - Vous essayez de supprimer tous les stashes. Êtes-vous sûr de vouloir continuer ? - Cloner repository distant - Paramètres supplémentaires : - Arguments additionnels au clônage. Optionnel. - Signet : - Groupe : - Nom local : - Nom de dépôt. Optionnel. - Dossier parent : - Initialiser et mettre à jour les sous-modules - URL du dépôt : - FERMER - Éditeur - Branches - Branches et tags - Actions personnalisées du dépôt - Fichiers de révision - Récupérer ce commit - Cherry-Pick ce commit - Cherry-Pick ... - Comparer avec HEAD - Comparer avec le worktree - Auteur - Message - Committer - SHA - Sujet - Action personnalisée - Rebase Interactif - Supprimer... - Modifier... - Fixup dans le Parent... - Rebaser Interactivement ${0}$ sur ${1}$ - Reformuler... - Squash dans le Parent... - Fusionner ... - Pousser ${0}$ vers ${1}$ - Rebaser ${0}$ sur ${1}$ - Réinitialiser ${0}$ sur ${1}$ - Annuler le commit - Enregistrer en tant que patch... - CHANGEMENTS - fichier(s) modifié(s) - Rechercher les changements... - Réduire les détails - FICHIERS - Fichier LFS - Rechercher des fichiers... - Sous-module - INFORMATIONS - AUTEUR - 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 - COL - Saisissez le message de commit. Utilisez une ligne vide pour séparer le sujet et la description ! - SUJET - Comparer - CHANGEMENTS - COMMITS - COMMITS UNIQUEMENT À GAUCHE - COMMITS UNIQUEMENT À DROITE - Astuce : vous pouvez cherry-pick les commits sélectionnés si l'autre côté est HEAD (via le menu contextuel). - 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 - Fichier - Remote - Dépôt - Tag - Attendre la fin de l'action - Adresse e-mail - Adresse e-mail - GIT - Demander avant mise à jour automatique des sous-modules - 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 - Ajouter une règle d'exemple pour Incidents GitLab - Ajouter une règle d'exemple pour Merge Request GitLab - Ajouter une règle d'exemple Jira - Nouvelle règle - Issue Regex Expression: - Nom de règle : - Partager cette règle dans le fichier .issuetracker - URL résultant: - Veuillez utiliser $1, $2 pour accéder aux valeurs des groupes regex. - IA - Service préféré: - Si le 'Service préféré' est défini, SourceGit l'utilisera seulement dans ce repository. Sinon, si plus d'un service est disponible, un menu contextuel permettant de choisir l'un d'eux sera affiché. - Proxy HTTP - 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 - Formateur de chaîne : - Optionnel. Utilisé pour formater la sortie. Ignoré si vide. Utilisez `${VALUE}` pour représenter la chaîne d'entrée. - Les variables intégrées ${REPO}, ${REMOTE}, ${BRANCH}, ${BRANCH_FRIENDLY_NAME}, ${SHA}, ${FILE}, et ${TAG} restent disponibles ici - Type : - Utiliser le nom convivial : - Espaces de travail - Couleur - Nom - Restaurer les onglets au démarrage - CONTINUER - Commit vide détecté ! Voulez-vous continuer (--allow-empty) ? - TOUT INDEXER & COMMIT - INDEXER LA SÉLECTION & 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 : - Détail des Modifications : - Portée : - Courte Description : - Type de Changement : - Copier - Copier tout le texte - Copier le chemin complet - Copier le chemin - Créer une branche... - Basé sur : - Récupérer la branche créée - Changements locaux : - Nom de la nouvelle branche : - Entrez le nom de la branche. - Créer une branche locale - Écraser la branche existante - Créer un tag... - Nouveau tag à : - Signature GPG - Message du tag : - Optionnel. - Nom du tag : - Format recommandé : v1.0.0-alpha - Pousser sur tous les dépôts distants après création - Créer un nouveau tag - Type : - annoté - léger - Maintenir Ctrl pour commencer directement - Couper - Annuler - Ne rien faire - Mettre en stash et réappliquer - 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: - Cible : - Tous les enfants seront retirés de la liste. - Cela le supprimera uniquement de la liste, pas du disque ! - Confirmer la suppression du groupe - Confirmer la suppression du dépôt - Supprimer le sous-module - Chemin du sous-module : - Supprimer le tag - Tag : - Supprimer des dépôts distants - DIFF BINAIRE - 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 - + {0} changements non commités - Permuter - Coloration syntaxique - Retour à la ligne - 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 modifiés/supprimés - Inclure les fichiers non suivis - {0} changements seront rejetés - Vous ne pouvez pas annuler cette action !!! - Modifier la description de la branche - Cible : - 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 - Fetch sans les tags - Remote : - Récupérer les changements distants - Présumer inchangé - Action personnalisée - Rejeter... - Rejeter {0} fichiers... - Résoudre en utilisant ${0}$ - Enregistrer en tant que patch... - Indexer - Indexer {0} fichiers - Stash... - Stash {0} fichiers... - Désindexer - Désindexer {0} fichiers - Utiliser les miennes (checkout --ours) - Utiliser les leurs (checkout --theirs) - Historique du fichier - MODIFICATION - CONTENU - Git-Flow - Branche de développement : - Feature: - Feature Prefix: - FLOW - Terminer Feature - FLOW - Terminer Hotfix - FLOW - Terminer Release - Cible: - Squash lors de la fusion - Hotfix: - Hotfix Prefix: - Initialiser Git-Flow - Garder la branche - Branche de production : - Release : - Release Prefix : - Commencer Feature... - FLOW - Commencer Feature - Commencer Hotfix... - FLOW - Commencer Hotfix - Saisir le nom - Commencer Release... - FLOW - Commencer Release - Préfixe Tag de Version : - Git LFS - Ajouter un pattern de suivi... - Le pattern est un nom de fichier - Pattern personnalisé : - Ajouter un pattern de suivi à Git LFS - Fetch - Lancer `git lfs fetch` pour télécharger les objets Git LFS. Cela ne met pas à jour la copie de travail. - Fetch les objets LFS - Installer les hooks Git LFS - Afficher les verrous - Pas de fichiers verrouillés - Verrouiller - 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 - Pull - Lancer `git lfs pull` pour télécharger tous les fichier Git LFS de la référence actuelle & récupérer - Pull les objets LFS - Pousser - Transférer les fichiers volumineux en file d'attente vers le point de terminaison Git LFS - Pousser les objets LFS - Dépôt : - Suivre les fichiers appelés '{0}' - Suivre tous les fichiers *{0} - Sélectionner un commit - AUTEUR - HEURE DE L'AUTEUR - HEURE DE COMMIT - GRAPHE & SUJET - SHA - MISE EN ÉVIDENCE AU GRAPHE - Tout - Branche courante uniquement - Branche courante et commits sélectionnés - Commits sélectionnés uniquement - {0} COMMITS SÉLECTIONNÉS - AFFICHER LES COLONNES - Maintenir 'Ctrl' ou 'Shift' enfoncée pour sélectionner plusieurs commits. - Maintenir ⌘ ou ⇧ enfoncée pour sélectionner plusieurs commits. - CONSEILS: - Ouvrir dans une fenêtre séparée - Détails du commit - Comparaison de révision - Référence des raccourcis clavier - GLOBAL - Cloner un nouveau dépôt - Fermer la page en cours - Aller à la page suivante - Aller à la page précédente - Créer une nouvelle page - Ouvrir un dépôt local - Ouvrir le dialogue des préférences - Afficher le menu des espaces de travail - Changer d'onglet actif - Zoom avant/arrière - DÉPÔT - Commit les changements de l'index - Commit et pousser les changements de l'index - Ajouter tous les changements et commit - Créer une nouvelle branche - Fetch, démarre directement - Aller au commit enfant - Aller au commit parent - Ouvrir la palette de commandes - Pull, démarre directement - Push, démarre directement - Forcer le rechargement du dépôt - Basculer vers 'Changements' - Basculer vers 'Stashes' - Rejeter - Indexer - Retirer de l'index - Initialiser le repository - Voulez-vous exécuter `git init` dans ce dossier ? - Échec de l'ouverture du dépôt. Raison : - Chemin : - Cherry-Pick en cours. - Traitement du commit - Merge request en cours. - Fusionnement - Rebase en cours. - Arrêté à - Annulation en cours. - Annulation du commit - Rebase interactif - Stash & réappliquer changements locaux - Contourner le hook de pre-rebase - 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: - D'abord les miens, puis les leurs - D'abord les leurs, puis les miens - UTILISER LES DEUX - Tous les conflits sont résolus - {0} conflit(s) restant(s) - MIENS - Conflit suivant - Conflit précédent - RÉSULTAT - SAUVER ET INDEXER - LEURS - Conflits de fusion - Abandonner les modifications non sauvegardées ? - UTILISER LES MIENS - UTILISER LES LEURS - ANNULER - Fusionner (Plusieurs) - 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 : - NON - 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 un fichier - Ouvrir dans l'outil de fusion - Ouvrir un dépôt local - Signet : - Groupe : - Dossier : - Optionnel. - Créer un nouvel onglet - Fermer l'onglet - Fermer les autres onglets - Fermer les onglets à droite - Copier le chemin vers le dépôt - Éditer - Se déplacer vers l'espace de travail - Actualiser - Dépôts - Coller - il y a {0} jours - il y a 1 heure - il y a {0} heures - A l'instant - Le mois dernier - L'an dernier - il y a {0} minutes - il y a {0} mois - il y a {0} ans - Hier - Préférences - IA - Prompt supplémentaire (utilisez `-` pour lister vos exigences) - Clé d'API - Modèle - Récupérer automatiquement les modèles disponibles - Nom - La valeur saisie est le nom pour charger la clé API depuis l'ENV - Serveur - APPARENCE - Police par défaut - Largeur de tab dans l'éditeur - Taille de police - Défaut - Éditeur - Police monospace - 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 - Arguments de diff - Variables disponibles : $LOCAL, $REMOTE - Arguments de merge - Variables disponibles : $BASE, $LOCAL, $REMOTE, $MERGED - Chemin d'installation - Saisir le chemin d'installation de l'outil diff/merge - Outil - GÉNÉRAL - Vérifier les mises à jour au démarrage - Format de date - Activer les dossiers compacts dans l'arborescence des changements - Language - Historique de commits - Afficher la page 'CHANGEMENTS LOCAUX' par défaut - Afficher l'onglet 'CHANGEMENTS' dans les détails du commit par défaut - Afficher le temps relatif dans le graphe de commits - Afficher les tags dans le graphique des commits - Guide de longueur du sujet - Format 24 heures - 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 - Utiliser stash & réappliquer par défaut lors des checkout/merge - Version de Git - SIGNATURE GPG - Signature GPG de commit - Format GPG - Chemin d'installation du programme - Saisir le chemin d'installation vers le programme GPG - Signature GPG de tag - Clé de signature de l'utilisateur - Clé de signature GPG de l'utilisateur - INTEGRATION - SHELL/TERMINAL - Arguments - Utilisez '.' pour représenter le répertoire de travail - Chemin - Shell/Terminal - Élaguer une branche distant - Cible : - Élaguer les Worktrees - Élaguer les information de worktree dans `$GIT_COMMON_DIR/worktrees` - Pull - Branche distante : - Dans : - Changements locaux : - Dépôt distant : - Pull (Fetch & Merge) - Utiliser rebase au lieu de merge - Pousser - Assurez-vous que les submodules ont été poussés - Poussage forcé - Branche locale : - NOUVEAU - Contourner le hook de pre-push - 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 - Pousser tous les tags - Pousser les tags vers le dépôt distant - 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 - Contourner le hook de pre-rebase - Sur : - Ajouter dépôt distant - Modifier dépôt distant - Nom : - Nom du dépôt distant - URL du repository : - URL du dépôt distant - Copier l'URL - Action personnalisée - Supprimer... - Editer... - Activer l'auto-fetch - Fetch - Ouvrir dans le navigateur - Elaguer - Confirmer la suppression du Worktree - Activer l'option `--force` - Cible : - 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 - Rejeter tous les changements - Ouvrir dans l'explorateur de fichiers - Rechercher Branches/Tags/Submodules - Visibilité dans le graphique - Réinitialiser - Cacher dans le graphique des commits - Filtrer dans le graphique des commits - DISPOSITION - Horizontal - Vertical - ORDRE DES COMMITS - Date du commit - Topologiquement - BRANCHES LOCALES - Naviguer vers le HEAD - Créer une branche - EFFACER LES NOTIFICATIONS - Ouvrir comme dossier - Ouvrir dans {0} - Ouvrir dans un outil externe - DEPOTS DISTANTS - AJOUTER DEPOT DISTANT - RÉSOUDRE - Rechercher un commit - Auteur - 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 - SUBMODULES - AJOUTER SUBMODULE - METTRE A JOUR SUBMODULE - TAGS - NOUVEAU TAG - Par date de créateur - Par nom - Trier - Ouvrir dans un terminal - Voir les Logs - Visiter '{0}' dans le navigateur - WORKTREES - AJOUTER WORKTREE - ELAGUER - URL du repository Git - Reset branche actuelle à la révision - 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 : - Commit les changements de l'annulation - En exécution. Veuillez patienter... - SAUVEGARDER - Sauvegarder en tant que... - 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 : - Version actuelle : - La vérification de mise à jour à échouée ! - Télécharger - Passer cette version - Date de la nouvelle 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 à - Clé privée SSH : - Chemin du magasin de clés privées SSH - START - Stash - 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 - Appliquer les changements - Créer une branche - Copier le Message - Effacer - Sauver comme Patch... - Effacer le Stash - Effacer : - Stashes - CHANGEMENTS - STASHES - Statistiques - APERCU - MOIS - SEMAINE - AUTEURS : - 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 - Détails des changements du sous-module - OUVRIR LES DÉTAILS - OK - TAGUEUR - HEURE - Comparer 2 tags - Comparer avec... - Comparer avec HEAD - Message - Nom - Tagueur - Copier le nom du tag - Action personnalisée - Supprimer ${0}$... - Supprimer les {0} tags sélectionnés... - Pousser ${0}$... - Actualiser les sous-modules - Tous les sous-modules - Initialiser au besoin - 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 - Créer un sous-groupe - Cloner un dépôt - Supprimer - GLISSER / DEPOSER DE DOSSIER SUPPORTÉ. GROUPAGE PERSONNALISÉ SUPPORTÉ. - Éditer - Déplacer vers un autre groupe - Ouvrir tous les dépôts - Ouvrir un dépôt - Ouvrir le terminal - Réanalyser les repositories dans le dossier de clonage par défaut - Chercher des dépôts... - Changements - 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 - FUSIONNER - Fusion avec un outil 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 - No-Verify - Réinitialiser l'Auteur - Signer - INDEXÉ - RETIRER DE L'INDEX - RETIRER TOUT DE L'INDEX - NON INDEXÉ - INDEXER - INDEXER TOUT - VOIR LES FICHIERS PRÉSUMÉS INCHANGÉS - Modèle: ${0}$ - ESPACE DE TRAVAIL : - Configurer les espaces de travail... - WORKTREE - BRANCHE - Copier le chemin - HEAD - Verrouiller - Ouvrir - CHEMIN - Supprimer - Déverrouiller - OUI - diff --git a/src/Resources/Locales/he_IL.axaml b/src/Resources/Locales/he_IL.axaml deleted file mode 100644 index 2ba8cc88c1..0000000000 --- a/src/Resources/Locales/he_IL.axaml +++ /dev/null @@ -1,991 +0,0 @@ - - - - - - אודות - אודות SourceGit - תאריך שחרור: {0} - הערות שחרור - לקוח Git גרפי, חופשי ובקוד פתוח - הוסף קבצים ל־Ignore - תבנית: - קובץ אחסון: - הוסף Worktree - מיקום: - נתיב ל־worktree זה. נתיב יחסי נתמך. - שם Branch: - לא חובה. ברירת המחדל היא שם תיקיית היעד. - Branch למעקב: - מעקב אחר branch מרוחק - מה לבצע לו checkout: - צור Branch חדש - Branch קיים - עוזר AI - מודל - צור מחדש - שימוש ב־AI ליצירת הודעת commit - שימוש - הסתר SourceGit - הסתר אחרים - הצג הכול - 3-Way Merge - בחר קובץ patch להחלה - התעלמות משינויי whitespace - החל Patch - Whitespace: - החל Stash - מחק לאחר ההחלה - שחזר שינויי ה־index - Stash: - ארכב... - שמור ארכיון אל: - בחר נתיב לקובץ הארכיון - Revision: - ארכב - SourceGit Askpass - הזן passphrase: - קבצים בהנחת assume-unchanged - אין קבצים בהנחת assume-unchanged - טען תמונה... - רענן - Bisect - ביטול - פגום (Bad) - תקין (Good) - דלג - מתבצע Bisect. יש לסמן את ה־commit הנוכחי כתקין או כפגום ולבצע checkout לאחר. - מתבצע Bisect. האם ה־HEAD הנוכחי תקין או פגום? - Blame - Blame ל־revision הקודם - התעלמות משינויי whitespace - לא ניתן לבצע Blame על קובץ מסוג זה!!! - Checkout ל־${0}$... - השווה בין 2 ה־branches שנבחרו - השווה עם... - השווה עם HEAD - השווה עם ${0}$ - העתק שם ה־Branch - צור PR... - צור PR ל־upstream ${0}$... - פעולה מותאמת אישית - מחק ${0}$... - מחק {0} ה־branches שנבחרו - ערוך תיאור ל־${0}$... - Fast-Forward אל ${0}$ - Fetch של ${0}$ אל ${1}$... - Git Flow - סיים ${0}$ - Interactive Rebase של ${0}$ על ${1}$ - Merge של ${0}$ אל ${1}$... - Merge של {0} ה־branches שנבחרו אל הנוכחי - Pull ${0}$ - Pull של ${0}$ אל ${1}$... - Push ${0}$ - Rebase של ${0}$ על ${1}$... - שנה שם ${0}$... - Reset של ${0}$ אל ${1}$... - עבור אל ${0}$ (worktree) - הגדר Tracking Branch... - {0} commits לפני - {0} commits לפני, {1} commits אחרי - {0} commits אחרי - לא תקין - REMOTE - סטטוס - TRACKING - URL - WORKTREE - ביטול - Checkout ל־revision של ההורה - Checkout ל־revision זה - צור הודעת commit - Merge (מובנה) - Merge (כלי חיצוני) - Reset של הקבצים אל ${0}$ - שנה מצב תצוגה - הצג כרשימת קבצים ותיקיות - הצג כרשימת נתיבים - הצג כעץ מערכת קבצים - שנה ה־URL של Submodule - Submodule: - URL: - Checkout של Branch - שינויים מקומיים: - Branch: - ה־HEAD הנוכחי מכיל commits שאינם מקושרים לאף branch או tag! האם להמשיך? - יש לעדכן את ה־submodules הבאים:{0}לעדכן אותם? - Checkout ו־Fast-Forward - Fast-Forward אל: - Checkout של Branch מתוך Stash - Branch חדש: - Stash: - Cherry-Pick - הוסף המקור להודעת ה־commit - Commits: - צור commit לכל השינויים - Mainline: - בדרך כלל לא ניתן לבצע cherry-pick ל־merge מכיוון שאין דרך לדעת איזה צד של ה־merge צריך להיחשב כ־mainline. אפשרות זו מאפשרת ל־cherry-pick לשחזר את השינוי ביחס להורה שצוין. - נקה Stashes - פעולה זו תנקה את כל ה־stashes. להמשיך? - שכפל מאגר מרוחק - פרמטרים נוספים: - ארגומנטים נוספים ל־clone. לא חובה. - סימנייה: - קבוצה: - שם מקומי: - שם המאגר. לא חובה. - תיקיית אב: - אתחול ועדכון submodules - URL של המאגר: - סגור - עורך - Branches - Branches ו־Tags - פעולות מותאמות של המאגר - קבצי Revision - Checkout של Commit - Cherry-Pick של Commit - Cherry-Pick ... - השווה עם HEAD - השווה עם ה־Worktree - Author - הודעה - Committer - SHA - Subject - פעולה מותאמת אישית - Interactive Rebase - Drop... - Edit... - Fixup לתוך ההורה... - Interactive Rebase של ${0}$ על ${1}$ - Reword... - Squash לתוך ההורה... - Merge ... - Push של ${0}$ אל ${1}$ - Rebase של ${0}$ על ${1}$ - Reset של ${0}$ אל ${1}$ - Revert של Commit - שמור כ־Patch... - שינויים - קבצים שונו - חיפוש בשינויים... - כיווץ הפרטים - קבצים - קובץ LFS - חיפוש קבצים... - Submodule - מידע - AUTHOR - COMMITTER - בדוק refs המכילים את ה־commit הזה - ה־COMMIT כלול ב־ - העתק דוא"ל - העתק שם - העתק שם ודוא"ל - מוצגים רק 100 השינויים הראשונים. כל השינויים זמינים בלשונית CHANGES. - מפתח: - הודעה - הורים - REFS - SHA - חותם: - פתח בדפדפן - עמודה - הזן הודעת commit. יש להפריד בין subject לתיאור באמצעות שורה ריקה! - SUBJECT - השווה - שינויים - COMMITS - COMMITS בצד שמאל בלבד - COMMITS בצד ימין בלבד - טיפ: ניתן לבצע cherry-pick ל־commits שנבחרו אם הצד השני הוא HEAD (דרך תפריט ההקשר). - הגדרות מאגר - תבנית COMMIT - פרמטרים מובנים: - - ${branch_name} שם ה־local branch הנוכחי. - ${files_num} מספר הקבצים ששונו - ${files} נתיבי הקבצים ששונו - ${files:N} עד N נתיבים של קבצים ששונו - ${pure_files} כמו ${files}, אך רק שמות קבצים נקיים - ${pure_files:N} כמו ${files:N}, אך ללא תיקיות - תוכן התבנית: - שם התבנית: - פעולה מותאמת אישית - ארגומנטים: - פרמטרים מובנים: - - ${REPO} נתיב המאגר - ${REMOTE} ה־remote שנבחר או ה־remote של ה־branch שנבחר - ${BRANCH} ה־branch שנבחר, ללא חלק ה־${REMOTE} עבור branches מרוחקים - ${BRANCH_FRIENDLY_NAME} שם ידידותי של ה־branch שנבחר, כולל את חלק ה־${REMOTE} עבור branches מרוחקים - ${SHA} ה־hash של ה־commit שנבחר - ${TAG} ה־tag שנבחר - ${FILE} הקובץ שנבחר, יחסי לשורש המאגר - $1, $2 ... ערכי שדות קלט - קובץ הרצה: - שדות קלט: - ערוך - שם: - תחום: - Branch - Commit - קובץ - Remote - מאגר - Tag - המתן לסיום הפעולה - כתובת דוא"ל - כתובת דוא"ל - GIT - לבקש אישור לפני עדכון אוטומטי של submodules - Fetch אוטומטי מ־remotes - דקות - סוגי Conventional Commit - Remote ברירת מחדל - מצב Merge מועדף - ISSUE TRACKER - הוסף כלל Azure DevOps - הוסף כלל Gerrit Change-Id Commit - הוסף כלל Gitee Issue - הוסף כלל Gitee Pull Request - הוסף כלל GitHub - הוסף כלל GitLab Issue - הוסף כלל GitLab Merge Request - הוסף כלל Jira - כלל חדש - ביטוי Regex לזיהוי Issue: - שם הכלל: - שיתוף כלל זה בקובץ .issuetracker - URL התוצאה: - השתמש ב־$1, $2 לגישה לערכי קבוצות ה־regex. - AI - שירות מועדף: - אם מוגדר 'שירות מועדף', SourceGit ישתמש רק בו במאגר זה. אחרת, אם זמינים מספר שירותים, יוצג תפריט הקשר לבחירת אחד מהם. - HTTP Proxy - HTTP proxy לשימוש המאגר הזה - שם משתמש - שם משתמש למאגר זה - ערוך שדות קלט של פעולה מותאמת אישית - ערך כאשר מסומן: - כאשר מסומן, ערך זה ישמש בארגומנטים של שורת הפקודה - תיאור: - ברירת מחדל: - תיקייה: - תווית: - אפשרויות: - השתמש ב־'|' כמפריד בין אפשרויות - String Formatter: - לא חובה. משמש לעיצוב מחרוזת הפלט. מתעלם כאשר הקלט ריק. השתמש ב־`${VALUE}` לייצוג מחרוזת הקלט. - המשתנים המובנים ${REPO}, ${REMOTE}, ${BRANCH}, ${BRANCH_FRIENDLY_NAME}, ${SHA}, ${FILE}, ו־${TAG} זמינים גם כאן - סוג: - שימוש בשם ידידותי: - סביבות עבודה - צבע - שם - שחזר לשוניות בעת ההפעלה - המשך - זוהה commit ריק! האם להמשיך (--allow-empty)? - Stage לכל ו־Commit - Stage לנבחרים ו־Commit - זוהה commit ריק! האם להמשיך (--allow-empty) או לבצע stage אוטומטי ואז commit? - נדרשת הפעלה מחדש - יש להפעיל את האפליקציה מחדש כדי להחיל את השינויים. - עוזר Conventional Commit - Breaking Change: - Issue שנסגר: - פירוט השינויים: - תחום: - תיאור קצר: - סוג השינוי: - העתק - העתק כל הטקסט - העתק נתיב מלא - העתק נתיב - צור Branch... - מבוסס על: - בצע checkout ל־branch שייווצר - שינויים מקומיים: - שם ה־Branch החדש: - הזן שם branch. - צור Branch מקומי - דריסת branch קיים - צור Tag... - Tag חדש על: - חתימת GPG - הודעת Tag: - לא חובה. - שם Tag: - פורמט מומלץ: v1.0.0-alpha - Push לכל ה־remotes לאחר היצירה - צור Tag - סוג: - annotated - lightweight - החזק Ctrl להפעלה ישירה - גזור - השלך - לא לעשות דבר - Stash והחלה מחדש - ביטול אתחול של Submodule - לכפות ביטול אתחול גם אם יש בו שינויים מקומיים. - Submodule: - מחק Branch - Branch: - פעולה זו תמחק branch מרוחק!!! - למחוק גם את ה־branch המרוחק ${0}$ - מחק מספר Branches - פעולה זו תמחק מספר branches בו זמנית. בדוק היטב לפני הביצוע! - מחק מספר Tags - מחק גם מה־remotes - פעולה זו תמחק מספר tags בו זמנית. בדוק היטב לפני הביצוע! - מחק Remote - Remote: - נתיב: - יעד: - כל הצאצאים יוסרו מהרשימה. - פעולה זו רק תסיר מהרשימה, לא תמחק מהדיסק! - אישור מחיקת קבוצה - אישור מחיקת מאגר - מחק Submodule - נתיב Submodule: - מחק Tag - Tag: - מחק גם ממאגרים מרוחקים - DIFF בינארי - ההבדל הראשון - התעלמות משינויי Whitespace - מיזוג - הבדל - זה לצד זה - החלקה - ההבדל האחרון - שינוי אובייקט LFS - חדש - ההבדל הבא - אין שינויים או רק שינויי EOL - ישן - ההבדל הקודם - שמור כ־Patch - הצג סמלים מוסתרים - Diff זה לצד זה - SUBMODULE - נמחק - חדש - + {0} שינויים שלא בוצע להם commit - החלף - הדגשת תחביר - גלישת שורות - פתח בכלי Merge - הצג כל השורות - הקטנת מספר השורות הנראות - הגדלת מספר השורות הנראות - בחר קובץ להצגת השינויים - היסטוריית תיקייה - קיימים שינויים מקומיים - אינו תואם ל־upstream - כבר מעודכן - השלך שינויים - כל השינויים המקומיים ב־working copy. - שינויים: - כולל קבצים שב־ignore - כולל קבצים ששונו או נמחקו - כולל קבצים untracked - {0} שינויים יושלכו - לא ניתן לבטל פעולה זו!!! - ערוך תיאור ה־Branch - יעד: - סימנייה: - שם חדש: - יעד: - ערוך הקבוצה שנבחרה - ערוך המאגר שנבחר - יעד: - מאגר זה - Fetch - Fetch מכל ה־remotes - כפה דריסה של refs מקומיים - Fetch ללא tags - Remote: - Fetch של שינויים מרוחקים - Assume unchanged - פעולה מותאמת אישית - השלך... - השלך של {0} קבצים... - פתור באמצעות ${0}$ - שמור כ־Patch... - Stage - Stage של {0} קבצים - Stash... - Stash של {0} קבצים... - Unstage - Unstage של {0} קבצים - שימוש בשלי (checkout --ours) - שימוש בשלהם (checkout --theirs) - היסטוריית קובץ - שנה - תוכן - Git-Flow - Branch לפיתוח: - Feature: - קידומת Feature: - FLOW - סיים Feature - FLOW - סיים Hotfix - FLOW - סיים Release - יעד: - Squash בעת ה־merge - Hotfix: - קידומת Hotfix: - אתחול Git-Flow - השארת ה־branch - Branch ייצור: - Release: - קידומת Release: - התחל Feature... - FLOW - התחל Feature - התחל Hotfix... - FLOW - התחל Hotfix - הזן שם - התחל Release... - FLOW - התחל Release - קידומת Version Tag: - Git LFS - הוסף תבנית למעקב... - התבנית היא שם קובץ - תבנית מותאמת אישית: - הוסף תבנית למעקב ב־Git LFS - Fetch - הרץ `git lfs fetch` להורדת אובייקטי Git LFS. אינה מעדכנת את ה־working copy. - Fetch של אובייקטי LFS - התקן hooks של Git LFS - הצג Locks - אין קבצים נעולים - נעל - הצג הנעילות שלי בלבד - LFS Locks - שחרר נעילה - שחרר כל הנעילות שלי - האם לשחרר את כל הקבצים שנעלת? - שחרר נעילה בכוח - Prune - הרץ `git lfs prune` למחיקת קבצי LFS ישנים מהאחסון המקומי - Pull - הרץ `git lfs pull` להורדת כל קבצי Git LFS עבור ה־ref הנוכחי וביצוע checkout - Pull של אובייקטי LFS - Push - Push של קבצים גדולים בתור אל endpoint של Git LFS - Push של אובייקטי LFS - Remote: - מעקב אחר קבצים בשם '{0}' - מעקב אחר כל הקבצים *{0} - בחר Commit - AUTHOR - זמן AUTHOR - זמן COMMIT - גרף ו־SUBJECT - SHA - הדגשות בגרף - הכול - ה־Branch הנוכחי בלבד - ה־Branch הנוכחי ו־Commits שנבחרו - Commits שנבחרו בלבד - נבחרו {0} COMMITS - הצג עמודות - החזק 'Ctrl' או 'Shift' לבחירת מספר commits. - החזק ⌘ או ⇧ לבחירת מספר commits. - טיפים: - פתח בחלון נפרד - פרטי Commit - השווה Revisions - קיצורי מקלדת - גלובלי - שכפל מאגר חדש - סגור הלשונית הנוכחית - עבור ללשונית הבאה - עבור ללשונית הקודמת - צור לשונית חדשה - פתח מאגר מקומי - פתח חלון ההעדפות - הצג תפריט נפתח של סביבת העבודה - החלף לשונית פעילה - הגדל/הקטן - מאגר - Commit לשינויים ב־staged - Commit ו־push לשינויים ב־staged - Stage לכל השינויים ו־commit - צור branch חדש - Fetch, מתחיל מיידית - עבור לצאצא של ה־commit שנבחר - עבור להורה של ה־commit שנבחר - פתח command palette - Pull, מתחיל מיידית - Push, מתחיל מיידית - טען את המאגר מחדש בכוח - עבור ל־'LOCAL CHANGES' - עבור ל־'STASHES' - השלך - Stage - Unstage - אתחול מאגר - האם להריץ `git init` בנתיב זה? - פתיחת המאגר נכשלה. סיבה: - נתיב: - Cherry-Pick בתהליך. - מעבד commit - Merge בתהליך. - מתבצע Merge - Rebase בתהליך. - נעצר ב־ - Revert בתהליך. - מבצע Revert ל־commit - Interactive Rebase - Stash והחלה מחדש של שינויים מקומיים - דלג על pre-rebase hook - על: - גרור כדי לסדר מחדש commits - Branch יעד: - העתק קישור - פתח בדפדפן - פקודות - שגיאה - הודעה - מאגרים פתוחים - לשוניות - סביבות עבודה - Merge של Branch - התאם הודעת merge - אל: - אפשרות Merge: - מקור: - תחילה שלי, אחר כך שלהם - תחילה שלהם, אחר כך שלי - שימוש בשניהם - כל הקונפליקטים נפתרו - נותרו {0} קונפליקטים - שלי - הקונפליקט הבא - הקונפליקט הקודם - תוצאה - שמור ו־Stage - שלהם - קונפליקטי Merge - להשליך שינויים שלא נשמרו? - שימוש בשלי - שימוש בשלהם - ביטול - Merge (מרובה) - Commit לכל השינויים - אסטרטגיה: - יעדים: - העבר Submodule - העבר אל: - Submodule: - העבר רכיב מאגר - בחר רכיב אב עבור: - שם: - לא - Git אינו מוגדר. עבור ל־[העדפות] והגדר אותו תחילה. - פתח - עורך ברירת מחדל (מערכת) - פתח תיקיית אחסון נתונים - פתח קובץ - פתח בכלי Merge חיצוני - פתח מאגר מקומי - סימנייה: - קבוצה: - תיקייה: - לא חובה. - צור לשונית חדשה - סגור לשונית - סגור לשוניות אחרות - סגור לשוניות מימין - העתק נתיב המאגר - ערוך - העבר לסביבת עבודה - רענן - מאגרים - הדבק - לפני {0} ימים - לפני שעה - לפני {0} שעות - הרגע - בחודש שעבר - בשנה שעברה - לפני {0} דקות - לפני {0} חודשים - לפני {0} שנים - אתמול - העדפות - AI - Prompt נוסף (השתמש ב־`-` לרשימת דרישות) - API Key - מודל - Fetch אוטומטי של model-ids זמינים - שם - הערך שהוזן הוא שם משתנה סביבה לטעינת ה־API key - שרת - מראה - גופן ברירת מחדל - רוחב Tab בעורך - גודל גופן - ברירת מחדל - עורך - גופן Monospace - ערכת נושא - דריסות ערכת נושא - שימוש בפסי גלילה המוסתרים אוטומטית - רוחב לשונית קבוע בשורת הכותרת - שימוש במסגרת חלון מקומית - כלי DIFF/MERGE - ארגומנטים ל־Diff - משתנים זמינים: $LOCAL, $REMOTE - ארגומנטים ל־Merge - משתנים זמינים: $BASE, $LOCAL, $REMOTE, $MERGED - נתיב התקנה - הזן נתיב לכלי diff/merge - כלי - כללי - בדוק עדכונים בעת ההפעלה - תבנית תאריך - תיקיות מצומצמות בעץ השינויים - שפה - Commits בהיסטוריה - הצג דף `LOCAL CHANGES` כברירת מחדל - הצג לשונית `CHANGES` בפרטי ה־commit כברירת מחדל - הצג זמן יחסי בגרף ה־commits - הצג tags בגרף ה־commits - אורך מנחה ל־Subject - 24 שעות - צור אווטאר ברירת מחדל בסגנון GitHub - GIT - הפעל CRLF אוטומטי - תיקיית clone ברירת מחדל - דוא"ל משתמש - דוא"ל משתמש גלובלי של git - Prune ל־branches מתים לאחר fetch - התעלמות מ־CR בסוף שורה ב־diff טקסט - נדרש Git (>= 2.25.1) עבור אפליקציה זו - נתיב התקנה - הפעל אימות HTTP SSL - שימוש ב־git-credential-libsecret במקום git-credential-manager - שם משתמש - שם משתמש גלובלי של git - Stash והחלה מחדש של שינויים כברירת מחדל בעת checkout או merge של branches - גרסת Git - חתימת GPG - חתימת GPG ל־commits - פורמט GPG - נתיב התקנת התוכנה - הזן נתיב לתוכנת gpg מותקנת - חתימת GPG ל־tags - מפתח חתימה של המשתמש - מפתח חתימת gpg של המשתמש - אינטגרציה - SHELL/טרמינל - ארגומנטים - השתמש ב־'.' לציון תיקיית העבודה - נתיב - Shell/טרמינל - Prune Remote - יעד: - Prune Worktrees - Prune למידע על worktrees ב־`$GIT_COMMON_DIR/worktrees` - Pull - Branch מרוחק: - אל: - שינויים מקומיים: - Remote: - Pull (Fetch ו־Merge) - שימוש ב־rebase במקום merge - Push - לוודא ש־submodules בוצע להם push - Force push - Branch מקומי: - חדש - דלג על pre-push hook - Remote: - Revision: - Push של Revision ל־Remote - Push של שינויים ל־Remote - Branch מרוחק: - הגדר כ־tracking branch - Push לכל ה־tags - Push של Tag ל־Remote - Push לכל ה־remotes - Remote: - Tag: - Push ל־branch חדש - הזן שם ל־branch המרוחק החדש: - יציאה - Rebase של ה־Branch הנוכחי - Stash והחלה מחדש של שינויים מקומיים - דלג על pre-rebase hook - על: - הוסף Remote - ערוך Remote - שם: - שם Remote - URL של המאגר: - URL של מאגר git מרוחק - העתק URL - פעולה מותאמת אישית - מחק... - ערוך... - הפעל Auto-Fetch - Fetch - פתח בדפדפן - Prune - אישור הסרת Worktree - הפעל אפשרות `--force` - יעד: - שנה שם Branch - שם חדש: - שם ייחודי ל־branch זה - Branch: - ביטול - Fetch אוטומטי של שינויים מ־remotes... - מיון - לפי תאריך Committer - לפי שם - נקה (GC ו־Prune) - הרץ `git gc` עבור המאגר. - נקה הכול - נקה - הגדר מאגר זה - המשך - פעולות מותאמות אישית - אין פעולות מותאמות אישית - השלך כל השינויים - פתח בסייר הקבצים - חיפוש Branches/Tags/Submodules - נראות בגרף - לא מוגדר - הסתר בגרף ה־commits - סינון בגרף ה־commits - פריסה - אופקי - אנכי - סדר COMMITS - תאריך Commit - טופולוגי - BRANCHES מקומיים - ניווט אל HEAD - צור Branch - נקה התראות - פתח כתיקייה - פתח ב־{0} - פתח בכלים חיצוניים - REMOTES - הוסף Remote - פתור - חיפוש Commit - Author - תוכן - הודעה - נתיב - SHA - ב־Branch הנוכחי - Commits מעוטרים בלבד - First-parent בלבד - הצג דגלים - הצג commits אבודים - הצג Submodules כעץ - הצג Tags כעץ - דלג - סטטיסטיקות - SUBMODULES - הוסף Submodule - עדכון Submodule - TAGS - Tag חדש - לפי תאריך צור - לפי שם - מיון - פתח בטרמינל - הצג לוגים - בקר ב־'{0}' בדפדפן - WORKTREES - הוסף Worktree - Prune - URL של מאגר Git - Reset של ה־Branch הנוכחי ל־Revision - מצב Reset: - העבר אל: - Branch נוכחי: - Reset של Branch (ללא Checkout) - העבר אל: - Branch: - הצג בסייר הקבצים - Revert של Commit - Commit: - Commit לשינויי ה־revert - פועל. נא להמתין... - שמור - שמור בשם... - ה־Patch נשמר בהצלחה! - סרוק מאגרים - תיקיית שורש: - סרוק תיקייה מותאמת אישית אחרת - בדוק עדכונים... - גרסה חדשה של התוכנה זמינה: - גרסה נוכחית: - בדוק העדכונים נכשלה! - הורד - דלג על גרסה זו - תאריך שחרור הגרסה החדשה: - עדכון תוכנה - כרגע אין עדכונים זמינים. - הגדר Branch של Submodule - Submodule: - נוכחי: - שנה אל: - לא חובה. אם ריק, יוגדר לברירת המחדל. - הגדר Tracking Branch - Branch: - ביטול upstream - Upstream: - העתק SHA - עבור אל - מפתח SSH פרטי: - נתיב לאחסון מפתח SSH פרטי - התחל - Stash - כולל קבצים untracked - הודעה: - לא חובה. הודעה ל־stash זה - מצב: - קבצים ב־staged בלבד - גם השינויים שב־staged וגם אלו שלא יוכנסו ל־stash עבור הקבצים שנבחרו!!! - Stash לשינויים מקומיים - החל - החל שינויים - Checkout ל־Branch חדש - העתק הודעה - מחק - שמור כ־Patch... - מחק Stash - מחק: - STASHES - שינויים - STASHES - סטטיסטיקות - סקירה כללית - חודש - שבוע - AUTHORS: - COMMITS: - SUBMODULES - הוסף Submodule - BRANCH - Branch - נתיב יחסי - ביטול אתחול - Fetch ל־submodules מקוננים - היסטוריה - העבר אל - פתח מאגר - נתיב יחסי: - תיקייה יחסית לאחסון המודול. - מחק - הגדר Branch - שנה URL - סטטוס - שונה - לא אותחל - ה־revision שונה - unmerged - עדכון - URL - פרטי שינויים ב־Submodule - פתח פרטים - אישור - TAGGER - זמן - השווה בין 2 tags - השווה עם... - השווה עם HEAD - הודעה - שם - Tagger - העתק שם ה־Tag - פעולה מותאמת אישית - מחק ${0}$... - מחק {0} ה־tags שנבחרו... - Push ${0}$... - עדכון Submodules - כל ה־submodules - אתחול לפי הצורך - Submodule: - עדכון ל־remote tracking branch של ה־submodule - URL: - לוגים - נקה הכול - העתק - מחק - אזהרה - דף פתח - צור קבוצה - צור תת־קבוצה - שכפל מאגר - מחק - נתמכת גרירה ושחרור של תיקיות. נתמך קיבוץ מותאם אישית. - ערוך - העבר לקבוצה אחרת - פתח כל המאגרים - פתח מאגר - פתח טרמינל - סרוק מחדש של מאגרים בתיקיית ה־Clone ברירת מחדל - חיפוש מאגרים... - שינויים מקומיים - Git Ignore - התעלמות מכל הקבצים *{0} - התעלמות מקבצי *{0} באותה תיקייה - התעלמות מקבצים untracked בתיקייה זו - התעלמות מקובץ זה בלבד - Amend - ניתן לבצע stage לקובץ זה כעת. - נקה היסטוריה - האם לנקות את כל היסטוריית הודעות ה־commit? לא ניתן לבטל פעולה זו. - COMMIT - COMMIT ו־PUSH - תבנית/היסטוריה - הפעל אירוע לחיצה - Commit (ערוך) - Stage לכל השינויים ו־commit - פעולה זו תיצור commit על HEAD שמצבו detached. האם להמשיך? - ביצעת stage ל־{0} קבצים אך מוצגים רק {1} קבצים ({2} מסוננים החוצה). האם להמשיך? - זוהו קונפליקטים - MERGE - Merge עם כלי חיצוני - פתח כל הקונפליקטים בכלי Merge חיצוני - קונפליקטי הקובץ נפתרו - שימוש בשלי - שימוש בשלהם - כולל קבצים UNTRACKED - אין הודעות שהוזנו לאחרונה - אין תבניות commit - No-Verify - Reset ל־Author - SignOff - STAGED - UNSTAGE - UNSTAGE לכול - UNSTAGED - STAGE - STAGE לכול - הצג ASSUME UNCHANGED - תבנית: ${0}$ - סביבת עבודה: - הגדר סביבות עבודה... - WORKTREE - BRANCH - העתק נתיב - HEAD - נעל - פתח - נתיב - הסר - שחרר נעילה - כן - diff --git a/src/Resources/Locales/id_ID.axaml b/src/Resources/Locales/id_ID.axaml deleted file mode 100644 index 0ff7f394c4..0000000000 --- a/src/Resources/Locales/id_ID.axaml +++ /dev/null @@ -1,1036 +0,0 @@ - - - - - - Tentang - Tentang SourceGit - Tanggal Rilis: {0} - Catatan Rilis - 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 - Model - BUAT ULANG - Gunakan AI untuk membuat pesan commit - Gunakan - Sembunyikan SourceGit - Sembunyikan Lainnya - Tampilkan Semua - Merge 3 Arah - Pilih berkas patch untuk diterapkan - Abaikan perubahan whitespace - Sumber: - Berkas - Papan Klip - 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 - Bisect - Batalkan - Buruk - Baik - Lewati - Bisect sedang berjalan. Checkout commit lain, lalu tandai sebagai baik atau buruk. - Bisect sedang berjalan. Tandai commit saat ini sebagai buruk atau checkout commit lain, lalu tandai sebagai buruk. - Bisect berjalan. Tandai commit saat ini sebagai baik atau buruk dan checkout yang lain. - Bisect berjalan. Apakah HEAD saat ini baik atau buruk? - Blame - Blame pada Revisi Sebelumnya - Abaikan perubahan whitespace - BLAME PADA BERKAS INI TIDAK DIDUKUNG!!! - Checkout ${0}$... - Bandingkan 2 branch yang dipilih - Bandingkan dengan... - Bandingkan dengan HEAD - Bandingkan dengan ${0}$ - Salin Nama Branch - Buat PR... - Buat PR untuk upstream ${0}$... - Aksi Kustom - Hapus ${0}$... - Hapus {0} branch yang dipilih - Sunting deskripsi ${0}$... - Fast-Forward ke ${0}$ - Fetch ${0}$ ke ${1}$... - Git Flow - Selesaikan ${0}$ - Rebase ${0}$ pada ${1}$ secara Interaktif - 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... - {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 - Merge (Bawaan) - Merge (Eksternal) - Reset Berkas ke ${0}$ - 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 - Perubahan Lokal: - Branch: - HEAD saat ini mengandung commit yang tidak terhubung ke branch/tag manapun! Lanjutkan? - Submodule berikut perlu diperbarui:{0}Apakah Anda ingin memperbaruinya? - Checkout & Fast-Forward - Fast-Forward ke: - Checkout Branch dari Stash - Branch Baru: - Stash: - Checkout Commit atau Tag - Target: - Peringatan: Setelah proses ini, HEAD akan terlepas - 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. - Markah: - Grup: - Nama Lokal: - Nama repositori. Opsional. - Folder Parent: - Inisialisasi & perbarui submodule - URL Repositori: - TUTUP - Editor - Branch - Branch & Tag - Aksi Kustom Repositori - Berkas Revisi - Checkout Commit - Cherry-Pick Commit - Cherry-Pick ... - Bandingkan dengan HEAD - Bandingkan dengan Worktree - Author - Waktu Penulis - Pesan - Committer - Waktu Committer - SHA - Subjek - Aksi Kustom - Interactive Rebase - Drop... - Edit... - Fixup ke Parent... - Rebase ${0}$ pada ${1}$ secara Interaktif - Reword... - Squash ke Parent... - Merge ... - Push ${0}$ ke ${1}$ - Rebase ${0}$ pada ${1}$ - Reset ${0}$ ke ${1}$ - Revert Commit - Simpan sebagai Patch... - PERUBAHAN - berkas berubah - Cari Perubahan... - Ciutkan detail - BERKAS - Berkas LFS - Cari Berkas... - Submodule - INFORMASI - AUTHOR - 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 - KOL - Masukkan pesan commit. Gunakan baris kosong untuk memisahkan subjek dan deskripsi! - SUBJEK - Perbandingan - PERUBAHAN - COMMIT - COMMIT HANYA DI KIRI - COMMIT HANYA DI KANAN - Tips: Anda dapat melakukan cherry-pick pada commit yang dipilih jika sisi lainnya adalah HEAD (melalui menu konteks). - Konfigurasi Repositori - TEMPLATE COMMIT - Parameter bawaan: - - ${branch_name} Nama branch lokal saat ini. - ${files_num} Jumlah berkas yang berubah - ${files} Jalur berkas yang berubah - ${files:N} Maksimal N jalur berkas yang berubah - ${pure_files} Seperti ${files}, tetapi hanya nama berkas - ${pure_files:N} Seperti ${files:N}, tetapi tanpa folder - 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 - Tanyakan sebelum memperbarui submodule secara otomatis - Fetch remote secara otomatis - Menit - Tipe Conventional Commit - Remote Default - Aktifkan `--recursive` saat memperbarui submodule secara otomatis - 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 - Pemformat String: - Opsional. Digunakan untuk memformat string keluaran. Diabaikan jika input kosong. Gunakan `${VALUE}` untuk mewakili string input. - Variabel bawaan ${REPO}, ${REMOTE}, ${BRANCH}, ${BRANCH_FRIENDLY_NAME}, ${SHA}, ${FILE}, dan ${TAG} tetap tersedia di sini - Jenis: - Gunakan Nama Ramah: - Workspace - Warna - Nama - Pulihkan tab saat startup - LANJUTKAN - Commit kosong terdeteksi! Lanjutkan (--allow-empty)? - STAGE SEMUA & COMMIT - STAGE PILIHAN & 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 sebagai Patch - Salin Jalur Lengkap - Salin Jalur - Buat Branch... - Berdasarkan: - Checkout branch yang dibuat - Perubahan Lokal: - 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 - Buang - Jangan Lakukan Apa Pun - Stash & Terapkan Ulang - De-initialize Submodule - Paksa de-init meski mengandung perubahan lokal. - Submodule: - Hapus Branch - Branch: - Paksa hapus meskipun berisi commit yang belum di-merge - 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 - BERKAS KOSONG - 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 - + {0} Perubahan Belum Di-commit - 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 - Sertakan berkas yang diubah/dihapus - Termasuk berkas yang tidak dilacak - {0} perubahan akan dibuang - Anda tidak dapat membatalkan aksi ini!!! - Sunting Deskripsi Branch - Target: - 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 - Aksi Kustom - 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 - Perubahan mode berkas: - Mode berkas yang dihapus: - Direktori - Dapat Dieksekusi - Mode berkas baru: - Normal - Submodule - Symlink - Tidak Diketahui - Git-Flow - Branch Development: - Feature: - Prefix Feature: - Selesaikan ${0}$ - FLOW - Selesaikan Feature - FLOW - Selesaikan Hotfix - FLOW - Selesaikan Release - Target: - Rebase sebelum merge - Squash saat merge - Hotfix: - Prefix Hotfix: - Inisialisasi Git-Flow - Simpan branch - Branch Production: - Release: - Prefix Release: - Mulai dari: - Mulai Feature... - FLOW - Mulai Feature - Mulai Hotfix... - FLOW - Mulai Hotfix - Nama: - 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 - Buka semua lock saya - Yakin ingin membuka lock semua berkas yang Anda kunci? - 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} - Pilih Commit - AUTHOR - WAKTU AUTHOR - WAKTU COMMIT - GRAFIK & SUBJEK - SHA - SOROTAN DALAM GRAFIK - Semua - Hanya Branch Saat Ini - Branch Saat Ini & Commit Terpilih - Hanya Commit Terpilih - DIPILIH {0} COMMIT - TAMPILKAN KOLOM - Tahan 'Ctrl' atau 'Shift' untuk memilih beberapa commit. - Tahan ⌘ atau ⇧ untuk memilih beberapa commit. - TIPS: - Buka di jendela terpisah - Detail Commit - Perbandingan Revisi - Referensi Shortcut Keyboard - GLOBAL - Clone repositori baru - Tutup tab saat ini - Ke tab berikutnya - Ke tab sebelumnya - Buat tab baru - Buka repositori lokal - Buka dialog Preferensi - Tampilkan menu tarik-turun workspace - Ganti tab aktif - Perbesar/perkecil - REPOSITORI - Commit perubahan yang di-stage - Commit dan push perubahan yang di-stage - Stage semua perubahan dan commit - Buat branch baru - Fetch, langsung dimulai - Ke turunan commit yang dipilih - Ke induk commit yang dipilih - Buka palet perintah - Pull, langsung dimulai - Push, langsung dimulai - Paksa muat ulang repositori ini - Pindah ke 'Changes' - Pindah ke 'Stashes' - Buang - Stage - Unstage - Inisialisasi Repositori - Apakah Anda ingin menjalankan perintah `git init` di jalur ini? - Gagal membuka repositori. Alasan: - 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 - Lewati hook pre-rebase - Pada: - Drag-drop untuk mengurutkan ulang commit - Branch Target: - Salin Link - Buka di Browser - Perintah - ERROR - PEMBERITAHUAN - Versi Baru Tersedia - Buka Repositori - Tab - Workspace - Merge Branch - Sesuaikan pesan merge - Ke: - Opsi Merge: - Sumber: - Menguji merge... - Merge dapat dilakukan tanpa konflik - Terjadi kesalahan yang tidak diketahui saat menguji merge - Merge akan menyebabkan konflik - Milik Saya dahulu, lalu Milik Mereka - Milik Mereka dahulu, lalu Milik Saya - GUNAKAN KEDUANYA - Semua konflik terselesaikan - {0} konflik tersisa - MILIK SAYA - Konflik Berikutnya - Konflik Sebelumnya - HASIL - SIMPAN & STAGE - MILIK MEREKA - Konflik Merge - Buang perubahan yang belum disimpan? - GUNAKAN MILIK SAYA - GUNAKAN MILIK MEREKA - URUNGKAN - Merge (Beberapa) - Commit semua perubahan - Strategi: - Target: - Pindahkan Submodule - Pindahkan Ke: - Submodule: - Pindahkan Node Repositori - Pilih node parent untuk: - Nama: - TIDAK - Git BELUM dikonfigurasi. Silakan ke [Preferences] dan konfigurasikan terlebih dahulu. - Buka - Editor Default (Sistem) - Buka Direktori Penyimpanan Data - Buka Berkas - Buka di Merge Tool - Buka Repositori Lokal - Markah: - Grup: - Folder: - Opsional. - Buat Tab Baru - Tutup Tab - Tutup Tab Lain - Tutup Tab di Kanan - Salin Jalur Repositori - Sunting - Pindahkan ke Workspace - Segarkan - 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 Tambahan (Gunakan `-` untuk mencantumkan kebutuhan Anda) - API Key - Header Tambahan (satu `Nama: Nilai` per baris) - Model - Ambil model-id yang tersedia secara otomatis - Nama - Nilai yang dimasukkan adalah nama untuk memuat API key dari ENV - Server - 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 - Argumen Diff - Variabel tersedia: $LOCAL, $REMOTE - Argumen Merge - Variabel tersedia: $BASE, $LOCAL, $REMOTE, $MERGED - 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 halaman `LOCAL CHANGES` secara default - Tampilkan tab `CHANGES` di detail commit secara default - Tampilkan waktu relatif pada grafik commit - Tampilkan tag di grafik commit - Panjang Panduan Subjek - Format 24 Jam - Gunakan nama branch ringkas pada grafik commit - 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 - Stash & terapkan ulang perubahan secara default saat checkout atau merge branch - 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 - Argumen - Gunakan '.' untuk menunjukkan direktori kerja - Jalur - Shell/Terminal - Prune Remote - Target: - Prune Worktree - Prune informasi worktree di `$GIT_COMMON_DIR/worktrees` - Pull - Remote Branch: - Ke: - Perubahan Lokal: - Remote: - Pull (Fetch & Merge) - Gunakan rebase alih-alih merge - Push - Pastikan submodule sudah di-push - Paksa push - Branch Lokal: - BARU - Lewati hook pre-push - 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: - Push ke branch BARU - Masukkan nama remote branch baru: - Keluar - Rebase Branch Saat Ini - Stash & terapkan ulang perubahan lokal - Lewati hook pre-rebase - Pada: - Menguji rebase... - Rebase dapat dilakukan tanpa konflik - Terjadi kesalahan yang tidak diketahui saat menguji rebase - Rebase akan menyebabkan konflik - Tambah Remote - Sunting Remote - Nama: - Nama remote - URL Repositori: - URL repositori git remote - Salin URL - Aksi Kustom - Hapus... - Sunting... - Aktifkan Fetch Otomatis - 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 - Buang semua perubahan - Buka di File Browser - Cari Branch/Tag/Submodule - Visibilitas di Grafik - Ciutkan Filter - Tidak Diatur - Sembunyikan di grafik commit - Bentangkan Filter - Filter di grafik commit - filter aktif - TATA LETAK - Horizontal - Vertikal - URUTAN COMMIT - Tanggal Commit - Topologis - BRANCH LOKAL - Navigasi ke HEAD - Buat Branch - BERSIHKAN NOTIFIKASI - Buka sebagai Folder - Buka di {0} - Buka di Tool Eksternal - REMOTE - Tambah Remote - SELESAIKAN - Cari Commit - Author - 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 - 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 - 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: - Versi Saat Ini: - Pemeriksaan pembaruan gagal! - Unduh - Lewati Versi Ini - Tanggal Rilis Versi Baru: - 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 - Terapkan Perubahan - Checkout Branch Baru - 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 - Detail Perubahan Submodule - BUKA DETAIL - OK - TAGGER - WAKTU - Checkout Tag... - Bandingkan 2 tag - Bandingkan dengan... - Bandingkan dengan HEAD - 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 - Submodule: - Perbarui submodule bertingkat - 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 - Abaikan semua berkas yang tidak dilacak di folder yang sama - 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 - MERGE - Merge dengan Alat 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 - BRANCH - Salin Jalur - HEAD - Lock - Buka - JALUR - Hapus - Unlock - YA - diff --git a/src/Resources/Locales/it_IT.axaml b/src/Resources/Locales/it_IT.axaml deleted file mode 100644 index e595a13df9..0000000000 --- a/src/Resources/Locales/it_IT.axaml +++ /dev/null @@ -1,926 +0,0 @@ - - - - - - Informazioni - Informazioni su SourceGit - Data di Rilascio: {0} - Note di Rilascio - 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. - Nome Branch: - Facoltativo. Predefinito è il nome della cartella di destinazione. - Traccia Branch: - Traccia branch remoto - Di cosa fare il checkout: - Crea nuovo branch - Branch esistente - Assistente AI - Modello - RIGENERA - Usa AI per generare il messaggio di commit - Nascondi SourceGit - Mostra Tutto - Seleziona file patch da applicare - Ignora modifiche agli spazi - Applica Patch - Spazi: - Applica lo stash - Rimuovi dopo aver applicato - Ripristina le modifiche all'indice - Stash: - Archivia... - Salva Archivio In: - Seleziona il percorso del file archivio - Revisione: - Archivia - Richiedi Password SourceGit - Inserisci passphrase: - FILE ASSUNTI COME INVARIATI - NESSUN FILE ASSUNTO COME INVARIATO - Carico l'Immagine... - Aggiorna - Biseca - Annulla - Cattiva - Buona - Salta - Bisecando. Marca il commit corrente come buono o cattivo e fai checkout di un altro. - Bisecando. La HEAD corrente è buona o cattiva? - Attribuisci - Attribuisci sulla Revisione Precedente - Ignora modifiche agli spazi - L'ATTRIBUZIONE SU QUESTO FILE NON È SUPPORTATA!!! - Checkout ${0}$... - Confronta i 2 branch selezionati - Confronta con... - Confronta con HEAD - Copia Nome Branch - Crea PR... - Crea PR per upstream ${0}$... - Azione personalizzata - Elimina ${0}$... - Elimina i {0} branch selezionati - Modifica descrizione per ${0}$... - Avanzamento Veloce a ${0}$ - Recupera ${0}$ in ${1}$... - Git Flow - Completa ${0}$ - Ribasare interattivamente ${0}$ su ${1}$ - Unisci ${0}$ in ${1}$... - Unisci i {0} branch selezionati in quello corrente - Scarica ${0}$ - Scarica ${0}$ in ${1}$... - Invia ${0}$ - Riallinea ${0}$ su ${1}$... - Rinomina ${0}$... - Resetta ${0}$ a ${1}$... - Passa a ${0}$ (worktree) - Imposta Branch di Tracciamento... - {0} commit avanti - {0} commit avanti, {1} commit indietro - {0} commit indietro - Invalido - REMOTO - STATO - TRACCIAMENTO - URL - WORKTREE - ANNULLA - Ripristina la Revisione Padre - Ripristina Questa Revisione - Genera messaggio di commit - Merge (Integrato) - Merge (Esterno) - CAMBIA MODALITÀ DI VISUALIZZAZIONE - 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 - Modifiche Locali: - Branch: - Il tuo HEAD attuale contiene commit non connessi ad alcun branch/tag! Sicuro di voler continuare? - I seguenti sottomoduli devono essere aggiornati:{0}Vuoi aggiornarli? - Checkout & Avanzamento Veloce - Avanzamento Veloce verso: - Cherry Pick - Aggiungi sorgente al messaggio di commit - Commit(s): - Conferma tutte le modifiche - Mainline: - Di solito non è possibile fare cherry-pick sdi una unione perché non si sa quale lato deve essere considerato il mainline. Questa opzione consente di riprodurre la modifica relativa al genitore specificato. - Cancella Stash - Stai per cancellare tutti gli stash. Sei sicuro di voler continuare? - Clona Repository Remoto - Parametri Extra: - Argomenti addizionali per clonare il repository. Facoltativo. - Nome Locale: - Nome del repository. Facoltativo. - Cartella Principale: - Inizializza e aggiorna i sottomoduli - URL del Repository: - CHIUDI - Editor - Checkout Commit - Cherry-Pick Questo Commit - Cherry-Pick... - 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 ... - Invia ${0}$ a ${1}$ - Ribasa ${0}$ su ${1}$ - Resetta ${0}$ su ${1}$ - Annulla Commit - Salva come Patch... - MODIFICHE - file modificati - Cerca Modifiche... - FILE - File LFS - Cerca File... - Sottomodulo - INFORMAZIONI - AUTORE - CHI HA COMMITTATO - Controlla i riferimenti che contengono questo commit - IL COMMIT È CONTENUTO DA - Copia Email - Copia Nome - Copia Nome ed Email - Mostra solo le prime 100 modifiche. Vedi tutte le modifiche nella scheda MODIFICHE. - Chiave: - MESSAGGIO - GENITORI - RIFERIMENTI - SHA - Firmatario: - Apri nel Browser - Inserisci il messaggio di commit. Usa una riga vuota per separare oggetto e descrizione! - OGGETTO - Confronto - Configura Repository - TEMPLATE DI COMMIT - Parametri integrati: - -${branch_name} Nome del branch locale corrente. -${files_num} Numero di file modificati -${files} Percorsi dei file modificati -${files:N} Massimo N percorsi di file modificati -${pure_files} Come ${files}, ma solo nomi file puri -${pure_files:N} Come ${files:N}, ma senza cartelle - 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 - GIT - Chiedi prima di aggiornare automaticamente i sottomoduli - Recupera automaticamente i remoti - Minuto/i - Tipi di Commit Convenzionali - Remoto Predefinito - 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 - Aggiungi una regola di esempio per Issue GitLab - Aggiungi una regola di esempio per una Merge Request GitLab - Aggiungi una regola di esempio per Jira - Nuova Regola - Espressione Regex Issue: - Nome Regola: - Condividi questa regola nel file .issuetracker - URL Risultato: - Utilizza $1, $2 per accedere ai valori dei gruppi regex. - AI - Servizio preferito: - Se il 'Servizio Preferito' é impostato, SourceGit utilizzerà solo quello per questo repository. Altrimenti, se ci sono più servizi disponibili, verrà mostrato un menu contestuale per sceglierne uno. - Proxy HTTP - Proxy HTTP usato da questo repository - Nome Utente - 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 - Le variabili integrate ${REPO}, ${REMOTE}, ${BRANCH}, ${BRANCH_FRIENDLY_NAME}, ${SHA}, ${FILE} e ${TAG} rimangono disponibili qui - Tipo: - Spazi di Lavoro - Colore - Nome - Ripristina schede all'avvio - CONTINUA - 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: - Dettaglio Modifiche: - Ambito: - Descrizione Breve: - Tipo di Modifica: - Copia - Copia Tutto il Testo - Copia Intero Percorso - Copia Percorso - Crea Branch... - Basato Su: - Checkout del Branch Creato - Modifiche Locali: - Nome Nuovo Branch: - Inserisci il nome del branch. - Crea Branch Locale - Sovrascrivi branch esistente - Crea Tag... - Nuovo Tag Su: - Firma con GPG - Messaggio Tag: - Facoltativo. - Nome Tag: - Formato consigliato: v1.0.0-alpha - Invia a tutti i remoti dopo la creazione - Crea Nuovo Tag - Tipo: - annotato - leggero - Tieni premuto Ctrl per avviare direttamente - Taglia - Scarta - Non fare nulla - Stash e Ripristina - 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: - Destinazione: - Tutti i figli verranno rimossi dalla lista. - Lo rimuoverà solamente dalla lista, non dal disco! - Conferma Eliminazione Gruppo - Conferma Eliminazione Repository - Elimina Sottomodulo - Percorso Sottomodulo: - Elimina Tag - Tag: - Elimina dai repository remoti - DIFF BINARIO - Prima differenza - Ignora Modifiche agli Spazi - FUSIONE - DIFFERENZA - 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 - 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 - Ha Modifiche Locali - Non allineato con Upstream - Già Aggiornato - 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!!! - Modifica Descrizione del Branch - Destinazione: - Segnalibro: - Nuovo Nome: - Destinazione: - Modifica Gruppo Selezionato - Modifica Repository Selezionato - Destinazione: - Questo repository - Recupera - Recupera da tutti i remoti - Forza la sovrascrittura dei riferimenti locali - Recupera senza tag - Remoto: - Recupera Modifiche Remote - Presumi invariato - Azione Personalizzata - Scarta... - Scarta {0} file... - Risolvi Usando ${0}$ - Salva come Patch... - Stage - Stage di {0} file - Stasha... - Stasha {0} file... - Rimuovi da Stage - Rimuovi da Stage {0} file - Usa Il Mio (checkout --ours) - Usa Il Loro (checkout --theirs) - Cronologia File - MODIFICA - CONTENUTO - Git-Flow - Branch di Sviluppo: - Feature: - Prefisso Feature: - FLOW - Completa Feature - FLOW - Completa Hotfix - FLOW - Completa Rilascio - Target: - Esegui squash durante il merge - Hotfix: - Prefisso Hotfix: - Inizializza Git-Flow - Mantieni branch - Branch di Produzione: - Rilascio: - Prefisso Rilascio: - Inizia Feature... - FLOW - Inizia Feature - Inizia Hotfix... - FLOW - Inizia Hotfix - Inserisci nome - Inizia Rilascio... - FLOW - Inizia Rilascio - Prefisso Tag Versione: - Git LFS - Aggiungi Modello di Tracciamento... - Il modello è un nome file - Modello Personalizzato: - Aggiungi Modello di Tracciamento a Git LFS - Recupera - Esegui `git lfs fetch` per scaricare gli oggetti Git LFS. Questo non aggiorna la copia di lavoro. - Recupera Oggetti LFS - Installa hook di Git LFS - Mostra Blocchi - Nessun File Bloccato - Blocca - Mostra solo i miei blocchi - Blocchi LFS - Sblocca - Sblocca tutti i miei blocchi - Sei sicuro di voler sbloccare tutti i tuoi file bloccati? - Forza Sblocco - Elimina - Esegui `git lfs prune` per eliminare vecchi file LFS dallo storage locale - Scarica - Esegui `git lfs pull` per scaricare tutti i file LFS per il ref corrente e fare il checkout - Scarica Oggetti LFS - Invia - Invia grandi file in coda al punto finale di Git LFS - Invia Oggetti LFS - Remoto: - Traccia file con nome '{0}' - Traccia tutti i file *{0} - AUTORE - ORA AUTORE - ORA COMMIT - GRAFICO E OGGETTO - SHA - {0} COMMIT SELEZIONATI - Tieni premuto 'Ctrl' o 'Shift' per selezionare più commit. - Tieni premuto ⌘ o ⇧ per selezionare più commit. - SUGGERIMENTI: - Riferimento Scorciatoie da Tastiera - GLOBALE - Clona una nuova repository - Chiudi la pagina corrente - Vai alla pagina successiva - Vai alla pagina precedente - Crea una nuova pagina - Apri la finestra delle preferenze - Mostra menu a tendina workspace - Cambia scheda attiva - Ingrandisci/Rimpicciolisci - REPOSITORY - Committa le modifiche in tsage - Committa e invia le modifiche in stage - Fai lo stage di tutte le modifiche e committa - Recupera, avvia direttamente - Apri tavolozza comandi - Scarica, avvia direttamente - Invia, avvia direttamente - Forza l'aggiornamento di questo repository - Passa a 'Modifiche' - Passa a 'Stashes' - Scarta - Aggiungi in stage - Rimuovi - Inizializza Repository - Percorso: - Cherry-Pick in corso. - Elaborando il commit - Unione in corso. - Unendo - Riallineamento in corso. - Interrotto a - Ripristino in corso. - Ripristinando il commit - Riallinea Interattivamente - Stasha e Riapplica modifiche locali - Su: - Trascina per riordinare i commit - Branch di destinazione: - Copia il Link - Apri nel Browser - Comandi - ERRORE - AVVISO - Apri Repository - Schede - Workspaces - Unisci Branch - Personalizza messaggio di merge - In: - Opzione di Unione: - Sorgente: - Prima Il Mio, poi Il Loro - Prima Il Loro, poi Il Mio - USA ENTRAMBI - Tutti i conflitti risolti - {0} conflitto/i rimanente/i - IL MIO - Conflitto Successivo - Conflitto Precedente - RISULTATO - SALVA E STAGE - IL LORO - Conflitti di Merge - Scartare le modifiche non salvate? - USA IL MIO - USA IL LORO - ANNULLA - Unione (multipla) - Commit di tutte le modifiche - Strategia: - Obiettivi: - Sposta Sottomodulo - Sposta Verso: - Sottomodulo: - Sposta Nodo Repository - Seleziona nodo padre per: - Nome: - NO - Git NON è configurato. Prima vai su [Preferenze] per configurarlo. - Apri - Editor Predefinito (Sistema) - Apri Cartella Dati App - Apri File - Apri nello Strumento di Merge - Opzionale. - Crea Nuova Pagina - Chiudi Tab - Chiudi Altri Tab - Chiudi i Tab a Destra - Copia Percorso Repository - Modifica - Sposta nel Workspace - Aggiorna - Repository - Incolla - {0} giorni fa - 1 ora fa - {0} ore fa - Proprio ora - Il mese scorso - L'anno scorso - {0} minuti fa - {0} mesi fa - {0} anni fa - Ieri - Preferenze - AI - Chiave API - Nome - Il valore inserito è il nome per caricare la chiave API da ENV - Server - ASPETTO - Font Predefinito - Larghezza della Tab Editor - Dimensione Font - Dimensione Font Predefinita - Dimensione Font Editor - Font Monospaziato - Tema - Sostituzioni Tema - Usa barre di scorrimento a scomparsa automatica - Usa larghezza fissa per i tab nella barra del titolo - Usa cornice finestra nativa - STRUMENTO DI DIFFERENZA/UNIONE - Argomenti Diff - Variabili disponibili: $LOCAL, $REMOTE - Argomenti Merge - Variabili disponibili: $BASE, $LOCAL, $REMOTE, $MERGED - Percorso Installazione - Inserisci il percorso per lo strumento di differenza/unione - Strumento - GENERALE - Controlla aggiornamenti all'avvio - Formato data - Abilita cartelle compatte nell'albero delle modifiche - Lingua - Numero massimo di commit nella cronologia - Mostra pagina `MODIFICHE LOCALI` per impostazione predefinita - Mostra scheda `MODIFICHE` nei dettagli del commit per impostazione predefinita - Mostra i tag nel grafico dei commit - Lunghezza Guida Oggetto - Genera avatar predefinito stile GitHub - GIT - Abilita Auto CRLF - Cartella predefinita per cloni - Email Utente - Email utente Git globale - Abilita --prune durante il fetch - Abilita --ignore-cr-at-eol nel diff - 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 - FIRMA GPG - Firma GPG per commit - Formato GPG - Percorso Programma Installato - Inserisci il percorso per il programma GPG installato - Firma GPG per tag - Chiave Firma Utente - Chiave GPG dell'utente per la firma - INTEGRAZIONE - SHELL/TERMINALE - Argomenti - Usa '.' per indicare la cartella di lavoro - Percorso - Shell/Terminale - Potatura Remota - Destinazione: - Potatura Worktrees - Potatura delle informazioni di worktree in `$GIT_COMMON_DIR/worktrees` - Scarica - Branch Remoto: - In: - Modifiche Locali: - Remoto: - Scarica (Recupera e Unisci) - Riallineare anziché unire - Invia - Assicurati che i sottomoduli siano stati inviati - Forza l'invio - Branch Locale: - NUOVO - Ignora l'hook di pre-push - Remoto: - Revisione: - Invia Revisione Al Remoto - Invia modifiche al remoto - Branch Remoto: - Imposta come branch di tracciamento - Invia tutti i tag - Invia Tag al Remoto - Invia a tutti i remoti - Remoto: - Tag: - Push su un NUOVO branch - Inserisci il nome del nuovo branch remoto: - Esci - Riallinea Branch Corrente - Stasha e Riapplica modifiche locali - Su: - Aggiungi Remoto - Modifica Remoto - Nome: - Nome del remoto - URL del Repository: - URL del repository Git remoto - Copia URL - Azione Personalizzata - Elimina... - Modifica... - Recupera - Apri nel Browser - Pota - Conferma Rimozione Worktree - Abilita opzione `--force` - Destinazione: - Rinomina Branch - Nuovo Nome: - Nome univoco per questo branch - Branch: - ANNULLA - Recupero automatico delle modifiche dai remoti... - Ordina - Per data del committer - Per nome - Pulizia (GC e Potatura) - Esegui il comando `git gc` per questo repository. - Cancella tutto - Cancella - Configura questo repository - CONTINUA - Azioni Personalizzate - Nessuna Azione Personalizzata - Scarta tutte le modifiche - Apri nell'Esplora File - Cerca Branch/Tag/Sottomodulo - Visibilità nel grafico - Non impostato - Nascondi nel grafico dei commit - Filtra nel grafico dei commit - LAYOUT - Orizzontale - Verticale - Ordine dei commit - Per data del commit - Topologicamente - BRANCH LOCALI - Vai a HEAD - Crea Branch - CANCELLA LE NOTIFICHE - Apri come Cartella - Apri in {0} - Apri in Strumenti Esterni - REMOTI - AGGIUNGI REMOTO - RISOLVI - Cerca Commit - Autore - 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 - Statistiche - SOTTOMODULI - AGGIUNGI SOTTOMODULI - AGGIORNA SOTTOMODULI - TAG - NUOVO TAG - Per data di creazione - Per nome - Ordina - Apri nel Terminale - Visualizza i Log - Visita '{0}' nel Browser - WORKTREE - AGGIUNGI WORKTREE - POTATURA - URL del Repository Git - Reset Branch Corrente alla Revisione - Modalità Reset: - Sposta a: - Branch Corrente: - Resetta Branch (Senza Checkout) - Sposta Verso: - Branch: - Mostra nell'Esplora File - Ripristina Commit - Commit: - Commit delle modifiche di ripristino - In esecuzione. Attendere... - SALVA - Salva come... - La patch è stata salvata con successo! - Scansiona Repository - Cartella Principale: - Scansiona un'altra cartella personalizzata - Controlla Aggiornamenti... - È disponibile una nuova versione del software: - Errore durante il controllo degli aggiornamenti! - Scarica - 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 - Chiave Privata SSH: - Percorso per la chiave SSH privata - AVVIA - Stasha - 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 - Elimina: - STASH - MODIFICHE - STASH - Statistiche - PANORAMICA - MESE - SETTIMANA - AUTORI: - 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 - AUTORE TAG - DATA - Confronta 2 tag - Confronta con... - Confronta con HEAD - Messaggio - Nome - Autore - Copia Nome Tag - Azione Personalizzata - Elimina ${0}$... - Elimina i {0} tag selezionati... - Invia ${0}$... - Aggiorna Sottomoduli - Tutti i sottomoduli - Inizializza se necessario - Sottomodulo: - Aggiorna al branch di tracciamento remoto del sottomodulo - URL: - Log - CANCELLA TUTTO - Copia - Elimina - Avviso - Pagina di Benvenuto - Crea Gruppo - Crea Sottogruppo - Clona Repository - Elimina - TRASCINA E RILASCIA CARTELLA SUPPORTATO. RAGGRUPPAMENTI PERSONALIZZATI SUPPORTATI. - Modifica - Sposta in un Altro Gruppo - Apri Tutti i Repository - Apri Repository - Apri Terminale - Riscansiona Repository nella Cartella Clone Predefinita - Cerca Repository... - MODIFICHE LOCALI - 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. - Cancella Cronologia - Sei sicuro di voler cancellare tutta la cronologia dei messaggi di commit? Questa azione non può essere annullata. - COMMIT - COMMIT E INVIA - Template/Storico - 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 - MERGE - APRI STRUMENTO DI MERGE ESTERNO - APRI TUTTI I CONFLITTI NELLO STRUMENTO DI MERGE ESTERNO - CONFLITTI NEI FILE RISOLTI - USO IL MIO - USO IL LORO - INCLUDI FILE NON TRACCIATI - NESSUN MESSAGGIO RECENTE INSERITO - NESSUN TEMPLATE DI COMMIT - No-Verify - Reimposta Autore - SignOff - IN STAGE - RIMUOVI DA STAGE - RIMUOVI TUTTO DA STAGE - NON IN STAGE - FAI LO STAGE - FAI LO STAGE DI TUTTO - VISUALIZZA COME NON MODIFICATO - Template: ${0}$ - WORKSPACE: - Configura Workspaces... - WORKTREE - Copia Percorso - Blocca - Apri - Rimuovi - Sblocca - SÌ - diff --git a/src/Resources/Locales/ja_JP.axaml b/src/Resources/Locales/ja_JP.axaml deleted file mode 100644 index ec73701055..0000000000 --- a/src/Resources/Locales/ja_JP.axaml +++ /dev/null @@ -1,1079 +0,0 @@ - - - - - - 情報 - SourceGit について - リリース日: {0} - リリースノート - オープンソース & フリーな Git GUI クライアント - ファイルの変更を無視 - パターン: - 登録先のファイル: - 作業ツリーを追加 - 場所: - この作業ツリーへのパス (相対パスも使用できます) - ブランチの名前: - 省略可能 - 既定では宛先のフォルダーと同じ名前が使用されます - 追跡するブランチ: - 追跡するリモートブランチを設定 - チェックアウトする内容: - 新しいブランチを作成 - 既存のブランチ - AI アシスタント - モデル - 再生成 - AI を使用してコミットメッセージを生成 - 使用 - SourceGit を隠す - 他を隠す - すべて表示 - 3 分割マージ - 適用するパッチファイルを選択 - 空白文字の変更を無視 - 適用元: - ファイル - クリップボード - パッチを適用 - 空白文字: - スタッシュを適用 - 適用後に削除 - インデックスの変更を復元 - スタッシュ: - アーカイブ化... - アーカイブの保存先: - アーカイブファイルへのパスを選択 - リビジョン: - アーカイブ化 - SourceGit Askpass - パスフレーズを入力: - 未変更と見なしたファイル - 未変更と見なしたファイルはありません - 画像を選択... - 再読み込み - 問題の発生源を特定 - 中止 - 問題あり - 問題なし - スキップ - 問題の発生源となったコミットを特定しています。別のコミットをチェックアウトし、そのコミットに問題があるかどうかを調査してください。 - 問題の発生源となったコミットを特定しています。問題があるコミットをチェックアウト・選択してください。 - 問題の発生源となったコミットを特定しています。現在のコミットに問題があるかどうかを調査したあと、別のコミットをチェックアウトしてみてください。 - 問題の発生源となったコミットを特定しています。現在の HEAD に問題はありませんか? - 著者の履歴 - 前のリビジョンの著者の履歴 - 空白文字の変更を無視 - Ctrl (Windows/Linux) または ⌘ (macOS) キーを押しながらコミットの SHA をクリックすると、そのリビジョンを基点に著者の履歴データを再構築します。 - このファイルに著者の履歴は表示できません!!! - ${0}$ をチェックアウト... - 選択した 2 つのブランチを比較 - 比較対象を選択... - HEAD と比較 - ${0}$ と比較 - ブランチ名をコピー - プルリクエストを作成... - 上流の ${0}$ にプルリクエストを作成... - カスタムアクション - ${0}$ を削除... - 選択した {0} 個のブランチを削除... - ${0}$ の説明を編集... - ${0}$ まで早送り - ${0}$ から ${1}$ にフェッチ - Git フロー - ${0}$ を完了... - ${0}$ を ${1}$ で対話式リベース - ${0}$ を ${1}$ にマージ... - 現在のブランチに、選択した {0} 個のブランチをマージ... - ${0}$ からプル... - ${0}$ から ${1}$ にプル... - ${0}$ をプッシュ... - ${0}$ を ${1}$ でリベース... - ${0}$ の名前を変更... - ${0}$ を ${1}$ にリセット... - ${0}$ に切り替え (作業ツリー) - 追跡するブランチを設定... - ローカルに {0} コミット済み - ローカルに {0} コミット済み、リモートに {1} コミットあり - リモートに {0} コミットあり - 無効 - プッシュ先の URL - リモート - 状態 - 追跡対象 - URL - 作業ツリー - キャンセル - 親リビジョンにリセット - このリビジョンにリセット - コミットメッセージを生成 - マージ (組み込みツール) - マージ (外部ツール) - ファイルを ${0}$ にリセット - 表示形式を変更 - ファイルとディレクトリの一覧で表示 - パスの一覧で表示 - ファイルシステムのツリーで表示 - サブモジュールの URL を変更 - サブモジュール: - URL: - ブランチをチェックアウト - ローカルの変更: - ブランチ: - 現在の HEAD には、どのブランチやタグにも繋がっていないコミットが含まれています!それでも続行しますか? - これらのサブモジュールを更新する必要があります:{0}更新しますか? - チェックアウト & 早送り - 早送り先: - スタッシュからブランチをチェックアウト - 新しいブランチ: - スタッシュ: - コミットまたはタグをチェックアウト - 対象: - 警告: これを行うと、HEAD が切断されます - コミットを取り込む - 取り込み元をコミットメッセージに明記 - コミット: - すべての変更をコミット - メインライン: - 通常、マージコミットを取り込むことはできません。どちらのマージ元をメインラインとして扱うべきかが分からないためです。このオプションを使用すると、指定した親コミットに対して、変更を再適用する形で取り込みを実行できます。 - スタッシュを消去 - すべてのスタッシュを消去します。よろしいですか? - リモートリポジトリをクローン - 追加の引数: - リポジトリをクローンする際の追加の引数 (省略可能) - ブックマーク: - グループ: - ローカル名: - リポジトリの名前 (省略可能) - 親フォルダー: - サブモジュールを初期化して更新 - リポジトリの URL: - 閉じる - エディター - ブランチ - ブランチ & タグ - リポジトリのカスタムアクション - リビジョンのファイル - コミットをチェックアウト... - コミットを取り込む... - 取り込む... - HEAD と比較 - 作業ツリーと比較 - 著者 - 著者の日時 - メッセージ - コミッター - コミット日時 - SHA - タイトル - カスタムアクション - 対話式リベース - 削除... - 編集... - 親コミットに統合... - ${0}$ を ${1}$ で対話式リベース - 書き直す... - 親コミットに記録付きで統合... - マージ... - ${0}$ を ${1}$ にプッシュ... - ${0}$ を ${1}$ でリベース... - ${0}$ を ${1}$ にリセット... - コミットを取り消す... - パッチとして保存... - 変更 - 個の変更されたファイル - 変更を検索... - 詳細を折りたたむ - ファイル - LFS ファイル - ファイルを検索... - サブモジュール - コミットの情報 - 著者 - コミッター - このコミットが含まれる参照を確認 - これらの参照にコミットが含まれています - メールアドレスをコピー - 名前をコピー - 名前 & メールアドレスをコピー - 最初の 100 件の変更のみが表示されています。'変更' タブですべての変更を確認できます。 - 鍵: - メッセージ - 親コミット - 参照 - SHA - 署名者: - ブラウザーで開く - 列 - コミットメッセージを入力してください。タイトルと説明は、空行で分けて記述してください! - タイトル - 比較 - 変更 - コミット - 左側のみに含まれるコミット - 右側のみに含まれるコミット - ヒント: もう片側が HEAD を指しているのであれば、(コンテキストメニューから) コミットを選択して取り込むことができます。 - リポジトリの設定 - コミットテンプレート - 組み込みのパラメーター: - - ${branch_name} 現在のローカルブランチ名 - ${files_num} 変更されたファイル数 - ${files} 変更されたファイルへのパス - ${files:N} 変更されたファイルへのパス (最大 N 件) - ${pure_files} 変更されたファイルの名前 - ${pure_files:N} 変更されたファイルの名前 (最大 N 件) - テンプレートの内容: - テンプレート名: - カスタムアクション - 引数: - 組み込みのパラメーター: - - ${REPO} リポジトリへのパス - ${REMOTE} 選択したリモート名、または選択したブランチのリモート名 - ${BRANCH} 選択したブランチ名 (リモートブランチの場合に ${REMOTE} の部分を含まない) - ${BRANCH_FRIENDLY_NAME} 選択したブランチの分かりやすい名前 (リモートブランチの場合に ${REMOTE} の部分を含む) - ${SHA} 選択したコミットのハッシュ - ${TAG} 選択したタグ名 - ${FILE} リポジトリのルートから辿った、選択したファイルへの相対パス - $1, $2 ... 入力プロンプトの値 - 実行ファイル: - 入力プロンプト: - 編集 - 名前: - 利用範囲: - ブランチ - コミット - ファイル - リモート - リポジトリ - タグ - アクションの終了を待機 - メールアドレス - E メールアドレス - Git - サブモジュールを自動更新する前に尋ねる - リモートから - 分ごとに自動フェッチ - コンベンショナルコミットの種類定義 - 既定のリモート - サブモジュールを自動更新する際は再帰的に実行 - 優先するマージ方式 - イシュートラッカー - Azure DevOps のルールを追加 - Gerrit Change-Id コミットのルールを追加 - Gitee イシューのルールを追加 - Gitee プルリクエストのルールを追加 - GitHub のルールを追加 - GitLab イシューのルールを追加 - GitLab マージリクエストのルールを追加 - Jira のルールを追加 - 新しいルール - イシューの正規表現: - ルール名: - このルールを .issuetracker ファイルで共有 - 最終的な URL: - 正規表現のグループ値は $1, $2 で取得してください。 - AI - 優先するサービス: - '優先するサービス' を設定すると、このリポジトリではそのサービスのみを使用するようになります。そうでなければ、複数のサービスが存在する場合に限り、その中からひとつを選択できるコンテキストメニューが表示されます。 - HTTP プロキシ - このリポジトリで使用する HTTP プロキシ - ユーザー名 - このリポジトリにおけるユーザー名 - カスタムアクションのプロンプトを編集 - チェック時の値: - チェックされたときにのみ、この値がコマンドライン引数として渡されます - 説明: - 既定値: - フォルダー選択: - ラベル: - 選択肢: - 選択肢は '|' で区切って記述します - 文字列の整形ツール: - 省略可能 - 最終的な出力文字列を整形するために使用されます (入力がなければ何もしません)。入力された値は `${VALUE}` で参照してください。 - ここでも組み込みの変数 ${REPO}, ${REMOTE}, ${BRANCH}, ${BRANCH_FRIENDLY_NAME}, ${SHA}, ${FILE}, ${TAG} がそのまま利用できます - 種類: - リモート名付きの名前を使用: - ワークスペース - 色 - 名前 - 起動時にタブを復元 - 続行 - コミットの内容が何もありません!それでも続行しますか (--allow-empty)? - すべてステージに上げてからコミット - 選択した変更をステージに上げてからコミット - コミットの内容が何もありません!コミットする前に、変更をステージに上げますか?それともこのまま続行しますか (--allow-empty)? - 再起動が必要です - この変更は、アプリを再起動したあとに反映されます。 - コンベンショナルコミットの生成補助ツール - 破壊的変更: - 閉じるイシュー: - 詳細な変更: - スコープ: - 簡単な説明: - 変更の種類: - コピー - すべてのテキストをコピー - パッチとしてコピー - 絶対パスをコピー - パスをコピー - ブランチを作成... - 派生元: - 作成したブランチにチェックアウト - ローカルの変更: - 新しいブランチ名: - ブランチの名前を入力 - ローカルブランチを作成 - 既存のブランチを上書き - タグを作成... - 付与するコミット: - GPG で署名 - タグメッセージ: - 省略可能 - タグ名: - 推奨される形式: v1.0.0-alpha - タグの作成後、すべてのリモートにプッシュ - タグを作成 - 種類: - 注釈付き - 軽量 - Ctrl キーを押しながらで直接実行できます - 切り取り - ダッシュボード - 破棄 - 何もしない - スタッシュして再適用 - サブモジュールの初期化を解除 - ローカルの変更の有無に関わらず、強制的に解除 - サブモジュール: - ブランチを削除 - ブランチ: - 未マージのコミットがあっても強制的に削除 - リモートブランチを削除しようとしています!!! - リモートブランチの ${0}$ も削除 - 複数のブランチを削除 - 複数のブランチをまとめて削除しようとしています。操作を行う前によく確認してください! - 複数のタグを削除 - リモートからも削除 - 複数のタグをまとめて削除しようとしています。操作を行う前によく確認してください! - リモートを削除 - リモート: - パス: - 対象: - このグループ配下の項目も含め、すべて一覧から削除されます。 - 一覧から削除されるのみで、ディスクから削除されるわけではありません! - グループの削除を確認 - リポジトリの削除を確認 - サブモジュールを削除 - サブモジュールへのパス: - タグを削除 - タグ: - リモートリポジトリからも削除 - バイナリの差分 - 新しい内容を表示 - 空のファイル - 最初の差分 - 空白文字の変更を無視 - ブレンド - 色差 - 左右に並べる - スライド - 最後の差分 - LFS オブジェクトの変更 - 新版 - 次の差分 - 変更なし、または行末コードの変更のみ - 旧版 - 前の差分 - パッチとして保存 - 空白文字を可視化 - 左右に並べて差分を表示 - サブモジュール - 削除 - 新規 - さらに {0} 件のコミットされていない変更があります - 入れ替え - 構文を強調表示 - 行を折り返す - マージツールで開く - すべての行を表示 - 表示する行数を減らす - 表示する行数を増やす - ファイルを選択すると、変更内容が表示されます - ディレクトリの履歴 - ローカルの変更あり - 上流のブランチとの相違あり - すでに最新です - 変更を破棄 - 作業コピーに対するローカルのすべての変更 - 変更: - 無視されたファイルを含める - 変更/削除されたファイルを含める - 未追跡のファイルを含める - {0} 件の変更が破棄されます - この操作は元に戻せません!!! - ブランチの説明を編集 - 対象: - ブックマーク: - 新しい名前: - 対象: - 選択したグループを編集 - 選択したリポジトリを編集 - 対象: - このリポジトリ - フェッチ - すべてのリモートをフェッチ - ローカルの参照を強制的に上書き - タグなしでフェッチ - リモート: - リモートの変更をフェッチ - バイナリファイル - バイナリビューアー - アドレスに移動... - 未変更と見なす - カスタムアクション - 破棄... - {0} 個のファイルを破棄... - ${0}$ を使用して解決 - パッチとして保存... - ステージに上げる - {0} 個のファイルをステージに上げる - スタッシュ... - {0} 個のファイルをスタッシュ... - ステージから降ろす - {0} 個のファイルをステージから降ろす - 自分の変更を使用 (checkout --ours) - 相手の変更を使用 (checkout --theirs) - ファイルの履歴 - 変更 - ファイルの内容 - ファイルモードの変更: - 削除されたファイルのモード: - ディレクトリ - 実行可能 - 新しいファイルのモード: - 通常 - サブモジュール - シンボリックリンク - 不明 - Git フロー - 開発ブランチ: - 新機能の実装: - 新機能の実装用のプレフィックス: - ${0}$ を完了 - 新機能の実装を完了 - 緊急のバグ修正を完了 - リリース作業を完了 - 対象: - マージする前にリベース - スカッシュしてマージ - 緊急のバグ修正: - 緊急のバグ修正用のプレフィックス: - Git フローを初期化 - ブランチを維持 - 本番ブランチ: - リリース作業: - リリース作業用のプレフィックス: - 開始地点: - 新機能の実装を開始... - 新機能の実装を開始 - 緊急のバグ修正を開始... - 緊急のバグ修正を開始 - 名前: - 名前を入力 - リリース作業を開始... - リリース作業を開始 - バージョンタグのプレフィックス: - Git LFS - 追跡パターンを追加... - パターンをファイル名として扱う - カスタムパターン: - Git LFS に追跡パターンを追加 - フェッチ - `git lfs fetch` を実行し、Git LFS オブジェクトをダウンロードします。作業コピーは更新されません。 - LFS オブジェクトをフェッチ - Git LFS フックをインストール - ロックを表示 - ロックされたファイルはありません - ロック - 自分のロックのみを表示 - LFS ロック - ロックを解除 - 自分のロックをすべて解除 - 自分でロックしたファイルをすべて解除しますか? - 強制的にロックを解除 - 掃除 - `git lfs prune` を実行し、ローカルの保存領域から古い LFS ファイルを削除します - プル - `git lfs pull` を実行し、現在の参照の Git LFS ファイルをすべてダウンロード & チェックアウトします - LFS オブジェクトをプル - プッシュ - キューにある大容量ファイルを Git LFS エンドポイントにプッシュします - LFS オブジェクトをプッシュ - リモート: - '{0}' という名前のファイルを追跡 - *{0} ファイルをすべて追跡 - コミットを選択 - 詳細オプション - 著者 - 著者の日時 - コミット日時 - グラフ & コミットのタイトル - SHA - グラフでの強調表示 - 全範囲 - 現在のブランチのみ - 現在のブランチ & 選択したコミット - 選択したコミットのみ - 選択したコミットかつ最初の親コミットのみ - {0} コミットを選択しました - 表示する列 - 'Ctrl' または 'Shift' キーを押しながらで、複数のコミットを選択できます。 - ⌘ または ⇧ キーを押しながらで、複数のコミットを選択できます。 - ヒント: - 別のウィンドウで開く - コミットの詳細 - リビジョンを比較 - キーボードショートカットを確認 - 総合 - リモートリポジトリをクローン - 現在のタブを閉じる - 次のタブに移動 - 前のタブに移動 - 新しいタブを作成 - ローカルリポジトリを開く - 設定ダイアログを開く - ワークスペースのドロップダウンメニューを表示 - アクティブなタブを切り替え - 拡大/縮小 - リポジトリ - ステージに上げた変更をコミット - ステージに上げた変更をコミットしてプッシュ - すべての変更をステージに上げてコミット - 新しいブランチを作成 - フェッチ (直接実行) - 選択したコミットの子コミットに移動 - 選択したコミットの親コミットに移動 - コマンドパレットを開く - プル (直接実行) - プッシュ (直接実行) - 現在のリポジトリを強制的に再読み込み - コミットの詳細パネルを広げる/折りたたむ - コミットの検索パネルを切り替え - 'ローカルの変更' に切り替え - 'ダッシュボード' に切り替え - 'スタッシュ' に切り替え - 破棄 - ステージに上げる - ステージから降ろす - リポジトリを初期化 - このパスで `git init` コマンドを実行しますか? - リポジトリを開けませんでした。理由: - パス: - 取り込み作業が進行中です。 - 取り込み対象のコミット: - マージ作業が進行中です。 - マージ対象: - リベース作業が進行中です。 - 停止地点: - 取り消し作業が進行中です。 - 取り消し対象のコミット: - 対話式リベース - ローカルの変更をスタッシュして再適用 - リベース前のフックを実行しない - リベース地点: - ドラッグ & ドロップでコミットを並べ替えられます - 対象のブランチ: - リンクをコピー - ブラウザーで開く - コマンド - エラー - 通知 - 新しいバージョンが利用できます - リポジトリを開く - タブ - ワークスペース - ブランチをマージ - マージメッセージを編集 - マージ先: - マージオプション: - マージ元: - マージができるかを確認しています... - マージは衝突せずに行えます - マージ時に何らかのエラーが発生します - マージに衝突が発生します - 自分の変更 → 相手の変更の順で適用 - 相手の変更 → 自分の変更の順で適用 - 両方を使用 - すべての衝突が解決されました - {0} 件の衝突が残っています - 自分 - 次の衝突 - 前の衝突 - 結果 - 保存 & ステージに上げる - 相手 - マージ衝突 - 保存されていない変更を破棄しますか? - 自分の変更を使用 - 相手の変更を使用 - 元に戻す - マージ (複数) - すべての変更をコミット - マージ方式: - 対象: - サブモジュールを移動 - 移動先: - サブモジュール: - リポジトリを別のグループに移動 - このリポジトリの新しい所属先を選択: - 名前: - いいえ - Git の設定が行われていません。[設定] を開いて初期設定をしてください。 - 開く - 既定のエディター (システム) - データの保管ディレクトリを開く - キャッシュ - 設定 - ファイルを開く - 外部のマージツールで開く - ローカルリポジトリを開く - ブックマーク: - グループ: - フォルダー: - 省略可能 - 新しいタブを作成 - タブを閉じる - 他のタブを閉じる - 右側のタブを閉じる - リポジトリへのパスをコピー - 編集 - ワークスペースに移動 - 再読み込み - リポジトリ - 貼り付け - {0} 日前 - 1 時間前 - {0} 時間前 - たった今 - 先月 - 昨年 - {0} 分前 - {0} ヶ月前 - {0} 年前 - 昨日 - 設定 - AI - 追加のプロンプト (`-` で必要事項を羅列してください) - API キー - 追加のヘッダー (`名前: 値` を一行ごとに指定してください) - モデル - 利用できるモデル ID を自動的に取得 - 名前 - この値を環境変数の名前とし、そこから API キーを読み込む - 思考努力レベル - サーバー - 外観 - 既定のフォント - エディターのタブ幅 - フォントの大きさ - 既定 - エディター - 等幅フォント - テーマ - テーマの上書き - 自動的にスクロールバーを隠す - タイトルバーに固定タブ幅を使用 - ネイティブなウィンドウフレームを使用 - 差分/マージツール - 差分時の引数 - 利用できる変数: $LOCAL, $REMOTE - マージ時の引数 - 利用できる変数: $BASE, $LOCAL, $REMOTE, $MERGED - インストールパス - 差分/マージツールへのパスを入力 - ツール - 総合 - 起動時に更新を確認 - 日付の書式 - 変更ツリーのフォルダー階層をまとめる - 言語 - コミット履歴 - 初めから `ローカルの変更` ページを表示 - 初めからコミットの詳細の `変更` タブを表示 - コミットグラフを相対時間で表記 - コミットグラフにタグを表示 - 適切とするコミットタイトルの長さ - 24 時間 - コミットグラフのブランチ名をまとめる - GitHub のような既定のアバターを生成 - Git - 自動 CRLF 変換を有効化 - 既定のクローンディレクトリ - ユーザーのメールアドレス - Git ユーザーのメールアドレス (グローバル設定) - フェッチ時に不要なブランチを掃除 - テキストの差分で行末の CR コードを無視 - このアプリには Git (>= 2.25.1) が必須です - インストールパス - HTTP の SSL 検証を有効化 - git-credential-manager ではなく git-credential-libsecret を使用 - ユーザー名 - Git ユーザーの名前 (グローバル設定) - ブランチのチェックアウトやマージ時に、既定で変更をスタッシュして再適用 - Git バージョン - GPG 署名 - コミットを GPG で署名 - GPG 形式 - プログラムのインストールパス - インストールされている gpg プログラムへのパスを入力 - タグを GPG で署名 - ユーザーの署名鍵 - ユーザーの GPG 署名鍵 - 統合 - シェル/端末 - 引数 - 作業ディレクトリの明示には '.' を使用してください - パス - シェル/端末 - リモートを掃除 - 対象: - 作業ツリーを掃除 - `$GIT_COMMON_DIR/worktrees` 内の作業ツリー情報を掃除 - プル - リモートブランチ: - プル先: - ローカルの変更: - リモート: - プル (フェッチ & マージ) - マージではなくリベースを使用 - プッシュ - サブモジュールがプッシュされていることを確認 - 強制的にプッシュ - ローカルブランチ: - 新規 - プッシュ前のフックを実行しない - リモート: - リビジョン: - リビジョンをリモートにプッシュ - 変更をリモートにプッシュ - リモートブランチ: - 追跡するブランチとして設定 - すべてのタグをプッシュ - タグをリモートにプッシュ - すべてのリモートにプッシュ - リモート: - タグ: - 新しいブランチにプッシュ - 新しいリモートブランチ名を入力: - 終了 - 現在のブランチをリベース - ローカルの変更をスタッシュして再適用 - リベース前のフックを実行しない - リベース地点: - リベースができるかを確認しています... - リベースは衝突せずに行えます - リベース時に何らかのエラーが発生します - リベースに衝突が発生します - リモートを追加 - リモートを編集 - 名前: - リモート名 - プッシュ先の URL を、このリポジトリの URL にリセット - リポジトリの URL: - リモートの Git リポジトリの URL - URL をコピー - カスタムアクション - 削除... - 編集... - 自動フェッチを有効化 - フェッチ - ブラウザーで開く - 掃除 - プッシュ先の URL を設定... - 作業ツリーの削除を確認 - `--force` オプションを有効化 - 対象: - ブランチ名を変更 - 新しい名前: - このブランチに付ける一意な名前 - ブランチ: - 中止 - リモートから変更を自動取得しています... - 並べ替え - コミット日時順 - 名前順 - クリーンアップ (GC & Prune) - このリポジトリに `git gc` コマンドを実行します。 - すべて消去 - 消去 - このリポジトリの設定 - 続行 - カスタムアクション - カスタムアクションがありません - すべての変更を破棄 - ファイルブラウザーで開く - ブランチ/タグ/サブモジュールを絞り込み - グラフでの可視性 - 絞り込み条件を折りたたむ - 解除 - コミットグラフから隠す - 絞り込み条件を広げる - コミットグラフで絞り込む - 個の条件で絞り込んでいます - レイアウト - 水平 - 垂直 - コミットの並び順 - コミット日時 - トポロジカル - ローカルブランチ - HEAD に移動 - ブランチを作成 - 通知を消去 - フォルダーとして開く - {0} で開く - 外部ツールで開く - リモート - リモートを追加 - 解決 - コミットを検索 - 著者 - ファイルの内容 - メッセージ - パス - SHA - 現在のブランチ - 検索対象 - コミットを検索 - 参照付きのコミットのみ - 最初の親コミットのみ - 表示フラグ - 消失したコミットを表示 - サブモジュールをツリー形式で表示 - タグをツリー形式で表示 - スキップ - 統計 - サブモジュール - サブモジュールを追加 - サブモジュールを更新 - タグ - タグを作成 - 作成者の日時順 - 名前順 - 並べ替え - 端末で開く - ログを表示 - ブラウザーで '{0}' を訪問 - 作業ツリー - 作業ツリーを追加 - 掃除 - Git リポジトリの URL - 現在のブランチをリビジョンにリセット - リセット方式: - 移動先: - 現在のブランチ: - ブランチをリセット (チェックアウトなし) - 移動先: - ブランチ: - ファイルエクスプローラーで表示 - コミットを取り消す - コミット: - 取り消しの変更をコミット - 実行しています。お待ちください... - 保存 - 名前を付けて保存... - パッチが正常に保存されました! - リポジトリをスキャン - ルートディレクトリ: - 任意の別ディレクトリをスキャン - 更新を確認... - このソフトウェアの新しいバージョンが利用できます: - 現在のバージョン: - 更新の確認に失敗しました! - ダウンロード - このバージョンをスキップ - 新しいバージョンのリリース日: - ソフトウェアの更新 - 利用できる更新はありません。 - リモートにプッシュ先の URL を設定 - プッシュ先の URL: - リモート: - URL: - サブモジュールのブランチを設定 - サブモジュール: - 現在: - 変更先: - 省略可能 - 空欄で既定値を使用します - 追跡するブランチを設定 - ブランチ: - 上流のブランチを解除 - 上流のブランチ: - SHA をコピー - このコミットに移動 - SSH の秘密鍵: - SSH の秘密鍵が保管されているパス - SSH の鍵ツールを開く - これらの鍵を削除しますか? - フィンガープリント - SSH 鍵を生成 - パスフレーズを確認: - メールアドレス: - 必須 - 鍵の名前: - 必須 - 例: id_github - パスフレーズ: - 生成 - 種類: - 秘密鍵にパスフレーズを使用 - パス - 公開鍵 - SSH の鍵ツール - 開始 - スタッシュ - 未追跡のファイルを含める - メッセージ: - 省略可能 - このスタッシュのメッセージ - 方式: - ステージに上げたファイルのみ - 選択したファイルの、ステージに上がっている変更とそうではない変更の両方がスタッシュされます!!! - ローカルの変更をスタッシュ - 適用 - 変更を適用 - 新しいブランチをチェックアウト - メッセージをコピー - 削除 - パッチとして保存... - スタッシュを削除 - 削除: - スタッシュ - 変更 - スタッシュ - 統計 - 概要 - 月間 - 週間 - 対象のブランチの 200,000 コミットまでのみを分析して表示しています。 - 著者: - コミット: - サブモジュール - サブモジュールを追加 - ブランチ - ブランチ - 相対パス - 初期化を解除 - 入れ子になったサブモジュールも取得 - 履歴 - 移動 - リポジトリを開く - 相対パス: - このモジュールを保存するフォルダーへの相対パス - 削除 - ブランチを設定 - URL を変更 - 状態 - 変更あり - 未初期化 - リビジョンに更新あり - 未マージ - 更新 - URL - サブモジュールの変更の詳細 - 詳細を開く - OK - タグの作成者 - 日時 - タグをチェックアウト... - 2 つのタグを比較 - 比較対象を選択... - HEAD と比較 - メッセージ - 名前 - タグの作成者 - タグ名をコピー - カスタムアクション - ${0}$ を削除... - 選択した {0} 個のタグを削除... - ${0}$ を ${1}$ にマージ... - ${0}$ をプッシュ... - 中止 - サブモジュールを更新 - すべてのサブモジュール - 必要に応じて初期化 - サブモジュール: - 入れ子になったサブモジュールも更新 - サブモジュールのリモート追跡ブランチに更新 - URL: - ログ - すべて消去 - コピー - 削除 - 警告 - ようこそページ - グループを作成 - サブグループを作成 - リポジトリをクローン - 削除 - ドラッグ & ドロップでフォルダーを追加できます。また、グループの作成・編集もできます。 - 編集 - 別のグループに移動 - すべてのリポジトリを開く - リポジトリを開く - 端末を開く - 既定のクローンディレクトリ内のリポジトリを再スキャン - リポジトリを検索... - ローカルの変更 - 無視 - *{0} ファイルをすべて無視 - 同じフォルダーの *{0} ファイルを無視 - このフォルダーで未追跡のファイルを無視 - このファイルのみを無視 - 同じフォルダーで未追跡のファイルをすべて無視 - 最後のコミットをやり直す - このファイルをステージに上げられるようになりました。 - 履歴を消去 - コミットメッセージの履歴をすべて消去しますか?この操作は元に戻せません。 - コミット - コミットしてプッシュ - テンプレート/履歴 - クリックイベントを発動 - コミット (編集) - すべての変更をステージに上げてコミット - 切断された HEAD にコミットを作成しようとしています。それでも続行しますか? - ステージに上げた {0} 個のファイルのうち、{1} 個のファイルのみが表示されています ({2} 個のファイルは非表示状態です)。続行しますか? - 衝突が検出されました - マージ - 外部ツールでマージ - すべての衝突を外部マージツールで開く - ファイルの衝突が解決されました - 自分の変更を使用 - 相手の変更を使用 - すべて破棄 - 変更を絞り込み... - 未追跡のファイルを含める - 最近の入力メッセージはありません - コミットテンプレートがありません - 検証しない - 著者をリセット - 署名の行を追記 - ステージに上げたファイル - ステージから降ろす - すべてステージから降ろす - 未ステージのファイル - ステージに上げる - すべてステージに上げる - 未変更と見なしたファイルを表示 - テンプレート: ${0}$ - ワークスペース: - ワークスペースの設定... - 作業ツリー - ブランチ - パスをコピー - HEAD - ロック - 開く - パス - 削除 - ロックを解除 - はい - diff --git a/src/Resources/Locales/ko_KR.axaml b/src/Resources/Locales/ko_KR.axaml deleted file mode 100644 index 939f8a4c1c..0000000000 --- a/src/Resources/Locales/ko_KR.axaml +++ /dev/null @@ -1,999 +0,0 @@ - - - - - - 정보 - SourceGit 정보 - 배포일: {0} - 릴리스 노트 - 오픈소스 & 무료 Git GUI 클라이언트 - 무시할 파일 추가 - 패턴: - 저장 파일: - 워크트리 추가 - 위치: - 이 워크트리의 경로입니다. 상대 경로를 지원합니다. - 브랜치 이름: - 선택 사항. 기본값은 대상 폴더 이름입니다. - 추적할 브랜치: - 원격 브랜치 추적 - 체크아웃할 대상: - 새 브랜치 생성 - 기존 브랜치 - AI 어시스턴트 - 모델 - 재생성 - AI를 사용하여 커밋 메시지 생성 - 사용 - SourceGit 숨기기 - 다른 항목 숨기기 - 모두 보기 - 3방향 병합 - 적용할 패치 파일을 선택하세요 - 공백 변경 사항 무시 - 원본: - 파일 - 클립보드 - 패치 적용 - 공백: - 스태시 적용 - 적용 후 삭제 - 인덱스의 변경 사항 복원 - 스태시: - 아카이브... - 아카이브 저장 위치: - 아카이브 파일 경로 선택 - 리비전: - 아카이브 - SourceGit Askpass - 암호 입력: - 변경되지 않음으로 간주된 파일 - 변경되지 않음으로 간주된 파일 없음 - 이미지 불러오기... - 새로 고침 - 이진 탐색 - 중단 - 나쁨 - 좋음 - 건너뛰기 - 이진 탐색 중. 현재 커밋을 '좋음' 또는 '나쁨'으로 표시하고 다른 커밋을 체크아웃하세요. - 이진 탐색 중. 현재 HEAD가 '좋음' 상태입니까, '나쁨' 상태입니까? - 블레임 - 이전 리비전으로 책임 추적 - 공백 변경 무시 - 이 파일은 책임 추적 기능을 지원하지 않습니다 - ${0}$(으)로 체크아웃... - 선택한 두 브랜치 비교하기 - 다음과 비교... - HEAD와 비교 - ${0}$와 비교 - 브랜치 이름 복사 - PR 생성 - 업스트림 ${0}$에 대한 PR 생성... - 사용자 지정 작업 - ${0}$ 삭제... - 선택한 {0}개의 브랜치 삭제 - ${0}$ 설명 편집... - ${0}$(으)로 Fast-Forward - ${0}$에서 ${1}$(으)로 Fetch... - Git Flow - ${0}$ 완료 - ${1}$을(를) 기반으로 ${0}$ 대화형 리베이스 - ${0}$을(를) ${1}$(으)로 병합... - 선택한 {0}개의 브랜치를 현재 브랜치로 병합 - ${0}$ Pull - ${0}$에서 ${1}$(으)로 Pull... - ${0}$(으)로 Push - ${1}$을(를) 기반으로 ${0}$ 리베이스... - ${0}$ 이름 바꾸기... - ${0}$을(를) ${1}$(으)로 리셋... - ${0}$(워크트리)로 전환 - 추적 브랜치 설정... - {0}개 커밋 앞섬 - {0}개 커밋 앞섬, {1}개 커밋 뒤처짐 - {0}개 커밋 뒤처짐 - 유효하지 않음 - 원격 - 상태 - 추적 중 - URL - 워크트리 - 취소 - 부모 리비전으로 리셋 - 이 리비전으로 리셋 - 커밋 메시지 생성 - 병합(내장) - 병합(외부 도구) - 파일을 ${0}$(으)로 되돌리기 - 표시 모드 변경 - 파일 및 디렉터리 목록으로 보기 - 경로 목록으로 보기 - 파일 시스템 트리로 보기 - 서브모듈 URL 변경 - 서브모듈: - URL: - 브랜치 체크아웃 - 로컬 변경 사항: - 브랜치: - 현재 HEAD에 브랜치/태그에 연결되지 않은 커밋이 있습니다! 계속하시겠습니까? - 다음 서브모듈을 업데이트해야 합니다:{0}업데이트하시겠습니까? - 체크아웃 & Fast-Forward - Fast-Forward 대상: - 스태시에서 브랜치 체크아웃 - 새로운 브랜치: - 스태시: - 체리픽 - 커밋 메시지에 원본 추가 - 커밋: - 모든 변경 사항 커밋 - 메인라인: - 어느 쪽을 메인라인으로 간주해야 할지 알 수 없기 때문에 일반적으로 병합(merge)을 체리픽할 수 없습니다. 이 옵션을 사용하면 지정된 부모를 기준으로 변경 사항을 다시 적용할 수 있습니다. - 모든 스태시 지우기 - 모든 스태시를 지우려고 합니다. 계속하시겠습니까? - 원격 저장소 복제 - 추가 파라미터: - 저장소 복제 시 추가 인수. 선택 사항. - 북마크: - 그룹: - 로컬 이름: - 저장소 이름. 선택 사항. - 상위 폴더: - 서브모듈 초기화 & 업데이트 - 저장소 URL: - 닫기 - 에디터 - 브랜치 - 브랜치 & 태그 - 저장소 사용자 지정 작업 - 리비전 파일 - 커밋 체크아웃 - 커밋 체리픽 - 체리픽... - HEAD와 비교 - 워크트리와 비교 - 작성자 - 작성 시간 - 메시지 - 커밋터 - 커밋 시간 - SHA - 제목 - 사용자 지정 작업 - 대화형 리베이스 - 삭제(Drop)... - 수정(Edit)... - 부모에 합치기(Fixup)... - ${1}$을(를) 기반으로 ${0}$(을)를 대화형 리베이스 - 메시지 수정(Reword)... - 부모에 합치기(Squash)... - 병합... - ${0}$을(를) ${1}$(으)로 푸시 - ${1}$을(를) 기반으로 ${0}$(을)를 리베이스 - ${0}$을(를) ${1}$(으)로 리셋 - 커밋 되돌리기 - 패치로 저장... - 변경 사항 - 변경된 파일 - 변경 사항 검색... - 세부 정보 접기 - 파일 - LFS 파일 - 파일 검색... - 서브모듈 - 정보 - 작성자 - 커밋터 - 이 커밋을 포함하는 ref 확인 - 커밋 포함 REF - 이메일 복사 - 이름 복사 - 이름 & 이메일 복사 - 처음 100개의 변경 사항만 표시합니다. 모든 변경 사항은 '변경 사항' 탭에서 확인하세요. - 키: - 메시지 - 부모 - REFS - SHA - 서명자: - 브라우저에서 열기 - 열 - 커밋 메시지를 입력하세요. 제목과 설명은 빈 줄로 구분하세요! - 제목 - 비교 - 변경점 - 커밋 - 왼쪽에만 있는 커밋 - 오른쪽에만 있는 커밋 - 팁: 반대편이 HEAD인 경우 선택한 커밋을 체리픽할 수 있습니다(컨텍스트 메뉴 사용). - 저장소 설정 - 커밋 템플릿 - ${files_num}, ${branch_name}, ${files} 및 ${files:N} (N은 출력할 최대 파일 경로 수)을(를) 사용할 수 있습니다. - 템플릿 내용: - 템플릿 이름: - 사용자 지정 작업 - 인수: - 내장 파라미터: - - ${REPO} 저장소 경로 - ${REMOTE} 선택한 원격 또는 선택한 브랜치의 원격 - ${BRANCH} 선택한 브랜치 (원격 브랜치의 경우 ${REMOTE} 부분 제외) - ${BRANCH_FRIENDLY_NAME} 선택한 브랜치의 식별하기 쉬운 이름 (원격 브랜치의 경우 ${REMOTE} 부분 포함) - ${SHA} 선택한 커밋의 해시 - ${TAG} 선택한 태그 - ${FILE} 저장소 루트에 상대적인 선택된 파일 - $1, $2 ... 입력 컨트롤 값 - 실행 파일: - 입력 컨트롤: - 편집 - 이름: - 범위: - 브랜치 - 커밋 - 파일 - 원격 - 저장소 - 태그 - 작업이 끝날 때까지 대기 - 이메일 주소 - 이메일 주소 - GIT - 서브모듈 자동 업데이트 전에 확인 - 원격 자동 Fetch - 분 - Conventional Commit 유형 - 기본 원격 - 선호하는 병합 모드 - 이슈 트래커 - Azure DevOps 규칙 추가 - Gerrit Change-Id 커밋 규칙 추가 - Gitee 이슈 규칙 추가 - Gitee Pull Request 규칙 추가 - GitHub 규칙 추가 - GitLab 이슈 규칙 추가 - GitLab Merge Request 규칙 추가 - Jira 규칙 추가 - 새 규칙 - 이슈 정규식: - 규칙 이름: - .issuetracker 파일에 이 규칙 공유 - 결과 URL: - 정규식 그룹 값에 접근하려면 $1, $2를 사용하세요. - AI - 선호하는 서비스: - '선호하는 서비스'가 설정되면, SourceGit은 이 저장소에서 해당 서비스만 사용합니다. 그렇지 않고 사용 가능한 서비스가 두 개 이상인 경우, 하나를 선택할 수 있는 컨텍스트 메뉴가 표시됩니다. - HTTP 프록시 - 이 저장소에서 사용하는 HTTP 프록시 - 사용자 이름 - 이 저장소의 사용자 이름 - 사용자 지정 작업 컨트롤 편집 - 선택 시 값: - 선택 시, 이 값이 명령줄 인수로 사용됩니다 - 설명: - 기본값: - 폴더 여부: - 레이블: - 옵션: - 옵션 구분자로 '|'를 사용하세요 - 문자열 포매터: - 선택 사항. 출력 문자열 형식 지정에 사용합니다. 입력이 비어 있으면 무시됩니다. 입력 문자열은 `${VALUE}`로 표시하세요. - 여기에서도 내장 변수 ${REPO}, ${REMOTE}, ${BRANCH}, ${BRANCH_FRIENDLY_NAME}, ${SHA}, ${FILE}, ${TAG}를 사용할 수 있습니다 - 유형: - 표시용 이름 사용: - 작업 공간 - 색상 - 이름 - 시작 시 탭 복원 - 계속 - 빈 커밋이 감지되었습니다! 계속하시겠습니까 (--allow-empty)? - 모두 스테이징 & 커밋 - 선택 항목 스테이징 후 커밋 - 빈 커밋이 감지되었습니다! 계속하시겠습니까 (--allow-empty) 아니면 모두 스테이징 후 커밋하시겠습니까? - 재시작 필요 - 변경 사항을 적용하려면 앱을 다시 시작해야 합니다. - Conventional Commit 도우미 - 주요 변경 사항(Breaking Change): - 종료된 이슈: - 상세 변경 내역: - 범위: - 간단한 설명: - 변경 유형: - 복사 - 전체 텍스트 복사 - 패치로 복사 - 전체 경로 복사 - 경로 복사 - 브랜치 생성... - 기준: - 생성된 브랜치로 체크아웃 - 로컬 변경 사항: - 새 브랜치 이름: - 브랜치 이름을 입력하세요. - 로컬 브랜치 생성 - 기존 브랜치 덮어쓰기 - 태그 생성... - 태그 생성 위치: - GPG 서명 - 태그 메시지: - 선택 사항. - 태그 이름: - 권장 형식: v1.0.0-alpha - 생성 후 모든 원격에 푸시 - 새 태그 생성 - 종류: - 주석 태그 - 경량 태그 - Ctrl을 누른 채 클릭하면 바로 시작합니다 - 잘라내기 - 폐기 - 아무것도 하지 않기 - 스태시 & 재적용 - 서브모듈 초기화 해제 - 로컬 변경 사항이 있어도 강제로 초기화 해제합니다. - 서브모듈: - 브랜치 삭제 - 브랜치: - 원격 브랜치를 삭제하려고 합니다!!! - 원격 브랜치 ${0}$도 함께 삭제 - 여러 브랜치 삭제 - 한 번에 여러 브랜치를 삭제하려고 합니다. 실행하기 전에 다시 한번 확인하세요! - 여러 태그 삭제 - 원격 저장소에서도 삭제 - 한 번에 여러 태그를 삭제하려고 합니다. 실행하기 전에 다시 한번 확인하세요! - 원격 삭제 - 원격: - 경로: - 대상: - 모든 하위 항목이 목록에서 제거됩니다. - 목록에서만 제거되며, 디스크에서 삭제되지 않습니다! - 그룹 삭제 확인 - 저장소 삭제 확인 - 서브모듈 삭제 - 서브모듈 경로: - 태그 삭제 - 태그: - 원격 저장소에서도 삭제 - 바이너리 비교 - 첫 번째 차이점 - 공백 변경 사항 무시 - 혼합 - 차이점 - 나란히 보기 - 스와이프 - 마지막 차이점 - LFS 객체 변경 - 신규 - 다음 차이점 - 변경 사항 없음 또는 줄바꿈(EOL) 변경만 있음 - 기존 - 이전 차이점 - 패치로 저장 - 숨겨진 기호 표시 - 나란히 비교 - 서브모듈 - 삭제됨 - 신규 - 커밋 안 한 변경 사항 + {0}개 - 전환 - 구문 강조 - 줄 바꿈 - 병합 도구에서 열기 - 모든 줄 표시 - 표시 줄 수 줄이기 - 표시 줄 수 늘리기 - 파일을 선택하여 변경 사항 보기 - 디렉터리 히스토리 - 로컬 변경 사항 있음 - 업스트림과 불일치 - 이미 최신 상태 - 변경 사항 폐기 - 작업 사본의 모든 로컬 변경 사항. - 변경 사항: - 무시된 파일 포함 - 수정/삭제된 파일 포함 - 추적하지 않는 파일 포함 - {0}개의 변경 사항이 폐기됩니다 - 이 작업은 되돌릴 수 없습니다!!! - 브랜치 설명 수정 - 대상: - 북마크: - 새 이름: - 대상: - 선택한 그룹 편집 - 선택한 저장소 편집 - 대상: - 이 저장소 - 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 (바로 시작) - 푸시 (바로 시작) - 이 저장소 강제 새로고침 - '변경 사항'으로 전환 - '스태시'로 전환 - 폐기 - 스테이지 - 언스테이지 - 저장소 초기화 - 이 경로에서 `git init` 명령을 실행하시겠습니까? - 저장소를 열지 못했습니다. 원인: - 경로: - 체리픽 진행 중. - 커밋 처리 중 - 병합 진행 중. - 병합 중 - 리베이스 진행 중. - 중단 지점 - 되돌리기 진행 중. - 커밋 되돌리는 중 - 대화형 리베이스 - 로컬 변경 사항 스태시 & 재적용 - pre-rebase 훅 건너뛰기 - 기준: - 드래그 앤 드롭으로 커밋 순서 변경 - 대상 브랜치: - 링크 복사 - 브라우저에서 열기 - 명령 - 오류 - 알림 - 저장소 열기 - 탭 - 작업 공간 - 브랜치 병합 - 병합 메시지 수정 - 대상: - 병합 옵션: - 소스: - 병합 가능 여부 확인 중... - 충돌 없이 병합할 수 있습니다 - 병합 테스트 중 알 수 없는 오류가 발생했습니다 - 병합 시 충돌이 발생합니다 - 내 변경 먼저, 상대 변경 나중 - 상대 변경 먼저, 내 변경 나중 - 둘 다 사용 - 모든 충돌 해결됨 - 남은 충돌 {0}개 - 내 변경 - 다음 충돌 - 이전 충돌 - 결과 - 저장 후 스테이징 - 상대 변경 - 병합 충돌 - 저장하지 않은 변경사항을 버리시겠습니까? - 내 변경 사용 - 상대 변경 사용 - 실행 취소 - 병합 (다중) - 모든 변경 사항 커밋 - 전략: - 대상: - 서브모듈 이동 - 이동 위치: - 서브모듈: - 저장소 노드 이동 - 상위 노드 선택: - 이름: - 아니요 - Git이 구성되지 않았습니다. [환경설정]으로 이동하여 먼저 구성하세요. - 열기 - 시스템 기본 편집기 - 데이터 저장 디렉터리 열기 - 파일 열기 - 병합 도구에서 열기 - 로컬 저장소 열기 - 북마크: - 그룹: - 폴더: - 선택 사항. - 새 탭 만들기 - 탭 닫기 - 다른 탭 닫기 - 오른쪽 탭 닫기 - 저장소 경로 복사 - 편집 - 작업 공간으로 이동 - 새로 고침 - 저장소 - 붙여넣기 - {0}일 전 - 1시간 전 - {0}시간 전 - 방금 전 - 지난 달 - 작년 - {0}분 전 - {0}개월 전 - {0}년 전 - 어제 - 환경설정 - AI - 추가 프롬프트(`-`로 요구 사항 나열) - API 키 - 모델 - 사용 가능한 모델 ID 자동 가져오기 - 이름 - 입력된 값은 환경변수(ENV)에서 API 키를 불러올 이름입니다 - 서버 - 모양 - 기본 글꼴 - 에디터 탭 너비 - 글꼴 크기 - 기본 - 에디터 - 고정폭 글꼴 - 테마 - 테마 재정의 - 스크롤바 자동 숨기기 사용 - 제목 표시줄에서 고정 탭 너비 사용 - 네이티브 윈도우 프레임 사용 - DIFF/MERGE 도구 - 비교 인수 - 사용 가능한 변수: $LOCAL, $REMOTE - 병합 인수 - 사용 가능한 변수: $BASE, $LOCAL, $REMOTE, $MERGED - 설치 경로 - diff/merge 도구 경로 입력 - 도구 - 일반 - 시작 시 업데이트 확인 - 날짜 형식 - 변경 사항 트리에서 폴더 압축 활성화 - 언어 - 히스토리 커밋 수 - 기본으로 `로컬 변경 사항` 페이지 표시 - 커밋 세부 정보에서 기본으로 `변경 사항` 탭 표시 - 커밋 그래프에 상대 시간 표시 - 커밋 그래프에 태그 표시 - 제목 가이드 길이 - 24시간 형식 - 커밋 그래프에서 축약 브랜치 이름 사용 - 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 & 병합) - 병합 대신 리베이스 사용 - 푸시 - 서브모듈이 푸시되었는지 확인 - 강제 푸시 - 로컬 브랜치: - 신규 - pre-push 훅 건너뛰기 - 원격: - 리비전: - 리비전을 원격에 푸시 - 변경 사항을 원격에 푸시 - 원격 브랜치: - 추적 브랜치로 설정 - 모든 태그 푸시 - 태그를 원격에 푸시 - 모든 원격에 푸시 - 원격: - 태그: - 새 브랜치로 푸시 - 새 원격 브랜치 이름을 입력하세요: - 종료 - 현재 브랜치 리베이스 - 로컬 변경 사항 스태시 & 재적용 - pre-rebase 훅 건너뛰기 - 기준: - 리베이스 가능 여부 확인 중... - 충돌 없이 리베이스할 수 있습니다 - 리베이스 테스트 중 알 수 없는 오류가 발생했습니다 - 리베이스 시 충돌이 발생합니다 - 원격 추가 - 원격 편집 - 이름: - 원격 이름 - 저장소 URL: - 원격 git 저장소 URL - URL 복사 - 사용자 지정 작업 - 삭제... - 편집... - 자동 Fetch 사용 - Fetch - 브라우저에서 열기 - 정리 - 워크트리 제거 확인 - `--force` 옵션 활성화 - 대상: - 브랜치 이름 변경 - 새 이름: - 이 브랜치의 고유한 이름 - 브랜치: - 중단 - 원격에서 변경 사항 자동 Fetch 중... - 정렬 - 커밋 날짜 순 - 이름 순 - 정리 (GC & Prune) - 이 저장소에 대해 `git gc` 명령을 실행합니다. - 모두 지우기 - 지우기 - 이 저장소 설정 - 계속 - 사용자 지정 작업 - 사용자 지정 작업 없음 - 모든 변경 사항 폐기 - 파일 탐색기에서 열기 - 브랜치/태그/서브모듈 검색 - 그래프에 표시 여부 - 설정 안 함 - 커밋 그래프에서 숨기기 - 커밋 그래프에서 필터링 - 레이아웃 - 수평 - 수직 - 커밋 순서 - 커밋 날짜 - 위상 정렬 - 로컬 브랜치 - HEAD로 이동 - 브랜치 생성 - 알림 지우기 - 폴더로 열기 - {0}에서 열기 - 외부 도구에서 열기 - 원격 - 원격 추가 - 해결 - 커밋 검색 - 작성자 - 내용 - 메시지 - 경로 - SHA - 현재 브랜치 - 장식된(Decorated) 커밋만 - 첫 번째 부모만 - 플래그 표시 - 유실된(Lost) 커밋 표시 - 서브모듈을 트리로 표시 - 태그를 트리로 표시 - 건너뛰기 - 통계 - 서브모듈 - 서브모듈 추가 - 서브모듈 업데이트 - 태그 - 새 태그 - 생성 날짜 순 - 이름 순 - 정렬 - 터미널에서 열기 - 로그 보기 - 브라우저에서 '{0}' 방문 - 워크트리 - 워크트리 추가 - 정리 - Git 저장소 URL - 현재 브랜치를 리비전으로 리셋 - 리셋 모드: - 이동 대상: - 현재 브랜치: - 브랜치 리셋 (체크아웃 없음) - 이동 대상: - 브랜치: - 파일 탐색기에서 보기 - 커밋 되돌리기 - 커밋: - 되돌린 변경 사항 커밋 - 실행 중. 잠시만 기다려주세요... - 저장 - 다른 이름으로 저장... - 패치가 성공적으로 저장되었습니다! - 저장소 스캔 - 루트 디렉터리: - 다른 사용자 정의 디렉터리 스캔 - 업데이트 확인... - 이 소프트웨어의 새 버전을 사용할 수 있습니다: - 현재 버전: - 업데이트 확인 실패! - 다운로드 - 이 버전 건너뛰기 - 새 버전 릴리스 날짜: - 소프트웨어 업데이트 - 현재 사용 가능한 업데이트가 없습니다. - 서브모듈 브랜치 설정 - 서브모듈: - 현재: - 변경: - 선택 사항. 비어 있으면 기본값으로 설정됩니다. - 추적 브랜치 설정 - 브랜치: - 업스트림 설정 해제 - 업스트림: - SHA 복사 - 이동 - SSH 개인 키: - 개인 SSH 키 저장 경로 - 시작 - 스태시 - 추적하지 않는 파일 포함 - 메시지: - 선택 사항. 이 스태시의 메시지 - 모드: - 스테이징된 변경 사항만 - 선택한 파일의 스테이징된 변경 사항과 스테이징되지 않은 변경 사항이 모두 스태시됩니다!!! - 로컬 변경 사항 스태시 - 적용 - 변경 사항 적용 - 새 브랜치 체크아웃 - 메시지 복사 - 삭제 - 패치로 저장... - 스태시 삭제 - 삭제: - 스태시 - 변경 사항 - 스태시 - 통계 - 개요 - 이번 달 - 이번 주 - 작성자: - 커밋: - 서브모듈 - 서브모듈 추가 - 브랜치 - 브랜치 - 상대 경로 - 초기화 해제 - 중첩된 서브모듈 Fetch - 히스토리 - 이동 - 저장소 열기 - 상대 경로: - 이 모듈을 저장할 상대 폴더입니다. - 삭제 - 브랜치 설정 - URL 변경 - 상태 - 수정됨 - 초기화 안 됨 - 리비전 변경됨 - 병합되지 않음 - 업데이트 - URL - 서브모듈 변경 상세 - 상세 열기 - 확인 - 태그 생성자 - 시간 - 태그 2개 비교 - 다음과 비교... - HEAD와 비교 - 메시지 - 이름 - 태그 생성자 - 태그 이름 복사 - 사용자 지정 작업 - ${0}$ 삭제... - 선택한 {0}개의 태그 삭제... - ${0}$ 푸시... - 서브모듈 업데이트 - 모든 서브모듈 - 필요시 초기화 - 서브모듈: - 서브모듈의 원격 추적 브랜치로 업데이트 - URL: - 로그 - 모두 지우기 - 복사 - 삭제 - 경고 - 시작 페이지 - 그룹 생성 - 하위 그룹 생성 - 저장소 복제 - 삭제 - 폴더 끌어다 놓기 지원. 사용자 정의 그룹화 지원. - 편집 - 다른 그룹으로 이동 - 모든 저장소 열기 - 저장소 열기 - 터미널 열기 - 기본 복제 디렉터리의 저장소 다시 스캔 - 저장소 검색... - 로컬 변경 사항 - Git 무시 - 모든 *{0} 파일 무시 - 같은 폴더의 *{0} 파일 무시 - 이 폴더의 추적하지 않는 파일 무시 - 이 파일만 무시 - 수정 - 이제 이 파일을 스테이징할 수 있습니다. - 히스토리 지우기 - 모든 커밋 메시지 히스토리를 지우시겠습니까? 이 작업은 되돌릴 수 없습니다. - 커밋 - 커밋 & 푸시 - 템플릿/히스토리 - 클릭 이벤트 트리거 - 커밋 (수정) - 모든 변경 사항 스테이징 후 커밋 - 분리된(detached) HEAD에 커밋을 생성하고 있습니다. 계속하시겠습니까? - {0}개의 파일을 스테이징했지만 {1}개의 파일만 표시됩니다 ({2}개의 파일은 필터링됨). 계속하시겠습니까? - 충돌 감지됨 - 병합 - 외부 도구로 병합 - 모든 충돌을 외부 병합 도구에서 열기 - 파일 충돌 해결됨 - 내 것 사용 - 상대방 것 사용 - 추적하지 않는 파일 포함 - 최근 입력한 메시지 없음 - 커밋 템플릿 없음 - 검증 안 함 - 작성자 리셋 - 서명(SignOff) - 스테이징됨 - 언스테이지 - 모두 언스테이지 - 스테이징 안 됨 - 스테이지 - 모두 스테이지 - 변경되지 않음으로 간주된 파일 보기 - 템플릿: ${0}$ - 작업 공간: - 작업 공간 설정... - 워크트리 - 브랜치 - 경로 복사 - HEAD - 잠금 - 열기 - 경로 - 제거 - 잠금 해제 - 예 - diff --git a/src/Resources/Locales/pt_BR.axaml b/src/Resources/Locales/pt_BR.axaml deleted file mode 100644 index 0e1a405bcd..0000000000 --- a/src/Resources/Locales/pt_BR.axaml +++ /dev/null @@ -1,644 +0,0 @@ - - - - - - Sobre - Sobre o SourceGit - Data de Lançamento - Notas de Lançamento - Cliente Git GUI Livre e de Código Aberto - Adicionar Arquivo(s) ao Ignore - Padrão: - Salvar arquivo: - Adicionar Worktree - Localização: - Caminho para este worktree. Caminho relativo é suportado. - Nome do Branch: - Opcional. O padrão é o nome da pasta de destino. - Rastrear Branch: - Rastreando branch remoto - O que Checar: - Criar Novo Branch - Branch Existente - Assietente IA - Modelo - Gerar novamente - Utilizar IA para gerar mensagem de commit - Esconder SourceGit - Mostrar Todos - Selecione o arquivo patch para aplicar - Ignorar mudanças de espaço em branco - Aplicar Patch - Espaço em Branco: - Aplicar Stash - Apagar depois de aplicar - Restabelecer as alterações do índice - Stash: - Arquivar... - Salvar Arquivo Como: - Selecione o caminho do arquivo de arquivo - Revisão: - Arquivar - SourceGit Askpass - Entre com a senha - ARQUIVOS CONSIDERADOS SEM ALTERAÇÕES - NENHUM ARQUIVO CONSIDERADO SEM ALTERAÇÕES - Carregar imagem... - Atualizar - Bisect - Abortar - Inválido - Válido - Pular - Bisect. Marcar o commit atual como válido ou inválido e checar outro commit. - Bisect. O HEAD atual é válido ou inválido? - Blame - Ignorar espaços em branco - BLAME NESSE ARQUIVO NÃO É SUPORTADO!!! - Checkout ${0}$... - Comparar ambos os branches selecionados - Comparar com... - Comparar com HEAD - Copiar Nome do Branch - Criar PR... - Criar PR para o upstream ${0}$... - Ação personalizada - Excluir ${0}$... - Excluir {0} branches selecionados - Editar descri ção para %{0}%... - Fast-Forward para ${0}$ - Buscar ${0}$ em ${1}$... - Git Flow - Finalizar ${0}$ - Mesclar ${0}$ em ${1}$... - Mesclar os {0} branches no branch atual - Puxar ${0}$ - Puxar ${0}$ para ${1}$... - Subir ${0}$ - Rebase ${0}$ em ${1}$... - Renomear ${0}$... - Restaurar ${0}$ para ${1}$... - Mudar para ${0}$ (worktree) - Definir Branch de Rastreamento... - {0} commit(s) à frente - Inválido - REMOTO - ESTADO - CANCELAR - Resetar para Revisão Pai - Resetar para Esta Revisão - Gerar mensagem de commit - ALTERAR MODO DE EXIBIÇÃO - Exibir como Lista de Arquivos e Diretórios - Exibir como Lista de Caminhos - Exibir como Árvore de Sistema de Arquivos - Checkout Branch - Alterações Locais: - Branch: - Cherry-Pick - Adicionar origem à mensagem de commit - Commit(s): - Commitar todas as alterações - Mainline: - Geralmente você não pode fazer cherry-pick de um merge commit porque você não sabe qual lado do merge deve ser considerado na mainline. Esta opção permite ao cherry-pick reaplicar a mudança relativa ao parent especificado. - Limpar Stashes - Você está tentando limpar todas as stashes. Tem certeza que deseja continuar? - Clonar Repositório Remoto - Parâmetros Extras: - Argumentos adicionais para clonar o repositório. Opcional. - Nome Local: - Nome do repositório. Opcional. - Pasta Pai: - URL do Repositório: - FECHAR - Editor - Checar Commit - Cherry-Pick este commit - Cherry-Pick ... - Comparar com HEAD - Comparar com Worktree - SHA - Ação customizada - Reverter Commit - Salvar como Patch... - ALTERAÇÕES - Buscar Alterações... - ARQUIVOS - Arquivo LFS - Submódulo - INFORMAÇÃO - AUTOR - COMMITTER - Verificar referências que contenham este commit - COMMIT EXISTE EM - Mostra apenas as primeiras 100 alterações. Veja todas as alterações na aba ALTERAÇÕES. - MENSAGEM - PAIS - REFERÊNCIAS - SHA - Abrir no navegador - Comparação - Configurar Repositório - TEMPLATE DE COMMIT - Conteúdo do Template: - Nome do Template: - AÇÃO CUSTOMIZADA - Argumentos: - Caminho do executável: - Nome: - Escopo: - Commit - Repositório - Endereço de email - Endereço de email - GIT - Buscar remotos automaticamente - Minuto(s) - Remoto padrão - RASTREADOR DE PROBLEMAS - Adicionar Regra de Exemplo do Azure DevOps - Adicionar Regra de Exemplo do GitHub - Adicionar Regra de Exemplo do GitLab - Adicionar regra de exemplo de Merge Request do GitLab - Adicionar Regra de Exemplo do Jira - Nova Regra - Expressão Regex de Issue: - Nome da Regra: - URL de Resultado: - Por favor, use $1, $2 para acessar os valores de grupos do regex. - IA - Serviço desejado: - Se o 'Serviço desejado' for definido, SourceGit usará ele neste Repositório. Senão, caso haja mais de um serviço disponível, será exibido um menu para seleção. - Proxy HTTP - Proxy HTTP usado por este repositório - Nome de Usuário - Nome de usuário para este repositório - Workspaces - Cor - Nome - Restaurar abas ao inicializar - Assistente de Conventional Commit - Breaking Change: - Ticket encerrado: - Detalhes: - Escopo: - Breve resumo: - Tipo de mudança: - Copiar - Copiar todo o texto - Copiar Caminho - Criar Branch... - Baseado Em: - Checar o branch criado - Alterações Locais: - Nome do Novo Branch: - Insira o nome do branch. - Criar Branch Local - Criar Tag... - Nova Tag Em: - Assinatura GPG - Mensagem da Tag: - Opcional. - Nome da Tag: - Formato recomendado: v1.0.0-alpha - Enviar para todos os remotos após criação - Criar Nova Tag - Tipo: - anotada - leve - Pressione Ctrl para iniciar diretamente - Recortar - Descartar - Nada - Stash & Reaplicar - Excluir Branch - Branch: - Você está prestes a excluir uma branch remota!!! - Também excluir branch remoto ${0}$ - Excluir Múltiplos Branches - Você está tentando excluir vários branches de uma vez. Certifique-se de verificar antes de agir! - Excluir Remoto - Remoto: - Alvo: - Confirmar Exclusão do Grupo - Confirmar Exclusão do Repositório - Excluir Submódulo - Caminho do Submódulo: - Excluir Tag - Tag: - Excluir dos repositórios remotos - DIFERENÇA BINÁRIA - Ignorar mudanças de espaço em branco - MUDANÇA DE OBJETO LFS - Próxima Diferença - SEM MUDANÇAS OU APENAS MUDANÇAS DE EOL - Diferença Anterior - Salvar como um Patch - Exibir símbolos ocultos - Diferença Lado a Lado - SUBMÓDULO - NOVO - Trocar - Realce de Sintaxe - Quebra de Linha - Abrir na Ferramenta de Mesclagem - Exibir todas as linhas - Diminuir Número de Linhas Visíveis - Aumentar Número de Linhas Visíveis - SELECIONE O ARQUIVO PARA VISUALIZAR AS MUDANÇAS - Descartar Alterações - Todas as alterações locais na cópia de trabalho. - Alterações: - Incluir arquivos ignorados - Um total de {0} alterações será descartado - Você não pode desfazer esta ação!!! - Favorito: - Novo Nome: - Alvo: - Editar Grupo Selecionado - Editar Repositório Selecionado - Buscar - Buscar todos os remotos - Buscar sem tags - Remoto: - Buscar Alterações Remotas - Assumir não alterado - Descartar... - Descartar {0} arquivos... - Salvar Como Patch... - Preparar - Preparar {0} arquivos - Stash... - Stash {0} arquivos... - Desfazer Preparação - Desfazer Preparação de {0} arquivos - Usar Meu (checkout --ours) - Usar Deles (checkout --theirs) - Histórico de Arquivos - MUDANÇA - CONTEUDO - Git-Flow - Branch de Desenvolvimento: - Feature: - Prefixo da Feature: - FLOW - Concluir Feature - FLOW - Concluir Hotfix - FLOW - Concluir Release - Alvo: - Hotfix: - Prefixo do Hotfix: - Inicializar Git-Flow - Manter branch - Branch de Produção: - Release: - Prefixo da Release: - Iniciar Feature... - FLOW - Iniciar Feature - Iniciar Hotfix... - FLOW - Iniciar Hotfix - Digite o nome - Iniciar Release... - FLOW - Iniciar Release - Prefixo da Tag de Versão: - Git LFS - Adicionar Padrão de Rastreamento... - Padrão é nome do arquivo - Padrão Personalizado: - Adicionar Padrão de Rastreamento ao Git LFS - Buscar - Execute `git lfs fetch` para baixar objetos Git LFS. Isso não atualiza a cópia de trabalho. - Buscar Objetos LFS - Instalar hooks do Git LFS - Exibir bloqueios - Sem Arquivos Bloqueados - Bloquear - Exibir apenas meus bloqueios - Bloqueios LFS - Desbloquear - Forçar Desbloqueio - Prune - Execute `git lfs prune` para excluir arquivos LFS antigos do armazenamento local - Puxar - Execute `git lfs pull` para baixar todos os arquivos Git LFS para a referência atual e checkout - Puxar Objetos LFS - Enviar - Envie arquivos grandes enfileirados para o endpoint Git LFS - Enviar Objetos LFS - Remoto: - Rastrear arquivos nomeados '{0}' - Rastrear todos os arquivos *{0} - AUTOR - DATA DO AUTOR - HORA DO COMMIT - GRÁFICO & ASSUNTO - SHA - SELECIONADO {0} COMMITS - Segure 'Ctrl' ou 'Shift' para selecionar múltiplos commits. - Segure ⌘ ou ⇧ para selecionar múltiplos commits. - DICAS: - Referência de Atalhos de Teclado - GLOBAL - Fechar página atual - Ir para a próxima página - Ir para a página anterior - Criar nova página - Abrir diálogo de preferências - REPOSITÓRIO - Commitar mudanças preparadas - Commitar e enviar mudanças preparadas - Preparar todas as mudanças e commitar - Buscar, imediatamente - Puxar, imediatamente - Enviar, imediatamente - Forçar recarregamento deste repositório - Alternar para 'Mudanças' - Alternar para 'Stashes' - Descartar - Preparar - Despreparar - Inicializar Repositório - Caminho: - Cherry-Pick em andamento. - Merge em andamento. - Rebase em andamento. - Revert em andamento. - Rebase Interativo - Guardar & reaplicar alterações locais - Em: - Ramo Alvo: - Copiar link - Abrir no navegador - ERRO - AVISO - Mesclar Ramo - Para: - Opção de Mesclagem: - Mover nó do repositório - Selecionar nó pai para: - Nome: - 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 - Opcional. - Criar Nova Página - Fechar Aba - Fechar Outras Abas - Fechar Abas à Direita - Copiar Caminho do Repositório - Editar - Repositórios - Colar - {0} dias atrás - 1 hora atrás - {0} horas atrás - Agora mesmo - Mês passado - Ano passado - {0} minutos atrás - {0} meses atrás - {0} anos atrás - Ontem - Preferências - INTELIGÊNCIA ARTIFICIAL - Chave da API - Nome - Servidor - APARÊNCIA - Fonte Padrão - Tamanho da Fonte - Padrão - Editor - Fonte Monoespaçada - Tema - Substituições de Tema - Usar largura fixa de aba na barra de título - Usar moldura de janela nativa - FERRAMENTA DE DIFF/MERGE - Caminho de Instalação - Insira o caminho para a ferramenta de diff/merge - Ferramenta - GERAL - Verificar atualizações na inicialização - Idioma - Commits do Histórico - Comprimento do Guia de Assunto - GIT - Habilitar Auto CRLF - Diretório de Clone Padrão - Email do Usuário - Email global do usuário git - Habilita --prune ao buscar - Git (>= 2.25.1) é necessário para este aplicativo - Caminho de Instalação - Nome do Usuário - Nome global do usuário git - Versão do Git - ASSINATURA GPG - Assinatura GPG de commit - Formato GPG - Caminho de Instalação do Programa - Insira o caminho para o programa gpg instalado - Assinatura GPG de tag - Chave de Assinatura do Usuário - Chave de assinatura gpg do usuário - INTEGRAÇÃO - SHELL/TERMINAL - Caminho - Shell/Terminal - Prunar Remoto - Alvo: - Podar Worktrees - Podar informações de worktree em `$GIT_COMMON_DIR/worktrees` - Puxar - Branch Remoto: - Para: - Alterações Locais: - Remoto: - Puxar (Buscar & Mesclar) - Usar rebase em vez de merge - Empurrar - Certifica de que submodules foram enviadas - Forçar push - Branch Local: - Ignorar o hook de pre-push - Remoto: - Empurrar Alterações para o Remoto - Branch Remoto: - Definir como branch de rastreamento - Empurrar todas as tags - Empurrar Tag para o Remoto - Empurrar para todos os remotos - Remoto: - Tag: - Sair - Rebase da Branch Atual - Guardar & reaplicar alterações locais - Em: - Adicionar Remoto - Editar Remoto - Nome: - Nome do remoto - URL do Repositório: - URL do repositório git remoto - Copiar URL - Excluir... - Editar... - Buscar - Abrir no Navegador - Podar - Confirmar Remoção de Worktree - Habilitar Opção `--force` - Alvo: - Renomear Branch - Novo Nome: - Nome único para este branch - Branch: - ABORTAR - Buscando automaticamente mudanças dos remotos... - Limpar (GC & Podar) - Execute o comando `git gc` para este repositório. - Limpar tudo - Configurar este repositório - CONTINUAR - Ações customizada - Nenhuma ação customizada - Descartar todas as alterações - Abrir no Navegador de Arquivos - Pesquisar Branches/Tags/Submódulos - Desfazer - Esconder no gráfico de commit - Incluir no gráfico de commit - Data do Commit - Topologicamente - BRANCHES LOCAIS - Navegar para HEAD - Criar Branch - Abrir em {0} - Abrir em Ferramentas Externas - REMOTOS - ADICIONAR REMOTO - Pesquisar Commit - Autor - Mensagem - SHA - Branch Atual - Exibir Tags como Árvore - Estatísticas - SUBMÓDULOS - ADICIONAR SUBMÓDULO - ATUALIZAR SUBMÓDULO - TAGS - NOVA TAG - Abrir no Terminal - WORKTREES - ADICIONAR WORKTREE - PODAR - URL do Repositório Git - Resetar Branch Atual para Revisão - Modo de Reset: - Mover Para: - Branch Atual: - Revelar no Explorador de Arquivos - Reverter Commit - Commit: - Commitar alterações de reversão - Executando. Por favor, aguarde... - SALVAR - Salvar Como... - Patch salvo com sucesso! - Escanear Repositórios - Diretório Raiz: - Verificar atualizações... - Nova versão deste software disponível: - Falha ao verificar atualizações! - Baixar - Ignorar esta versão - Atualização de Software - Não há atualizações disponíveis no momento. - Copiar SHA - Chave SSH Privada: - Caminho para a chave SSH privada - INICIAR - Stash - Incluir arquivos não rastreados - Mensagem: - Opcional. Informações deste stash - Apenas mudanças em stage - Tanto mudanças em stage e fora de stage dos arquivos selecionados serão enviadas para stash!!! - Guardar Alterações Locais - Aplicar - Descartar - Descartar Stash - Descartar: - Stashes - ALTERAÇÕES - STASHES - Estatísticas - VISÃO GERAL - MÊS - SEMANA - AUTORES: - COMMITS: - SUBMÓDULOS - Adicionar Submódulo - Caminho Relativo - Buscar submódulos aninhados - Abrir Repositório do Submódulo - Caminho Relativo: - Pasta relativa para armazenar este módulo. - Excluir Submódulo - OK - Excluir ${0}$... - Enviar ${0}$... - Atualizar Submódulos - Todos os submódulos - Inicializar conforme necessário - Submódulo: - URL: - Aviso - Página de Boas-vindas - Criar Grupo Raíz - Criar Subgrupo - Clonar Repositório - Excluir - ARRASTAR E SOLTAR PASTAS SUPORTADO. AGRUPAMENTO PERSONALIZADO SUPORTADO. - Editar - Mover para Outro Grupo - Abrir Todos os Repositórios - Abrir Repositório - Abrir Terminal - Reescanear Repositórios no Diretório de Clone Padrão - Buscar Repositórios... - Alterações - Git Ignore - Ignorar todos os arquivos *{0} - Ignorar arquivos *{0} na mesma pasta - Ignorar apenas este arquivo - Corrigir - Você pode stagear este arquivo agora. - COMMIT - COMMITAR E ENVIAR - Modelo/Históricos - Acionar evento de clique - Preparar todas as mudanças e commitar - CONFLITOS DETECTADOS - CONFLITOS DE ARQUIVO RESOLVIDOS - INCLUIR ARQUIVOS NÃO RASTREADOS - SEM MENSAGENS DE ENTRADA RECENTES - SEM MODELOS DE COMMIT - STAGED - UNSTAGE - UNSTAGE TODOS - UNSTAGED - STAGE - STAGE TODOS - VER SUPOR NÃO ALTERADO - Template: ${0}$ - Workspaces: - Configurar workspaces... - WORKTREE - Copiar Caminho - Bloquear - Remover - Desbloquear - diff --git a/src/Resources/Locales/ru_RU.axaml b/src/Resources/Locales/ru_RU.axaml deleted file mode 100644 index 7566fe27f4..0000000000 --- a/src/Resources/Locales/ru_RU.axaml +++ /dev/null @@ -1,1061 +0,0 @@ - - - - - - О программе - О SourceGit - Дата выпуска: {0} - Примечания выпуска - Бесплатный графический клиент Git с исходным кодом - Добавить файл(ы) к игнорируемым - Шаблон: - Файл хранилища: - Добавить рабочий каталог - Расположение: - Путь к рабочему каталогу (поддерживается относительный путь) - Имя ветки: - Имя целевого каталога по умолчанию (необязательно) - Отслеживание ветки: - Отслеживание внешней ветки - Переключиться на: - Создать новую ветку - Ветку из списка - Помощник OpenAI - Модель - ПЕРЕСОЗДАТЬ - Использовать OpenAI для создания сообщения о ревизии - Использовать - Скрыть SourceGit - Скрыть остальные - Показать все - Трехстороннее слияние - Выберите файл заплатку для применения - Игнорировать изменения пробелов - Источник: - Файл - Буфер обмена - Применить заплатку - Пробел: - Отложить - Удалить после применения - Восстановить изменения индекса - Отложенный: - Архивировать... - Сохранить архив в: - Выберите путь к архивному файлу - Ревизия: - Архив - Спросить разрешения SourceGit - Введите парольную фразу: - НЕОТСЛЕЖИВАЕМЫЕ ФАЙЛЫ - СПИСОК ПУСТ - Загрузить картинку... - Обновить - Раздвоить - О - Плохая - Хорошая - Пропустить - Раздвоение. Пожалуйста, переключитесь на другой, затем отметьте его как хороший или плохой. - Раздвоение. Отметить текущую ревизию как плохую или переключиться на другую, а затем отметить её как плохую. - Раздвоение. Отметить текущую ревизию хорошей или плохой и переключиться на другой. - Раздвоение. Текущая ГОЛОВА (HEAD) хорошая или плохая? - Расследование - Расследование на предыдущей редакции - Игнорировать изменения пробелов - РАССЛЕДОВАНИЕ В ЭТОМ ФАЙЛЕ НЕ ПОДДЕРЖИВАЕТСЯ!!! - Переключиться на ${0}$... - Сравнить две выбранные ветки - Сравнить с ... - Сравнить с ГОЛОВОЙ - Сравнить с ${0}$ - Копировать имя ветки - Создать PR... - Создать PR для основной ветки ${0}$... - Изменить действие - Удалить ${0}$... - Удалить выбранные {0} ветки - Править описание для ${0}$... - Перемотать вперёд к ${0}$ - Извлечь ${0}$ в ${1}$... - Git-процесс - Завершение ${0}$ - Интерактивное перемещение ${0}$ в ${1}$ - Влить ${0}$ в ${1}$... - Влить {0} выделенных веток в текущую - Загрузить ${0}$ - Загрузить ${0}$ в ${1}$... - Выложить ${0}$ - Переместить ${0}$ на ${1}$... - Переименовать ${0}$... - Сбросить ${0}$ к ${1}$... - Переключить на ${0}$ (рабочий каталог) - Отслеживать ветку... - {0} ревизий вперёд - {0} ревизий вперёд, {1} ревизий назад - {0} ревизий назад - Неверно - УДАЛЁННЫЙ - СОСТОЯНИЕ - ОТСЛЕЖИВАНИЕ - URL-АДРЕС - РАБОЧИЙ КАТАЛОГ - ОТМЕНА - Сбросить родительскую ревизию - Сбросить эту ревизию - Произвести сообщение о ревизии - Слить (встроенный) - Слить (внешний) - Сбросить файл(ы) в ${0}$ - ИЗМЕНИТЬ РЕЖИМ ОТОБРАЖЕНИЯ - Показывать в виде списка файлов и каталогов - Показывать в виде списка путей - Показывать в виде дерева файловой системы - Изменить URL-адрес подмодуля - Подмодуль: - URL-адрес: - Переключить ветку - Локальные изменения: - Ветка: - Ваша текущая ГОЛОВА содержит ревизию(и), не связанные ни с к какими ветками или метками! Вы хотите продолжить? - Подмодулям требуется обновление:{0}Обновить их? - Переключиться и перемотать - Перемотать к: - Переключить ветку из отложенного - Новая ветка: - Отложенный: - Переключить ревизию или метку - Цель: - Предупреждение: После этого ГОЛОВА будет отсоединена - Частичный выбор - Добавить источник для ревизии сообщения - Ревизия(и): - Ревизия всех изменений. - Основной: - Обычно вы не можете выделить слияние, потому что не знаете, какую сторону слияния следует считать основной. Эта опция позволяет отобразить изменения относительно указанного родительского элемента. - Очистить отложенные - Вы пытаетесь очистить все отложенные. Вы уверены, что хотите продолжить? - Клонировать внешний репозиторий - Параметры: - Аргументы git clone (необязательно) - Закладка: - Группа: - Локальное имя: - Имя репозитория (необязательно) - Родительский каталог: - Создать и обновить подмодули - Адрес репозитория: - ЗАКРЫТЬ - Редактор - Ветки - Ветки и метки - Пользовательские действия репозитория - Ревизия файлов - Переключиться на эту ревизию - Применить эту ревизию (cherry-pick) - Применить несколько ревизий ... - Сравнить c ГОЛОВОЙ (HEAD) - Сравнить с рабочим каталогом - Автор - Автор (время) - Сообщение - Ревизор - Ревизор (время) - SHA - Субъект - Пользовательское действие - Интерактивное перемещение - Бросить... - Редактировать... - Исправить в родительском... - Интерактивное перемещение ${0}$ в ${1}$ - Изменить комментарий... - Втиснуть в родительский... - Влить ... - Выложить ${0}$ в ${1}$ - Переместить ${0}$ в ${1}$ - Сбросить ${0}$ к ${1}$ - Отменить ревизию - Сохранить как заплатки... - ИЗМЕНЕНИЯ - изменённый(х) файл(ов) - Найти изменения.... - Свернуть подробности - ФАЙЛЫ - Файл LFS - Поиск файлов... - Подмодуль - ИНФОРМАЦИЯ - АВТОР - РЕВИЗОР (ИСПОЛНИТЕЛЬ) - Найти все ветки с этой ревизией - ВЕТКИ С ЭТОЙ РЕВИЗИЕЙ - Копировать адрес почты - Копировать имя - Копировать имя и адрес почты - Отображаются только первые 100 изменений. Смотрите все изменения на вкладке ИЗМЕНЕНИЯ. - Ключ: - СООБЩЕНИЕ - РОДИТЕЛИ - ССЫЛКИ - SHA - Подписант: - Открыть в браузере - СТБ - Введите сообщение ревизии. Пожалуйста, используйте пустые строки для разделения субъекта и описания! - СУБЪЕКТ - Сравнить - ИЗМЕНЕНИЯ - РЕВИЗИИ - РЕВИЗИИ ТОЛЬКО СЛЕВА - РЕВИЗИИ ТОЛЬКО СПРАВА - Подсказка: Если другая сторона является ГОЛОВОЙ (используя контекстное меню), вы можете использовать частично выбранные ревизии (cherry-pick). - Настройка репозитория - ШАБЛОН РЕВИЗИИ - Встроенные параметры: - - ${branch_name} Имя текущей локальной ветки - ${files_num} Количество изменённых файлов - ${files} Пути изменённых файлов - ${files:N} Пути изменённых файлов, не более N - ${pure_files} То же, что и ${files}, но только имена файлов - ${pure_files:N} То же, что и ${files:N}, но только имена файлов - Содержание: - Название: - ПОЛЬЗОВАТЕЛЬСКОЕ ДЕЙСТВИЕ - Аргументы: - Встроенные параметры: - - ${REPO} Путь репозитория - ${REMOTE} Выбранная удалённая ветка - ${BRANCH} Выбранная ветка, без ${REMOTE} удалённых веток - ${BRANCH_FRIENDLY_NAME} Понятное имя выбранной ветки, содержащую ${REMOTE} удалённые ветки - ${SHA} Хеш выбранной ревизии - ${TAG} Выбранная метка - ${FILE} Выбранный файл, относительно корня репозитория - $1, $2 ... Ввод управляющих значений - Исполняемый файл: - Элементы управления вводом: - Редактор - Имя: - Диапазон: - Ветка - Ревизия - Файл - Удалённый - Репозиторий - Метка - Ждать для выполнения выхода - Адрес электронной почты - Адрес электронной почты - GIT - Спрашивать перед автоматическим обновлением подмодулей. - Автозагрузка изменений - Минут(а/ы) - Общепринятые типы ревизии - Внешний репозиторий по умолчанию - Включить (--recursive) при автоматическом обновлении подмодулей - Предпочтительный режим слияния - ОТСЛЕЖИВАНИЕ ПРОБЛЕМ - Добавить пример правила Azure DevOps - Добавить правило Gerrit ревизии идентификатора изменения - Добавить пример правила для тем в Gitea - Добавить пример правила запроса скачивания из Gitea - Добавить пример правила для Git - Добавить пример правила выдачи GitLab - Добавить пример правила запроса на слияние в GitLab - Добавить пример правила Jira - Новое правило - Проблема с регулярным выражением: - Имя правила: - Опубликовать это правило в файле .issuetracker - Адрес результата: - Пожалуйста, используйте $1, $2 для доступа к значениям групп регулярных выражений. - ОТКРЫТЬ ИИ - Предпочтительный сервис: - Если «Предпочтительный сервис» установлен, SourceGit будет использовать только этот репозиторий. В противном случае, если доступно более одной услуги, будет отображено контекстное меню для выбора одной из них. - HTTP-прокси - HTTP-прокси для репозитория - Имя пользователя - Имя пользователя репозитория - Пользовательское редактирование элементами действий - Проверяемое значение: - Если установлено, то данное значение будет использоваться в аргументах командной строки - Описание: - По умолчанию: - Это каталог: - Метка: - Опции: - Используйте разделитель «|» для опций - Строка форматирования: - Не обязательно. Использовать для форматирования выходной строки. Игнорировать пустые входные данные. Пожалуйста, используйте «${VALUE}» для представления входной строки. - Встроенные переменные ${REPO}, ${REMOTE}, ${BRANCH}, ${BRANCH_FRIENDLY_NAME}, ${SHA}, ${FILE}, и ${TAG} останутся здесь доступными - Тип: - Используйте понятное имя: - Рабочие пространства - Цвет - Имя - Восстанавливать вкладки при запуске - ПРОДОЛЖИТЬ - Обнаружена пустая ревизия! Вы хотите продолжить (--allow-empty)? - Сформировать всё и зафиксировать ревизию - Сформировать выбранные и зафиксировать - Обнаружена пустая ревизия! Вы хотите продолжить (--allow-empty) или отложить всё, а затем зафиксировать ревизию? - Требуется перезапуск - Вы должны перезапустить приложение после применения изменений. - Общепринятый помощник по ревизии - Кардинальные изменения: - Закрытая тема: - Детали изменений: - Область: - Короткое описание: - Тип изменения: - Копировать - Копировать весь текст - Копировать как исправление - Копировать полный путь - Копировать путь - Создать ветку... - Основан на: - Переключиться на созданную ветку - Локальные изменения: - Имя новой ветки: - Введите имя ветки. - Создать локальную ветку - Перезаписать существующую ветку - Создать метку... - Новая метка у: - GPG подпись - Сообщение с меткой: - Необязательно. - Имя метки: - Рекомендуемый формат: v1.0.0-alpha - Выложить на все внешние репозитории после создания - Создать новую метку - Вид: - С примечаниями - Простой - Удерживайте Ctrl, чтобы сразу начать - Вырезать - Отклонить - Ничего не делать - Отложить и применить повторно - Удалить подмодуль - Принудительно удалить даже если содержит локальные изменения. - Подмодуль: - Удалить ветку - Ветка: - Принудительно удалить, даже если содержит неслитые ревизии - Вы собираетесь удалить внешнюю ветку!!! - Также удалите внешнюю ветку ${0}$ - Удаление нескольких веток - Вы пытаетесь удалить несколько веток одновременно. Обязательно перепроверьте, прежде чем предпринимать какие-либо действия! - Удалить несколько меток - Удалить их с удалённого - Вы пытаетесь удалить сразу несколько меток. Перепроверьте обязательно перед выполнением! - Удалить внешний репозиторий - Внешний репозиторий: - Путь: - Цель: - Все дочерние элементы будут удалены из списка. - Будет удалён из списка. На диске останется. - Подтвердите удаление группы - Подтвердите удаление репозитория - Удалить подмодуль - Путь подмодуля: - Удалить метку - Метка: - Удалить из внешнего репозитория - СРАВНЕНИЕ БИНАРНИКОВ - ПРОСМОТР НОВОГО СОДЕРЖИМОГО - ФАЙЛ ПУСТ - Первое сравнение - Игнорировать изменения пробелов - СМЕСЬ - СРАВНЕНИЕ - РЯДОМ - СМАХИВАНИЕ - Последнее сравнение - ИЗМЕНЕНИЕ ОБЪЕКТА LFS - НОВЫЙ - Следующее сравнение - НИКАКИХ ИЗМЕНЕНИЙ ИЛИ МЕНЯЕТСЯ ТОЛЬКО EOL - СТАРЫЙ - Предыдущее сравнение - Сохранить как заплатку - Показывать скрытые символы - Сравнение рядом - ПОДМОДУЛЬ - УДАЛЁН - НОВЫЙ - + {0} Незафиксированных изменений - Обмен - Подсветка синтаксиса - Перенос слов в строке - Открыть в инструменте слияния - Показывать все строки - Меньше видимых строк - Больше видимых строк - ВЫБЕРИТЕ ФАЙЛ ДЛЯ ПРОСМОТРА ИЗМЕНЕНИЙ - Каталог историй - Есть локальные изменения - Не соответствует с исходящим потоком - В актуальном состоянии - Отклонить изменения - Все локальные изменения в рабочей копии. - Изменения: - Включить игнорируемые файлы - Включить изменённые/удалённые файлы - Включить неотслеживаемые файлы - {0} изменений будут отменены - Вы не можете отменить это действие!!! - Править описание ветки - Цель: - Закладка: - Новое имя: - Цель: - Редактировать выбранную группу - Редактировать выбранный репозиторий - Цель: - Этот репозиторий - Извлечь - Извлечь все внешние репозитории - Разрешить опцию (--force) - Извлечь без меток - Внешний репозиторий: - Извлечь внешние изменения - ДВОИЧНЫЙ ФАЙЛ - ПРОСМОТР В ШЕСТНАДЦАТЕРИЧНОМ ФОРМАТЕ - Перейти по адресу... - Не отслеживать - Пользовательское действие - Отклонить... - Отклонить файлы ({0})... - Взять версию ${0}$ - Сохранить как файл заплатки... - Сформировать - Сформировать файлы ({0}) - Отложить... - Отложить файлы ({0})... - Расформировать - Расформировать файлы ({0}) - Использовать мой (checkout --ours) - Использовать их (checkout --theirs) - История файлов - ИЗМЕНИТЬ - СОДЕРЖИМОЕ - Изменение режима файла: - Режим удалённого файла: - Каталог - Исполняемый - Новый режим файла: - Обычный - Подмодуль - Символическая ссылка - Неизвестно - Git-процесс - Ветка разработчика: - Свойство: - Свойство префикса: - Завершение ${0}$ - ПРОЦЕСС - Свойства завершения - ПРОЦЕСС - Закончить исправление - ПРОЦЕСС - Завершить выпуск - Цель: - Перенос перед слиянием - Втиснуть при слиянии - Исправление: - Префикс исправлений: - Создать Git-процесс - Держать ветку - Производственная ветка: - Выпуск: - Префикс выпуска: - Начать с: - Свойство запуска... - ПРОЦЕСС - Свойство запуска - Запуск исправлений... - ПРОЦЕСС - Запуск исправлений - Имя: - Ввести имя - Запуск выпуска... - ПРОЦЕСС - Запуск выпуска - Префикс метки версии: - Git LFS (хранилище больших файлов) - Добавить шаблон отслеживания... - Шаблон — это имя файла - Изменить шаблон: - Добавить шаблон отслеживания в LFS Git - Извлечь - Запустить (git lfs fetch), чтобы загрузить объекты LFS Git. При этом рабочая копия не обновляется. - Извлечь объекты LFS - Установить перехват LFS Git - Показывать блокировки - Нет заблокированных файлов - Блокировка - Показывать только мои блокировки - Блокировки LFS - Разблокировать - Снять все мои блокировки - Вы уверены, что хотите снять все свои блокировки? - Принудительно разблокировать - Обрезать - Запустить (git lfs prune), чтобы удалить старые файлы LFS из локального хранилища - Загрузить - Запустить (git lfs pull), чтобы загрузить все файлы LFS Git для текущей ссылки и проверить - Загрузить объекты LFS - Выложить - Отправляйте большие файлы, помещенные в очередь, в конечную точку LFS Git - Выложить объекты LFS - Внешнее хранилище: - Отслеживать файлы с именем «{0}» - Отслеживать все файлы (*{0}) - Выбрать ревизию - АВТОР - ВРЕМЯ АВТОРА - ВРЕМЯ РЕВИЗИИ - ГРАФ И СУБЪЕКТ - SHA - ПОДСВЕТКА В ГРАФЕ - ВСЕ - Только текущая ветка - Текущая ветка и выбранные ревизии - Только выбранные ревизии - Выбранные ревизии (Только первый родитель) - ВЫБРАНО РЕВИЗИЙ: {0} - ПОКАЗЫВАТЬ КОЛОНКИ - Удерживайте Ctrl или Shift, чтобы выбрать несколько ревизий. - Удерживайте ⌘ или ⇧, чтобы выбрать несколько ревизий. - ПОДСКАЗКИ: - Открыть в отдельном окне - Подробности ревизии - Сравнить ревизию - Справка по сочетаниям клавиш - ГЛОБАЛЬНЫЕ - Клонировать репозиторий - Закрыть текущую вкладку - Перейти на следующую вкладку - Перейти на предыдущую вкладку - Создать новую вкладку - Открыть локальный репозиторий - Открыть диалоговое окно настроек - Показать рабочее пространство в выпадающем меню - Переключиться на вкладку - Масштабирование - РЕПОЗИТОРИЙ - Зафиксировать сформированные изменения - Зафиксировать и выложить сформированные изменения - Сформировать все изменения и зафиксировать - Создать новую ветку - Извлечь (fetch), запускается сразу - К дочернему выбранной ревизии - К родительскому выбранной ревизии - Открыть палитру команд - Загрузить (pull), запускается сразу - Выложить (push), запускается сразу - Принудительно перечитать репозиторий - Переключить на «Изменения» - Переключить на «Отложенные» - Отклонить - Сформировать - Расформировать - Создать репозиторий - Вы действительно хотите запустить команду «git init» по этому пути? - Не удалось открыть репозиторий. Причина: - Путь: - Выполняется частичный перенос ревизий (cherry-pick). - Обработка ревизии. - Выполняется слияние. - Выполняется. - Выполняется перенос. - Остановлен на - Выполняется отмена ревизии. - Выполняется отмена - Интерактивное перемещение - Отложить и применить повторно локальные изменения - Обходной зацеп предварительного перемещения - На: - Перетаскивайте для переупорядочивания ревизий - Целевая ветка: - Копировать ссылку - Открыть в браузере - Команды - ОШИБКА - УВЕДОМЛЕНИЕ - Доступна новая версия - Открыть репозитории - Вкладки - Рабочие места - Влить ветку - Изменить сообщение слияния - В: - Опции слияния: - Источник: - Тестировать на слияние... - Слияние может быть выполнено без конфликтов - Неизвестная ошибка при тестировании слияния - Слияние вызовет конфликты - Сначала мои, а потом их - Сначала их, а потом мои - ИСПОЛЬЗОВАТЬ ОБА - Все конфликты разрешены - Осталось конфликтов: {0} - MINE - Следующий конфликт - Предыдущий конфликт - РЕЗУЛЬТАТ - СОХРАНИТЬ И СФОРМИРОВАТЬ - ИХ - Конфликты при слиянии - Отменить несохранённые изменения? - ИСПОЛЬЗОВАТЬ МОИ - ИСПОЛЬЗОВАТЬ ИХ - Отменить - Влить несколько веток - Зафиксировать все изменения - Стратегия: - Цели: - Переместить подмодуль - Переместить в: - Подмодуль: - Переместить репозиторий в другую группу - Выбрать группу для: - Имя: - Нет - Git НЕ был настроен. Пожалуйста, перейдите в [Настройки] и сначала настройте его. - Открыть - Редактор по умолчанию (Системный) - Открыть каталог данных программы - Кеш - Конфигурация - Открыть файл - Открыть в инструменте слияния - Открыть локальный репозиторий - Закладка: - Группа: - Каталог: - Необязательно. - Создать новую вкладку - Закрыть вкладку - Закрыть другие вкладки - Закрыть вкладки справа - Копировать путь репозитория - Редактировать... - Переместить в рабочее пространство - Обновить - Репозитории - Вставить - {0} дней назад - 1 час назад - {0} часов назад - Сейчас - Последний месяц - В прошлом году - {0} минут назад - {0} месяцев назад - {0} лет назад - Вчера - Параметры - ОТКРЫТЬ ИИ - Дополнительная подсказка (Для перечисления ваших требований используйте `-`) - Ключ API - Модель - Автоматическое получение доступных идентификаторов моделей - Имя: - Введённое значение — это имя для загрузки API-ключа из ENV - Уровень обоснованности усилий - Сервер - ВИД - Шрифт по умолчанию - Редактировать ширину вкладки - Размер шрифта - По умолчанию - Редактор - Моноширинный шрифт - Тема - Переопределение темы - Автоматически скрывать прокрутку - Использовать фиксированную ширину табуляции в строке заголовка. - Использовать системное окно - ИНСТРУМЕНТ СРАВНЕНИЙ/СЛИЯНИЯ - Аргументы сравнения - Доступны переменные: $LOCAL, $REMOTE - Слить аргументы - Доступны переменные: $BASE, $LOCAL, $REMOTE, $MERGED - Путь установки - Введите путь для инструмента сравнения/слияния - Инструмент - ОСНОВНЫЕ - Проверить обновления при старте - Формат даты - Включить компактные каталоги в дереве изменений - Язык - Максимальная длина истории - Показывать вкладку «ЛОКАЛЬНЫЕ ИЗМЕНЕНИЯ» по умолчанию - Показывать вкладку «Изменения» в сведении ревизии по умолчанию - Отображение относительного времени на графе ревизии - Показывать метки на графике - Длина темы ревизии - 24-часовой - Использовать компактные имена веток в графе ревизии - Создать Github-подобный аватар по умолчанию - GIT - Включить автозавершение CRLF - Каталог клонирования по умолчанию - Электронная почта пользователя - Общая электронная почта пользователя git - Разрешить (--prune) при скачивании - Разрешить (--ignore-cr-at-eol) в сравнении - Для работы программы требуется версия Git (>= 2.25.1) - Путь установки - Разрешить верификацию HTTP SSL - Использовать git-credential-libsecret вместо git-credential-manager - Имя пользователя - Общее имя пользователя git - Отложить и повторно применить изменения по умолчанию при извлечении или объединении веток - Версия Git - GPG ПОДПИСЬ - GPG подпись ревизии - Формат GPG - Путь установки программы - Введите путь для установленной программы GPG - GPG подпись метки - Ключ подписи пользователя - Ключ GPG подписи пользователя - ВНЕДРЕНИЕ - ОБОЛОЧКА/ТЕРМИНАЛ - Аргументы - Используйте, пожалуйста, точку «.» для индикации рабочего каталога - Путь - Оболочка/Терминал - Удалить внешний репозиторий - Цель: - Удалить рабочий каталог - Информация об обрезке рабочего каталога в «$GIT_COMMON_DIR/worktrees» - Загрузить - Ветка внешнего репозитория: - В: - Локальные изменения: - Внешний репозиторий: - Загрузить (Получить и слить) - Использовать перемещение вместо слияния - Выложить - Убедитесь, что подмодули были вставлены - Принудительно выложить - Локальная ветка: - НОВЫЙ - Обходной зацеп предварительного выкладывания - Внешний репозиторий: - Ревизия: - Выложить ревизию на удалённую - Выложить изменения на внешний репозиторий - Ветка внешнего репозитория: - Отслеживать ветку - Выложить все метки - Выложить метку на внешний репозиторий - Выложить на все внешние репозитории - Внешний репозиторий: - Метка: - Отправить к НОВОЙ ветке - Введите имя для новой удалённой ветки: - Выйти - Перемещение текущей ветки - Отложить и применить повторно локальные изменения - Обходной зацеп предварительного перемещения - На: - Тестировать на перемещение... - Перемещение может быть выполнено без конфликтов - Неизвестная ошибка при тестировании перемещения - Перемещение вызовет конфликты - Добавить внешний репозиторий - Редактировать внешний репозиторий - Имя: - Имя внешнего репозитория - Адрес: - Адрес внешнего репозитория git - Копировать адрес - Пользовательские действия - Удалить... - Редактировать... - Включить автоизвлечение - Извлечь - Открыть в браузере - Удалить - Подтвердить удаление рабочего каталога - Включить опцию (--force) - Цель: - Переименовать ветку - Новое имя: - Уникальное имя для данной ветки - Ветка: - Отказ - Автоматическое извлечение изменений с внешних репозиторий... - Сортировать - По дате ревизора (исполнителя) - По имени - Очистить (Сбор мусора и удаление) - Запустить команду (git gc) для данного репозитория. - Очистить всё - Очистить - Настройка репозитория - ПРОДОЛЖИТЬ - Изменить действия - Не изменять действия - Отклонить все изменения. - Открыть в файловом менеджере - Поиск веток, меток и подмодулей - Видимость на графике - Свернуть фильтры - Не установлен (по умолчанию) - Скрыть в графе ревизии - Развернуть фильтры - Фильтр в графе ревизии - фильтры включены - РАСПОЛОЖЕНИЕ - Горизонтально - Вертикально - ЗАПРОС РЕВИЗИЙ - Дата ревизии - Топологически - ЛОКАЛЬНЫЕ ВЕТКИ - Навигация по ГОЛОВЕ (HEAD) - Создать ветку - ОЧИСТКА УВЕДОМЛЕНИЙ - Открыть как каталог - Открыть в {0} - Открыть в расширенном инструменте - ВНЕШНИЕ РЕПОЗИТОРИИ - ДОБАВИТЬ ВНЕШНИЙ РЕПОЗИТОРИЙ - РАЗРЕШИТЬ - Поиск ревизии - Автор - Содержимое - Сообщение - Путь - SHA - Текущая ветка - Только оформленные ревизии - Показывать только первый родительский - ПОКАЗЫВАТЬ ФЛАГИ - Показывать потерянные ревизии - Показывать подмодули как дерево - Показывать метки как каталог - ПРОПУСТИТЬ - Статистика - ПОДМОДУЛИ - ДОБАВИТЬ ПОДМОДУЛЬ - ОБНОВИТЬ ПОДМОДУЛЬ - МЕТКИ - НОВАЯ МЕТКА - По дате создания - По имени - Сортировать - Открыть в терминале - Просмотр журналов - Посетить '{0}' в браузере - РАБОЧИЕ КАТАЛОГИ - ДОБАВИТЬ РАБОЧИЙ КАТАЛОГ - ОБРЕЗАТЬ - Адрес репозитория Git - Сбросить текущую ветку до версии - Режим сброса: - Переместить в: - Текущая ветка: - Сброс ветки (без переключения) - Переместить в: - Ветка: - Открыть в файловом менеджере - Отменить ревизию - Ревизия: - Отмена ревизии - Запуск. Подождите пожалуйста... - СОХРАНИТЬ - Сохранить как... - Заплатка успешно сохранена! - Обнаружение репозиториев - Корневой каталог: - Сканировать другой пользовательский каталог - Проверить обновления... - Доступна новая версия программного обеспечения: - Текущая версия: - Не удалось проверить наличие обновлений! - Загрузка - Пропустить эту версию - Дата выпуска новой версии: - Обновление ПО - Сейчас нет обновлений. - Установить ветку подмодуля - Подмодуль: - Текущий: - Изменить в: - Не обязательно. Установить по умолчанию, когда пусто. - Отслеживать ветку - Ветка: - Снять основную ветку - Основная ветка: - Копировать SHA - Перейти - Приватный ключ SSH: - Путь хранения частного SSH-ключа - Открыть помощника SSH-ключей - Вы действительно хотите удалить следующие ключи? - Отпечаток - Создать SSH-ключ - Подтвердить парольную фразу: - Почта: - Требуется. - Имя ключа: - Требуется. К примеру: id_github - Парольная фраза: - СОЗДАТЬ - Тип: - Использовать парольную фразу для частного ключа - Путь - Открытый ключ - Помощник SSH-ключа - ЗАПУСК - Отложить - Включить неотслеживаемые файлы - Сообщение: - Имя тайника (необязательно) - Режим: - Только сформированные изменения - Сформированные так и несформированные изменения выбранных файлов будут сохранены!!! - Отложить локальные изменения - Принять - Применить изменения - Переключить на новую ветку - Копировать сообщение - Отбросить - Сохранить как заплатку... - Отбросить тайник - Отбросить: - Отложенные - ИЗМЕНЕНИЯ - ОТЛОЖЕННЫЕ - Статистика - ОБЗОР - МЕСЯЦ - НЕДЕЛЯ - АВТОРЫ: - РЕВИЗИИ: - ПОДМОДУЛИ - Добавить подмодули - ВЕТКА - Ветка - Каталог - Удалить подмодуль - Извлечение вложенных подмодулей - Истории - Переместить в - Открыть подмодуль репозитория - Каталог: - Относительный путь для хранения подмодуля. - Удалить подмодуль - Установить ветку - Изменить URL-адрес - СОСТОЯНИЕ - изменён - не создан - ревизия изменена - не слита - Обновить - URL-адрес - Подробности изменения подмодуля - ОТКРЫТЬ ПОДРОБНОСТИ - ОК - РАЗМЕТЧИК - ВРЕМЯ - Переключить метку... - Сравнить две ветки - Сравнить с ... - Сравнить с ГОЛОВОЙ - Сообщение - Имя - Разметчик - Копировать имя метки - Пользовательское действие - Удалить ${0}$... - Удалить выбранные метки ({0})... - Влить ${0}$ в ${1}$... - Выложить ${0}$... - ПРЕКРАТИТЬ - Обновление подмодулей - Все подмодули - Создавать по необходимости - Подмодуль: - Обновить вложенные подмодули - Обновить до отслеживаемой ветки удалённого подмодуля - Сетевой адрес: - Журналы - ОЧИСТИТЬ ВСЁ - Копировать - Удалить - Предупреждение - Приветствие - Создать группу - Создать подгруппу... - Клонировать репозиторий - Удалить... - ПОДДЕРЖИВАЕТСЯ: ПЕРЕТАСКИВАНИЕ КАТАЛОГОВ, ПОЛЬЗОВАТЕЛЬСКАЯ ГРУППИРОВКА. - Редактировать... - Переместить в другую группу... - Открыть все репозитории - Открыть репозиторий - Открыть терминал - Обнаружить репозитории в каталоге клонирования по умолчанию - Найти репозиторий... - Изменения - Игнорировать Git - Игнорировать все *{0} файлы - Игнорировать *{0} файлы в том же каталоге - Игнорировать неотслеживаемые файлы в этом каталоге - Игнорировать только эти файлы - Игнорировать все неотслеживаемые файлы в одном и том же каталоге - Изменить - Теперь вы можете сформировать этот файл. - Очистить историю - Вы действительно хотите очистить всю историю сообщений ревизии? Данное действие нельзя отменить. - ЗАФИКСИРОВАТЬ - ЗАФИКСИРОВАТЬ и ОТПРАВИТЬ - Шаблон/Истории - Запустить событие щелчка - Зафиксировать (Редактировать) - Сформировать все изменения и зафиксировать - Вы создаёте ревизию на отсоединённой ГОЛОВЕ. Вы хотите продолжить? - Вы сформировали {0} файл(ов), но отображается только {1} файл(ов) ({2} файл(ов) отфильтровано). Вы хотите продолжить? - ОБНАРУЖЕНЫ КОНФЛИКТЫ - СЛИТЬ - Слить с помощью внешнего инструмента - ОТКРЫТЬ ВСЕ КОНФЛИКТЫ ВО ВНЕШНЕМ ИНСТРУМЕНТЕ СЛИЯНИЯ - КОНФЛИКТЫ ФАЙЛОВ РАЗРЕШЕНЫ - ИСПОЛЬЗОВАТЬ МОИ - ИСПОЛЬЗОВАТЬ ИХ - Фильтр изменений... - ВКЛЮЧИТЬ НЕОТСЛЕЖИВАЕМЫЕ ФАЙЛЫ - НЕТ ПОСЛЕДНИХ ВХОДНЫХ СООБЩЕНИЙ - НЕТ ШАБЛОНОВ РЕВИЗИИ - Не проверять - Сбросить автора - Завершение работы - СФОРМИРОВАННЫЕ - РАСФОРМИРОВАТЬ - РАСФОРМИРОВАТЬ ВСЁ - НЕСФОРМИРОВАННЫЕ - СФОРМИРОВАТЬ - СФОРМИРОВАТЬ ВСЁ - ОТКРЫТЬ СПИСОК НЕОТСЛЕЖИВАЕМЫХ ФАЙЛОВ - Шаблон: ${0}$ - РАБОЧЕЕ ПРОСТРАНСТВО: - Настройка рабочего пространства... - РАБОЧИЙ КАТАЛОГ - ВЕТКА - Копировать путь - ГОЛОВА - Заблокировать - Открыть - ПУТЬ - Удалить - Разблокировать - Да - diff --git a/src/Resources/Locales/ta_IN.axaml b/src/Resources/Locales/ta_IN.axaml deleted file mode 100644 index f2f12bcfee..0000000000 --- a/src/Resources/Locales/ta_IN.axaml +++ /dev/null @@ -1,661 +0,0 @@ - - - - - - பற்றி - மூலஅறிவிலி பற்றி - திறந்தமூல & கட்டற்ற அறிவிலி இடைமுக வாடிக்கயாளர் - பணிமரத்தைச் சேர் - இடம்: - இந்த பணிமரத்திற்கான பாதை. தொடர்புடைய பாதை ஆதரிக்கப்படுகிறது. - கிளை பெயர்: - விருப்பத்தேர்வு. இயல்புநிலை இலக்கு கோப்புறை பெயர். - கிளை கண்காணி: - தொலை கிளையைக் கண்காணித்தல் - என்ன சரிபார்க்க வேண்டும்: - புதிய கிளையை உருவாக்கு - ஏற்கனவே உள்ள கிளை - செநு உதவியாளர் - மாதிரி - மறு-உருவாக்கு - உறுதிமொழி செய்தியை உருவாக்க செநுவைப் பயன்படுத்து - .ஒட்டு இடுவதற்கு கோப்பைத் தேர்ந்தெடு - வெள்ளைவெளி மாற்றங்களைப் புறக்கணி - ஒட்டு இடு - வெள்ளைவெளி: - பதுக்கிவைத்ததை இடு - பயன்படுத்திய பின் நீக்கு - குறியீட்டின் மாற்றங்களை மீண்டும் நிறுவு - பதுக்கிவை: - காப்பகம்... - இதற்கு காப்பகத்தை சேமி: - காப்பகக் கோப்பு பாதையைத் தேர்ந்தெடு - திருத்தம்: - காப்பகம் - மூலஅறிவிலி கடவுகேள் - கோப்புகள் மாற்றப்படவில்லை எனக் கருதப்படுகிறது - எந்த கோப்புகளும் மாற்றப்படவில்லை எனக் கருதப்படுகிறது - புதுப்பி - குற்றச்சாட்டு - இந்த கோப்பில் குற்றம் சாட்ட ஆதரிக்கப்படவில்லை!!! - ${0}$ சரிபார்... - கிளை பெயரை நகலெடு - தனிப்பயன் செயல் - ${0}$ ஐ நீக்கு... - தேர்ந்தெடுக்கப்பட்ட {0} கிளைகளை நீக்கு - ${0}$ இதற்கு வேகமாக முன்னோக்கிச் செல் - ${0}$ ஐ ${1}$இல் பெறு... - அறிவிலி ஓட்டம் - முடி ${0}$ - ${0}$ ஐ ${1}$இல் இணை... - தேர்ந்தெடுக்கப்பட்ட {0} கிளைகளை தற்பொதையதில் இணை - இழு ${0}$ - இழு ${0}$ஐ ${1}$-க்குள்... - தள்ளு ${0}$ - மறுதளம் ${0}$ இதன்மேல் ${1}$... - மறுபெயரிடு ${0}$... - கண்காணிப்பு கிளையை அமை... - விடு - பெற்றோர் திருத்தத்திற்கு மீட்டமை - இந்த திருத்தத்திற்கு மீட்டமை - உறுதிமொழி செய்தி உருவாக்கு - காட்சி பயன்முறையை மாற்று - கோப்பு மற்றும் கோப்புறை பட்டியலாக காட்டு - பாதை பட்டியலாகக் காட்டு - கோப்பு முறைமை மரமாகக் காட்டு - கிளை சரிபார் - உள்ளக மாற்றங்கள்: - கிளை: - கனி பறி - உறுதிமொழி செய்திக்கு மூலத்தைச் சேர் - உறுதிமொழி(கள்): - அனைத்து மாற்றங்களையும் உறுதிமொழி - முதன்மைகோடு: - பொதுவாக நீங்கள் ஒரு ஒன்றிணையை கனி-பறிக்க முடியாது, ஏனெனில் இணைப்பின் எந்தப் பக்கத்தை முதன்மையாகக் கருத வேண்டும் என்பது உங்களுக்குத் தெரியாது. இந்த விருப்பம் குறிப்பிட்ட பெற்றோருடன் தொடர்புடைய மாற்றத்தை மீண்டும் இயக்க கனி-பறி அனுமதிக்கிறது. - பதுக்கிவைத்தையும் அழி - நீங்கள் அனைத்து பதுக்கிவைத்தையும் அழிக்க முயற்சிக்கிறீர்கள் தொடர விரும்புகிறீர்களா? - நகலி தொலை களஞ்சியம் - கூடுதல் அளவுருக்கள்: - நகலி களஞ்சியத்திற்கான கூடுதல் வாதங்கள். விருப்பத்தேர்வு. - உள்ளக பெயர்: - களஞ்சியப் பெயர். விருப்பத்தேர்வு. - பெற்றோர் கோப்புறை: - துவக்கு & துணை தொகுதிகளைப் புதுப்பி - களஞ்சிய முகவரி: - மூடு - திருத்தி - உறுதிமொழி சரிபார் - கனி-பறி உறுதிமொழி - கனி-பறி ... - தலையுடன் ஒப்பிடுக - பணிமரத்துடன் ஒப்பிடுக - பாகொவ-வை - தனிப்பயன் செயல் - ஒன்றிணை ... - உறுதிமொழி திரும்பபெறு - ஒட்டாக சேமி... - மாற்றங்கள் - மாற்றங்களைத் தேடு... - கோப்புகள் - பெகோஅ கோப்பு - கோப்புகளைத் தேடு... - துணைத்தொகுதி - தகவல் - ஆசிரியர் - உறுதிமொழியாளர் - இந்த உறுதிமொழிடைக் கொண்ட குறிப்புகளைச் சரிபார் - உறுதிமொழி இதில் உள்ளது - முதல் 100 மாற்றங்களை மட்டும் காட்டுகிறது மாற்றங்கள் தாவலில் அனைத்து மாற்றங்களையும் காண்க. - செய்தி - பெற்றோர்கள் - குறிகள் - பாகொவ - உலாவியில் திற - ஒப்பிடு - களஞ்சியம் உள்ளமை - உறுதிமொழி வளர்புரு - வார்ப்புரு உள்ளடக்கம்: - வார்ப்புரு பெயர்: - தனிப்பயன் செயல் - வாதங்கள்: - இயக்கக்கூடிய கோப்பு: - பெயர்: - நோக்கம்: - கிளை - உறுதிமொழி - களஞ்சியம் - செயல்பாட்டிலிருந்து வெளியேற காத்திரு - மின்னஞ்சல் முகவரி - மின்னஞ்சல் முகவரி - அறிவிலி - தொலைகளை தானாக எடு - நிமையங்கள் - இயல்புநிலை தொலை - சிக்கல் கண்காணி - மாதிரி அசூர் வளர்பணிகள் விதியைச் சேர் - மாதிரி அறிவிலிஈ சிக்கலுக்கான விதியைச் சேர் - மாதிரி அறிவிலிஈ இழு கோரிக்கை விதியைச் சேர் - மாதிரி அறிவிலிமையம் விதியைச் சேர் - மாதிரி அறிவிலிஆய்வு சிக்கலுக்கான விதியைச் சேர் - மாதிரி அறிவிலிஆய்வு இணைப்பு கோரிக்கை விதியைச் சேர் - மாதிரி சீரா விதியைச் சேர் - புதிய விதி - வழக்கவெளி வெளிப்பாடு வெளியீடு: - விதியின் பெயர்: - முடிவு முகவரி: - வழக்கவெளி குழுக்கள் மதிப்புகளை அணுக $1, $2 ஐப் பயன்படுத்து - செநு - விருப்பமான சேவை: - 'விருப்பமான சேவை' அமைக்கப்பட்டிருந்தால், மூலஅறிவிலி இந்த களஞ்சியத்தில் மட்டுமே அதைப் பயன்படுத்தும். இல்லையெனில், ஒன்றுக்கு மேற்பட்ட சேவைகள் இருந்தால், அவற்றில் ஒன்றைத் தேர்ந்தெடுப்பதற்கான சூழல் பட்டயல் காண்பிக்கப்படும். - உஉபநெ பதிலாள் - இந்த களஞ்சியத்தால் பயன்படுத்தப்படும் உஉபநெ பதிலாள் - பயனர் பெயர் - இந்த களஞ்சியத்திற்கான பயனர் பெயர் - பணியிடங்கள் - நிறம் - பெயர் - தாவல்களை மீட்டமை - வழக்கமான உறுதிமொழி உதவியாளர் - உடைக்கும் மாற்றம்: - மூடப்பட்ட வெளியீடு சிக்கல்: - மாற்ற விவரங்கள்: - நோக்கம்: - குறுகிய விளக்கம்: - மாற்ற வகை: - நகல் - அனைத்து உரையையும் நகலெடு - முழு பாதையை நகலெடு - நகல் பாதை - கிளையை உருவாக்கு... - இதன் அடிப்படையில்: - உருவாக்கப்பட்ட கிளையைப் சரிபார் - உள்ளக மாற்றங்கள்: - புதிய கிளை பெயர்: - கிளை பெயரை உள்ளிடவும். - உள்ளக கிளையை உருவாக்கு - குறிச்சொல்லை உருவாக்கு... - இங்கு புதிய குறிச்சொல்: - சீபிசீ கையொப்பமிடுதல் - குறிச்சொல் செய்தி: - விருப்பத்தேர்வு. - குறிச்சொல் பெயர்: - பரிந்துரைக்கப்பட்ட வடிவம்: ப1.0.0-ஆனா - உருவாக்கப்பட்ட பிறகு அனைத்து தொலைகளுக்கும் தள்ளு - புதிய குறிசொல் உருவாக்கு - வகை: - annotated - குறைந்தஎடை - நேரடியாகத் தொடங்க கட்டுப்பாட்டை அழுத்திப் பிடி - வெட்டு - நிராகரி - பதுக்கிவை & மீண்டும் இடு - கிளையை நீக்கு - கிளை: - நீங்கள் ஒரு தொலை கிளையை நீக்கப் போகிறீர்கள்!!! - தொலை ${0}$ கிளையையும் நீக்கு - பல கிளைகளை நீக்கு - நீங்கள் ஒரே நேரத்தில் பல கிளைகளை நீக்க முயற்சிக்கிறீர்கள் நடவடிக்கை எடுப்பதற்கு முன் மீண்டும் சரிபார்! - தொலையை நீக்கு - தொலை: - பாதை: - இலக்கு: - எல்லா குழந்தைகளும் பட்டியலிலிருந்து நீக்கப்படுவார்கள். - இது பட்டியலிலிருந்து மட்டுமே அகற்றும், வட்டிலிருந்து அல்ல! - குழுவை நீக்குவதை உறுதிப்படுத்து - களஞ்சியத்தை நீக்குவதை உறுதிப்படுத்து - துணைத்தொகுதியை நீக்கு - துணைத்தொகுதி பாதை: - குறிச்சொல்லை நீக்கு - குறிசொல்: - தொலை களஞ்சியங்களிலிருந்து நீக்கு - இருமம் வேறுபாடு - முதல் வேறுபாடு - வெள்ளைவெளி மாற்றத்தை புறக்கணி - கடைசி வேறுபாடு - பெகோஅ பொருள் மாற்றம் - அடுத்த வேறுபாடு - மாற்றங்கள் இல்லை அல்லது வரிமுடிவு மாற்றங்கள் மட்டும் - முந்தைய வேறுபாடு - ஒட்டாகச் சேமி - மறைக்கப்பட்ட சின்னங்களைக் காட்டு - பக்கவாட்டு வேறுபாடு - துணைத் தொகுதி - புதிய - இடமாற்று - தொடரியல் சிறப்பம்சமாக்கல் - வரி சொல் மடக்கு - ஒன்றிணை கருவியில் திற - அனைத்து வரிகளையும் காட்டு - தெரியும் வரிகளின் எண்ணிக்கையைக் குறை - தெரியும் வரிகளின் எண்ணிக்கையை அதிகரி - மாற்றங்களைக் காண கோப்பைத் தேர்ந்தெடு - மாற்றங்களை நிராகரி - செயல்படும் நகலில் உள்ள அனைத்து உள்ளக மாற்றங்கள். - மாற்றங்கள்: - புறக்கணிக்கப்பட்ட கோப்புகளைச் சேர் - {0} மாற்றங்கள் நிராகரிக்கப்படும் - இந்தச் செயலை நீங்கள் செயல்தவிர்க்க முடியாது!!! - புத்தகக்குறி: - புதிய பெயர்: - இலக்கு: - தேர்ந்தெடுக்கப்பட்ட குழுவைத் திருத்து - தேர்ந்தெடுக்கப்பட்ட களஞ்சியத்தைத் திருத்து - பெறு - எல்லா தொலைகளையும் பெறு - உள்ளக குறிப்புகளை கட்டாயமாக மீறு - குறிச்சொற்கள் இல்லாமல் பெறு - தொலை: - தொலை மாற்றங்களைப் பெறு - மாறாமல் என கருது - நிராகரி... - {0} கோப்புகளை நிராகரி... - ${0}$ஐப் பயன்படுத்தி தீர் - ஒட்டு என சேமி... - நிலைபடுத்து - {0} fகோப்புகள் நிலைபடுத்து - பதுக்கிவை... - {0} கோப்புகள் பதுக்கிவை... - நிலைநீக்கு - நிலைநீக்கு {0} கோப்புகள் - என்னுடையதைப் பயன்படுத்து (சரிபார் --நமது) - அவர்களுடையதைப் பயன்படுத்து (சரிபார் --அவர்களது) - கோப்பு வரலாறு - மாற்றம் - உள்ளடக்கம் - அறிவிலி-ஓட்டம் - மேம்பாட்டு கிளை: - நற்பொருத்தம்: - நற்பொருத்தம் முன்னொட்டு: - ஓட்டம் - நற்பொருத்தம் முடி - ஓட்டம் - சூடானதிருத்தம் முடி - ஓட்டம் - வெளியீட்டை முடி - இலக்கு: - சூடானதிருத்தம்: - சூடானதிருத்தம் முன்னொட்டு: - அறிவிலி-ஓட்டம் துவக்கு - கிளையை வைத்திரு - உற்பத்தி கிளை: - வெளியீடு: - வெளியீடு முன்னொட்டு: - நற்பொருத்தம் தொடங்கு... - ஓட்டம் - நற்பொருத்தம் தொடங்கு - சூடானதிருத்தம் தொடங்கு... - ஓட்டம் - சூடானதிருத்தம் தொடங்கு - பெயரை உள்ளிடு - வெளியீட்டைத் தொடங்கு... - ஓட்டம் - வெளியீட்டைத் தொடங்கு - பதிப்பு குறிச்சொல் முன்னொட்டு: - அறிவிலி பெகோஅ - அறிவிலி கண்காணி வடிவத்தைச் சேர்... - வடிவம் என்பது கோப்பு பெயர் - தனிப்பயன் வடிவம்: - அறிவிலி பெகோஅ இல் கண்காணி வடிவங்களைச் சேர் - பெறு - அறிவிலி பெகோஅ பொருள்களைப் பதிவிறக்க `அறிவிலி பெகோஅ பெறு` ஐ இயக்கவும் இது செயல்படும் நகலை புதுப்பிக்காது. - அறிவிலி பெகோஅ பொருள்களைப் பெறு - அறிவிலி பெகோஅ கொக்கிகளை நிறுவு - பூட்டுகளைக் காட்டு - பூட்டப்பட்ட கோப்புகள் இல்லை - பூட்டு - எனது பூட்டுகளை மட்டும் காட்டு - பெகோஅ பூட்டுகள் - திற - கட்டாயம் திற - கத்தரி - உள்ளக சேமிப்பகத்திலிருந்து பழைய பெகோஅ கோப்புகளை நீக்க `அறிவிலி பெகோஅ கத்தரி` ஐ இயக்கு - இழு - தற்போதைய குறிக்கு அனைத்து அறிவிலி பெகோஅ கோப்புகளையும் பதிவிறக்கி சரிபார்க்க `அறிவிலி பெகோஅ இழு`ஐ இயக்கு - பெகோஅ பொருள்களை இழு - தள்ளு - வரிசைப்படுத்தப்பட்ட பெரிய கோப்புகளை அறிவிலி பெகோஅ முடிவுபுள்ளிக்கு தள்ளு - பெகோஅ பொருள்கள் தள்ளு - தொலை: - '{0}' என பெயரிடப்பட்ட கோப்புகளைக் கண்காணி - அனைத்து *{0} கோப்புகளையும் கண்காணி - ஆசிரியர் - ஆசிரியர் நேரம் - உறுதிமொழி நேரம் - வரைபடம் & பொருள் - பாகொவ - தேர்ந்தெடுக்கப்பட்ட {0} உறுதிமொழிகள் - பல உறுதிமொழிகளைத் தேர்ந்தெடுக்க 'கட்டுப்பாடு' அல்லது 'உயர்த்து'ஐ அழுத்திப் பிடி. - பல உறுதிமொழிகளைத் தேர்ந்தெடுக்க ⌘ அல்லது ⇧ ஐ அழுத்திப் பிடி. - குறிப்புகள்: - விசைப்பலகை குறுக்குவழிகள் குறிப்பு - உலகளாவிய - புதிய களஞ்சியத்தை நகலி செய் - தற்போதைய பக்கத்தை மூடு - அடுத்த பக்கத்திற்குச் செல் - முந்தைய பக்கத்திற்குச் செல் - புதிய பக்கத்தை உருவாக்கு - விருப்பத்தேர்வுகள் உரையாடலைத் திற - களஞ்சியம் - நிலைபடுத்திய மாற்றங்களை உறுதிமொழி - நிலைபடுத்திய மாற்றங்களை உறுதிமொழி மற்றும் தள்ளு - அனைத்து மாற்றங்களையும் நிலைபடுத்தி உறுதிமொழி - எடு, நேரடியாகத் தொடங்குகிறது - இழு, நேரடியாகத் தொடங்குகிறது - தள்ளு, நேரடியாகத் தொடங்குகிறது - இந்த களஞ்சியத்தை மீண்டும் ஏற்ற கட்டாயப்படுத்து - 'மாற்றங்கள்' என்பதற்கு மாறு - 'பதுகிவைத்தவை' என்பதற்கு மாறு - நிராகரி - நிலைபடுத்து - நிலைநீக்கு - களஞ்சியத்தைத் துவக்கு - பாதை: - கனி-பறி செயல்பாட்டில் உள்ளது. - உறுதிமொழி செயலாக்குதல் - இணைத்தல் செயல்பாட்டில் உள்ளது. - இணைத்தல் - மறுதளம் செயல்பாட்டில் உள்ளது - இல் நிறுத்தப்பட்டது - திரும்ப்பெறும் செயல்பாட்டில் உள்ளது. - திரும்பபெறும் உறுதிமொழி - ஊடாடும் மறுதளம் - உள்ளக மாற்றங்களை பதுக்கிவை & மீண்டும் இடு - மேல்: - இலக்கு கிளை: - இணைப்பை நகலெடு - உலாவியில் திற - பிழை - அறிவிப்பு - கிளையை ஒன்றிணை - Into: - இணைப்பு விருப்பம்: - இதனுள்: - ஒன்றிணை (பல) - அனைத்து மாற்றங்களையும் உறுதிமொழி - சூழ்ச்சிமுறை: - இலக்குகள்: - களஞ்சிய முனையை நகர்த்து - இதற்கான பெற்றோர் முனையைத் தேர்ந்தெடு - பெயர்: - அறிவிலி உள்ளமைக்கப்படவில்லை. [விருப்பத்தேர்வுகள்]க்குச் சென்று முதலில் அதை உள்ளமை. - தரவு சேமிப்பக கோப்பகத்தைத் திற - ஒன்றிணை கருவியில் திற - விருப்பத்தேர்வு. - புதிய பக்கத்தை உருவாக்கு - மூடு தாவல் - பிற தாவல்களை மூடு - வலதுபுறத்தில் உள்ள தாவல்களை மூடு - களஞ்சிய பாதை நகலெடு - திருத்து - களஞ்சியங்கள் - ஒட்டு - {0} நாட்களுக்கு முன்பு - 1 மணி நேரத்திற்கு முன்பு - {0} மணி நேரத்திற்கு முன்பு - சற்றுமுன் - கடந்த திங்கள் - கடந்த ஆண்டு - {0} நிமையங்களுக்கு முன்பு - {0} திங்களுக்கு முன்பு - {0} ஆண்டுகளுக்கு முன்பு - நேற்று - விருப்பத்தேர்வுகள் - செநு - பநிஇ திறவுகோல் - பெயர் - சேவையகம் - தோற்றம் - இயல்புநிலை எழுத்துரு - திருத்தி தாவல் அகலம் - எழுத்துரு அளவு - இயல்புநிலை - திருத்தி - ஒற்றைவெளி எழுத்துரு - கருப்பொருள் - கருப்பொருள் மேலெழுதப்படுகிறது - தலைப்புப்பட்டியில் நிலையான தாவல் அகலத்தைப் பயன்படுத்து - சொந்த சாளர சட்டத்தைப் பயன்படுத்து - வேறு/ஒன்றிணை கருவி - நிறுவல் பாதை - வேறு/ஒன்றிணை கருவிக்கான பாதை உள்ளிடு - கருவி - பொது - தொடக்கத்தில் புதுப்பிப்புகளைச் சரிபார் - தேதி வடிவம் - மொழி - வரலாற்று உறுதிமொழிகள் - உறுதிமொழி வரைபடத்தில் குறிச்சொற்களைக் காட்டு - பொருள் வழிகாட்டி நீளம் - அறிவிலி - தானியங்கி வரிமுடிவை இயக்கு - இயல்புநிலை நகலி அடைவு - பயனர் மின்னஞ்சல் - உலகளாவிய அறிவிலி பயனர் மின்னஞ்சல் - --prune எடுக்கும்போது இயக்கு - அறிவிலி (>= 2.25.1) இந்த பயன்பாட்டிற்கு தேவைப்படுகிறது - நிறுவல் பாதை - உஉபநெ பாகுஅ சரிபார்ப்பை இயக்கு - பயனர் பெயர் - உலகளாவிய அறிவிலி பயனர் பெயர் - அறிவிலி பதிப்பு - சிபிசி கையொப்பமிடுதல் - சிபிசி கையொப்பமிடுதல் உறுதிமொழி - சிபிசி வடிவம் - நிரல் நிறுவல் பாதை - நிறுவப்பட்ட சிபிசி நிரலுக்கான உள்ளீட்டு பாதை - சிபிசி கையொப்பமிடுதலை குறிச்சொலிடு - பயனர் கையொப்பமிடும் திறவுகோல் - பயனரின் கையொப்பமிடும் திறவுகோல் - ஒருங்கிணைப்பு - ஓடு/முனையம் - பாதை - ஓடு/முனையம் - தொலை கத்தரி - இலக்கு: - பணிமரங்கள் கத்தரி - `$GIT_COMMON_DIR/பணிமரங்கள்` இதில் பணிமரம் தகவலை கத்தரி - இழு - தொலை கிளை: - இதனுள்: - உள்ளக மாற்றங்கள்: - தொலை: - இழு (எடுத்து ஒன்றிணை) - ஒன்றிணை என்பதற்குப் பதிலாக மறுதளத்தைப் பயன்படுத்து - தள்ளு - துணைத் தொகுதிகள் தள்ளப்பட்டது என்பதை உறுதிசெய் - கட்டாயமாக தள்ளு - உள்ளக கிளை: - pre-push hook-ஐத் தவிர் - தொலை: - மாற்றங்களை தொலைக்கு தள்ளு - தொலை கிளை: - கண்காணிப்பு கிளையாக அமை - அனைத்து குறிச்சொற்களையும் தள்ளு - தொலைக்கு குறிச்சொல்லை தள்ளு - அனைத்து தொலைகளுக்கும் தள்ளு - தொலை: - குறிச்சொல்: - வெளியேறு - தற்போதைய கிளையை மறுதளம் செய் - உள்ளக மாற்றங்களை பதுக்கிவை & மீண்டும் இடு - மேல்: - தொலையைச் சேர் - தொலையைத் திருத்து - பெயர்: - களஞ்சிய பெயர் - களஞ்சிய முகவரி: - தொலை அறிவிலி களஞ்சிய முகவரி: - முகவரியை நகலெடு - நீக்கு... - திருத்து... - பெறு - உலாவியில் திற - கத்தரித்தல் - பணிமரத்தை அகற்றுவதை உறுதிப்படுத்து - `--கட்டாயம்` விருப்பத்தை இயக்கு - இலக்கு: - கிளையை மறுபெயரிடு - புதிய பெயர்: - இந்தக் கிளைக்கான தனித்துவமான பெயர் - கிளை: - நிறுத்து - தொலைகளிலிருந்து மாற்றங்களைத் தானாகப் பெறுதல்... - சுத்தப்படுத்தல்(சீசி & கத்தரித்தல்) - இந்த களஞ்சியத்திற்கு `அறிவிலி சீசி` கட்டளையை இயக்கு. - அனைத்தையும் அழி - இந்த களஞ்சியத்தை உள்ளமை - தொடர்க - தனிப்பயன் செயல்கள் - தனிப்பயன் செயல்கள் இல்லை - எல்லா மாற்றங்களையும் நிராகரி - கோப்பு உலாவியில் திற - கிளைகள்/குறிச்சொற்கள்/துணைத் தொகுதிகளைத் தேடு - வரைபடத்தில் தெரிவுநிலை - அமைவை நீக்கு - உறுதிமொழி வரைபடத்தில் மறை - உறுதிமொழி வரைபடத்தில் வடிகட்டு - தளவமைப்பு - கிடைமட்டம் - செங்குத்து - உறுதிமொழி வரிசை - உறுதிமொழி தேதி - இடவியல் மூலமாக - உள்ளக கிளைகள் - தலைக்கு செல் - கிளையை உருவாக்கு - அறிவிப்புகளை அழி - {0} இல் திற - வெளிப்புற கருவிகளில் திற - தொலைகள் - தொலையைச் சேர் - உறுதிமொழி தேடு - ஆசிரியர் - செய்தி - பாகொவ - தற்போதைய கிளை - குறிச்சொற்களை மரமாகக் காட்டு - தவிர் - புள்ளிவிவரங்கள் - துணைத் தொகுதிகள் - துணைத் தொகுதியைச் சேர் - துணைத் தொகுதியைப் புதுப்பி - குறிசொற்கள் - புதிய குறிசொல் - படைப்பாளர் தேதியின்படி - பெயர் மூலம் - வரிசைப்படுத்து - முனையத்தில் திற - பணிமரங்கள் - பணிமரத்தைச் சேர் - கத்தரித்தல் - அறிவிலி களஞ்சிய முகவரி - தற்போதைய கிளையை திருத்தத்திற்கு மீட்டமை - மீட்டமை பயன்முறை: - இதற்கு நகர்த்து: - தற்போதைய கிளை: - கோப்பு உலாவியில் வெளிப்படுத்து - பின்வாங்கு உறுதிமொழி - உறுதிமொழி: - பின்வாங்கு மாற்றங்களை உறுதிமொழி - இயங்குகிறது. காத்திருக்கவும்... - சேமி - எனச் சேமி... - ஒட்டு வெற்றிகரமாக சேமிக்கப்பட்டது! - களஞ்சியங்களை வருடு - வேர் அடைவு: - புதுப்பிப்புகளைச் சரிபார்... - இந்த மென்பொருளின் புதிய பதிப்பு கிடைக்கிறது: - புதுப்பிப்புகளைச் சரிபார்க்க முடியவில்லை! - பதிவிறக்கம் - இந்தப் பதிப்பைத் தவிர் - மென்பொருள் புதுப்பி - தற்போது புதுப்பிப்புகள் எதுவும் கிடைக்கவில்லை. - கண்காணிப்பு கிளையை அமை - கிளை: - மேல்ஓடையை நீக்கு - மேல்ஓடை: - SHA ஐ நகலெடு - இதற்கு செல் - பாஓடு தனியார் திறவுகோல்: - தனியார் பாஓடு திறவுகோல் கடை பாதை - தொடங்கு - பதுக்கிவை - கண்காணிக்கப்படாத கோப்புகளைச் சேர் - செய்தி: - விருப்பத்தேர்வு. இந்த பதுக்கலின் பெயர் - நிலைப்படுத்தப்பட்ட மாற்றங்கள் மட்டும் - தேர்ந்தெடுக்கப்பட்ட கோப்புகளின் நிலைப்படுத்தப்பட்ட மற்றும் நிலைப்படுத்தப்படாத மாற்றங்கள் இரண்டும் பதுக்கிவைக்கப்படும்!!! - உள்ளக மாற்றங்களை பதுக்கிவை - இடு - கைவிடு - ஒட்டாகச் சேமி... - பதுக்கிவைத்தவை கைவிடு - கைவிடு: - பதுக்கிவைத்தவைகள் - மாற்றங்கள் - பதுக்கிவைத்தவைகள் - புள்ளிவிவரங்கள் - மேலோட்டப் பார்வை - திங்கள் - வாரம் - ஆசிரியர்கள்: - உறுதிமொழிகள்: - துணைத் தொகுதி - துணைத் தொகுதியைச் சேர் - உறவு பாதை - உள்ளமைக்கப்பட்ட துணைத் தொகுதிகளை எடு - துணைத் தொகுதி களஞ்சியத்தைத் திற - உறவு பாதை: - இந்த தொகுதியை சேமிப்பதற்கான தொடர்புடைய கோப்புறை. - துணை தொகுதியை நீக்கு - சரி - நீக்கு ${0}$... - தள்ளு ${0}$... - துணைத்தொகுதிகளைப் புதுப்பி - அனைத்து துணைத்தொகுதிகள் - தேவைக்கேற்றப துவக்கு - முகவரி: - முன்னறிவிப்பு - வரவேற்பு பக்கம் - குழுவை உருவாக்கு - துணைக் குழுவை உருவாக்கு - நகலி களஞ்சியம் - நீக்கு - கோப்புறையை இழுத்து & விடு ஆதரிக்கப்படுகிறது. தனிப்பயன் குழுவாக்க ஆதரவு. - திருத்து - வேறொரு குழுவிற்கு நகர்த்து - அனைத்து களஞ்சியங்களையும் திற - களஞ்சியத்தைத் திற - முனையத்தைத் திற - இயல்புநிலை நகலி அடைவில் களஞ்சியங்களை மீண்டும் வருடு - களஞ்சியங்களைத் தேடு... - உள்ளக மாற்றங்கள் - அறிவிலி புறக்கணி - எல்லா *{0} கோப்புகளையும் புறக்கணி - ஒரே கோப்புறையில் *{0} கோப்புகளைப் புறக்கணி - இந்த கோப்பை மட்டும் புறக்கணி - பின்னொட்டு - இந்த கோப்பை இப்போது நீங்கள் நிலைப்படுத்தலாம். - உறுதிமொழி - உறுதிமொழி & தள்ளு - வளர்புரு/வரலாறுகள் - சொடுக்கு நிகழ்வைத் தூண்டு - உறுதிமொழி (திருத்து) - அனைத்து மாற்றங்களையும் நிலைப்படுத்தி உறுதிமொழி - நீங்கள் {0} கோப்புகளை நிலைப்படுத்தியுள்ளீர்கள், ஆனால் {1} கோப்புகள் மட்டுமே காட்டப்பட்டுள்ளன ({2} கோப்புகள் வடிகட்டப்பட்டுள்ளன). தொடர விரும்புகிறீர்களா? - மோதல்கள் கண்டறியப்பட்டது - கோப்பு மோதல்கள் தீர்க்கப்பட்டது - கண்காணிக்கப்படாத கோப்புகளைச் சேர் - அண்மைக் கால உள்ளீட்டு செய்திகள் இல்லை - உறுதிமொழி வளர்புருகள் இல்லை - கையெழுத்திடு - நிலைபடுத்தியது - நிலைநீக்கு - அனைத்தும் நிலைநீக்கு - நிலைநீக்கு - நிலைபடுத்து - அனைத்தும் நிலைபடுத்து - மாறாதது எனநினைப்பதை பார் - வளர்புரு: ${0}$ - பணியிடம்: - பணியிடங்களை உள்ளமை... - பணிமரம் - பாதையை நகலெடு - பூட்டு - நீக்கு - திற - diff --git a/src/Resources/Locales/uk_UA.axaml b/src/Resources/Locales/uk_UA.axaml deleted file mode 100644 index a6e5b89ae5..0000000000 --- a/src/Resources/Locales/uk_UA.axaml +++ /dev/null @@ -1,669 +0,0 @@ - - - - - - Про програму - Про SourceGit - Безкоштовний Git GUI клієнт з відкритим кодом - Додати робоче дерево - Розташування: - Шлях для цього робочого дерева. Відносний шлях підтримується. - Назва гілки: - Необов'язково. За замовчуванням — назва кінцевої папки. - Відстежувати гілку: - Відстежувати віддалену гілку - Що перемкнути: - Створити нову гілку - Наявна гілка - AI Асистент - Модель - ПЕРЕГЕНЕРУВАТИ - Використати AI для генерації повідомлення коміту - Виберіть файл .patch для застосування - Ігнорувати зміни пробілів - Застосувати Патч - Пробіли: - Застосувати схованку - Видалити після застосування - Відновити зміни індексу - Схованка: - Архівувати... - Зберегти архів у: - Виберіть шлях до файлу архіву - Ревізія: - Архівувати - SourceGit Askpass - ФАЙЛИ, ЩО ВВАЖАЮТЬСЯ НЕЗМІНЕНИМИ - НЕМАЄ ФАЙЛІВ, ЩО ВВАЖАЮТЬСЯ НЕЗМІНЕНИМИ - Оновити - Автор рядка - ПОШУК АВТОРА РЯДКА ДЛЯ ЦЬОГО ФАЙЛУ НЕ ПІДТРИМУЄТЬСЯ!!! - Перейти на ${0}$... - Копіювати назву гілки - Спеціальна дія - Видалити ${0}$... - Видалити вибрані {0} гілок - Перемотати до ${0}$ - Отримати ${0}$ в ${1}$... - Git Flow - Завершити ${0}$ - Злиття ${0}$ в ${1}$... - Злити вибрані {0} гілок в поточну - Витягти ${0}$ - Витягти ${0}$ в ${1}$... - Надіслати ${0}$ - Перебазувати ${0}$ на ${1}$... - Перейменувати ${0}$... - Встановити відстежувану гілку... - СКАСУВАТИ - Скинути до батьківської ревізії - Скинути до цієї ревізії - Згенерувати повідомлення коміту - ЗМІНИТИ РЕЖИМ ВІДОБРАЖЕННЯ - Показати як список файлів та тек - Показати як список шляхів - Показати як дерево файлової системи - Перейти на гілку - Локальні зміни: - Гілка: - Cherry-pick - Додати джерело до повідомлення коміту - Коміт(и): - Закомітити всі зміни - Батьківський коміт: - Зазвичай неможливо cherry-pick злиття, бо невідомо, яку сторону злиття вважати батьківською (mainline). Ця опція дозволяє відтворити зміни відносно вказаного батьківського коміту. - Очистити схованки - Ви намагаєтеся очистити всі схованки. Ви впевнені? - Клонувати віддалене сховище - Додаткові параметри: - Додаткові аргументи для клонування сховища. Необов'язково. - Локальна назва: - Назва сховища. Необов'язково. - Батьківська тека: - Ініціалізувати та оновити підмодулі - URL сховища: - ЗАКРИТИ - Редактор - Перейти на коміт - Cherry-pick коміт - Cherry-pick ... - Порівняти з HEAD - Порівняти з робочим деревом - SHA - Спеціальна дія - Злити ... - Скасувати коміт - Зберегти як патч... - ЗМІНИ - Пошук змін... - ФАЙЛИ - LFS Файл - Пошук файлів... - Підмодуль - ІНФОРМАЦІЯ - АВТОР - КОМІТЕР - Перевірити посилання, що містять цей коміт - КОМІТ МІСТИТЬСЯ В - Показано лише перші 100 змін. Дивіться всі зміни на вкладці ЗМІНИ. - ПОВІДОМЛЕННЯ - БАТЬКІВСЬКІ - ПОСИЛАННЯ (Refs) - SHA - Відкрити в браузері - Порівняти - Налаштування сховища - ШАБЛОН КОМІТУ - Зміст шаблону: - Назва шаблону: - СПЕЦІАЛЬНА ДІЯ - Аргументи: - Виконуваний файл: - Назва: - Область застосування: - Гілка - Коміт - Репозиторій - Чекати завершення дії - Адреса Email - Адреса електронної пошти - GIT - Автоматично отримувати зміни з віддалених сховищ - хвилин(и) - Віддалене сховище за замовчуванням - Бажаний режим злиття - ТРЕКЕР ЗАВДАНЬ - Додати приклад правила для Azure DevOps - Додати приклад правила для Gitee Issue - Додати приклад правила для Gitee Pull Request - Додати приклад правила для GitHub - Додати приклад правила для GitLab Issue - Додати приклад правила для GitLab Merge Request - Додати приклад правила для Jira - Нове правило - Регулярний вираз для завдання: - Назва правила: - URL результату: - Використовуйте $1, $2 для доступу до значень груп регулярного виразу. - AI - Бажаний сервіс: - Якщо 'Бажаний сервіс' встановлено, SourceGit буде використовувати лише його у цьому сховищі. Інакше, якщо доступно більше одного сервісу, буде показано контекстне меню для вибору. - HTTP Проксі - HTTP проксі, що використовується цим сховищем - Ім'я користувача - Ім'я користувача для цього сховища - Робочі простори - Колір - Відновлювати вкладки при запуску - ПРОДОВЖИТИ - Виявлено порожній коміт! Продовжити (--allow-empty)? - ІНДЕКСУВАТИ ВСЕ ТА ЗАКОМІТИТИ - Виявлено порожній коміт! Продовжити (--allow-empty) чи індексувати все та закомітити? - Допомога Conventional Commit - Зворотньо несумісні зміни: - Закрите завдання: - Детальні зміни: - Область застосування: - Короткий опис: - Тип зміни: - Копіювати - Копіювати весь текст - Копіювати повний шлях - Копіювати шлях - Створити гілку... - На основі: - Перейти на створену гілку - Локальні зміни: - Назва нової гілки: - Введіть назву гілки. - Створити локальну гілку - Створити тег... - Новий тег для: - Підпис GPG - Повідомлення тегу: - Необов'язково. - Назва тегу: - Рекомендований формат: v1.0.0-alpha - Надіслати на всі віддалені сховища після створення - Створити Новий Тег - Тип: - анотований - легкий - Утримуйте Ctrl для запуску без діалогу - Вирізати - Скасувати - Сховати та Застосувати - Видалити гілку - Гілка: - Ви збираєтеся видалити віддалену гілку!!! - Також видалити віддалену гілку ${0}$ - Видалити кілька гілок - Ви намагаєтеся видалити кілька гілок одночасно. Перевірте ще раз перед виконанням! - Видалити віддалене сховище - Віддалене сховище: - Шлях: - Ціль: - Усі дочірні елементи будуть видалені зі списку. - Це видалить сховище лише зі списку, а не з диска! - Підтвердити видалення групи - Підтвердити видалення сховища - Видалити підмодуль - Шлях до підмодуля: - Видалити тег - Тег: - Видалити з віддалених сховищ - РІЗНИЦЯ ДЛЯ БІНАРНИХ ФАЙЛІВ - Перша відмінність - Ігнорувати зміни пробілів - Остання відмінність - ЗМІНА ОБ'ЄКТА LFS - Наступна відмінність - НЕМАЄ ЗМІН АБО ЛИШЕ ЗМІНИ КІНЦЯ РЯДКА - Попередня відмінність - Зберегти як патч - Показати приховані символи - Порівняння пліч-о-пліч - ПІДМОДУЛЬ - НОВИЙ - Поміняти місцями - Підсвітка синтаксису - Перенос слів - Відкрити в інструменті злиття - Показати всі рядки - Зменшити кількість видимих рядків - Збільшити кількість видимих рядків - ОБЕРІТЬ ФАЙЛ ДЛЯ ПЕРЕГЛЯДУ ЗМІН - Скасувати зміни - Усі локальні зміни в робочій копії. - Зміни: - Включити файли, які ігноруються - {0} змін будуть відхилені - Ви не можете скасувати цю дію!!! - Закладка: - Нова назва: - Ціль: - Редагувати вибрану групу - Редагувати вибраний репозиторій - Витягти - Витягти всі віддалені сховища - Примусово перезаписати локальні refs - Витягти без тегів - Віддалений: - Витягти зміни з віддалених репозиторіїв - Вважати незмінними - Скасувати... - Скасувати {0} файлів... - Розв'язати за допомогою ${0}$ - Зберегти як патч... - Стагнути - Стагнути {0} файлів - Схованка... - Схованка {0} файлів... - Скинути стаг - Скинути {0} файлів - Використовувати Mine (checkout --ours) - Використовувати Theirs (checkout --theirs) - Історія файлу - ЗМІНА - ЗМІСТ - Git-Flow - Розробка гілки: - Функція: - Префікс функції: - FLOW - Завершити функцію - FLOW - Завершити гарячу поправку - FLOW - Завершити реліз - Ціль: - Гаряча поправка: - Префікс гарячої поправки: - Ініціалізувати Git-Flow - Залишити гілку - Гілка виробництва: - Реліз: - Префікс релізу: - Почати функцію... - FLOW - Почати функцію - Почати гарячу поправку... - FLOW - Почати гарячу поправку - Введіть назву - Почати реліз... - FLOW - Почати реліз - Тег версії Префікс: - Git LFS - Додати шаблон для відстеження... - Шаблон є ім'ям файлу - Спеціальний шаблон: - Додати шаблон для відстеження до Git LFS - Витягти - Запустіть `git lfs fetch`, щоб завантажити об'єкти Git LFS. Це не оновлює робочу копію. - Витягти об'єкти LFS - Встановити Git LFS hooks - Показати блокування - Немає заблокованих файлів - Заблокувати - Показати лише мої блокування - LFS блокування - Розблокувати - Примусово розблокувати - Принт - Запустіть `git lfs prune`, щоб видалити старі файли з локального сховища - Витягти - Запустіть `git lfs pull`, щоб завантажити всі файли Git LFS для поточної ref & checkout - Витягти об'єкти LFS - Надіслати - Надіслати чернетки великих файлів до кінця Git LFS - Надіслати об'єкти LFS - Віддалений: - Відстежувати файли, названі '{0}' - Відстежувати всі *{0} файли - АВТОР - ЧАС АВТОРА - ЧАС КОМІТУ - ГРАФ ТА ТЕМА - SHA - ВИБРАНО {0} КОМІТІВ - Утримуйте 'Ctrl' або 'Shift' для вибору кількох комітів. - Утримуйте ⌘ або ⇧ для вибору кількох комітів. - ПОРАДИ: - Гарячі клавіші - ГЛОБАЛЬНІ - Клонувати нове сховище - Закрити поточну вкладку - Перейти до наступної вкладки - Перейти до попередньої вкладки - Створити нову вкладку - Відкрити діалог Налаштування - СХОВИЩЕ - Закомітити проіндексовані зміни - Закомітити та надіслати проіндексовані зміни - Індексувати всі зміни та закомітити - Fetch, запускається без діалогу - Pull, запускається без діалогу - Push, запускається без діалогу - Примусово перезавантажити це сховище - Перейти до 'Зміни' - Перейти до 'Схованки' - Скасувати - Індексувати - Видалити з індексу - Ініціалізувати сховище - Шлях: - Cherry-pick в процесі. - Обробка коміту - Злиття в процесі. - Виконується злиття - Перебазування в процесі. - Зупинено на - Скасування в процесі. - Скасування коміту - Інтерактивне перебазування - Сховати та застосувати локальні зміни - На: - Цільова гілка: - Копіювати посилання - Відкрити в браузері - ПОМИЛКА - ПОВІДОМЛЕННЯ - Злиття гілки - В: - Опція злиття: - Джерело: - Злиття (Кілька) - Закомітити всі зміни - Стратегія: - Цілі: - Перемістити вузол сховища - Виберіть батьківський вузол для: - Назва: - Git не налаштовано. Будь ласка, перейдіть до [Налаштування] та налаштуйте його. - Відкрити теку зберігання даних - Відкрити в інструменті злиття - Необов'язково. - Створити нову вкладку - Закрити вкладку - Закрити інші вкладки - Закрити вкладки праворуч - Копіювати шлях до сховища - Редагувати - Сховища - Вставити - {0} днів тому - годину тому - {0} годин тому - Щойно - Минулого місяця - Минулого року - {0} хвилин тому - {0} місяців тому - {0} років тому - Вчора - Налаштування - AI - Ключ API - Назва - Сервер - ВИГЛЯД - Шрифт за замовчуванням - Ширина табуляції в редакторі - Розмір шрифту - За замовчуванням - Редактор - Моноширинний шрифт - Тема - Перевизначення теми - Використовувати фіксовану ширину вкладки в заголовку - Використовувати системну рамку вікна - ІНСТРУМЕНТ DIFF/MERGE - Шлях встановлення - Введіть шлях до інструменту diff/merge - Інструмент - ЗАГАЛЬНІ - Перевіряти оновлення при запуску - Формат дати - Мова - Кількість комітів в історії - Показувати теги в графі комітів - Довжина лінії-орієнтира для теми - GIT - Увімкнути авто-CRLF - Тека клонування за замовчуванням - Email користувача - Глобальний email користувача git - Увімкнути --prune при fetch - Git (>= 2.25.1) є обов'язковим для цієї програми - Шлях встановлення - Увімкнути перевірку HTTP SSL - Ім'я користувача - Глобальне ім'я користувача git - Версія Git - ПІДПИС GPG - Підпис GPG для комітів - Формат GPG - Шлях встановлення програми - Введіть шлях до встановленої програми GPG - Підпис GPG для тегів - Ключ підпису користувача - Ключ підпису GPG користувача - ІНТЕГРАЦІЯ - КОНСОЛЬ/ТЕРМІНАЛ - Шлях - Консоль/Термінал - Prune для віддаленого сховища - Ціль: - Prune для робочих дерев - Видалити застарілу інформацію про робочі дерева в `$GIT_COMMON_DIR/worktrees` - Pull (Витягти) - Віддалена гілка: - В: - Локальні зміни: - Віддалене сховище: - Pull (Fetch & Merge) - Використовувати rebase замість merge - Push (Надіслати) - Переконатися, що підмодулі надіслано - Примусовий push - Локальна гілка: - Обхід pre-push hook - Віддалене сховище: - Надіслати зміни на віддалене сховище - Віддалена гілка: - Встановити як відстежувану гілку - Надіслати всі теги - Надіслати тег на віддалене сховище - Надіслати на всі віддалені сховища - Віддалене сховище: - Тег: - Вийти - Перебазувати поточну гілку - Сховати та застосувати локальні зміни - На: - Додати віддалене сховище - Редагувати віддалене сховище - Назва: - Назва віддаленого сховища - URL сховища: - URL віддаленого git сховища - Копіювати URL - Видалити... - Редагувати... - Fetch (Отримати) - Відкрити у браузері - Prune (Очистити) - Підтвердити видалення робочого дерева - Увімкнути опцію `--force` - Ціль: - Перейменувати гілку - Нова назва: - Унікальна назва для цієї гілки - Гілка: - ПЕРЕРВАТИ - Автоматичне отримання змін з віддалених сховищ... - Очистка (GC & Prune) - Виконати команду `git gc` для цього сховища. - Очистити все - Налаштувати це сховище - ПРОДОВЖИТИ - Спеціальні дії - Немає спеціальних дій - Скасувати всі зміни - Відкрити у файловому менеджері - Пошук гілок/тегів/підмодулів - Видимість у графі - Не встановлено - Приховати в графі комітів - Фільтрувати в графі комітів - РОЗТАШУВАННЯ - Горизонтальне - Вертикальне - ПОРЯДОК КОМІТІВ - За датою коміту - Топологічний - ЛОКАЛЬНІ ГІЛКИ - Перейти до HEAD - Створити гілку - ОЧИСТИТИ СПОВІЩЕННЯ - Відкрити в {0} - Відкрити в зовнішніх інструментах - ВІДДАЛЕНІ СХОВИЩА - ДОДАТИ ВІДДАЛЕНЕ СХОВИЩЕ - Пошук коміту - Автор - Повідомлення - SHA - Поточна гілка - Показати теги як дерево - ПРОПУСТИТИ - Статистика - ПІДМОДУЛІ - ДОДАТИ ПІДМОДУЛЬ - ОНОВИТИ ПІДМОДУЛЬ - ТЕГИ - НОВИЙ ТЕГ - За датою створення - За назвою - Сортувати - Відкрити в терміналі - РОБОЧІ ДЕРЕВА - ДОДАТИ РОБОЧЕ ДЕРЕВО - PRUNE (ОЧИСТИТИ) - URL Git сховища - Скинути поточну гілку до ревізії - Режим скидання: - Перемістити до: - Поточна гілка: - Показати у файловому менеджері - Revert (Скасувати коміт) - Коміт: - Закомітити зміни скасування - Виконується. Будь ласка, зачекайте... - ЗБЕРЕГТИ - Зберегти як... - Патч успішно збережено! - Сканувати сховища - Коренева тека: - Перевірити оновлення... - Доступна нова версія програми: - Не вдалося перевірити оновлення! - Завантажити - Пропустити цю версію - Оновлення програми - У вас встановлена остання версія. - Встановити відстежувану гілку - Гілка: - Скасувати upstream - Upstream: - Копіювати SHA - Перейти до - Приватний ключ SSH: - Шлях до сховища приватного ключа SSH - ПОЧАТИ - Stash (Сховати) - Включити невідстежувані файли - Повідомлення: - Необов'язково. Назва цієї схованки - Лише проіндексовані зміни - Будуть сховані як проіндексовані, так і не проіндексовані зміни вибраних файлів!!! - Сховати локальні зміни - Застосувати - Видалити - Зберегти як патч... - Видалити схованку - Видалити: - СХОВАНКИ - ЗМІНИ - СХОВАНКИ - Статистика - ОГЛЯД - МІСЯЦЬ - ТИЖДЕНЬ - АВТОРІВ: - КОМІТІВ: - ПІДМОДУЛІ - Додати підмодуль - відносний шлях - Отримати вкладені підмодулі - Відкрити сховище підмодуля - Відносний шлях: - Відносна тека для зберігання цього модуля. - Видалити підмодуль - OK - Видалити ${0}$... - Надіслати ${0}$... - Оновити підмодулі - Усі підмодулі - Ініціалізувати за потреби - Підмодуль: - URL: - Попередження - Вітальна сторінка - Створити групу - Створити підгрупу - Клонувати сховище - Видалити - ПІДТРИМУЄТЬСЯ ПЕРЕТЯГУВАННЯ ТЕК. МОЖЛИВЕ ГРУПУВАННЯ. - Редагувати - Перемістити до іншої групи - Відкрити всі сховища - Відкрити сховище - Відкрити термінал - Пересканувати сховища у теці клонування за замовчуванням - Пошук сховищ... - ЛОКАЛЬНІ ЗМІНИ - Git Ignore - Ігнорувати всі файли *{0} - Ігнорувати файли *{0} у цій же теці - Ігнорувати лише цей файл - Amend (Доповнити) - Тепер ви можете проіндексувати цей файл. - КОМІТ - КОМІТ ТА PUSH - Шаблон/Історії - Викликати подію кліку - Коміт (Редагувати) - Індексувати всі зміни та закомітити - Ви проіндексували {0} файл(ів), але відображено лише {1} ({2} файлів відфільтровано). Продовжити? - ВИЯВЛЕНО КОНФЛІКТИ - ВІДКРИТИ ВСІ КОНФЛІКТИ В ЗОВНІШНЬОМУ ІНСТРУМЕНТІ ЗЛИТТЯ - КОНФЛІКТИ ФАЙЛІВ ВИРІШЕНО - ВИКОРИСТАТИ МОЮ ВЕРСІЮ - ВИКОРИСТАТИ ЇХНЮ ВЕРСІЮ - ВКЛЮЧИТИ НЕВІДСТЕЖУВАНІ ФАЙЛИ - НЕМАЄ ОСТАННІХ ПОВІДОМЛЕНЬ - НЕМАЄ ШАБЛОНІВ КОМІТІВ - Підпис - ПРОІНДЕКСОВАНІ - ВИДАЛИТИ З ІНДЕКСУ - ВИДАЛИТИ ВСЕ З ІНДЕКСУ - НЕПРОІНДЕКСОВАНІ - ІНДЕКСУВАТИ - ІНДЕКСУВАТИ ВСЕ - ПЕРЕГЛЯНУТИ ФАЙЛИ, ЩО ВВАЖАЮТЬСЯ НЕЗМІНЕНИМИ - Шаблон: ${0}$ - РОБОЧИЙ ПРОСТІР: - Налаштувати робочі простори... - РОБОЧЕ ДЕРЕВО - Копіювати шлях - Заблокувати - Видалити - Розблокувати - diff --git a/src/Resources/Locales/zh_CN.axaml b/src/Resources/Locales/zh_CN.axaml deleted file mode 100644 index 761cc724a2..0000000000 --- a/src/Resources/Locales/zh_CN.axaml +++ /dev/null @@ -1,1082 +0,0 @@ - - - - - - 关于软件 - 关于本软件 - 发布日期:{0} - 浏览版本更新说明 - 开源免费的Git客户端 - 新增忽略文件 - 匹配模式 : - 保存位置 : - 新增工作树 - 工作树路径 : - 填写该工作树的路径。支持相对路径。 - 分支名 : - 选填。默认使用目标文件夹名称。 - 跟踪分支 - 设置上游跟踪分支 - 检出分支方式 : - 创建新分支 - 已有分支 - AI助手 - 模型 - 重新生成 - 使用AI助手生成提交信息 - 应用 - 隐藏 SourceGit - 隐藏其他 - 显示全部 - 尝试三路合并 - 选择补丁文件 - 忽略空白符号 - 补丁来源 : - 文件 - 剪贴板 - 应用补丁 - 空白符号处理 : - 应用贮藏 - 在成功应用后丢弃该贮藏 - 恢复索引中已暂存的变化 - 已选贮藏 : - 存档(archive)... - 存档文件路径: - 选择存档文件的存放路径 - 指定的提交: - 存档 - SourceGit Askpass - 请输入密码 : - 不跟踪更改的文件 - 没有不跟踪更改的文件 - 加载本地图片 - 重新加载 - 二分定位(bisect) - 终止 - 标记错误 - 标记正确 - 无法判定 - 二分定位进行中。请检出另一个提交并标记其是【正确】还是【错误】 - 二分定位进行中。请标记当前提交为【错误】,或检出另一个提交并标记为【错误】。 - 二分定位进行中。请标记当前的提交是【正确】还是【错误】,然后检出另一个提交。 - 二分定位进行中。当前提交是【正确】还是【错误】? - 逐行追溯(blame) - 对当前版本的前一版本执行逐行追溯操作 - 忽略空白符变化 - 按住 Ctrl (Windows及Linux平台) 或 ⌘ (macOS平台) 键并点击提交哈希将基于所选的提交重新计算逐行追溯 - 选中文件不支持该操作!!! - 检出(checkout) ${0}$... - 比较选中的 2 个分支 - 与其他分支或标签比较... - 与当前 HEAD 比较 - 与 ${0}$ 比较 - 复制分支名 - 创建合并请求... - 为上游分支 ${0}$ 创建合并请求... - 自定义操作 - 删除 ${0}$... - 删除选中的 {0} 个分支... - 编辑 ${0}$ 的描述... - 快进(fast-forward) 到 ${0}$ - 拉取(fetch) ${0}$ 至 ${1}$... - GIT工作流 - 完成 ${0}$... - 交互式变基 ${0}$ 到 ${1}$ - 合并(merge) ${0}$ 到 ${1}$... - 合并(merge) {0} 个分支到当前分支... - 拉回(pull) ${0}$... - 拉回(pull) ${0}$ 内容至 ${1}$... - 推送(push) ${0}$... - 变基(rebase) ${0}$ 至 ${1}$... - 重命名 ${0}$... - 重置(reset) ${0}$ 到 ${1}$... - 切换到 ${0}$ (工作树) - 切换上游分支... - 领先 {0} 个提交 - 领先 {0} 个提交,落后 {1} 个提交 - 落后 {0} 个提交 - 不存在 - 推送地址 - 远程 - 状态 - 上游分支 - 远程地址 - 工作树 - 取 消 - 重置文件到上一版本 - 重置文件到该版本 - 生成提交信息 - 解决冲突(内部工具) - 解决冲突(外部工具) - 重置文件到 ${0}$ - 切换变更显示模式 - 文件名+路径列表模式 - 全路径列表模式 - 文件目录树形结构模式 - 修改子模块远程地址 - 子模块 : - 远程地址 : - 检出(checkout)分支 - 未提交更改 : - 目标分支 : - 您当前游离的HEAD包含未被任何分支及标签引用的提交!是否继续? - 以下子模块需要更新:{0}是否立即更新? - 检出分支并快进 - 上游分支 : - 从所选贮藏检出分支 - 新分支 : - 所选贮藏 : - 检出提交或标签 - 目标 : - 注意:执行该操作后,当前HEAD会变为游离(detached)状态! - 挑选提交 - 提交信息中追加来源信息 - 提交列表 : - 提交变化 - 对比的父提交 : - 通常你不能对一个合并进行挑选,因为你不知道合并的哪一边应该被视为主线。这个选项指定了作为主线的父提交,允许挑选相对于该提交的修改。 - 丢弃贮藏确认 - 您正在丢弃所有的贮藏,一经操作,无法回退,是否继续? - 克隆远程仓库 - 额外参数 : - 其他克隆参数,选填。 - 书签 : - 自定义分组 : - 本地仓库名 : - 本地仓库目录的名字,选填。 - 父级目录 : - 初始化并更新子模块 - 远程仓库 : - 关闭 - 提交信息编辑器 - 分支列表 - 分支 & 标签 - 自定义操作列表 - 文件列表 - 检出此提交... - 挑选(cherry-pick)此提交... - 挑选(cherry-pick)... - 与当前HEAD比较 - 与本地工作树比较 - 作者 - 修改时间 - 提交信息 - 提交者 - 提交时间 - 提交指纹 - 主题 - 自定义操作 - 交互式变基(rebase -i) - 丢弃... - 编辑... - 修复至父提交... - 交互式变基 ${0}$ 到 ${1}$ - 修改提交信息... - 合并至父提交... - 合并(merge)... - 推送(push) ${0}$ 到 ${1}$... - 变基(rebase) ${0}$ 到 ${1}$... - 重置(reset) ${0}$ 到 ${1}$... - 回滚此提交... - 另存为补丁... - 变更对比 - 个文件发生变更 - 查找变更... - 折叠详细面板 - 文件列表 - LFS文件 - 查找文件... - 子模块 - 请选择查看的文件 - 基本信息 - 修改者 - 提交者 - 查看包含此提交的分支/标签 - 本提交已被以下分支/标签包含 - 复制电子邮箱 - 复制用户名 - 复制用户名及邮箱 - 仅显示前100项变更。请前往【变更对比】页面查看全部。 - 签名密钥 : - 提交信息 - 父提交 - 相关引用 - 提交指纹 - 签名者 : - 浏览器中查看 - 列 - 请输入提交的信息。注意:主题与具体描述中间需要空白行分隔! - 主题 - 比较 - 差异文件 - 差异提交 - 左侧独有提交 - 右侧独有提交 - 提示:如果比较的另一方是 HEAD,您可以挑选已选中的提交(使用右键菜单) - 仓库配置 - 提交信息模板 - 内置变量: - - ${branch_name} 当前分支名 - ${files_num} 变更文件数量 - ${files} 变更文件路径列表 - ${files:N} 变更文件路径列表(仅输出指定 N 条) - ${pure_files} 与 ${files} 类似,但仅输出文件名 - ${pure_files:N} 与 ${files:N} 类似,但仅输出文件名 - 模板内容 : - 模板名 : - 自定义操作 - 命令行参数 : - 内置变量: - - ${REPO} 仓库路径 - ${REMOTE} 选中的远程仓库或选中分支所属的远程仓库 - ${BRANCH} 选中的分支,对于远程分支不包含远程名 - ${BRANCH_FRIENDLY_NAME} 选中的分支,对于远程分支包含远程名 - ${SHA} 选中的提交哈希 - ${TAG} 选中的标签 - ${FILE} 选中的文件 - $1, $2 ... 输入控件中填写的值 - 可执行文件路径 : - 输入控件 : - 编辑 - 名称 : - 作用目标 : - 选中的分支 - 选中的提交 - 选中的文件 - 远程仓库 - 仓库 - 选中的标签 - 等待操作执行完成 - 电子邮箱 - 邮箱地址 - GIT配置 - 在自动更新子模块前询问用户 - 启用定时自动拉取远程更新 - 分钟 - 自定义规范化提交类型 - 默认远程 - 自动更新子模块时启用 '--recursive' 选项 - 默认合并方式 - ISSUE追踪 - 新增匹配Azure DevOps规则 - 新增匹配Gerrit Change-Id规则 - 新增匹配Gitee议题规则 - 新增匹配Gitee合并请求规则 - 新增匹配GitHub Issue规则 - 新增匹配GitLab议题规则 - 新增匹配GitLab合并请求规则 - 新增匹配Jira规则 - 新增自定义规则 - 匹配ISSUE的正则表达式 : - 规则名 : - 写入 .issuetracker 文件共享此规则 - 为ISSUE生成的URL链接 : - 可在URL中使用$1,$2等变量填入正则表达式匹配的内容 - AI - 启用特定服务 : - 当【启用特定服务】被设置时,SourceGit将在本仓库中仅使用该服务。否则将弹出可用的AI服务列表供用户选择。 - HTTP代理 - HTTP网络代理 - 用户名 - 应用于本仓库的用户名 - 编辑自定义操作输入控件 - 启用时命令行参数 : - 此CheckBox勾选后,该值会被应用于命令行参数 - 描述 : - 默认值 : - 目标是否是目录 : - 名称 : - 选项列表 : - 选项之间请使用英文 '|' 作为分隔符 - 输出内容格式化字串: - 可选。用于格式化输出结果。当用户输入为空时忽略该操作。请使用`${VALUE}`代替用户输入。 - 内置变量 ${REPO}, ${REMOTE}, ${BRANCH}, ${BRANCH_FRIENDLY_NAME}, ${SHA}, ${FILE} 与 ${TAG} 在这里仍然可用 - 类型 : - 输出结果带有远程名: - 工作区 - 颜色 - 名称 - 启动时恢复打开的仓库 - 确认继续 - 提交未包含变更文件!是否继续(--allow-empty)? - 暂存所有变更并提交 - 仅暂存所选变更并提交 - 提交未包含变更文件!是否继续(--allow-empty)或是自动暂存变更并提交? - 系统提示 - 程序需要重新启动,以便修改生效! - 规范化提交信息生成 - 破坏性更新: - 关闭的ISSUE: - 详细说明: - 模块: - 简述: - 类型: - 复制 - 复制全部文本 - 复制为补丁 - 复制完整路径 - 复制路径 - 新建分支... - 新分支基于 : - 完成后切换到新分支 - 未提交更改 : - 新分支名 : - 填写分支名称。 - 创建本地分支 - 允许重置已存在的分支 - 新建标签... - 标签位于 : - 使用GPG签名 - 标签描述 : - 选填。 - 标签名 : - 推荐格式 :v1.0.0-alpha - 推送到所有远程仓库 - 新建标签 - 类型 : - 附注标签 - 轻量标签 - 按住Ctrl键点击将以默认参数运行 - 剪切 - 仪表板 - 丢弃更改 - 不做处理 - 贮藏并自动恢复 - 取消初始化子模块 - 强制取消,即使包含本地变更 - 子模块 : - 删除分支确认 - 分支名 : - 强制删除,即使包含未合并的提交 - 您正在删除远程上的分支,请务必小心!!! - 同时删除远程分支 ${0}$ - 删除多个分支 - 您正在尝试一次性删除多个分支,请务必仔细检查后再执行操作! - 删除多个标签 - 同时在远程仓库中删除 - 您正在尝试一次性删除多个标签,请务必仔细检查后再执行操作! - 删除远程确认 - 远程名 : - 路径 : - 目标 : - 所有子节点将被同时从列表中移除。 - 仅从列表中移除,不会删除硬盘中的文件! - 删除分组确认 - 删除仓库确认 - 删除子模块确认 - 子模块路径 : - 删除标签确认 - 标签名 : - 同时删除远程仓库中的此标签 - 二进制文件 - 查看新内容 - 空文件 - 首个差异 - 忽略空白符号变化 - 混合对比 - 差异比较 - 分列对比 - 填充对比 - 最后一个差异 - LFS对象变更 - 变更后 - 下一个差异 - 没有变更或仅有换行符差异 - 变更前 - 上一个差异 - 保存为补丁文件 - 显示隐藏符号 - 分列对比 - 子模块 - 删除 - 新增 - + {0} 项未提交变更 - 交换比对双方 - 语法高亮 - 自动换行 - 使用外部合并工具查看 - 显示完整文件 - 减少可见的行数 - 增加可见的行数 - 请选择需要对比的文件 - 目录内容变更历史 - 未提交的本地变更 - 当前分支HEAD与远端不一致 - 已是最新 - 放弃更改确认 - 所有本仓库未提交的修改。 - 变更 : - 包括所有已忽略的文件 - 包括已修改或删除的文件 - 包括未跟踪的文件 - 总计{0}项选中更改 - 本操作不支持回退,请确认后继续!!! - 编辑分支描述 - 目标 : - 书签 : - 名称 : - 目标 : - 编辑分组 - 编辑仓库 - 目标: - 本仓库 - 拉取(fetch) - 拉取所有的远程仓库 - 强制覆盖本地REFs - 不拉取远程标签 - 远程仓库 : - 拉取远程仓库内容 - 二进制文件 - 查看内容 - 定位地址... - 不跟踪此文件的更改 - 自定义操作 - 放弃更改... - 放弃 {0} 个文件的更改... - 应用 ${0}$ - 另存为补丁... - 暂存(add) - 暂存(add){0} 个文件 - 贮藏(stash)... - 贮藏(stash)选中的 {0} 个文件... - 从暂存中移除 - 从暂存中移除 {0} 个文件 - 使用 MINE (checkout --ours) - 使用 THEIRS (checkout --theirs) - 文件历史 - 文件变更 - 文件内容 - 文件类型变更: - 删除: - 目录 - 可执行文件 - 新增文件类型: - 普通文件 - 子模块 - 符号链接 - 未知 - GIT工作流 - 开发分支 : - 特性分支 : - 特性分支名前缀 : - 完成 ${0}$ - 结束特性分支 - 结束修复分支 - 结束版本分支 - 目标分支 : - 合并前执行变基操作 - 压缩变更为单一提交后合并分支 - 修复分支 : - 修复分支名前缀 : - 初始化GIT工作流 - 保留分支 - 发布分支 : - 版本分支 : - 版本分支名前缀 : - 开始于 : - 开始特性分支... - 开始特性分支 - 开始修复分支... - 开始修复分支 - 分支名 : - 输入分支名 - 开始版本分支... - 开始版本分支 - 版本标签前缀 : - Git LFS - 添加追踪文件规则... - 匹配完整文件名 - 规则 : - 添加LFS追踪文件规则 - 拉取LFS对象 (fetch) - 执行`git lfs fetch`命令,下载远程LFS对象,但不会更新工作副本。 - 拉取LFS对象 - 启用Git LFS支持 - 显示LFS对象锁 - 没有锁定的LFS文件 - 锁定 - 仅显示被我锁定的文件 - LFS对象锁状态 - 解锁 - 解锁所有被我锁定的文件 - 确定要解锁所有被您锁定的文件吗? - 强制解锁 - 精简本地LFS对象存储 - 运行`git lfs prune`命令,从本地存储中精简当前版本不需要的LFS对象 - 拉回LFS对象 (pull) - 运行`git lfs pull`命令,下载远程LFS对象并更新工作副本。 - 拉回LFS对象 - 推送 - 将排队的大文件推送到Git LFS远程服务 - 推送LFS对象 - 远程 : - 跟踪名为'{0}'的文件 - 跟踪所有 *{0} 文件 - 选择前往的提交 - 高级设置 - 作者 - 修改时间 - 提交时间 - 路线图与主题 - 提交指纹 - 高亮分支 - 全部 - 仅当前分支 - 当前分支和选中的提交 - 仅选中的提交 - 仅选中的提交 (First-parent 模式) - 已选中 {0} 项提交 - 显示列 - 可以按住 Ctrl 或 Shift 键选择多个提交 - 可以按住 ⌘ 或 ⇧ 键选择多个提交 - 小提示: - 以独立窗口中打开 - 提交详情 - 比较 - 快捷键参考 - 全局快捷键 - 克隆远程仓库 - 关闭当前页面 - 切换到下一个页面 - 切换到上一个页面 - 新建页面 - 打开本地仓库 - 打开偏好设置面板 - 显示工作区下拉菜单 - 切换显示页面 - 缩放内容 - 仓库页面快捷键 - 提交暂存区更改 - 提交暂存区更改并推送 - 自动暂存全部变更并提交 - 新建分支 - 拉取 (fetch) 远程变更 - 前往选中提交的子提交 - 前往选中提交的父提交 - 打开快捷命令面板 - 拉回 (pull) 远程变更 - 推送本地变更到远程 - 重新加载仓库状态 - 展开/折叠提交的详情面板 - 打开/关闭搜索提交面板 - 显示本地更改 - 显示仪表盘 - 显示贮藏列表 - 丢弃 - 暂存 - 移出暂存区 - 初始化新仓库 - 是否在该路径下执行 `git init` 命令(初始化仓库)? - 打开本地仓库失败,原因: - 路径 : - 挑选(Cherry-Pick)操作进行中。 - 正在处理提交 - 合并操作进行中。 - 正在处理 - 变基(Rebase)操作进行中。 - 当前停止于 - 回滚提交操作进行中。 - 正在回滚提交 - 交互式变基 - 自动贮藏并恢复本地变更 - 绕过 pre-rebase 钩子 - 起始提交 : - 拖拽以便对提交重新排序 - 目标分支 : - 复制链接地址 - 在浏览器中访问 - 命令列表 - 出错了 - 系统提示 - 检测到新版本 - 打开其他仓库 - 页面列表 - 工作区列表 - 合并分支 - 编辑合并信息 - 目标分支 : - 合并方式 : - 合并目标 : - 检测合并冲突中... - 合并操作不会产生冲突 - 检测合并冲突时出现未知错误 - 合并操作将存在冲突文件 - 先应用 MINE 后 THEIRS - 先应用 THEIRS 后 MINE - 应用全部 - 所有冲突已解决 - {0} 个冲突未解决 - MINE - 下一个冲突 - 上一个冲突 - 合并结果 - 保存并暂存 - THEIRS - 合并冲突 - 放弃所有更改? - 仅应用 MINE - 仅应用 THEIRS - 撤销更改 - 合并(多目标) - 提交变化 - 合并策略 : - 目标列表 : - 移动子模块 - 移动到 : - 子模块 : - 调整仓库分组 - 请选择目标分组: - 名称 : - 不用了 - GIT尚未配置。请打开【偏好设置】配置GIT路径。 - 打开 - 系统默认编辑器 - 浏览应用数据目录 - 缓存数据 - 偏好设置数据 - 打开文件 - 使用外部对比工具查看 - 打开本地仓库 - 书签 : - 分组 : - 仓库位置 : - 选填。 - 新建空白页 - 关闭标签页 - 关闭其他标签页 - 关闭右侧标签页 - 复制仓库路径 - 编辑 - 移至工作区 - 刷新 - 新标签页 - 粘贴 - {0}天前 - 1小时前 - {0}小时前 - 刚刚 - 上个月 - 一年前 - {0}分钟前 - {0}个月前 - {0}年前 - 昨天 - 偏好设置 - AI - 附加提示词 (请使用 `-` 列出您的要求) - API密钥 - 附加 HTTP 请求头部 (格式:每行一条 Name: Value) - 模型 - 自动拉取可用模型列表 - 配置名称 - 从环境变量(填写环境变量名)中读取API密钥 - 推理努力等级 - 服务地址 - 外观配置 - 缺省字体 - 编辑器制表符宽度 - 字体大小 - 默认 - 代码编辑器 - 等宽字体 - 主题 - 主题自定义 - 允许滚动条自动隐藏 - 主标签使用固定宽度 - 使用系统默认窗体样式 - 对比/合并工具 - 对比命令参数 - 可用参数:$LOCAL, $REMOTE - 合并命令参数 - 可用参数:$BASE, $LOCAL, $REMOTE, $MERGED - 安装路径 - 填写工具可执行文件所在位置 - 工具 - 通用配置 - 启动时检测软件更新 - 日期时间格式 - 在变更列表树中启用紧凑文件夹模式 - 显示语言 - 最大历史提交数 - 默认显示【本地更改】页 - 在提交详情页默认打开【变更对比】标签页 - 在提交路线图中显示相对时间 - 在提交路线图中显示标签 - SUBJECT字数检测 - 24小时制 - 在提交路线图中使用精简分支名 - 生成GitHub风格的默认头像 - GIT配置 - 自动换行转换 - 默认克隆路径 - 邮箱 - 默认GIT用户邮箱 - 拉取更新时启用修剪 - 对比文件时,默认忽略换行符变更 - 本软件要求GIT最低版本为2.25.1 - 安装路径 - 启用HTTP SSL验证 - 使用 git-credential-libsecret 替代 git-credential-manager - 用户名 - 默认GIT用户名 - 迁出或合并分支时,默认贮藏并自动恢复本地更改 - Git 版本 - GPG签名 - 启用提交签名 - 签名格式 - 签名程序位置 - 签名程序所在路径 - 启用标签签名 - 用户签名KEY - 输入签名提交所使用的KEY - 第三方工具集成 - 终端/SHELL - 启动参数 - 请使用 '.' 来指定工作目录 - 安装路径 - 终端/SHELL - 清理远程已删除分支 - 目标 : - 清理工作树 - 清理在`$GIT_COMMON_DIR/worktrees`中的无效工作树信息 - 拉回(pull) - 拉取分支 : - 本地分支 : - 未提交更改 : - 远程 : - 拉回(拉取并合并) - 使用变基方式合并分支 - 推送(push) - 确保子模块变更已推送 - 启用强制推送 - 本地分支 : - 新建 - 绕过 pre-push 钩子 - 远程仓库 : - 修订 : - 推送指定修订到远程仓库 - 推送到远程仓库 - 远程分支 : - 跟踪远程分支 - 同时推送标签 - 推送标签到远程仓库 - 推送到所有远程仓库 - 远程仓库 : - 标签 : - 推送到新的分支 - 输入新的远端分支名 - 退出 - 变基(rebase)操作 - 自动贮藏并恢复本地变更 - 绕过 pre-rebase 钩子 - 目标提交 : - 检测变基冲突中... - 未检测到文件冲突 - 检测变基冲突时出现未知错误 - 检测到冲突文件 - 添加远程仓库 - 编辑远程仓库 - 远程名 : - 唯一远程名 - 重置推送地址为相同地址 - 仓库地址 : - 远程仓库的地址 - 复制远程地址 - 自定义操作 - 删除... - 编辑... - 启用自动拉取 - 拉取(fetch)更新 - 在浏览器中打开 - 清理远程已删除分支 - 设置独立推送地址... - 移除工作树操作确认 - 启用`--force`选项 - 目标工作树 : - 分支重命名 - 新的名称 : - 新的分支名不能与现有分支名相同 - 分支 : - 终止合并 - 自动拉取远端变更中... - 排序方式 - 按提交时间 - 按名称 - 清理本仓库(GC) - 本操作将执行`git gc`命令。 - 清空过滤规则 - 清空 - 配置本仓库 - 下一步 - 自定义操作 - 自定义操作未设置 - 放弃所有更改 - 在文件浏览器中打开 - 快速查找分支/标签/子模块 - 设置在列表中的可见性 - 折叠过滤项列表 - 不指定 - 在提交列表中隐藏 - 展开过滤项列表 - 使用其对提交列表过滤 - 个过滤项已被启用 - 布局方式 - 水平排布 - 竖直排布 - 提交列表排序规则 - 按提交时间 - 按拓扑排序 - 本地分支 - 定位HEAD - 新建分支 - 清空通知列表 - 本仓库(文件夹) - 在 {0} 中打开 - 使用外部工具打开 - 远程列表 - 添加远程 - 解决冲突 - 查找提交 - 作者 - 变更内容 - 提交信息 - 路径 - 提交指纹 - 仅在当前分支中查找 - 搜索方式 - 查找提交 - 仅显示分支、标签所引用的提交 - 仅显示合并提交中的第一个提交 - 显示内容 - 显示丢失引用的提交 - 以树型结构展示 - 以树型结构展示 - 跳过此提交 - 提交统计 - 子模块列表 - 添加子模块 - 更新子模块 - 标签列表 - 新建标签 - 按创建时间 - 按名称 - 排序 - 在终端中打开 - 查看命令日志 - 访问远程仓库 '{0}' - 工作树列表 - 新增工作树 - 清理 - 远程仓库地址 - 重置(reset)当前分支到指定版本 - 重置模式 : - 提交 : - 当前分支 : - 重置所选分支(非当前分支) - 重置点 : - 操作分支 : - 在文件浏览器中查看 - 回滚操作确认 - 目标提交 : - 回滚后提交更改 - 执行操作中,请耐心等待... - 保 存 - 另存为... - 补丁已成功保存! - 扫描仓库 - 根路径 : - 扫描其他自定义路径 - 检测更新... - 检测到软件有版本更新: - 当前版本 : - 获取最新版本信息失败! - 下 载 - 忽略此版本 - 新版发布时间 : - 软件更新 - 当前已是最新版本。 - 设置远程推送地址 - 推送地址 : - 远程 : - 拉取地址 : - 修改子模块追踪分支 - 子模块 : - 当前追踪分支 : - 修改为 : - 可选。当不填写时,恢复默认追踪分支。 - 切换上游分支 - 本地分支 : - 取消追踪 - 上游分支 : - 复制提交指纹 - 跳转到提交 - SSH密钥 : - SSH密钥文件 - 打开SSH密钥工具 - 您确定要删除以下SSH密钥吗? - SHA-256 指纹 - 生成SSH密钥 - 再次确认口令: - 邮箱: - 必填项 - 密钥文件名: - 必填项,如:id_github - 输入口令: - 生 成 - 密钥类型: - 为私钥文件设置口令 - 文件路径 - 公钥内容 - SSH密钥工具 - 开 始 - 贮藏(stash) - 包含未跟踪的文件 - 信息 : - 选填,此贮藏的描述信息 - 模式 : - 仅贮藏暂存区的变更 - 选中文件的所有变更均会被贮藏! - 贮藏本地变更 - 应用(apply) - 应用(apply)选中变更 - 检出新分支 - 复制描述信息 - 删除(drop) - 另存为补丁... - 丢弃贮藏确认 - 丢弃贮藏 : - 贮藏列表 - 查看变更 - 贮藏列表 - 提交统计 - 总览 - 本月 - 本周 - SourceGit 仅会按所选分支最多取出 200000 条提交记录进行分析 - 贡献者人数: - 提交次数: - 子模块 - 添加子模块 - 跟踪分支 - 跟踪分支 - 相对路径 - 取消初始化 - 拉取子孙模块 - 变更历史 - 移动 - 打开仓库 - 相对仓库路径 : - 本地存放的相对路径。 - 删除 - 修改跟踪分支 - 修改远程地址 - 状态 - 未提交修改 - 未初始化 - SHA变更 - 未解决冲突 - 更新 - 仓库 - 子模块变更详情 - 查看变更详情 - 确 定 - 创建者 - 创建时间 - 检出标签... - 比较 2 个标签 - 与其他分支或标签比较... - 与当前 HEAD 比较 - 标签信息 - 标签名 - 创建者 - 复制标签名 - 自定义操作 - 删除 ${0}$... - 删除选中 {0} 个标签... - 合并 ${0}$ 到 ${1}$... - 推送 ${0}$... - 终止运行 - 更新子模块 - 更新所有子模块 - 如未初始化子模块,先初始化 - 子模块 : - 递归更新子孙模块 - 更新到子模块自己的远程踪分支 - 仓库地址 : - 日志列表 - 清空日志 - 复制 - 删除 - 警告 - 起始页 - 新建分组 - 新建子分组 - 克隆远程仓库 - 删除 - 支持拖放目录添加。支持自定义分组。 - 编辑 - 调整分组 - 打开所有包含仓库 - 打开本地仓库 - 打开终端 - 重新扫描默认克隆路径下的仓库 - 快速查找仓库... - 本地更改 - 添加至 .gitignore 忽略列表 - 忽略所有 *{0} 文件 - 忽略同目录下所有 *{0} 文件 - 忽略该目录下的新文件 - 忽略本文件 - 忽略同目录下所有新文件 - 修补 - 现在您已可将其加入暂存区中 - 清空历史提交信息 - 您确定要清空所有的历史提交信息记录吗(执行操作后无法撤回)? - 隐藏左侧栏 - 提交 - 提交并推送 - 历史输入/模板 - 触发点击事件 - 提交(修改原始提交) - 自动暂存所有变更并提交 - 您正在向一个游离的 HEAD 提交变更,是否继续提交? - 当前有 {0} 个文件在暂存区中,但仅显示了 {1} 个文件({2} 个文件被过滤掉了),是否继续提交? - 检测到冲突 - 解决冲突 - 使用外部工具解决冲突 - 打开合并工具解决冲突 - 文件冲突已解决 - 使用 MINE - 使用 THEIRS - 放弃所有更改 - 显示左侧栏 - 查找变更... - 显示未跟踪文件 - 没有提交信息记录 - 没有可应用的提交信息模板 - 跳过GIT钩子 - 重置提交者 - 署名 - 已暂存 - 从暂存区移除选中 - 从暂存区移除所有 - 未暂存 - 暂存选中 - 暂存所有 - 查看忽略变更文件 - 模板:${0}$ - 工作区: - 配置工作区... - 本地工作树 - 連結分支 - 复制工作树路径 - 最新提交 - 锁定工作树 - 打开工作树 - 位置 - 移除工作树 - 解除工作树锁定 - 好的 - diff --git a/src/Resources/Locales/zh_TW.axaml b/src/Resources/Locales/zh_TW.axaml deleted file mode 100644 index 135596f6e9..0000000000 --- a/src/Resources/Locales/zh_TW.axaml +++ /dev/null @@ -1,1079 +0,0 @@ - - - - - - 關於 - 關於 SourceGit - 發行日期: {0} - 版本說明 - 開源免費的 Git 客戶端 - 新增忽略檔案 - 比對模式: - 儲存路徑: - 新增工作樹 - 工作樹路徑: - 填寫該工作樹的路徑。支援相對路徑。 - 分支名稱: - 選填。預設使用目標資料夾名稱。 - 追蹤分支 - 設定遠端追蹤分支 - 簽出分支方式: - 建立新分支 - 已有分支 - AI 助理 - 模型 - 重新產生 - 使用 AI 產生提交訊息 - 套用 - 隱藏 SourceGit - 隱藏其他 - 顯示全部 - 嘗試三向合併 - 選擇修補檔 - 忽略空白符號 - 修補檔來源: - 檔案 - 剪貼簿 - 套用修補檔 - 空白字元處理: - 套用擱置變更 - 套用擱置變更後刪除 - 還原索引中已暫存的變更 (--index) - 已選擇擱置變更: - 封存 (archive)... - 封存檔案路徑: - 選擇封存檔案的儲存路徑 - 指定的提交: - 封存 - SourceGit Askpass - 輸入您的密碼: - 不追蹤變更的檔案 - 沒有不追蹤變更的檔案 - 載入本機圖片... - 重新載入 - 二分搜尋 (bisect) - 中止 - 標記為錯誤 - 標記為良好 - 無法確認 - 二分搜尋進行中。請簽出另一個提交,然後標記該提交為「良好」或「錯誤」。 - 二分搜尋進行中。請標記目前的提交為「錯誤」,或簽出另一個提交並標記為「錯誤」。 - 二分搜尋進行中。請標記目前的提交為「良好」或「錯誤」,然後簽出另一個提交。 - 二分搜尋進行中。目前的提交是「良好」還是「錯誤」? - 逐行溯源 (blame) - 對上一個版本執行逐行溯源 - 忽略空白符號變化 - 按住 Ctrl 鍵 (Windows/Linux) 或 ⌘ 鍵 (macOS) 並點擊提交編號,將依據該次提交重新執行逐行溯源 - 所選擇的檔案不支援該操作! - 簽出 (checkout) ${0}$... - 比較所選的 2 個分支 - 與其他分支或標籤比較... - 與目前 HEAD 比較 - 與 ${0}$ 比較 - 複製分支名稱 - 建立拉取請求... - 為上游分支 ${0}$ 建立拉取請求... - 自訂動作 - 刪除 ${0}$... - 刪除所選的 {0} 個分支... - 編輯 ${0}$ 的描述... - 快轉 (fast-forward) 到 ${0}$ - 提取 (fetch) ${0}$ 到 ${1}$... - Git 工作流 - 完成 ${0}$... - 互動式重定基底 ${0}$ 至 ${1}$ - 合併 ${0}$ 到 ${1}$... - 合併 {0} 個分支到目前分支... - 拉取 (pull) ${0}$... - 拉取 (pull) ${0}$ 內容至 ${1}$... - 推送 (push) ${0}$... - 重定基底 (rebase) ${0}$ 分支至 ${1}$... - 重新命名 ${0}$... - 重設 ${0}$ 至 ${1}$... - 切換到 ${0}$ (工作樹) - 切換上游分支... - 領先 {0} 次提交 - 領先 {0} 次提交,落後 {1} 次提交 - 落後 {0} 次提交 - 無效 - 推送網址 - 遠端 - 狀態 - 上游分支 - 遠端網址 - 工作樹 - 取 消 - 重設檔案到上一版本 - 重設檔案為此版本 - 產生提交訊息 - 解決衝突 (內建工具) - 解決衝突 (外部工具) - 重設檔案到 ${0}$ - 切換變更顯示模式 - 檔案名稱 + 路徑列表模式 - 全路徑列表模式 - 檔案目錄樹狀結構模式 - 修改子模組的遠端網址 - 子模組: - 遠端網址: - 簽出 (checkout) 分支 - 未提交變更: - 目標分支: - 目前的 HEAD 包含未連結至任何分支或標籤的提交! 您是否要繼續? - 以下子模組需要更新: {0},您要立即更新嗎? - 簽出分支並快轉 - 上游分支: - 從所選擱置簽出分支 - 新分支: - 所選擱置: - 簽出提交或標籤 - 目標: - 注意: 執行該操作後,目前 HEAD 會變為分離 (detached) 狀態! - 揀選提交 - 提交資訊中追加來源資訊 - 提交列表: - 提交變更 - 對比的父提交: - 通常您無法揀選 (cherry-pick) 合併提交,因為無法判斷哪個父提交應視為主線。此選項可指定作為主線的父提交。 - 捨棄擱置變更確認 - 您正在捨棄所有的擱置變更,一經操作便無法復原,是否繼續? - 複製 (clone) 遠端存放庫 - 額外參數: - 其他複製參數,選填。 - 書籤: - 群組: - 本機存放庫名稱: - 本機存放庫目錄的名稱,選填。 - 上層目錄: - 初始化並更新子模組 - 遠端存放庫: - 關閉 - 提交訊息編輯器 - 分支列表 - 分支 & 標籤 - 自訂動作 - 檔案列表 - 簽出 (checkout) 此提交... - 揀選 (cherry-pick) 此提交... - 揀選 (cherry-pick)... - 與目前 HEAD 比較 - 與本機工作樹比較 - 作者 - 修改時間 - 提交訊息 - 提交者 - 提交時間 - 提交編號 - 標題 - 自訂動作 - 互動式重定基底 (rebase -i) - 捨棄... - 編輯... - 修正至父提交... - 互動式重定基底 ${0}$ 至 ${1}$ - 編輯提交訊息... - 合併至父提交... - 合併 (merge)... - 推送 (push) ${0}$ 至 ${1}$... - 重定基底 (rebase) ${0}$ 至 ${1}$... - 重設 (reset) ${0}$ 至 ${1}$... - 復原此提交... - 另存為修補檔 (patch)... - 變更對比 - 個檔案已變更 - 搜尋變更... - 收合詳細面板 - 檔案列表 - LFS 檔案 - 搜尋檔案... - 子模組 - 基本資訊 - 作者 - 提交者 - 檢視包含此提交的分支或標籤 - 本提交包含於以下分支或標籤 - 複製電子郵件 - 複製名稱 - 複製名稱及電子郵件 - 僅顯示前 100 項變更。請前往 [變更對比] 頁面以瀏覽所有變更。 - 簽章金鑰: - 提交訊息 - 前次提交 - 相關參照 - 提交編號 - 簽署人: - 在瀏覽器中檢視 - 欄 - 請輸入提交訊息,標題與詳細描述之間請使用單行空白區隔。 - 標題 - 比較 - 差異檔案 - 差異提交 - 左側獨有提交 - 右側獨有提交 - 提示: 如果比較的另一方是 HEAD,您可以揀選 (cherry-pick) 已選擇的提交 (使用滑鼠右鍵) - 存放庫設定 - 提交訊息範本 - 內建參數: - - ${branch_name} 目前分支名稱 - ${files_num} 已變更檔案數 - ${files} 已變更檔案路徑清單 - ${files:N} 已變更檔案路徑清單 (僅列出前 N 個) - ${pure_files} 類似 ${files},不含資料夾的純檔案名稱 - ${pure_files:N} 類似 ${files:N},不含資料夾的純檔案名稱 - 範本內容: - 範本名稱: - 自訂動作 - 指令參數: - 內建參數: - - ${REPO} 存放庫路徑 - ${REMOTE} 所選的遠端存放庫或所選分支的遠端 - ${BRANCH} 所選的分支。遠端分支不包含遠端名稱 - ${BRANCH_FRIENDLY_NAME} 所選的分支。遠端分支會包含遠端名稱 - ${SHA} 所選的提交編號 - ${TAG} 所選的標籤 - ${FILE} 所選的檔案,相對於存放庫根目錄的路徑 - $1, $2 ... 輸入控制項中的值 - 可執行檔案路徑: - 輸入控制項: - 編輯 - 名稱: - 執行範圍: - 選取的分支 - 選取的提交 - 選取的檔案 - 遠端存放庫 - 存放庫 - 選取的標籤 - 等待自訂動作執行結束 - 電子郵件 - 電子郵件地址 - Git 設定 - 在自動更新子模組之前先詢問 - 啟用定時自動提取 (fetch) 遠端更新 - 分鐘 - 自訂約定式提交類型 - 預設遠端存放庫 - 自動更新子模組時啟用「--recursive」選項 - 預設合併模式 - Issue 追蹤 - 新增符合 Azure DevOps 規則 - 新增符合 Gerrit Change-Id 規則 - 新增符合 Gitee 議題規則 - 新增符合 Gitee 合併請求規則 - 新增符合 GitHub Issue 規則 - 新增符合 GitLab 議題規則 - 新增符合 GitLab 合併請求規則 - 新增符合 Jira 規則 - 新增自訂規則 - 符合 Issue 的正規表達式: - 規則名稱: - 寫入 .issuetracker 檔案以共用此規則 - 為 Issue 產生的網址連結: - 可在網址中使用 $1、$2 等變數填入正規表達式相符的內容 - AI - 偏好服務: - 設定 [偏好服務] 後,SourceGit 將於此存放庫中使用該服務,否則會顯示 AI 服務列表供使用者選擇。 - HTTP 代理 - HTTP 網路代理 - 使用者名稱 - 用於本存放庫的使用者名稱 - 編輯自訂動作輸入控制項 - 啟用時的指令參數: - 勾選核取方塊後,此值將用於指令參數中 - 描述: - 預設值: - 目標路徑是否為資料夾: - 名稱: - 選項列表: - 請使用英文「|」符號分隔選項 - 字串格式化: - 選填。用於格式化輸出字串。若輸入為空則會忽略此設定。請使用 `${VALUE}` 來表示輸入字串。 - 內建變數 ${REPO}、${REMOTE}、${BRANCH}、${BRANCH_FRIENDLY_NAME}、${SHA}、${FILE} 及 ${TAG} 在此處仍可使用 - 類型: - 輸出包含遠端的名稱: - 工作區 - 顏色 - 名稱 - 啟動時還原上次開啟的存放庫 - 確認繼續 - 未包含任何檔案變更! 您是否仍要提交 (--allow-empty)? - 暫存全部變更並提交 - 僅暫存所選變更並提交 - 未包含任何檔案變更! 您是否仍要提交 (--allow-empty) 或自動暫存變更並提交? - 系統提示 - 您需要重新啟動此應用程式才能套用變更! - 產生約定式提交訊息 - 破壞性變更: - 關閉的 Issue: - 詳細資訊: - 模組: - 簡述: - 類型: - 複製 - 複製全部內容 - 複製為修補檔 - 複製完整路徑 - 複製路徑 - 新增分支... - 新分支基於: - 完成後切換到新分支 - 未提交變更: - 新分支名稱: - 輸入分支名稱。 - 建立本機分支 - 允許覆寫現有分支 - 新增標籤... - 標籤位於: - 使用 GPG 簽章 - 標籤描述: - 選填。 - 標籤名稱: - 建議格式: v1.0.0-alpha - 推送到所有遠端存放庫 - 新增標籤 - 類型: - 附註標籤 - 輕量標籤 - 按住 Ctrl 鍵將直接以預設參數執行 - 剪下 - 儀表板 - 捨棄變更 - 不做處理 - 擱置變更並自動復原 - 取消初始化子模組 - 強制取消,即使包含本機變更 - 子模組: - 刪除分支確認 - 分支名稱: - 強制刪除,即使包含未合併的提交 - 您正在刪除遠端上的分支,請務必小心! - 同時刪除遠端分支 ${0}$ - 刪除多個分支 - 您正在嘗試一次性刪除多個分支,請務必仔細檢查後再刪除! - 刪除多個標籤 - 同時刪除遠端存放庫中的這些標籤 - 您正在嘗試一次性刪除多個標籤,請務必仔細檢查後再刪除! - 刪除遠端確認 - 遠端名稱: - 路徑: - 目標: - 所有子節點都會從清單中移除。 - 只會從清單中移除,而不會刪除磁碟中的檔案! - 刪除群組確認 - 刪除存放庫確認 - 刪除子模組確認 - 子模組路徑: - 刪除標籤確認 - 標籤名稱: - 同時刪除遠端存放庫中的此標籤 - 二進位檔案 - 查看新內容 - 空檔案 - 第一個差異 - 忽略空白符號變化 - 混合對比 - 差異對比 - 並排對比 - 滑桿對比 - 最後一個差異 - LFS 物件變更 - 變更後 - 下一個差異 - 沒有變更或僅有換行字元差異 - 變更前 - 上一個差異 - 另存為修補檔 (patch) - 顯示隱藏符號 - 並排對比 - 子模組 - 已刪除 - 新增 - + {0} 項未提交變更 - 交換比對雙方 - 語法上色 - 自動換行 - 使用外部合併工具檢視 - 顯示檔案的全部內容 - 減少可見的行數 - 增加可見的行數 - 請選擇需要對比的檔案 - 目錄內容變更歷史 - 未提交的本機變更 - 目前分支 HEAD 與上游不相符 - 已更新至最新 - 捨棄變更 - 所有本機未提交的變更。 - 變更: - 包括所有已忽略的檔案 - 包括已變更或刪除的檔案 - 包含未追蹤檔案 - 將捨棄總計 {0} 項已選取的變更 - 您無法復原此操作,請確認後再繼續! - 編輯分支的描述 - 目標: - 書籤: - 名稱: - 目標: - 編輯群組 - 編輯存放庫 - 目標: - 本存放庫 - 提取 (fetch) - 提取所有的遠端存放庫 - 強制覆寫本機 REFs - 不提取遠端標籤 - 遠端存放庫: - 提取遠端存放庫內容 - 二進位檔案 - 檢視內容 - 前往地址... - 不追蹤此檔案的變更 - 自訂動作 - 捨棄變更... - 捨棄已選的 {0} 個檔案變更... - 使用 ${0}$ - 另存為修補檔 (patch)... - 暫存 (add) - 暫存 (add) 已選的 {0} 個檔案 - 擱置變更 (stash)... - 擱置變更 (stash) 所選的 {0} 個檔案... - 取消暫存 - 從暫存中移除 {0} 個檔案 - 使用我方版本 (ours) - 使用對方版本 (theirs) - 檔案歷史 - 檔案變更 - 檔案內容 - 檔案類型變更: - 刪除檔案類型: - 目錄 - 可執行檔案 - 新增檔案類型: - 一般檔案 - 子模組 - 符號連結 - 未知 - Git 工作流 - 開發分支: - 功能分支: - 功能分支前置詞: - 完成 ${0}$ - 完成功能分支 - 完成修復分支 - 完成發行分支 - 目標分支: - 合併前重定基底 - 壓縮為單一提交後合併 - 修復分支: - 修復分支前置詞: - 初始化 Git 工作流 - 保留分支 - 發行分支: - 版本分支: - 發行分支前置詞: - 開始於: - 開始功能分支... - 開始功能分支 - 開始修復分支... - 開始修復分支 - 分支名稱: - 輸入分支名稱 - 開始發行分支... - 開始發行分支 - 版本標籤前置詞: - Git LFS - 加入追蹤檔案規則... - 符合完整檔案名稱 - 規則: - 加入 LFS 追蹤檔案規則 - 提取 (fetch) - 執行 `git lfs fetch` 以下載遠端 LFS 物件,但不會更新工作副本。 - 提取 LFS 物件 - 啟用 Git LFS 支援 - 顯示 LFS 物件鎖 - 沒有鎖定的 LFS 物件 - 鎖定 - 僅顯示被我鎖定的檔案 - LFS 物件鎖 - 解鎖 - 解鎖所有由我鎖定的檔案 - 您確定要解鎖所有由您自己鎖定的檔案嗎? - 強制解鎖 - 清理 (prune) - 執行 `git lfs prune` 以從本機中清理目前版本不需要的 LFS 物件 - 拉取 (pull) - 執行 `git lfs pull` 以下載遠端 LFS 物件並更新工作副本。 - 拉取 LFS 物件 - 推送 (push) - 將大型檔案推送到 Git LFS 遠端服務 - 推送 LFS 物件 - 遠端存放庫: - 追蹤名稱為「{0}」的檔案 - 追蹤所有 *{0} 檔案 - 選取要前往的提交 - 進階選項 - 作者 - 修改時間 - 提交時間 - 路線圖與訊息標題 - 提交編號 - 上色分支 - 全部 - 僅目前分支 - 目前分支和選取的提交 - 僅選取的提交 - 僅選取的提交 (First-parent 模式) - 已選取 {0} 項提交 - 顯示欄位 - 可以按住 Ctrl 或 Shift 鍵選擇多個提交 - 可以按住 ⌘ 或 ⇧ 鍵選擇多個提交 - 小提示: - 在新視窗中開啟 - 提交詳細資訊 - 比較 - 快速鍵參考 - 全域快速鍵 - 複製 (clone) 遠端存放庫 - 關閉目前頁面 - 切換到下一個頁面 - 切換到上一個頁面 - 新增頁面 - 開啟本機存放庫 - 開啟偏好設定面板 - 顯示工作區的下拉式選單 - 切換目前頁面 - 放大/縮小內容 - 存放庫頁面快速鍵 - 提交暫存區變更 - 提交暫存區變更並推送 - 自動暫存全部變更並提交 - 新增分支 - 提取 (fetch) 遠端的變更 - 前往所選提交的子提交 - 前往所選提交的父提交 - 開啟命令面板 - 拉取 (pull) 遠端的變更 - 推送 (push) 本機變更到遠端存放庫 - 強制重新載入存放庫 - 展開/收合提交詳細面板 - 開啟/關閉搜尋提交面板 - 顯示本機變更 - 顯示儀表板 - 顯示擱置變更 - 捨棄 - 暫存 - 取消暫存 - 初始化存放庫 - 您是否要在該路徑執行 `git init` 以初始化存放庫? - 無法在指定路徑開啟本機存放庫。原因: - 路徑: - 揀選 (cherry-pick) 操作進行中。 - 正在處理提交 - 合併操作進行中。 - 正在處理 - 重定基底 (rebase) 操作進行中。 - 目前停止於 - 復原提交操作進行中。 - 正在復原提交 - 互動式重定基底 - 自動擱置變更並復原本機變更 - 繞過 pre-rebase hook - 起始提交: - 拖曳以重新排序提交 - 目標分支: - 複製連結 - 在瀏覽器中開啟連結 - 命令列表 - 發生錯誤 - 系統提示 - 有新版本可用 - 開啟存放庫 - 頁面列表 - 工作區列表 - 合併分支 - 編輯合併訊息 - 目標分支: - 合併方式: - 合併來源: - 正在偵測合併衝突... - 合併操作不會產生衝突 - 偵測合併衝突時發生未知錯誤 - 合併操作將產生檔案衝突 - 先套用我方版本 (ours),再套用對方版本 (theirs) - 先套用對方版本 (theirs),再套用我方版本 (ours) - 套用兩者 - 所有衝突已經解決 - {0} 個衝突尚未解決 - 我方版本 (ours) - 下一個衝突 - 上一個衝突 - 合併結果 - 儲存並暫存 - 對方版本 (theirs) - 解決衝突 - 捨棄未儲存的變更? - 僅套用我方版本 (ours) - 僅套用對方版本 (theirs) - 復原變更 - 合併 (多個來源) - 提交變更 - 合併策略: - 目標列表: - 移動子模組 - 移動到: - 子模組: - 調整存放庫分組 - 請選擇目標分組: - 名稱: - 否 - 尚未設定 Git。請開啟 [偏好設定] 以設定 Git 路徑。 - 開啟 - 系統預設編輯器 - 瀏覽程式資料目錄 - 快取資料 - 偏好設定資料 - 開啟檔案 - 使用外部比對工具檢視 - 開啟本機存放庫 - 書籤: - 群組: - 存放庫位置: - 選填。 - 新增分頁 - 關閉分頁 - 關閉其他分頁 - 關閉右側分頁 - 複製存放庫路徑 - 編輯 - 移至工作區 - 重新整理 - 新分頁 - 貼上 - {0} 天前 - 1 小時前 - {0} 小時前 - 剛剛 - 上個月 - 一年前 - {0} 分鐘前 - {0} 個月前 - {0} 年前 - 昨天 - 偏好設定 - AI - 附加提示詞 (請使用 '-' 列出您的要求) - API 金鑰 - 額外標頭 (每行一組 `名稱: 值`) - 模型 - 自動取得可用的模型列表 - 名稱 - 從環境變數中 (輸入環境變數名稱) 讀取 API 金鑰 - 推理努力等級 - 伺服器 - 外觀設定 - 預設字型 - 編輯器 Tab 寬度 - 字型大小 - 預設 - 程式碼 - 等寬字型 - 佈景主題 - 自訂主題 - 允許自動隱藏捲軸 - 使用固定寬度的分頁標籤 - 使用系統原生預設視窗樣式 - 對比/合併工具 - 對比命令參數 - 可用參數: $LOCAL, $REMOTE - 合併命令參數 - 可用參數: $BASE, $LOCAL, $REMOTE, $MERGED - 安裝路徑 - 填寫可執行檔案所在路徑 - 工具 - 一般設定 - 啟動時檢查軟體更新 - 日期時間格式 - 在樹狀變更目錄中啟用密集資料夾模式 - 顯示語言 - 最大歷史提交數 - 預設顯示 [本機變更] 頁面 - 在提交詳細資訊頁面預設顯示 [變更對比] - 在提交路線圖中顯示相對時間 - 在路線圖中顯示標籤 - 提交標題字數偵測 - 24 小時制 - 在提交路線圖中使用簡潔的分支標籤 - 產生 GitHub 風格的預設頭貼 - Git 設定 - 自動換行轉換 - 預設複製 (clone) 路徑 - 電子郵件 - 預設 Git 使用者電子郵件 - 提取後清理遠端已刪除分支 - 對比檔案時,預設忽略行末的 CR 變更 - 本軟體要求 Git 最低版本為 2.25.1 - 安裝路徑 - 啟用 HTTP SSL 驗證 - 使用 git-credential-libsecret 取代 git-credential-manager - 使用者名稱 - 預設 Git 使用者名稱 - 在簽出或合併分支時,預設擱置變更並自動復原 - Git 版本 - GPG 簽章 - 啟用提交簽章 - GPG 簽章格式 - 可執行檔案路徑 - 填寫 gpg.exe 所在路徑 - 啟用標籤簽章 - 使用者簽章金鑰 - 填寫簽章提交所使用的金鑰 - 第三方工具整合 - 終端機/Shell - 啟動參數 - 請使用「.」表示目前工作目錄 - 安裝路徑 - 終端機/Shell - 清理遠端已刪除分支 - 目標: - 清理工作樹 - 清理在 `$GIT_COMMON_DIR/worktrees` 中的無效工作樹資訊 - 拉取 (pull) - 拉取分支: - 本機分支: - 未提交變更: - 遠端: - 拉取 (提取並合併) - 使用重定基底 (rebase) 合併分支 - 推送 (push) - 確保已推送子模組 - 啟用強制推送 - 本機分支: - 新增 - 繞過 pre-push hook - 遠端存放庫: - 修訂: - 推送修訂到遠端存放庫 - 推送到遠端存放庫 - 遠端分支: - 追蹤遠端分支 - 同時推送標籤 - 推送標籤到遠端存放庫 - 推送到所有遠端存放庫 - 遠端存放庫: - 標籤: - 推送到新的分支 - 輸入新的遠端分支名稱: - 結束 - 重定基底 (rebase) 操作 - 自動擱置變更並復原本機變更 - 繞過 pre-rebase hook - 目標提交: - 正在偵測重定基底衝突... - 重定基底操作不會產生衝突 - 偵測重定基底衝突時發生未知錯誤 - 重定基底操作將產生檔案衝突 - 新增遠端存放庫 - 編輯遠端存放庫 - 遠端名稱: - 唯一遠端名稱 - 重設推送網址為存放庫網址 - 存放庫網址: - 遠端存放庫的網址 - 複製遠端網址 - 自訂動作 - 刪除... - 編輯... - 啟用定時自動提取 - 提取 (fetch) 更新 - 在瀏覽器中開啟網址 - 清理遠端已刪除分支 - 設定推送網址... - 刪除工作樹操作確認 - 啟用 [--force] 選項 - 目標工作樹: - 分支重新命名 - 新名稱: - 新的分支名稱不能與現有分支名稱相同 - 分支: - 中止 - 正在自動提取遠端變更... - 排序 - 依建立時間 - 依名稱遞增排序 - 清理本存放庫 (GC) - 本操作將執行 `git gc` 指令。 - 清空篩選規則 - 清空 - 設定本存放庫 - 下一步 - 自訂動作 - 沒有自訂的動作 - 捨棄所有變更 - 在檔案瀏覽器中開啟 - 快速搜尋分支/標籤/子模組 - 篩選以顯示或隱藏 - 摺疊篩選器 - 取消指定 - 在提交列表中隱藏 - 展開篩選器 - 以其篩選提交列表 - 個篩選規則已啟用 - 版面配置 - 橫向顯示 - 縱向顯示 - 提交顯示順序 - 依時間排序 - 依拓撲排序 - 本機分支 - 回到 HEAD - 新增分支 - 清除所有通知 - 此存放庫 (資料夾) - 在 {0} 中開啟 - 使用外部工具開啟 - 遠端列表 - 新增遠端 - 解決衝突 - 搜尋提交 - 作者 - 變更內容 - 提交訊息 - 路徑 - 提交編號 - 僅搜尋目前分支 - 搜尋方式 - 搜尋提交 - 只顯示分支和標籤引用的提交 - 只顯示合併提交的第一父提交 - 顯示內容 - 顯示失去參照的提交 - 以樹狀結構顯示 - 以樹狀結構顯示 - 跳過此提交 - 提交統計 - 子模組列表 - 新增子模組 - 更新子模組 - 標籤列表 - 新增標籤 - 依建立時間 - 依名稱 - 排序 - 在終端機中開啟 - 檢視 Git 指令記錄 - 檢視遠端存放庫 '{0}' - 工作樹列表 - 新增工作樹 - 清理 - 遠端存放庫網址 - 重設目前分支到指定版本 - 重設模式: - 移至提交: - 目前分支: - 重設選取的分支 (非目前分支) - 重設位置: - 選取分支: - 在檔案瀏覽器中檢視 - 復原操作確認 - 目標提交: - 復原後提交變更 - 正在執行操作,請耐心等待... - 儲存 - 另存新檔... - 修補檔已成功儲存! - 掃描存放庫 - 頂層目錄: - 掃描其他自訂目錄 - 檢查更新... - 軟體有版本更新: - 目前版本: - 取得最新版本資訊失敗! - 下載 - 忽略此版本 - 新版本發行日期: - 軟體更新 - 目前已是最新版本。 - 設定遠端存放庫的推送網址 - 推送網址: - 遠端: - 網址: - 設定子模組的追蹤分支 - 子模組: - 目前追蹤分支: - 變更為: - 選填。留空時設定為預設值。 - 切換上游分支 - 本機分支: - 取消設定上游分支 - 上游分支: - 複製提交編號 - 前往此提交 - SSH 金鑰: - SSH 金鑰檔案 - 開啟 SSH 金鑰工具 - 您確定要刪除以下的金鑰嗎? - 指紋 - 產生 SSH 金鑰 - 再次輸入您的密碼: - 電子郵件: - 必填。 - 金鑰名稱: - 必填,例如: id_github - 輸入您的密碼: - 產 生 - 類型: - 為私密金鑰檔案設定密碼 - 路徑 - 公開金鑰 - SSH 金鑰工具 - 開 始 - 擱置變更 (stash) - 包含未追蹤的檔案 - 擱置變更訊息: - 選填,用於描述此擱置變更 - 操作模式: - 僅擱置已暫存的變更 - 已選取的檔案中的變更均會被擱置! - 擱置本機變更 - 套用 (apply) - 套用 (apply) 所選變更 - 簽出分支 - 複製描述訊息 - 刪除 (drop) - 另存為修補檔 (patch)... - 捨棄擱置變更確認 - 捨棄擱置變更: - 擱置變更 - 檢視變更 - 擱置變更列表 - 提交統計 - 總覽 - 本月 - 本週 - SourceGit 僅會依所選分支取出最多 200,000 筆提交記錄進行分析 - 貢獻者人數: - 提交次數: - 子模組 - 新增子模組 - 追蹤分支 - 追蹤分支 - 相對路徑 - 取消初始化 - 提取子模組 - 變更歷史 - 移動 - 開啟存放庫 - 相對存放庫路徑: - 本機存放的相對路徑。 - 刪除 - 變更追蹤分支 - 變更遠端網址 - 狀態 - 未提交變更 - 未初始化 - SHA 變更 - 未解決的衝突 - 更新 - 存放庫 - 子模組變更詳細資訊 - 開啟變更詳細資訊 - 確 定 - 建立者 - 建立時間 - 簽出標籤... - 比較 2 個標籤 - 與其他分支或標籤比較... - 與目前 HEAD 比較 - 標籤訊息 - 標籤名稱 - 建立者 - 複製標籤名稱 - 自訂動作 - 刪除 ${0}$... - 刪除所選的 {0} 個標籤... - 合併 ${0}$ 到 ${1}$... - 推送 ${0}$... - 終止執行 - 更新子模組 - 更新所有子模組 - 如果子模組尚未初始化,則將其初始化 - 子模組: - 遞迴更新子模組 - 更新至子模組的遠端追蹤分支 - 存放庫網址: - 記錄 - 清除所有記錄 - 複製 - 刪除 - 警告 - 起始頁 - 新增群組 - 新增子群組 - 複製 (clone) 遠端存放庫 - 刪除 - 支援拖放以新增目錄與自訂群組。 - 編輯 - 調整存放庫分組 - 開啟所有存放庫 - 開啟本機存放庫 - 開啟終端機 - 重新掃描預設複製 (clone) 目錄下的存放庫 - 快速搜尋存放庫... - 本機變更 - 加入至 .gitignore 忽略清單 - 忽略所有 *{0} 檔案 - 忽略同路徑下所有 *{0} 檔案 - 忽略本路徑下的新增檔案 - 忽略本檔案 - 忽略同路徑下所有新增檔案 - 修補 - 現在您已可將其加入暫存區中 - 清除提交訊息記錄 - 您確定要清除所有提交訊息記錄嗎 (執行後無法復原)? - 提 交 - 提交並推送 - 提交訊息記錄/範本 - 觸發點擊事件 - 提交 (修改原始提交) - 自動暫存全部變更並提交 - HEAD 目前處於分離狀態。您確定要繼續提交變更嗎? - 您已暫存 {0} 個檔案,但只顯示 {1} 個檔案 ({2} 個檔案被篩選器隱藏)。您確定要繼續提交嗎? - 偵測到衝突 - 解決衝突 - 使用外部工具解決衝突 - 使用外部合併工具開啟 - 檔案衝突已解決 - 使用我方版本 (ours) - 使用對方版本 (theirs) - 捨棄所有變更 - 搜尋變更... - 顯示未追蹤檔案 - 沒有提交訊息記錄 - 沒有可套用的提交訊息範本 - 繞過 Hooks 檢查 - 重設作者 - 署名 - 已暫存 - 取消暫存選取的檔案 - 取消暫存所有檔案 - 未暫存 - 暫存選取的檔案 - 暫存所有檔案 - 檢視不追蹤變更的檔案 - 範本: ${0}$ - 工作區: - 設定工作區... - 本機工作樹 - 分支 - 複製工作樹路徑 - 最新提交 - 鎖定工作樹 - 開啟工作樹 - 位置 - 移除工作樹 - 解除鎖定工作樹 - 是 - diff --git a/src/ViewModels/AzureDevOpsAccount.cs b/src/ViewModels/AzureDevOpsAccount.cs new file mode 100644 index 0000000000..473af8ba1c --- /dev/null +++ b/src/ViewModels/AzureDevOpsAccount.cs @@ -0,0 +1,295 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +using Avalonia.Threading; +using CommunityToolkit.Mvvm.ComponentModel; + +namespace SourceGit.ViewModels +{ + /// + /// The signed-in Azure DevOps account. The login name lives in the preferences, the refresh token in the OS + /// credential store, where the `--azure-devops-credential` helper also reads it when git talks to Azure DevOps. + /// Access tokens only live for about an hour, so they are kept in memory and fetched again when needed. + /// + public class AzureDevOpsAccount : ObservableObject + { + public static AzureDevOpsAccount Instance { get; } = new(); + + public const string SecretKey = "azure-devops"; + + public bool IsAvailable => Models.AzureDevOps.IsConfigured; + + public string Login + { + get => Preferences.Instance.AzureDevOpsLogin; + } + + public bool IsSignedIn + { + get => IsAvailable && !string.IsNullOrEmpty(Login); + } + + public bool PreferSSH + { + get => Preferences.Instance.AzureDevOpsPreferSSH; + set + { + if (Preferences.Instance.AzureDevOpsPreferSSH != value) + { + Preferences.Instance.AzureDevOpsPreferSSH = value; + OnPropertyChanged(); + } + } + } + + /// + /// Whether git operations against Azure DevOps over HTTPS use this account instead of other credential helpers. + /// + public bool UseForGit + { + get => Preferences.Instance.AzureDevOpsUseForGit; + set + { + if (Preferences.Instance.AzureDevOpsUseForGit != value) + { + Preferences.Instance.AzureDevOpsUseForGit = value; + OnPropertyChanged(); + } + } + } + + public bool IsLoading + { + get => _isLoading; + private set => SetProperty(ref _isLoading, value); + } + + public string LoadError + { + get => _loadError; + private set => SetProperty(ref _loadError, value); + } + + /// + /// The last fetched repositories (sorted by organization, project and name), or an empty list. + /// + public List Repositories + { + get => _repositories; + private set => SetProperty(ref _repositories, value); + } + + /// + /// Stores the refresh token returned by the device flow and makes the account the signed-in one. + /// + public bool CompleteSignIn(string login, Models.AzureDevOpsTokens tokens) + { + if (!Native.SecretStore.Set(SecretKey, tokens.RefreshToken)) + return false; + + _accessToken = tokens.AccessToken; + _accessTokenExpiresAt = DateTime.UtcNow.AddSeconds(tokens.ExpiresIn); + Preferences.Instance.AzureDevOpsLogin = login; + Preferences.Instance.Save(); + NotifyAccountChanged(); + + _ = RefreshAsync(true); + return true; + } + + public void SignOut() + { + Native.SecretStore.Delete(SecretKey); + _accessToken = null; + _accessTokenExpiresAt = DateTime.MinValue; + _fetchedAt = DateTime.MinValue; + Repositories = []; + LoadError = null; + + Preferences.Instance.AzureDevOpsLogin = string.Empty; + Preferences.Instance.Save(); + NotifyAccountChanged(); + } + + /// + /// Fetches the repository list unless a recent one is cached. Concurrent callers share the same request. + /// + public Task RefreshAsync(bool force) + { + if (!IsSignedIn) + return Task.CompletedTask; + + if (_pending != null) + return _pending; + + if (!force && DateTime.Now - _fetchedAt < TimeSpan.FromMinutes(5)) + return Task.CompletedTask; + + _pending = DoRefreshAsync(); + return _pending; + } + + /// + /// Remote URL to clone the given repository with, following the protocol preference. + /// + public string GetCloneUrl(Models.AzureDevOpsRepository repo) + { + return PreferSSH && !string.IsNullOrEmpty(repo.SshUrl) ? repo.SshUrl : repo.RemoteUrl; + } + + /// + /// Folder to clone the given repository into: `/`, so the clone lands in a group + /// named after its project. The clone dialog creates it when missing. Returns null without a default clone dir. + /// + public static string PrepareParentFolder(Models.AzureDevOpsRepository repo) + { + var cloneDir = Preferences.Instance.GetDefaultCloneDir(); + if (string.IsNullOrEmpty(cloneDir) || !Directory.Exists(cloneDir)) + return null; + + return Path.Combine(cloneDir, repo.Project.Name); + } + + /// + /// Marks the repositories already cloned into one of the given local repositories. + /// + public static void MarkCloned(List repos, HashSet clonedFullNames) + { + foreach (var repo in repos) + repo.IsCloned = clonedFullNames.Contains(repo.FullName.ToLowerInvariant()); + } + + /// + /// Returns an access token for git, refreshing it with the stored refresh token. Runs in the short-lived + /// `--azure-devops-credential` process, so it only touches the credential store, never the preferences. + /// Returns null when not signed in or the refresh token is no longer valid. + /// + public static async Task GetAccessTokenForGitAsync(CancellationToken token) + { + var refreshToken = Native.SecretStore.Get(SecretKey); + if (string.IsNullOrEmpty(refreshToken)) + return null; + + try + { + var tokens = await Models.AzureDevOps.RefreshTokensAsync(refreshToken, token).ConfigureAwait(false); + StoreRotatedRefreshToken(refreshToken, tokens); + return tokens.AccessToken; + } + catch + { + return null; + } + } + + private async Task DoRefreshAsync() + { + IsLoading = true; + LoadError = null; + + try + { + var token = await GetAccessTokenAsync().ConfigureAwait(false); + var profile = await Models.AzureDevOps.GetProfileAsync(token, CancellationToken.None).ConfigureAwait(false); + var organizations = await Models.AzureDevOps.GetOrganizationsAsync(token, profile.Id, CancellationToken.None).ConfigureAwait(false); + + // One organization failing (e.g. one connected to another Entra tenant) should not hide the others. + var errors = new List(); + var tasks = new List>>(); + foreach (var organization in organizations) + tasks.Add(Models.AzureDevOps.GetRepositoriesAsync(token, organization, CancellationToken.None)); + + var repos = new List(); + for (var i = 0; i < tasks.Count; i++) + { + try + { + repos.AddRange(await tasks[i].ConfigureAwait(false)); + } + catch (Exception e) + { + errors.Add($"{organizations[i]}: {e.Message}"); + } + } + + repos.RemoveAll(x => x.IsDisabled); + repos.Sort((l, r) => string.Compare(l.FullName, r.FullName, StringComparison.OrdinalIgnoreCase)); + + Dispatcher.UIThread.Post(() => + { + _fetchedAt = DateTime.Now; + Repositories = repos; + if (repos.Count == 0) + LoadError = errors.Count > 0 ? string.Join('\n', errors) : App.Text("AzureDevOps.Picker.NoOrganizations"); + }); + } + catch (Models.AzureDevOpsException e) when (e.IsUnauthorized) + { + Dispatcher.UIThread.Post(() => + { + SignOut(); + Models.Notification.Send(null, App.Text("AzureDevOps.SignIn.Expired"), true); + }); + } + catch (Exception e) + { + Dispatcher.UIThread.Post(() => LoadError = e.Message); + } + finally + { + Dispatcher.UIThread.Post(() => + { + IsLoading = false; + _pending = null; + }); + } + } + + /// + /// The cached access token, or a new one from the stored refresh token once it is about to expire. + /// + private async Task GetAccessTokenAsync() + { + if (!string.IsNullOrEmpty(_accessToken) && DateTime.UtcNow < _accessTokenExpiresAt.AddMinutes(-5)) + return _accessToken; + + var refreshToken = await Task.Run(() => Native.SecretStore.Get(SecretKey)).ConfigureAwait(false); + if (string.IsNullOrEmpty(refreshToken)) + throw new Models.AzureDevOpsException(App.Text("AzureDevOps.SignIn.Missing"), true); + + var tokens = await Models.AzureDevOps.RefreshTokensAsync(refreshToken, CancellationToken.None).ConfigureAwait(false); + StoreRotatedRefreshToken(refreshToken, tokens); + + _accessToken = tokens.AccessToken; + _accessTokenExpiresAt = DateTime.UtcNow.AddSeconds(tokens.ExpiresIn); + return _accessToken; + } + + /// + /// Every refresh hands out a new refresh token with a fresh lifetime. Keeping the newest one means the + /// sign-in only expires after a long time without using it. + /// + private static void StoreRotatedRefreshToken(string old, Models.AzureDevOpsTokens tokens) + { + if (!string.IsNullOrEmpty(tokens.RefreshToken) && tokens.RefreshToken != old) + Native.SecretStore.Set(SecretKey, tokens.RefreshToken); + } + + private void NotifyAccountChanged() + { + OnPropertyChanged(nameof(Login)); + OnPropertyChanged(nameof(IsSignedIn)); + } + + private string _accessToken = null; + private DateTime _accessTokenExpiresAt = DateTime.MinValue; + private bool _isLoading = false; + private string _loadError = null; + private DateTime _fetchedAt = DateTime.MinValue; + private Task _pending = null; + private List _repositories = []; + } +} diff --git a/src/ViewModels/AzureDevOpsRepositoryPicker.cs b/src/ViewModels/AzureDevOpsRepositoryPicker.cs new file mode 100644 index 0000000000..c66ff048e8 --- /dev/null +++ b/src/ViewModels/AzureDevOpsRepositoryPicker.cs @@ -0,0 +1,162 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Threading.Tasks; + +using Avalonia.Threading; +using CommunityToolkit.Mvvm.ComponentModel; + +namespace SourceGit.ViewModels +{ + /// + /// Searchable list of the Azure DevOps repositories the signed-in account can access, filtered by project. + /// + public class AzureDevOpsRepositoryPicker : ObservableObject, IDisposable + { + public AzureDevOpsAccount Account => AzureDevOpsAccount.Instance; + + /// + /// Project names, prefixed with their organization when the account is a member of more than one. + /// + public List Projects + { + get => _projects; + private set => SetProperty(ref _projects, value); + } + + public string SelectedProject + { + get => _selectedProject; + set + { + if (SetProperty(ref _selectedProject, value)) + UpdateVisible(); + } + } + + public string SearchFilter + { + get => _searchFilter; + set + { + if (SetProperty(ref _searchFilter, value)) + UpdateVisible(); + } + } + + public List VisibleRepos + { + get => _visibleRepos; + private set => SetProperty(ref _visibleRepos, value); + } + + public Models.AzureDevOpsRepository SelectedRepo + { + get => _selectedRepo; + set => SetProperty(ref _selectedRepo, value); + } + + public AzureDevOpsRepositoryPicker() + { + Account.PropertyChanged += OnAccountPropertyChanged; + OnRepositoriesChanged(); + _ = Account.RefreshAsync(false); + + Task.Run(() => + { + var cloned = Models.AzureDevOps.CollectClonedFullNames(GitHubAccount.CollectLocalRepositoryPaths()); + Dispatcher.UIThread.Post(() => + { + _cloned = cloned; + UpdateVisible(); + }); + }); + } + + public void Dispose() + { + Account.PropertyChanged -= OnAccountPropertyChanged; + } + + public void ClearFilter() + { + SearchFilter = string.Empty; + } + + public void Refresh() + { + _ = Account.RefreshAsync(true); + } + + public void OpenOrganizations() + { + Native.OS.OpenBrowser(Models.AzureDevOps.OrganizationsUrl); + } + + private void OnAccountPropertyChanged(object sender, PropertyChangedEventArgs e) + { + if (e.PropertyName == nameof(AzureDevOpsAccount.Repositories)) + OnRepositoriesChanged(); + } + + private void OnRepositoriesChanged() + { + var organizations = new HashSet(); + foreach (var repo in Account.Repositories) + organizations.Add(repo.Organization); + + _projectOf.Clear(); + var projects = new List(); + foreach (var repo in Account.Repositories) + { + var project = organizations.Count > 1 ? $"{repo.Organization}/{repo.Project.Name}" : repo.Project.Name; + if (!projects.Contains(project)) + projects.Add(project); + + _projectOf[repo] = project; + } + + projects.Sort(StringComparer.OrdinalIgnoreCase); + projects.Insert(0, _allProjects); + + Projects = projects; + if (!projects.Contains(_selectedProject)) + _selectedProject = _allProjects; + OnPropertyChanged(nameof(SelectedProject)); + + UpdateVisible(); + } + + private void UpdateVisible() + { + var repos = Account.Repositories; + AzureDevOpsAccount.MarkCloned(repos, _cloned); + + var visible = new List(); + foreach (var repo in repos) + { + if (_selectedProject != _allProjects && !_selectedProject.Equals(_projectOf.GetValueOrDefault(repo), StringComparison.Ordinal)) + continue; + + if (!string.IsNullOrEmpty(_searchFilter) && !repo.FullName.Contains(_searchFilter, StringComparison.OrdinalIgnoreCase)) + continue; + + visible.Add(repo); + } + + var selected = _selectedRepo; + VisibleRepos = visible; + SelectedRepo = selected != null && visible.Contains(selected) ? selected : (visible.Count > 0 ? visible[0] : null); + } + + private readonly string _allProjects = App.Text("AzureDevOps.Picker.AllProjects"); + + private List _projects = []; + private Dictionary _projectOf = []; + private string _selectedProject = null; + private string _searchFilter = string.Empty; + private HashSet _cloned = []; + private List _visibleRepos = []; + private Models.AzureDevOpsRepository _selectedRepo = null; + } +} diff --git a/src/ViewModels/AzureDevOpsSignIn.cs b/src/ViewModels/AzureDevOpsSignIn.cs new file mode 100644 index 0000000000..279386441c --- /dev/null +++ b/src/ViewModels/AzureDevOpsSignIn.cs @@ -0,0 +1,97 @@ +using System; +using System.Threading; +using System.Threading.Tasks; + +using CommunityToolkit.Mvvm.ComponentModel; + +namespace SourceGit.ViewModels +{ + /// + /// OAuth device flow: shows a one-time code, which the user enters on microsoft.com/devicelogin. + /// + public class AzureDevOpsSignIn : ObservableObject + { + public string UserCode + { + get => _userCode; + private set => SetProperty(ref _userCode, value); + } + + public string VerificationUri + { + get => _verificationUri; + private set => SetProperty(ref _verificationUri, value); + } + + public string Error + { + get => _error; + private set => SetProperty(ref _error, value); + } + + public bool IsWaiting + { + get => _isWaiting; + private set => SetProperty(ref _isWaiting, value); + } + + /// + /// Runs the whole flow. Returns true once the account is signed in; `onCodeReady` runs as soon as the + /// code to enter on microsoft.com is known. + /// + public async Task RunAsync(Action onCodeReady) + { + _cancellation = new CancellationTokenSource(); + var token = _cancellation.Token; + + Error = null; + IsWaiting = true; + + try + { + var code = await Models.AzureDevOps.RequestDeviceCodeAsync(token); + UserCode = code.UserCode; + VerificationUri = code.VerificationUri; + onCodeReady?.Invoke(); + + var tokens = await Models.AzureDevOps.WaitForTokensAsync(code, token); + var profile = await Models.AzureDevOps.GetProfileAsync(tokens.AccessToken, token); + var login = string.IsNullOrEmpty(profile.EmailAddress) ? profile.DisplayName : profile.EmailAddress; + if (!AzureDevOpsAccount.Instance.CompleteSignIn(login, tokens)) + throw new Models.AzureDevOpsException(App.Text("AzureDevOps.SignIn.StoreFailed")); + + return true; + } + catch (OperationCanceledException) when (token.IsCancellationRequested) + { + return false; + } + catch (Exception e) + { + Error = e.Message; + return false; + } + finally + { + IsWaiting = false; + } + } + + public void OpenVerificationPage() + { + if (!string.IsNullOrEmpty(_verificationUri)) + Native.OS.OpenBrowser(_verificationUri); + } + + public void Cancel() + { + _cancellation?.Cancel(); + } + + private CancellationTokenSource _cancellation = null; + private string _userCode = string.Empty; + private string _verificationUri = string.Empty; + private string _error = null; + private bool _isWaiting = false; + } +} diff --git a/src/ViewModels/Clone.cs b/src/ViewModels/Clone.cs index aed33c5090..d06e6b7ac3 100644 --- a/src/ViewModels/Clone.cs +++ b/src/ViewModels/Clone.cs @@ -40,7 +40,17 @@ public string SSHKey public string ParentFolder { get => _parentFolder; - set => SetProperty(ref _parentFolder, value, true); + set + { + if (SetProperty(ref _parentFolder, value, true)) + IsParentFolderMissing = !string.IsNullOrWhiteSpace(value) && !Directory.Exists(value) && !File.Exists(value); + } + } + + public bool IsParentFolderMissing + { + get => _isParentFolderMissing; + private set => SetProperty(ref _isParentFolderMissing, value); } public string Local @@ -102,6 +112,34 @@ public Clone(string pageId) ParentFolder = _defaultCloneDir; } + /// + /// Fills in a repository picked from GitHub. It goes into `/`, so the "Auto" group + /// files it under its organization. + /// + public void UseGitHubRepository(Models.GitHubRepository repo) + { + Remote = GitHubAccount.Instance.GetCloneUrl(repo); + Local = string.Empty; + + var folder = GitHubAccount.PrepareParentFolder(repo); + if (!string.IsNullOrEmpty(folder)) + ParentFolder = folder; + } + + /// + /// Fills in a repository picked from Azure DevOps. It goes into `/`, so the "Auto" + /// group files it under its project. + /// + public void UseAzureDevOpsRepository(Models.AzureDevOpsRepository repo) + { + Remote = AzureDevOpsAccount.Instance.GetCloneUrl(repo); + Local = string.Empty; + + var folder = AzureDevOpsAccount.PrepareParentFolder(repo); + if (!string.IsNullOrEmpty(folder)) + ParentFolder = folder; + } + public static ValidationResult ValidateRemote(string remote, ValidationContext _) { if (!Models.Remote.IsValidURL(remote)) @@ -111,8 +149,10 @@ public static ValidationResult ValidateRemote(string remote, ValidationContext _ public static ValidationResult ValidateParentFolder(string folder, ValidationContext _) { - if (!Directory.Exists(folder)) - return new ValidationResult("Given path can NOT be found"); + if (!Path.IsPathFullyQualified(folder)) + return new ValidationResult("Given path must be absolute"); + if (File.Exists(folder)) + return new ValidationResult("Given path is a file"); return ValidationResult.Success; } @@ -126,12 +166,15 @@ public override async Task Sure() _cancellation = new CancellationTokenSource(); var token = _cancellation.Token; - var succ = await new Commands.Clone(_pageId, _parentFolder, _remote, _local, _useSSH ? _sshKey : "", _extraArgs) - .WithCancellation(token) - .Use(log) - .ExecAsync(); - if (!succ || token.IsCancellationRequested) + try + { + Directory.CreateDirectory(_parentFolder); + } + catch (Exception e) + { + Models.Notification.Send(_pageId, $"Failed to create folder '{_parentFolder}': {e.Message}", true); return false; + } var path = _parentFolder; if (!string.IsNullOrEmpty(_local)) @@ -149,6 +192,19 @@ public override async Task Sure() path = Path.GetFullPath(Path.Combine(path, name)); } + var existedBefore = Directory.Exists(path); + var succ = await new Commands.Clone(_pageId, _parentFolder, _remote, _local, _useSSH ? _sshKey : "", _extraArgs) + .WithCancellation(token) + .Use(log) + .ExecAsync(); + if (token.IsCancellationRequested) + return false; + + // When only the checkout fails (e.g. a file name the file system rejects), git keeps the cloned repository. + // The error is already reported, so open it anyway and let the user deal with the working tree there. + if (!succ && (existedBefore || !Directory.Exists(Path.Combine(path, ".git")))) + return false; + if (!Directory.Exists(path)) { Models.Notification.Send(_pageId, $"Folder '{path}' can NOT be found", true); @@ -162,7 +218,7 @@ public override async Task Sure() .SetAsync("remote.origin.sshkey", _sshKey); } - if (InitAndUpdateSubmodules && !token.IsCancellationRequested) + if (succ && InitAndUpdateSubmodules && !token.IsCancellationRequested) { var submodules = await new Commands.QueryUpdatableSubmodules(path, true).GetResultAsync(); if (submodules.Count > 0) @@ -240,6 +296,7 @@ private void CollectGroups(List outs, List collecti private bool _useSSH = false; private string _sshKey = string.Empty; private string _parentFolder = string.Empty; + private bool _isParentFolderMissing = false; private string _defaultCloneDir = string.Empty; private string _local = string.Empty; private string _extraArgs = string.Empty; diff --git a/src/ViewModels/CommitDetail.cs b/src/ViewModels/CommitDetail.cs index 636aad6654..c200518327 100644 --- a/src/ViewModels/CommitDetail.cs +++ b/src/ViewModels/CommitDetail.cs @@ -18,11 +18,6 @@ public int ActiveTabIndex get; set; } - - public CommitDetailSharedData() - { - ActiveTabIndex = Preferences.Instance.ShowChangesInCommitDetailByDefault ? 1 : 0; - } } public partial class CommitDetail : ObservableObject @@ -541,7 +536,7 @@ private void Refresh() private void UpdateDetails() { - if (ActiveTabIndex == 1 && _changeSelection is { Count: 1, HasFolder: false }) + if (ActiveTabIndex == 0 && _changeSelection is { Count: 1, HasFolder: false }) DiffContext = new DiffContext(_repo.FullPath, new Models.DiffOption(_commit, _changeSelection.Changes[0]), _diffContext); else DiffContext = null; diff --git a/src/ViewModels/GitHubAccount.cs b/src/ViewModels/GitHubAccount.cs new file mode 100644 index 0000000000..3f1805a51a --- /dev/null +++ b/src/ViewModels/GitHubAccount.cs @@ -0,0 +1,259 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +using Avalonia.Threading; +using CommunityToolkit.Mvvm.ComponentModel; + +namespace SourceGit.ViewModels +{ + /// + /// The signed-in GitHub account. The login name lives in the preferences, the access token in the OS + /// credential store, where the `--github-credential` helper also reads it when git talks to github.com. + /// + public class GitHubAccount : ObservableObject + { + public static GitHubAccount Instance { get; } = new(); + + public const string SecretKey = "github"; + + public bool IsAvailable => Models.GitHub.IsConfigured; + + public string Login + { + get => Preferences.Instance.GitHubLogin; + } + + public bool IsSignedIn + { + get => IsAvailable && !string.IsNullOrEmpty(Login); + } + + public bool PreferSSH + { + get => Preferences.Instance.GitHubPreferSSH; + set + { + if (Preferences.Instance.GitHubPreferSSH != value) + { + Preferences.Instance.GitHubPreferSSH = value; + OnPropertyChanged(); + } + } + } + + /// + /// Whether git operations against https://github.com use this account instead of other credential helpers. + /// + public bool UseForGit + { + get => Preferences.Instance.GitHubUseForGit; + set + { + if (Preferences.Instance.GitHubUseForGit != value) + { + Preferences.Instance.GitHubUseForGit = value; + OnPropertyChanged(); + } + } + } + + public bool IsLoading + { + get => _isLoading; + private set => SetProperty(ref _isLoading, value); + } + + public string LoadError + { + get => _loadError; + private set => SetProperty(ref _loadError, value); + } + + /// + /// The last fetched repositories (sorted by most recently pushed), or an empty list. + /// + public List Repositories + { + get => _repositories; + private set => SetProperty(ref _repositories, value); + } + + /// + /// Stores the token returned by the device flow and makes the account the signed-in one. + /// + public bool CompleteSignIn(string login, string token) + { + if (!Native.SecretStore.Set(SecretKey, token)) + return false; + + _token = token; + Preferences.Instance.GitHubLogin = login; + Preferences.Instance.Save(); + NotifyAccountChanged(); + + _ = RefreshAsync(true); + return true; + } + + public void SignOut() + { + Native.SecretStore.Delete(SecretKey); + _token = null; + _fetchedAt = DateTime.MinValue; + Repositories = []; + LoadError = null; + + Preferences.Instance.GitHubLogin = string.Empty; + Preferences.Instance.Save(); + NotifyAccountChanged(); + } + + /// + /// Fetches the repository list unless a recent one is cached. Concurrent callers share the same request. + /// + public Task RefreshAsync(bool force) + { + if (!IsSignedIn) + return Task.CompletedTask; + + if (_pending != null) + return _pending; + + if (!force && DateTime.Now - _fetchedAt < TimeSpan.FromMinutes(5)) + return Task.CompletedTask; + + _pending = DoRefreshAsync(); + return _pending; + } + + /// + /// Remote URL to clone the given repository with, following the protocol preference. + /// + public string GetCloneUrl(Models.GitHubRepository repo) + { + return PreferSSH ? repo.SshUrl : repo.CloneUrl; + } + + /// + /// Folder to clone the given repository into: `/`, so the clone lands in a group + /// named after the organization. The clone dialog creates it when missing. Returns null without a default + /// clone dir. + /// + public static string PrepareParentFolder(Models.GitHubRepository repo) + { + var cloneDir = Preferences.Instance.GetDefaultCloneDir(); + if (string.IsNullOrEmpty(cloneDir) || !Directory.Exists(cloneDir)) + return null; + + return Path.Combine(cloneDir, repo.Owner.Login); + } + + /// + /// Marks the repositories already cloned into one of the given local repositories. + /// + public static void MarkCloned(List repos, HashSet clonedFullNames) + { + foreach (var repo in repos) + repo.IsCloned = clonedFullNames.Contains(repo.FullName.ToLowerInvariant()); + } + + /// + /// Paths of every repository known to SourceGit plus the ones found under the default clone dir. + /// + public static List CollectLocalRepositoryPaths() + { + var paths = new List(); + CollectManaged(paths, Preferences.Instance.RepositoryNodes); + + var cloneDir = Preferences.Instance.GetDefaultCloneDir(); + if (!string.IsNullOrEmpty(cloneDir) && Directory.Exists(cloneDir)) + { + foreach (var (path, _) in LauncherPagesCommandPalette.ScanForRepositories(cloneDir)) + paths.Add(path); + } + + return paths; + } + + private async Task DoRefreshAsync() + { + IsLoading = true; + LoadError = null; + + try + { + var token = await GetTokenAsync().ConfigureAwait(false); + if (string.IsNullOrEmpty(token)) + throw new Models.GitHubException(App.Text("GitHub.SignIn.Missing"), true); + + var repos = await Models.GitHub.GetRepositoriesAsync(token, CancellationToken.None).ConfigureAwait(false); + repos.Sort((l, r) => string.CompareOrdinal(r.PushedAt, l.PushedAt)); + + Dispatcher.UIThread.Post(() => + { + _fetchedAt = DateTime.Now; + Repositories = repos; + }); + } + catch (Models.GitHubException e) when (e.IsUnauthorized) + { + Dispatcher.UIThread.Post(() => + { + SignOut(); + Models.Notification.Send(null, App.Text("GitHub.SignIn.Expired"), true); + }); + } + catch (Exception e) + { + Dispatcher.UIThread.Post(() => LoadError = e.Message); + } + finally + { + Dispatcher.UIThread.Post(() => + { + IsLoading = false; + _pending = null; + }); + } + } + + private Task GetTokenAsync() + { + if (!string.IsNullOrEmpty(_token)) + return Task.FromResult(_token); + + return Task.Run(() => + { + _token = Native.SecretStore.Get(SecretKey); + return _token; + }); + } + + private void NotifyAccountChanged() + { + OnPropertyChanged(nameof(Login)); + OnPropertyChanged(nameof(IsSignedIn)); + } + + private static void CollectManaged(List outs, List nodes) + { + foreach (var node in nodes) + { + if (node.IsRepository) + outs.Add(node.Id); + else + CollectManaged(outs, node.SubNodes); + } + } + + private string _token = null; + private bool _isLoading = false; + private string _loadError = null; + private DateTime _fetchedAt = DateTime.MinValue; + private Task _pending = null; + private List _repositories = []; + } +} diff --git a/src/ViewModels/GitHubRepositoryPicker.cs b/src/ViewModels/GitHubRepositoryPicker.cs new file mode 100644 index 0000000000..2c7d0a57b6 --- /dev/null +++ b/src/ViewModels/GitHubRepositoryPicker.cs @@ -0,0 +1,161 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Threading.Tasks; + +using Avalonia.Threading; +using CommunityToolkit.Mvvm.ComponentModel; + +namespace SourceGit.ViewModels +{ + /// + /// Searchable list of the GitHub repositories the signed-in account can access, filtered by owner. + /// + public class GitHubRepositoryPicker : ObservableObject, IDisposable + { + public GitHubAccount Account => GitHubAccount.Instance; + + public List Owners + { + get => _owners; + private set => SetProperty(ref _owners, value); + } + + public string SelectedOwner + { + get => _selectedOwner; + set + { + if (SetProperty(ref _selectedOwner, value)) + UpdateVisible(); + } + } + + public string SearchFilter + { + get => _searchFilter; + set + { + if (SetProperty(ref _searchFilter, value)) + UpdateVisible(); + } + } + + public List VisibleRepos + { + get => _visibleRepos; + private set => SetProperty(ref _visibleRepos, value); + } + + public Models.GitHubRepository SelectedRepo + { + get => _selectedRepo; + set => SetProperty(ref _selectedRepo, value); + } + + public GitHubRepositoryPicker() + { + Account.PropertyChanged += OnAccountPropertyChanged; + OnRepositoriesChanged(); + _ = Account.RefreshAsync(false); + + Task.Run(() => + { + var cloned = Models.GitHub.CollectClonedFullNames(GitHubAccount.CollectLocalRepositoryPaths()); + Dispatcher.UIThread.Post(() => + { + _cloned = cloned; + UpdateVisible(); + }); + }); + } + + public void Dispose() + { + Account.PropertyChanged -= OnAccountPropertyChanged; + } + + public void ClearFilter() + { + SearchFilter = string.Empty; + } + + public void Refresh() + { + _ = Account.RefreshAsync(true); + } + + public void GrantOrganizationAccess() + { + Native.OS.OpenBrowser(Models.GitHub.ApplicationSettingsUrl); + } + + private void OnAccountPropertyChanged(object sender, PropertyChangedEventArgs e) + { + if (e.PropertyName == nameof(GitHubAccount.Repositories)) + OnRepositoriesChanged(); + } + + private void OnRepositoriesChanged() + { + var owners = new List(); + foreach (var repo in Account.Repositories) + { + if (!owners.Contains(repo.Owner.Login)) + owners.Add(repo.Owner.Login); + } + + // The signed-in user first, then organizations alphabetically. + var login = Account.Login; + owners.Sort((l, r) => + { + if (l.Equals(login, StringComparison.OrdinalIgnoreCase)) + return -1; + if (r.Equals(login, StringComparison.OrdinalIgnoreCase)) + return 1; + return string.Compare(l, r, StringComparison.OrdinalIgnoreCase); + }); + owners.Insert(0, _allOwners); + + Owners = owners; + if (!owners.Contains(_selectedOwner)) + _selectedOwner = _allOwners; + OnPropertyChanged(nameof(SelectedOwner)); + + UpdateVisible(); + } + + private void UpdateVisible() + { + var repos = Account.Repositories; + GitHubAccount.MarkCloned(repos, _cloned); + + var visible = new List(); + foreach (var repo in repos) + { + if (_selectedOwner != _allOwners && !repo.Owner.Login.Equals(_selectedOwner, StringComparison.Ordinal)) + continue; + + if (!string.IsNullOrEmpty(_searchFilter) && + !repo.FullName.Contains(_searchFilter, StringComparison.OrdinalIgnoreCase) && + !(repo.Description?.Contains(_searchFilter, StringComparison.OrdinalIgnoreCase) ?? false)) + continue; + + visible.Add(repo); + } + + var selected = _selectedRepo; + VisibleRepos = visible; + SelectedRepo = selected != null && visible.Contains(selected) ? selected : (visible.Count > 0 ? visible[0] : null); + } + + private readonly string _allOwners = App.Text("GitHub.Picker.AllOwners"); + + private List _owners = []; + private string _selectedOwner = null; + private string _searchFilter = string.Empty; + private HashSet _cloned = []; + private List _visibleRepos = []; + private Models.GitHubRepository _selectedRepo = null; + } +} diff --git a/src/ViewModels/GitHubSignIn.cs b/src/ViewModels/GitHubSignIn.cs new file mode 100644 index 0000000000..5b01c38bd8 --- /dev/null +++ b/src/ViewModels/GitHubSignIn.cs @@ -0,0 +1,96 @@ +using System; +using System.Threading; +using System.Threading.Tasks; + +using CommunityToolkit.Mvvm.ComponentModel; + +namespace SourceGit.ViewModels +{ + /// + /// OAuth device flow: shows a one-time code, which the user enters on github.com/login/device. + /// + public class GitHubSignIn : ObservableObject + { + public string UserCode + { + get => _userCode; + private set => SetProperty(ref _userCode, value); + } + + public string VerificationUri + { + get => _verificationUri; + private set => SetProperty(ref _verificationUri, value); + } + + public string Error + { + get => _error; + private set => SetProperty(ref _error, value); + } + + public bool IsWaiting + { + get => _isWaiting; + private set => SetProperty(ref _isWaiting, value); + } + + /// + /// Runs the whole flow. Returns true once the account is signed in; `onCodeReady` runs as soon as the + /// code to enter on github.com is known. + /// + public async Task RunAsync(Action onCodeReady) + { + _cancellation = new CancellationTokenSource(); + var token = _cancellation.Token; + + Error = null; + IsWaiting = true; + + try + { + var code = await Models.GitHub.RequestDeviceCodeAsync(token); + UserCode = code.UserCode; + VerificationUri = code.VerificationUri; + onCodeReady?.Invoke(); + + var accessToken = await Models.GitHub.WaitForAccessTokenAsync(code, token); + var user = await Models.GitHub.GetUserAsync(accessToken, token); + if (!GitHubAccount.Instance.CompleteSignIn(user.Login, accessToken)) + throw new Models.GitHubException(App.Text("GitHub.SignIn.StoreFailed")); + + return true; + } + catch (OperationCanceledException) when (token.IsCancellationRequested) + { + return false; + } + catch (Exception e) + { + Error = e.Message; + return false; + } + finally + { + IsWaiting = false; + } + } + + public void OpenVerificationPage() + { + if (!string.IsNullOrEmpty(_verificationUri)) + Native.OS.OpenBrowser(_verificationUri); + } + + public void Cancel() + { + _cancellation?.Cancel(); + } + + private CancellationTokenSource _cancellation = null; + private string _userCode = string.Empty; + private string _verificationUri = string.Empty; + private string _error = null; + private bool _isWaiting = false; + } +} diff --git a/src/ViewModels/Launcher.cs b/src/ViewModels/Launcher.cs index 1cf00a848c..089207f624 100644 --- a/src/ViewModels/Launcher.cs +++ b/src/ViewModels/Launcher.cs @@ -42,7 +42,12 @@ public LauncherPage ActivePage public ICommandPalette CommandPalette { get => _commandPalette; - set => SetProperty(ref _commandPalette, value); + set + { + var old = _commandPalette; + if (SetProperty(ref _commandPalette, value) && old is IDisposable disposable) + disposable.Dispose(); + } } public Models.Version NewVersion @@ -176,7 +181,7 @@ public void MoveTab(LauncherPage from, LauncherPage to) _activeWorkspace.Repositories.Clear(); foreach (var p in Pages) { - if (p.Data is Repository r) + if (p.RootRepository is { } r) _activeWorkspace.Repositories.Add(r.FullPath); } @@ -209,13 +214,15 @@ public void CloseTab(LauncherPage page) if (Pages.Count == 1) { var last = Pages[0]; - if (last.Data is Repository repo) + if (last.RootRepository is { } repo) { _activeWorkspace.Repositories.Clear(); _activeWorkspace.ActiveIdx = 0; if (last.Node.IsUnmanaged) last.Node.SaveMinimalInfo(repo.GitDir); + last.Nested?.Close(); + last.Nested = null; repo.Close(); Welcome.Instance.ClearSearchFilter(); @@ -301,17 +308,17 @@ public void OpenRepositoryInTab(string repo, LauncherPage page) public void OpenRepositoryInTab(RepositoryNode node, LauncherPage page) { - foreach (var one in Pages) + if (TryActivateOpenedRepository(node.Id)) + return; + + if (!Directory.Exists(node.Id)) { - if (one.Node.Id == node.Id) + if (!node.IsUnmanaged && ActivePage.CanCreatePopup()) { - ActivePage = one; + ActivePage.Popup = new DeleteRepositoryNode(node); return; } - } - if (!Directory.Exists(node.Id)) - { ActivePage.Notifications.Add(new Models.Notification { Group = node.Id, @@ -340,6 +347,7 @@ public void OpenRepositoryInTab(RepositoryNode node, LauncherPage page) var repo = new Repository(isBare, node.Id, gitDir); repo.Open(); + page?.Nested?.Close(); if (page == null) { if (_activePage == null || _activePage.Node.IsRepository) @@ -360,10 +368,12 @@ public void OpenRepositoryInTab(RepositoryNode node, LauncherPage page) page.Data = repo; } + page.Nested = NestedRepositories.TryCreate(page, repo); + _activeWorkspace.Repositories.Clear(); foreach (var p in Pages) { - if (p.Data is Repository r) + if (p.RootRepository is { } r) _activeWorkspace.Repositories.Add(r.FullPath); } @@ -378,14 +388,8 @@ public void OpenSubRepository(LauncherPage ownerPage, string fullpath) var normalizedPath = fullpath.Replace('\\', '/').TrimEnd('/'); // Check if the sub-repository is already open in any of the tabs - foreach (var one in Pages) - { - if (one.Node.Id.Equals(normalizedPath, StringComparison.Ordinal)) - { - ActivePage = one; - return; - } - } + if (TryActivateOpenedRepository(normalizedPath)) + return; // Make sure the target directory exists if (!Directory.Exists(normalizedPath)) @@ -433,6 +437,7 @@ public void OpenSubRepository(LauncherPage ownerPage, string fullpath) repo.Open(); var page = new LauncherPage(node, repo); + page.Nested = NestedRepositories.TryCreate(page, repo); var idxOfOwner = Pages.IndexOf(ownerPage); Pages.Insert(idxOfOwner + 1, page); _activeWorkspace.Repositories.Insert(idxOfOwner + 1, normalizedPath); @@ -461,6 +466,18 @@ private void DispatchNotification(Models.Notification notification) page.Notifications.Add(notification); return; } + + if (page.Nested is { } nested) + { + foreach (var repo in nested.AllRepositories) + { + if (repo.FullPath.Equals(notification.Group, StringComparison.OrdinalIgnoreCase)) + { + page.Notifications.Add(notification); + return; + } + } + } } _activePage?.Notifications.Add(notification); @@ -497,9 +514,33 @@ private string GetRepositoryGitDir(string repo) return new Commands.QueryGitDir(repo).GetResult(); } + private bool TryActivateOpenedRepository(string path) + { + var normalizedPath = path.Replace('\\', '/').TrimEnd('/'); + foreach (var one in Pages) + { + if (one.Node.Id.Replace('\\', '/').TrimEnd('/').Equals(normalizedPath, StringComparison.Ordinal)) + { + ActivePage = one; + return true; + } + } + + foreach (var one in Pages) + { + if (one.Nested != null && one.Nested.TrySelect(normalizedPath)) + { + ActivePage = one; + return true; + } + } + + return false; + } + private void CloseRepositoryInTab(LauncherPage page, bool removeFromWorkspace = true) { - if (page.Data is Repository repo) + if (page.RootRepository is { } repo) { if (removeFromWorkspace) _activeWorkspace.Repositories.Remove(repo.FullPath); @@ -507,6 +548,8 @@ private void CloseRepositoryInTab(LauncherPage page, bool removeFromWorkspace = if (page.Node.IsUnmanaged) page.Node.SaveMinimalInfo(repo.GitDir); + page.Nested?.Close(); + page.Nested = null; repo.Close(); } @@ -520,7 +563,7 @@ private void PostActivePageChanged() if (_ignoreIndexChange) return; - if (_activePage is { Data: Repository repo }) + if (_activePage?.RootRepository is { } repo) _activeWorkspace.ActiveIdx = _activeWorkspace.Repositories.IndexOf(repo.FullPath); var builder = new StringBuilder(512); diff --git a/src/ViewModels/LauncherPage.cs b/src/ViewModels/LauncherPage.cs index 370e5a25c7..478e792821 100644 --- a/src/ViewModels/LauncherPage.cs +++ b/src/ViewModels/LauncherPage.cs @@ -16,7 +16,30 @@ public RepositoryNode Node public object Data { get => _data; - set => SetProperty(ref _data, value); + set + { + if (SetProperty(ref _data, value)) + UpdateDirtyState(); + } + } + + public NestedRepositories Nested + { + get => _nested; + set + { + if (SetProperty(ref _nested, value)) + UpdateDirtyState(); + } + } + + /// + /// The repository this page was opened for. When the page has nested repositories, `Data` may be one of + /// them instead. + /// + public Repository RootRepository + { + get => _nested?.Root ?? _data as Repository; } public Models.DirtyState DirtyState @@ -57,17 +80,22 @@ public void ClearNotifications() Notifications.Clear(); } - public void ChangeDirtyState(Models.DirtyState flag, bool remove) + public bool Owns(Repository repo) + { + return _data == repo || (_nested != null && _nested.Contains(repo)); + } + + public void UpdateDirtyState() { - var state = _dirtyState; - if (remove) + var state = Models.DirtyState.None; + if (_nested != null) { - if (state.HasFlag(flag)) - state -= flag; + foreach (var repo in _nested.AllRepositories) + state |= repo.DirtyState; } - else + else if (_data is Repository repo) { - state |= flag; + state = repo.DirtyState; } DirtyState = state; @@ -75,7 +103,7 @@ public void ChangeDirtyState(Models.DirtyState flag, bool remove) public bool CanCreatePopup() { - return _popup is not { InProgress: true }; + return _popup is not { InProgress: true } && _nested is not { IsBusy: true }; } public async Task ProcessPopupAsync() @@ -124,6 +152,7 @@ public void TerminatePopup() private RepositoryNode _node = null; private object _data = null; + private NestedRepositories _nested = null; private Models.DirtyState _dirtyState = Models.DirtyState.None; private Popup _popup = null; } diff --git a/src/ViewModels/LauncherPagesCommandPalette.cs b/src/ViewModels/LauncherPagesCommandPalette.cs index 265aa07040..abcf0db2f4 100644 --- a/src/ViewModels/LauncherPagesCommandPalette.cs +++ b/src/ViewModels/LauncherPagesCommandPalette.cs @@ -1,9 +1,14 @@ using System; using System.Collections.Generic; +using System.ComponentModel; +using System.IO; +using System.Threading.Tasks; + +using Avalonia.Threading; namespace SourceGit.ViewModels { - public class LauncherPagesCommandPalette : ICommandPalette + public class LauncherPagesCommandPalette : ICommandPalette, IDisposable { public List VisiblePages { @@ -17,6 +22,16 @@ public List VisibleRepos private set => SetProperty(ref _visibleRepos, value); } + /// + /// Repositories on GitHub (`Models.GitHubRepository`) and Azure DevOps (`Models.AzureDevOpsRepository`) that + /// are not cloned yet. + /// + public List VisibleHostedRepos + { + get => _visibleHostedRepos; + private set => SetProperty(ref _visibleHostedRepos, value); + } + public string SearchFilter { get => _searchFilter; @@ -33,7 +48,10 @@ public LauncherPage SelectedPage set { if (SetProperty(ref _selectedPage, value) && value != null) + { SelectedRepo = null; + SelectedHostedRepo = null; + } } } @@ -43,7 +61,23 @@ public RepositoryNode SelectedRepo set { if (SetProperty(ref _selectedRepo, value) && value != null) + { SelectedPage = null; + SelectedHostedRepo = null; + } + } + } + + public object SelectedHostedRepo + { + get => _selectedHostedRepo; + set + { + if (SetProperty(ref _selectedHostedRepo, value) && value != null) + { + SelectedPage = null; + SelectedRepo = null; + } } } @@ -57,9 +91,54 @@ public LauncherPagesCommandPalette(Launcher launcher) _opened.Add(page.Node.Id); } + CollectManagedRepository(Preferences.Instance.RepositoryNodes); + + var cloneDir = Preferences.Instance.GetDefaultCloneDir(); + if (!string.IsNullOrEmpty(cloneDir) && Directory.Exists(cloneDir)) + { + if (cloneDir.Equals(s_scannedDir, StringComparison.Ordinal)) + SetDiscovered(s_scanned); + + ScanDefaultCloneDir(cloneDir); + } + + var github = GitHubAccount.Instance; + if (github.IsSignedIn) + { + github.PropertyChanged += OnHostedAccountPropertyChanged; + _ = github.RefreshAsync(false); + } + + var azureDevOps = AzureDevOpsAccount.Instance; + if (azureDevOps.IsSignedIn) + { + azureDevOps.PropertyChanged += OnHostedAccountPropertyChanged; + _ = azureDevOps.RefreshAsync(false); + } + + if (github.IsSignedIn || azureDevOps.IsSignedIn) + UpdateClonedHostedRepos(); + UpdateVisible(); } + public void Dispose() + { + GitHubAccount.Instance.PropertyChanged -= OnHostedAccountPropertyChanged; + AzureDevOpsAccount.Instance.PropertyChanged -= OnHostedAccountPropertyChanged; + } + + /// + /// Same scan as the palette runs over the default clone dir: every repository found below `dir` with the + /// repository owning its tab. + /// + public static List<(string Path, string Root)> ScanForRepositories(string dir) + { + var found = new List<(string Path, string Root)>(); + ScanDirectory(new DirectoryInfo(dir), found, 0); + return found; + } + public void ClearFilter() { SearchFilter = string.Empty; @@ -74,8 +153,15 @@ public void OpenOrSwitchTo() if (_selectedPage != null) _launcher.ActivePage = _selectedPage; + else if (_selectedHostedRepo != null) + CloneHosted(_selectedHostedRepo); + else if (_selectedRepo != null && _discoveredRoots.TryGetValue(_selectedRepo, out var root)) + OpenDiscovered(_selectedRepo.Id, root); else if (_selectedRepo != null) _launcher.OpenRepositoryInTab(_selectedRepo, null); + + _discovered.Clear(); + _discoveredRoots.Clear(); } private void UpdateVisible() @@ -85,9 +171,14 @@ private void UpdateVisible() var repos = new List(); CollectVisibleRepository(repos, Preferences.Instance.RepositoryNodes); + CollectVisibleRepository(repos, _discovered); + + var hostedRepos = new List(); + CollectVisibleHostedRepository(hostedRepos); var autoSelectPage = _selectedPage; var autoSelectRepo = _selectedRepo; + var autoSelectHostedRepo = _selectedHostedRepo != null && hostedRepos.Contains(_selectedHostedRepo) ? _selectedHostedRepo : null; if (_selectedPage != null) { @@ -145,10 +236,18 @@ private void UpdateVisible() autoSelectRepo = null; } + // Hosted repositories come last: only pick one when nothing local matches. + if (autoSelectPage != null || autoSelectRepo != null) + autoSelectHostedRepo = null; + else if (autoSelectHostedRepo == null && hostedRepos.Count > 0) + autoSelectHostedRepo = hostedRepos[0]; + VisiblePages = pages; VisibleRepos = repos; + VisibleHostedRepos = hostedRepos; SelectedPage = autoSelectPage; SelectedRepo = autoSelectRepo; + SelectedHostedRepo = autoSelectHostedRepo; } private void CollectVisiblePages(List pages) @@ -185,10 +284,249 @@ private void CollectVisibleRepository(List outs, List + /// GitHub and Azure DevOps repositories that are not cloned yet. Only listed while searching, so they do not + /// bury the tabs and local repositories. + /// + private void CollectVisibleHostedRepository(List outs) + { + if (string.IsNullOrEmpty(_searchFilter)) + return; + + if (GitHubAccount.Instance.IsSignedIn) + { + foreach (var repo in GitHubAccount.Instance.Repositories) + { + if (repo.IsArchived || s_clonedGitHubRepos.Contains(repo.FullName.ToLowerInvariant())) + continue; + + if (repo.FullName.Contains(_searchFilter, StringComparison.OrdinalIgnoreCase)) + outs.Add(repo); + } + } + + if (AzureDevOpsAccount.Instance.IsSignedIn) + { + foreach (var repo in AzureDevOpsAccount.Instance.Repositories) + { + if (s_clonedAzureDevOpsRepos.Contains(repo.FullName.ToLowerInvariant())) + continue; + + if (repo.FullName.Contains(_searchFilter, StringComparison.OrdinalIgnoreCase)) + outs.Add(repo); + } + } + } + + private void OnHostedAccountPropertyChanged(object sender, PropertyChangedEventArgs e) + { + // Both accounts name their repository list `Repositories`. + if (e.PropertyName == nameof(GitHubAccount.Repositories) && _launcher.CommandPalette == this) + UpdateVisible(); + } + + private void UpdateClonedHostedRepos() + { + var paths = new List(_managed); + foreach (var (path, _) in s_scanned) + paths.Add(path); + + Task.Run(() => + { + var github = Models.GitHub.CollectClonedFullNames(paths); + var azureDevOps = Models.AzureDevOps.CollectClonedFullNames(paths); + Dispatcher.UIThread.Post(() => + { + s_clonedGitHubRepos = github; + s_clonedAzureDevOpsRepos = azureDevOps; + if (_launcher.CommandPalette == this) + UpdateVisible(); + }); + }); + } + + private void CloneHosted(object repo) + { + if (!Preferences.Instance.IsGitConfigured()) + { + Models.Notification.Send(null, App.Text("NotConfigured"), true); + return; + } + + // Cloning replaces the page it runs on, so never start it on top of an open repository. + if (_launcher.ActivePage is not { Node.IsRepository: false } page || !page.CanCreatePopup()) + { + _launcher.AddNewTab(); + page = _launcher.ActivePage; + } + + // Only fill in the clone dialog, so the local location can still be changed before cloning. + var clone = new Clone(page.Node.Id); + if (repo is Models.GitHubRepository github) + clone.UseGitHubRepository(github); + else if (repo is Models.AzureDevOpsRepository azureDevOps) + clone.UseAzureDevOpsRepository(azureDevOps); + page.Popup = clone; + } + + private void CollectManagedRepository(List nodes) + { + foreach (var node in nodes) + { + if (node.IsRepository) + _managed.Add(node.Id); + else + CollectManagedRepository(node.SubNodes); + } + } + + private void ScanDefaultCloneDir(string dir) + { + if (s_scanning) + return; + + s_scanning = true; + Task.Run(() => + { + var found = ScanForRepositories(dir); + + Dispatcher.UIThread.Post(() => + { + s_scanning = false; + s_scannedDir = dir; + s_scanned = found; + + if (_launcher.CommandPalette == this) + { + SetDiscovered(found); + UpdateVisible(); + + if (GitHubAccount.Instance.IsSignedIn || AzureDevOpsAccount.Instance.IsSignedIn) + UpdateClonedHostedRepos(); + } + }); + }); + } + + /// + /// Mirrors the rules of `ScanRepositories`, but only checks for a `.git` folder instead of asking git so + /// it is cheap enough to run every time the palette opens. Repositories nested directly inside another + /// one are reported with the outer repository as their root, since that is the one owning their tab. + /// + private static void ScanDirectory(DirectoryInfo dir, List<(string Path, string Root)> outs, int depth) + { + try + { + var subdirs = dir.EnumerateDirectories("*", new EnumerationOptions() + { + AttributesToSkip = FileAttributes.Hidden | FileAttributes.System, + IgnoreInaccessible = true, + }); + + foreach (var subdir in subdirs) + { + if (subdir.Name.StartsWith('.') || subdir.Name.Equals("node_modules", StringComparison.Ordinal)) + continue; + + var normalized = subdir.FullName.Replace('\\', '/').TrimEnd('/'); + var gitDir = Path.Combine(subdir.FullName, ".git"); + if (Directory.Exists(gitDir)) + { + outs.Add((normalized, normalized)); + foreach (var nested in NestedRepositories.Scan(normalized)) + outs.Add((nested, normalized)); + } + else if (File.Exists(gitDir) || IsBareRepository(subdir.FullName)) + { + outs.Add((normalized, normalized)); + } + else if (depth < 5) + { + ScanDirectory(subdir, outs, depth + 1); + } + } + } + catch (Exception e) + { + Native.OS.LogException(e); + } + } + + private static bool IsBareRepository(string dir) + { + return File.Exists(Path.Combine(dir, "HEAD")) && + Directory.Exists(Path.Combine(dir, "objects")) && + Directory.Exists(Path.Combine(dir, "refs")); + } + + private void SetDiscovered(List<(string Path, string Root)> found) + { + var existing = new Dictionary(); + foreach (var node in _discovered) + existing[node.Id] = node; + + _discovered = []; + _discoveredRoots.Clear(); + + foreach (var (path, root) in found) + { + if (_managed.Contains(path)) + continue; + + // Keep the same node instances across rescans, so the current selection survives. + if (!existing.TryGetValue(path, out var node)) + { + var name = Path.GetFileName(path); + if (path != root) + name = $"{Path.GetFileName(root)}/{name}"; + + node = new RepositoryNode() + { + Id = path, + Name = name, + Bookmark = 0, + IsRepository = true, + IsUnmanaged = true, + }; + } + + _discovered.Add(node); + _discoveredRoots[node] = root; + } + } + + private void OpenDiscovered(string path, string root) + { + var node = Preferences.Instance.FindNode(root); + if (node == null) + { + var group = Preferences.Instance.FindOrCreateGroupByDefaultCloneDir(root); + node = Preferences.Instance.FindOrAddNodeByRepositoryPath(root, group, false); + Welcome.Instance.Refresh(); + _ = node.UpdateStatusAsync(false, null); + } + + _launcher.OpenRepositoryInTab(node, null); + + if (path != root) + _launcher.ActivePage?.Nested?.TrySelect(path); + } + + private static bool s_scanning = false; + private static string s_scannedDir = null; + private static List<(string Path, string Root)> s_scanned = []; + private static HashSet s_clonedGitHubRepos = []; + private static HashSet s_clonedAzureDevOpsRepos = []; + private Launcher _launcher = null; private HashSet _opened = new HashSet(); + private HashSet _managed = new HashSet(); + private List _discovered = []; + private Dictionary _discoveredRoots = new Dictionary(); private List _visiblePages = []; private List _visibleRepos = []; + private List _visibleHostedRepos = []; + private object _selectedHostedRepo = null; private string _searchFilter = string.Empty; private LauncherPage _selectedPage = null; private RepositoryNode _selectedRepo = null; diff --git a/src/ViewModels/LayoutInfo.cs b/src/ViewModels/LayoutInfo.cs index 43b58f5013..7c26516c7b 100644 --- a/src/ViewModels/LayoutInfo.cs +++ b/src/ViewModels/LayoutInfo.cs @@ -47,6 +47,12 @@ public double RepositorySearchCommitWidth set; } = 250; + public double NestedRepositoriesWidth + { + get => _nestedRepositoriesWidth; + set => SetProperty(ref _nestedRepositoriesWidth, value); + } + public bool IsSidebarCollapsedInLocalChanges { get => _isSidebarCollapsedInLocalChanges; @@ -71,6 +77,12 @@ public GridLength CommitDetailChangesLeftWidth set => SetProperty(ref _commitDetailChangesLeftWidth, value); } + public GridLength CommitDetailInfoHeight + { + get => _commitDetailInfoHeight; + set => SetProperty(ref _commitDetailInfoHeight, value); + } + public GridLength CommitDetailFilesLeftWidth { get => _commitDetailFilesLeftWidth; @@ -80,7 +92,9 @@ public GridLength CommitDetailFilesLeftWidth private GridLength _workingCopyLeftWidth = new GridLength(300, GridUnitType.Pixel); private GridLength _stashesLeftWidth = new GridLength(300, GridUnitType.Pixel); private GridLength _commitDetailChangesLeftWidth = new GridLength(256, GridUnitType.Pixel); + private GridLength _commitDetailInfoHeight = new GridLength(240, GridUnitType.Pixel); private GridLength _commitDetailFilesLeftWidth = new GridLength(256, GridUnitType.Pixel); + private double _nestedRepositoriesWidth = 220; private bool _isSidebarCollapsedInLocalChanges = false; } } diff --git a/src/ViewModels/NestedRepositories.cs b/src/ViewModels/NestedRepositories.cs new file mode 100644 index 0000000000..0454762249 --- /dev/null +++ b/src/ViewModels/NestedRepositories.cs @@ -0,0 +1,676 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +using Avalonia.Collections; + +using CommunityToolkit.Mvvm.ComponentModel; + +namespace SourceGit.ViewModels +{ + public class NestedRepository + { + public string Name { get; } + public bool IsRoot { get; } + public Repository Repo { get; } + + public NestedRepository(string name, bool isRoot, Repository repo) + { + Name = name; + IsRoot = isRoot; + Repo = repo; + } + } + + /// + /// A set of linked worktrees of the nested repositories that belong together: the worktrees laid out as + /// `/` share the `` folder, any other worktree is a group of its own. The + /// repositories of a group are opened the first time it is selected. + /// + public class NestedWorktree : ObservableObject + { + public string Key { get; } + public string Name { get; } + public bool IsAll { get; } + public AvaloniaList Items { get; } = []; + public NestedRepository LastSelected { get; set; } + + public string Branch + { + get => _branch; + private set => SetProperty(ref _branch, value); + } + + public int Count + { + get => IsAll ? Items.Count : _members.Count; + } + + public NestedWorktree(string key, string name, bool isAll) + { + Key = key; + Name = name; + IsAll = isAll; + + if (isAll) + Items.CollectionChanged += (_, _) => OnPropertyChanged(nameof(Count)); + } + + public void SetMembers(List members) + { + _members = members; + + var branch = members.Count > 0 ? members[0].Branch : string.Empty; + foreach (var m in members) + { + if (!m.Branch.Equals(branch, StringComparison.Ordinal)) + branch = string.Empty; + } + + Branch = branch; + OnPropertyChanged(nameof(Count)); + if (_isOpened) + SyncItems(); + } + + public void Open() + { + // The items of the group with all repositories are maintained by `NestedRepositories` itself. + if (IsAll || _isOpened) + return; + + _isOpened = true; + SyncItems(); + } + + public void Close() + { + foreach (var item in Items) + item.Repo.Close(); + + Items.Clear(); + LastSelected = null; + } + + private void SyncItems() + { + // The worktrees are read again on every branch change, so leave the list alone when nothing moved. + if (Items.Count == _members.Count) + { + var same = true; + for (var i = 0; i < Items.Count && same; i++) + same = Items[i].Repo.FullPath.Equals(_members[i].Path, StringComparison.Ordinal); + + if (same) + return; + } + + var existing = new Dictionary(); + foreach (var item in Items) + existing.Add(item.Repo.FullPath, item); + + Items.Clear(); + foreach (var m in _members) + { + if (existing.Remove(m.Path, out var item)) + { + Items.Add(item); + continue; + } + + var gitDir = NestedRepositories.GetWorktreeGitDir(m.Path); + if (string.IsNullOrEmpty(gitDir)) + continue; + + var repo = new Repository(false, m.Path, gitDir) { IsBackground = true }; + repo.Open(); + Items.Add(new NestedRepository(m.Name, false, repo)); + } + + foreach (var kv in existing) + { + if (LastSelected == kv.Value) + LastSelected = null; + + kv.Value.Repo.Close(); + } + } + + public record Member(string Name, string Path, string Branch); + + private List _members = []; + private bool _isOpened = false; + private string _branch = string.Empty; + } + + /// + /// Independent git repositories living directly inside the root repository's folder (typically ignored by + /// the root repository). All of them are shown in the same page and share its tab. + /// + public class NestedRepositories : ObservableObject + { + public Repository Root + { + get => _root.Repo; + } + + /// + /// The repositories shown in the list: all nested repositories, or those of the selected worktree. + /// + public AvaloniaList Items + { + get => _worktree.Items; + } + + public NestedRepository Selected + { + get => _selected; + set + { + if (value == null || !SetProperty(ref _selected, value)) + return; + + foreach (var repo in AllRepositories) + repo.IsBackground = repo != value.Repo; + + _worktree.LastSelected = value; + _pendingWorktree = null; + _root.Repo.UIStates.SelectedNestedRepository = value.IsRoot ? string.Empty : value.Name; + _page.Data = value.Repo; + } + } + + /// + /// The first item shows all nested repositories, the others are the worktrees found in them. + /// + public AvaloniaList Worktrees + { + get; + } = []; + + public NestedWorktree SelectedWorktree + { + get => _worktree; + set + { + if (value == null || !SetProperty(ref _worktree, value)) + return; + + value.Open(); + _root.Repo.UIStates.SelectedNestedWorktree = value.IsAll ? string.Empty : value.Key; + OnPropertyChanged(nameof(Items)); + + if (value.Items.Count == 0) + { + SelectedWorktree = _all; + return; + } + + // Keep the same repository when it is part of the worktree too. + var next = value.LastSelected; + if (next == null && _selected != null) + { + foreach (var item in value.Items) + { + if (item.Name.Equals(_selected.Name, StringComparison.Ordinal)) + next = item; + } + } + + Selected = next ?? value.Items[0]; + } + } + + public bool HasWorktrees + { + get => _hasWorktrees; + private set => SetProperty(ref _hasWorktrees, value); + } + + /// + /// Every repository opened by this page, including the worktrees' ones. + /// + public IEnumerable AllRepositories + { + get + { + foreach (var wt in Worktrees) + { + foreach (var item in wt.Items) + yield return item.Repo; + } + } + } + + public bool IsBusy + { + get => _isBusy; + private set => SetProperty(ref _isBusy, value); + } + + public string BusyDescription + { + get => _busyDescription; + private set => SetProperty(ref _busyDescription, value); + } + + public static NestedRepositories TryCreate(LauncherPage page, Repository root) + { + if (root.IsBare) + return null; + + var paths = Scan(root.FullPath); + if (paths.Count == 0) + return null; + + var nested = new NestedRepositories(page, root); + nested.Sync(paths); + + var last = root.UIStates.SelectedNestedRepository; + nested.Selected = nested._root; + if (!string.IsNullOrEmpty(last)) + { + foreach (var item in nested.Items) + { + if (!item.IsRoot && item.Name.Equals(last, StringComparison.Ordinal)) + nested.Selected = item; + } + } + + // The worktrees are read in the background, so the last selected one is restored once it shows up. + var lastWorktree = root.UIStates.SelectedNestedWorktree; + if (!string.IsNullOrEmpty(lastWorktree)) + nested._pendingWorktree = lastWorktree; + + return nested; + } + + public bool Contains(Repository repo) + { + foreach (var r in AllRepositories) + { + if (r == repo) + return true; + } + + return false; + } + + public bool TrySelect(string fullpath) + { + foreach (var wt in Worktrees) + { + foreach (var item in wt.Items) + { + if (item.Repo.FullPath.Equals(fullpath, StringComparison.Ordinal)) + { + SelectedWorktree = wt; + Selected = item; + return true; + } + } + } + + return false; + } + + public void SelectAdjacent(int delta) + { + if (Items.Count < 2) + return; + + var idx = Items.IndexOf(_selected); + var next = Math.Clamp(idx + delta, 0, Items.Count - 1); + if (next != idx) + Selected = Items[next]; + } + + public void Rescan() + { + Sync(Scan(_root.Repo.FullPath)); + } + + public void RefreshAll() + { + Rescan(); + + // The nested repositories are always refreshed, as their worktrees make up the worktree list. + foreach (var item in _all.Items) + item.Repo.RefreshAll(); + + if (!_worktree.IsAll) + { + foreach (var item in _worktree.Items) + item.Repo.RefreshAll(); + } + } + + public Task FetchAllAsync() + { + return RunAllAsync(App.Text("Fetch"), repo => repo.Remotes.Count > 0 ? new Fetch(repo) : null); + } + + public Task PullAllAsync() + { + return RunAllAsync(App.Text("Pull"), repo => + { + if (repo.IsBare || repo.Remotes.Count == 0 || !HasValidUpstream(repo.CurrentBranch)) + return null; + + return new Pull(repo, null); + }); + } + + public Task PushAllAsync() + { + return RunAllAsync(App.Text("Push"), repo => + { + if (repo.IsBare || repo.Remotes.Count == 0 || !HasValidUpstream(repo.CurrentBranch) || repo.CurrentBranch.Ahead.Count == 0) + return null; + + return new Push(repo, null); + }); + } + + /// + /// Closes all nested repositories except the root one, which is owned by the launcher. + /// + public void Close() + { + foreach (var item in _all.Items) + { + item.Repo.PropertyChanged -= OnRepositoryPropertyChanged; + if (!item.IsRoot) + item.Repo.Close(); + } + + _all.Items.Clear(); + + foreach (var wt in Worktrees) + { + if (!wt.IsAll) + wt.Close(); + } + + Worktrees.Clear(); + } + + private NestedRepositories(LauncherPage page, Repository root) + { + _page = page; + _root = new NestedRepository(Path.GetFileName(root.FullPath), true, root); + _all = new NestedWorktree(string.Empty, App.Text("NestedRepos.AllRepositories"), true); + _all.Items.Add(_root); + _worktree = _all; + Worktrees.Add(_all); + root.PropertyChanged += OnRepositoryPropertyChanged; + } + + public static List Scan(string root) + { + var paths = new List(); + + try + { + foreach (var dir in new DirectoryInfo(root).EnumerateDirectories()) + { + if (dir.Name.StartsWith('.')) + continue; + + // Only folders with their own `.git` directory are independent repositories. A `.git` file + // means a submodule or a linked worktree, which are handled elsewhere. + var gitDir = Path.Combine(dir.FullName, ".git"); + if (Directory.Exists(Path.Combine(gitDir, "refs")) && + Directory.Exists(Path.Combine(gitDir, "objects")) && + File.Exists(Path.Combine(gitDir, "HEAD"))) + paths.Add(dir.FullName.Replace('\\', '/').TrimEnd('/')); + } + } + catch (Exception e) + { + Native.OS.LogException(e); + } + + paths.Sort((l, r) => Models.NumericSort.Compare(Path.GetFileName(l), Path.GetFileName(r))); + return paths; + } + + /// + /// Resolves the git dir of a linked worktree from the `gitdir: ` line in its `.git` file. + /// + public static string GetWorktreeGitDir(string path) + { + try + { + var file = Path.Combine(path, ".git"); + if (!File.Exists(file)) + return null; + + var redirect = File.ReadAllText(file).Trim(); + if (!redirect.StartsWith("gitdir: ", StringComparison.Ordinal)) + return null; + + redirect = redirect.Substring(8).Trim(); + if (!Path.IsPathRooted(redirect)) + redirect = Path.GetFullPath(Path.Combine(path, redirect)); + + return Directory.Exists(redirect) ? redirect : null; + } + catch (Exception e) + { + Native.OS.LogException(e); + return null; + } + } + + private static bool HasValidUpstream(Models.Branch branch) + { + return branch is { IsDetachedHead: false, IsUpstreamGone: false } && !string.IsNullOrEmpty(branch.Upstream); + } + + private void Sync(List paths) + { + var items = _all.Items; + var existing = new Dictionary(); + for (var i = items.Count - 1; i >= 1; i--) + { + var item = items[i]; + if (paths.Contains(item.Repo.FullPath)) + { + existing.Add(item.Repo.FullPath, item); + } + else + { + if (_selected == item) + Selected = _root; + if (_all.LastSelected == item) + _all.LastSelected = null; + + item.Repo.PropertyChanged -= OnRepositoryPropertyChanged; + item.Repo.Close(); + } + + items.RemoveAt(i); + } + + foreach (var path in paths) + { + if (!existing.TryGetValue(path, out var item)) + { + var repo = new Repository(false, path, $"{path}/.git") { IsBackground = true }; + repo.PropertyChanged += OnRepositoryPropertyChanged; + repo.Open(); + item = new NestedRepository(Path.GetFileName(path), false, repo); + } + + items.Add(item); + } + + SyncWorktrees(); + } + + private void OnRepositoryPropertyChanged(object sender, PropertyChangedEventArgs e) + { + if (e.PropertyName == nameof(Repository.Worktrees)) + SyncWorktrees(); + } + + /// + /// Rebuilds the worktree groups from the linked worktrees of the nested repositories. + /// + private void SyncWorktrees() + { + var groups = new Dictionary>(); + foreach (var item in _all.Items) + { + var repoName = Path.GetFileName(item.Repo.FullPath); + foreach (var wt in item.Repo.Worktrees) + { + if (wt.IsMain || wt.IsCurrent || wt.Backend.IsBare) + continue; + + var path = wt.FullPath.Replace('\\', '/').TrimEnd('/'); + if (!Directory.Exists(path)) + continue; + + var parent = Path.GetDirectoryName(path)?.Replace('\\', '/'); + var key = Path.GetFileName(path).Equals(repoName, StringComparison.Ordinal) && !string.IsNullOrEmpty(parent) ? parent : path; + if (!groups.TryGetValue(key, out var members)) + { + members = []; + groups.Add(key, members); + } + + members.Add(new NestedWorktree.Member(item.Name, path, wt.Branch)); + } + } + + for (var i = Worktrees.Count - 1; i >= 1; i--) + { + var wt = Worktrees[i]; + if (groups.Remove(wt.Key, out var members)) + { + wt.SetMembers(members); + if (wt == _worktree && wt.Items.Count == 0) + SelectedWorktree = _all; + else if (wt == _worktree && _selected != null && !wt.Items.Contains(_selected)) + Selected = wt.Items[0]; + continue; + } + + if (wt == _worktree) + SelectedWorktree = _all; + + Worktrees.RemoveAt(i); + wt.Close(); + } + + foreach (var kv in groups) + { + var wt = new NestedWorktree(kv.Key, Path.GetFileName(kv.Key), false); + wt.SetMembers(kv.Value); + + var idx = 1; + while (idx < Worktrees.Count && Models.NumericSort.Compare(Worktrees[idx].Name, wt.Name) < 0) + idx++; + Worktrees.Insert(idx, wt); + } + + HasWorktrees = Worktrees.Count > 1; + + if (!string.IsNullOrEmpty(_pendingWorktree)) + { + foreach (var wt in Worktrees) + { + if (wt.Key.Equals(_pendingWorktree, StringComparison.Ordinal)) + { + _pendingWorktree = null; + var name = _root.Repo.UIStates.SelectedNestedRepository; + SelectedWorktree = wt; + foreach (var item in wt.Items) + { + if (item.Name.Equals(name, StringComparison.Ordinal)) + Selected = item; + } + + break; + } + } + } + } + + private async Task RunAllAsync(string action, Func factory) + { + if (_isBusy || !_page.CanCreatePopup()) + return; + + var jobs = new List(); + var skipped = 0; + foreach (var item in Items) + { + item.Repo.CancelAutoFetch(); + + var job = factory(item.Repo); + if (job == null) + skipped++; + else + jobs.Add(job); + } + + var finished = 0; + var failed = 0; + IsBusy = true; + BusyDescription = $"{action} 0/{jobs.Count}"; + + // Everything runs on the UI thread, the git processes themselves run concurrently. + using var limiter = new SemaphoreSlim(MaxConcurrentJobs); + var tasks = new List(); + foreach (var job in jobs) + tasks.Add(RunJobAsync(job)); + + async Task RunJobAsync(Popup job) + { + await limiter.WaitAsync(); + + try + { + if (!job.Check() || !await job.Sure()) + failed++; + } + catch (Exception e) + { + Native.OS.LogException(e); + failed++; + } + finally + { + limiter.Release(); + job.Cleanup(); + finished++; + BusyDescription = $"{action} {finished}/{jobs.Count}"; + } + } + + await Task.WhenAll(tasks); + + IsBusy = false; + BusyDescription = string.Empty; + Models.Notification.Send(_root.Repo.FullPath, App.Text("NestedRepos.Summary", action, jobs.Count - failed, failed, skipped), failed > 0); + } + + private const int MaxConcurrentJobs = 4; + + private readonly LauncherPage _page; + private readonly NestedRepository _root; + private readonly NestedWorktree _all; + private NestedWorktree _worktree; + private NestedRepository _selected = null; + private string _pendingWorktree = null; + private bool _hasWorktrees = false; + private bool _isBusy = false; + private string _busyDescription = string.Empty; + } +} diff --git a/src/ViewModels/OpenLocalRepository.cs b/src/ViewModels/OpenLocalRepository.cs index 732c5c8acf..67693906a4 100644 --- a/src/ViewModels/OpenLocalRepository.cs +++ b/src/ViewModels/OpenLocalRepository.cs @@ -55,22 +55,7 @@ public override async Task Sure() RepositoryNode parent = null; if (_selectedGroupIndex == 0) // Auto (Based-on Default Clone Dir) { - var activeWorkspace = Preferences.Instance.GetActiveWorkspace(); - var defaultCloneDir = activeWorkspace?.DefaultCloneDir; - if (string.IsNullOrEmpty(defaultCloneDir)) - defaultCloneDir = Preferences.Instance.GitDefaultCloneDir; - - if (!string.IsNullOrEmpty(defaultCloneDir)) - { - var normalizedParentFolder = new DirectoryInfo(RepoPath).Parent!.FullName.Replace('\\', '/').TrimEnd('/') + "/"; - var normalizedDefaultCloneDir = defaultCloneDir.Replace('\\', '/').TrimEnd('/') + "/"; - if (normalizedParentFolder.Length > normalizedDefaultCloneDir.Length && - normalizedParentFolder.StartsWith(normalizedDefaultCloneDir, StringComparison.Ordinal)) - { - var relativePath = normalizedParentFolder.Substring(normalizedDefaultCloneDir.Length); - parent = Preferences.Instance.FindOrCreateGroupRecursive(relativePath.TrimEnd('/')); - } - } + parent = Preferences.Instance.FindOrCreateGroupByDefaultCloneDir(RepoPath); } else if (_selectedGroupIndex > 1 && _selectedGroupIndex < Groups.Count) // Existing group { diff --git a/src/ViewModels/Preferences.cs b/src/ViewModels/Preferences.cs index 4803ec4296..9b7512e34e 100644 --- a/src/ViewModels/Preferences.cs +++ b/src/ViewModels/Preferences.cs @@ -26,21 +26,12 @@ public static Preferences Instance _instance.PrepareShellOrTerminal(); _instance.PrepareExternalDiffMergeTool(); _instance.PrepareWorkspaces(); + Models.Shortcuts.Load(_instance.CustomShortcuts); return _instance; } } - public string Locale - { - get => _locale; - set - { - if (SetProperty(ref _locale, value) && !_isLoading) - App.SetLocale(value); - } - } - public string Theme { get => _theme; @@ -123,12 +114,6 @@ public bool ShowLocalChangesByDefault set; } = false; - public bool ShowChangesInCommitDetailByDefault - { - get; - set; - } = false; - public int MaxHistoryCommits { get => _maxHistoryCommits; @@ -326,6 +311,42 @@ public string GitDefaultCloneDir set => SetProperty(ref _gitDefaultCloneDir, value); } + public string GitHubLogin + { + get; + set; + } = string.Empty; + + public bool GitHubPreferSSH + { + get; + set; + } = false; + + public bool GitHubUseForGit + { + get; + set; + } = true; + + public string AzureDevOpsLogin + { + get; + set; + } = string.Empty; + + public bool AzureDevOpsPreferSSH + { + get; + set; + } = false; + + public bool AzureDevOpsUseForGit + { + get; + set; + } = true; + public bool UseLibsecretInsteadOfGCM { get => Native.OS.CredentialHelper.Equals("libsecret", StringComparison.Ordinal); @@ -456,6 +477,12 @@ public List Workspaces set; } = []; + public Dictionary CustomShortcuts + { + get; + set; + } = new(); + public AvaloniaList CustomActions { get; @@ -468,12 +495,6 @@ public AvaloniaList OpenAIServices set; } = []; - public double LastCheckUpdateTime - { - get => _lastCheckUpdateTime; - set => SetProperty(ref _lastCheckUpdateTime, value); - } - public void SetCanModify() { _isReadonly = false; @@ -485,21 +506,6 @@ public bool IsGitConfigured() return !string.IsNullOrEmpty(path) && File.Exists(path); } - public bool ShouldCheck4UpdateOnStartup() - { - if (!_check4UpdatesOnStartup) - return false; - - var lastCheck = DateTime.UnixEpoch.AddSeconds(LastCheckUpdateTime).ToLocalTime(); - var now = DateTime.Now; - - if (lastCheck.Year == now.Year && lastCheck.Month == now.Month && lastCheck.Day == now.Day) - return false; - - LastCheckUpdateTime = now.Subtract(DateTime.UnixEpoch.ToLocalTime()).TotalSeconds; - return true; - } - public Workspace GetActiveWorkspace() { foreach (var w in Workspaces) @@ -539,6 +545,32 @@ public RepositoryNode FindNode(string id) return FindNodeRecursive(id, RepositoryNodes); } + public string GetDefaultCloneDir() + { + var dir = GetActiveWorkspace().DefaultCloneDir; + return string.IsNullOrEmpty(dir) ? GitDefaultCloneDir : dir; + } + + /// + /// Finds or creates the group mirroring the folders between the default clone dir and the given repository. + /// Returns null when the repository lives directly in, or outside of, the default clone dir. + /// + public RepositoryNode FindOrCreateGroupByDefaultCloneDir(string repo) + { + var defaultCloneDir = GetDefaultCloneDir(); + if (string.IsNullOrEmpty(defaultCloneDir)) + return null; + + var normalizedParentFolder = new DirectoryInfo(repo).Parent!.FullName.Replace('\\', '/').TrimEnd('/') + "/"; + var normalizedDefaultCloneDir = defaultCloneDir.Replace('\\', '/').TrimEnd('/') + "/"; + if (normalizedParentFolder.Length <= normalizedDefaultCloneDir.Length || + !normalizedParentFolder.StartsWith(normalizedDefaultCloneDir, StringComparison.Ordinal)) + return null; + + var relativePath = normalizedParentFolder.Substring(normalizedDefaultCloneDir.Length); + return FindOrCreateGroupRecursive(relativePath.TrimEnd('/')); + } + public RepositoryNode FindOrCreateGroupRecursive(string path) { List collection = RepositoryNodes; @@ -807,7 +839,6 @@ private bool RemoveInvalidRepositoriesRecursive(List collection) private bool _isLoading = true; private bool _isReadonly = true; - private string _locale = "en_US"; private string _theme = "Default"; private string _themeOverrides = string.Empty; private string _defaultFontFamily = string.Empty; @@ -826,7 +857,6 @@ private bool RemoveInvalidRepositoriesRecursive(List collection) private bool _useCompactBranchNamesInGraph = true; private bool _check4UpdatesOnStartup = true; - private double _lastCheckUpdateTime = 0; private string _ignoreUpdateTag = string.Empty; private bool _showTagsInGraph = true; diff --git a/src/ViewModels/Repository.cs b/src/ViewModels/Repository.cs index 732f064814..a9d16984a1 100644 --- a/src/ViewModels/Repository.cs +++ b/src/ViewModels/Repository.cs @@ -241,6 +241,29 @@ public int LocalChangesCount private set => SetProperty(ref _localChangesCount, value); } + public Models.DirtyState DirtyState + { + get => _dirtyState; + private set => SetProperty(ref _dirtyState, value); + } + + public bool IsBackground + { + get => _isBackground; + set + { + if (_isBackground == value) + return; + + _isBackground = value; + if (!value && _isCommitsRefreshPending) + { + _isCommitsRefreshPending = false; + RefreshCommits(); + } + } + } + public int StashesCount { get => _stashesCount; @@ -476,6 +499,7 @@ public void Close() _watcher?.Dispose(); _autoFetchTimer.Dispose(); + CancelAutoFetch(); } public void SendNotification(string message, bool isError = false) @@ -486,10 +510,17 @@ public void SendNotification(string message, bool isError = false) public bool CanCreatePopup() { var page = GetOwnerPage(); - if (page == null) + if (page == null || !page.CanCreatePopup()) return false; - return !_isAutoFetching && page.CanCreatePopup(); + // What the user asks for comes before a background fetch, which may also hang on a stalled connection. + CancelAutoFetch(); + return true; + } + + public void CancelAutoFetch() + { + _autoFetchCancellation?.Cancel(); } public void ShowPopup(Popup popup) @@ -1145,7 +1176,7 @@ public void RefreshBranches() _workingCopy.HasRemotes = remotes.Count > 0; var hasPendingPullOrPush = CurrentBranch?.IsTrackStatusVisible ?? false; - GetOwnerPage()?.ChangeDirtyState(Models.DirtyState.HasPendingPullOrPush, !hasPendingPullOrPush); + ChangeDirtyState(Models.DirtyState.HasPendingPullOrPush, !hasPendingPullOrPush); }); }, token); } @@ -1185,6 +1216,14 @@ public void RefreshTags() public void RefreshCommits() { + // Repositories in the background of a page (nested repositories that are not shown) do not need the + // commit graph. It will be loaded once the repository becomes visible. + if (_isBackground) + { + _isCommitsRefreshPending = true; + return; + } + if (_cancellationRefreshCommits is { IsCancellationRequested: false }) _cancellationRefreshCommits.Cancel(); @@ -1322,7 +1361,7 @@ public void RefreshWorkingCopyChanges() _workingCopy.SetData(changes); LocalChangesCount = changes.Count; OnPropertyChanged(nameof(InProgressContext)); - GetOwnerPage()?.ChangeDirtyState(Models.DirtyState.HasLocalChanges, changes.Count == 0); + ChangeDirtyState(Models.DirtyState.HasLocalChanges, changes.Count == 0); }); }, token); } @@ -1630,13 +1669,30 @@ private LauncherPage GetOwnerPage() foreach (var page in launcher.Pages) { - if (page.Node.Id.Equals(FullPath)) + if (page.Owns(this)) return page; } return null; } + private void ChangeDirtyState(Models.DirtyState flag, bool remove) + { + var state = _dirtyState; + if (remove) + { + if (state.HasFlag(flag)) + state -= flag; + } + else + { + state |= flag; + } + + DirtyState = state; + GetOwnerPage()?.UpdateDirtyState(); + } + private BranchTreeNode.Builder BuildBranchTree(List branches, List remotes, bool validateExpandedNodes = true) { var builder = new BranchTreeNode.Builder(_uiStates.LocalBranchSortMode, _uiStates.RemoteBranchSortMode); @@ -1899,9 +1955,15 @@ private async Task AutoFetchOnUIThread() IsAutoFetching = true; log = CreateLog("Auto-Fetch"); + _autoFetchCancellation = new CancellationTokenSource(AutoFetchTimeout); foreach (var remote in remotes) - await new Commands.Fetch(FullPath, remote).Use(log).ExecAsync(); + { + if (_autoFetchCancellation.IsCancellationRequested) + break; + + await new Commands.Fetch(FullPath, remote) { CancellationToken = _autoFetchCancellation.Token }.Use(log).ExecAsync(); + } _lastFetchTime = DateTime.Now; } @@ -1910,6 +1972,8 @@ private async Task AutoFetchOnUIThread() // Ignore all exceptions. } + _autoFetchCancellation?.Dispose(); + _autoFetchCancellation = null; IsAutoFetching = false; log?.Complete(); } @@ -1930,6 +1994,9 @@ private async Task AutoFetchOnUIThread() private int _localBranchesCount = 0; private int _localChangesCount = 0; private int _stashesCount = 0; + private Models.DirtyState _dirtyState = Models.DirtyState.None; + private bool _isBackground = false; + private bool _isCommitsRefreshPending = false; private string _filter = string.Empty; private List _remotes = []; @@ -1944,7 +2011,10 @@ private async Task AutoFetchOnUIThread() private object _visibleSubmodules = null; private string _navigateToCommitDelayed = string.Empty; + private static readonly TimeSpan AutoFetchTimeout = TimeSpan.FromMinutes(3); + private bool _isAutoFetching = false; + private CancellationTokenSource _autoFetchCancellation = null; private Timer _autoFetchTimer = null; private DateTime _lastFetchTime = DateTime.MinValue; diff --git a/src/ViewModels/RepositoryNode.cs b/src/ViewModels/RepositoryNode.cs index 9d7ab9debc..5cf1ebb383 100644 --- a/src/ViewModels/RepositoryNode.cs +++ b/src/ViewModels/RepositoryNode.cs @@ -95,9 +95,12 @@ public void Open() if (!_isRepository) { foreach (var subNode in SubNodes) - subNode.Open(); + { + if (!subNode.IsInvalid) + subNode.Open(); + } } - else if (Directory.Exists(_id)) + else { App.GetLauncher().OpenRepositoryInTab(this, null); } diff --git a/src/Views/About.axaml b/src/Views/About.axaml index 265c601968..25ae73898c 100644 --- a/src/Views/About.axaml +++ b/src/Views/About.axaml @@ -65,7 +65,7 @@ - diff --git a/src/Views/About.axaml.cs b/src/Views/About.axaml.cs index 842022cf79..73714b3096 100644 --- a/src/Views/About.axaml.cs +++ b/src/Views/About.axaml.cs @@ -32,7 +32,7 @@ public About() { var ver = assembly.GetName().Version; if (ver != null) - TxtVersion.Text = $"v{ver.Major}.{ver.Minor:D2}"; + TxtVersion.Text = ver.Build > 0 ? $"v{ver.Major}.{ver.Minor:D2}.{ver.Build}" : $"v{ver.Major}.{ver.Minor:D2}"; } var copyright = assembly.GetCustomAttribute(); @@ -47,7 +47,7 @@ private void OnVisitReleaseNotes(object _, RoutedEventArgs e) if (endOfTagIdx > 0) ver = ver.Substring(0, endOfTagIdx); - Native.OS.OpenBrowser($"https://github.com/sourcegit-scm/sourcegit/releases/tag/{ver}"); + Native.OS.OpenBrowser($"https://github.com/holion/sourcegit/releases/tag/{ver}"); e.Handled = true; } @@ -59,11 +59,11 @@ private void OnVisitWebsite(object _, RoutedEventArgs e) private void OnVisitSourceCode(object _, RoutedEventArgs e) { - Native.OS.OpenBrowser("https://github.com/sourcegit-scm/sourcegit"); + Native.OS.OpenBrowser("https://github.com/holion/sourcegit"); e.Handled = true; } - [GeneratedRegex(@"^v\d{4}\.\d{1,2}(?:\-\d+\-[0-9a-f]{8})?(?:\-dirty)?$")] + [GeneratedRegex(@"^v\d{4}\.\d{1,2}(?:\.\d+)?(?:\-\d+\-[0-9a-f]{8})?(?:\-dirty)?$")] private static partial Regex REG_FRIENDLY_VERSION(); } } diff --git a/src/Views/AzureDevOpsRepositoryPicker.axaml b/src/Views/AzureDevOpsRepositoryPicker.axaml new file mode 100644 index 0000000000..a249174dac --- /dev/null +++ b/src/Views/AzureDevOpsRepositoryPicker.axaml @@ -0,0 +1,215 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -83,31 +99,42 @@ - + + + + + - - - - - - - - diff --git a/src/Views/Clone.axaml.cs b/src/Views/Clone.axaml.cs index f7791161c3..f26d906d49 100644 --- a/src/Views/Clone.axaml.cs +++ b/src/Views/Clone.axaml.cs @@ -22,8 +22,9 @@ protected override async void OnLoaded(RoutedEventArgs e) if (DataContext is not ViewModels.Clone vm) return; + // Keep a URL that was filled in before showing the dialog (e.g. a repository picked from GitHub or Azure DevOps). var clipboard = TopLevel.GetTopLevel(this)?.Clipboard; - if (clipboard != null) + if (clipboard != null && string.IsNullOrEmpty(vm.Remote)) { try { @@ -67,6 +68,24 @@ private async void SelectParentFolder(object _, RoutedEventArgs e) e.Handled = true; } + private async void SelectGitHubRepository(object _, RoutedEventArgs e) + { + e.Handled = true; + + var repo = await GitHubRepositoryPicker.ShowAsync(this); + if (repo != null && DataContext is ViewModels.Clone vm) + vm.UseGitHubRepository(repo); + } + + private async void SelectAzureDevOpsRepository(object _, RoutedEventArgs e) + { + e.Handled = true; + + var repo = await AzureDevOpsRepositoryPicker.ShowAsync(this); + if (repo != null && DataContext is ViewModels.Clone vm) + vm.UseAzureDevOpsRepository(repo); + } + private async void SelectSSHKey(object _, RoutedEventArgs e) { var toplevel = TopLevel.GetTopLevel(this); diff --git a/src/Views/CommitBaseInfo.axaml b/src/Views/CommitBaseInfo.axaml index c8544db7f6..d4d0a6ed90 100644 --- a/src/Views/CommitBaseInfo.axaml +++ b/src/Views/CommitBaseInfo.axaml @@ -9,15 +9,50 @@ mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" x:Class="SourceGit.Views.CommitBaseInfo" x:Name="ThisControl"> + + + + + + + + + + + + + - + - - - + + + @@ -35,9 +70,9 @@ - - - + + + @@ -59,23 +94,25 @@ - + + + - - + + - + - - - + @@ -95,7 +132,7 @@ - + diff --git a/src/Views/CommitChanges.axaml b/src/Views/CommitChanges.axaml index 6fcdad2815..e8801bf7b2 100644 --- a/src/Views/CommitChanges.axaml +++ b/src/Views/CommitChanges.axaml @@ -14,64 +14,89 @@ - - - - - - - + + + + + + - - - - + + + + - - + + + + + + + + + + + + + + - - - - + + + + + + + + - - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Views/CommitDetail.axaml.cs b/src/Views/CommitDetail.axaml.cs index dd175eadd8..382a92c971 100644 --- a/src/Views/CommitDetail.axaml.cs +++ b/src/Views/CommitDetail.axaml.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.IO; using Avalonia; @@ -310,53 +309,6 @@ private void OnTabHeaderPointerPressed(object sender, PointerPressedEventArgs e) vm.IsCollapseDetails = false; } - private async void OnCommitListKeyDown(object sender, KeyEventArgs e) - { - if (DataContext is not ViewModels.CommitDetail vm) - return; - - if (sender is not ListBox { SelectedItem: Models.Change change }) - return; - - if (e.Key == Key.C && - e.KeyModifiers.HasFlag(OperatingSystem.IsMacOS() ? KeyModifiers.Meta : KeyModifiers.Control)) - { - if (e.KeyModifiers.HasFlag(KeyModifiers.Shift)) - await this.CopyTextAsync(vm.GetAbsPath(change.Path)); - else - await this.CopyTextAsync(change.Path); - - e.Handled = true; - return; - } - - if (e.Key == Key.D && - e.KeyModifiers.HasFlag(OperatingSystem.IsMacOS() ? KeyModifiers.Meta : KeyModifiers.Control) && - e.KeyModifiers.HasFlag(KeyModifiers.Shift)) - { - vm.OpenChangeInMergeTool(change); - e.Handled = true; - } - } - - private void OnChangeDoubleTapped(object sender, TappedEventArgs e) - { - if (DataContext is ViewModels.CommitDetail detail && sender is Grid { DataContext: Models.Change change }) - { - detail.ChangeSelection = new(new List { change }); - detail.ActiveTabIndex = 1; - } - - e.Handled = true; - } - - private void OnChangeContextRequested(object sender, ContextRequestedEventArgs e) - { - if (sender is Grid { DataContext: Models.Change change } grid) - CreateChangeContextMenu(change)?.Open(grid); - e.Handled = true; - } - private bool _isDetailsPanelExpanded = true; } } diff --git a/src/Views/Compare.axaml.cs b/src/Views/Compare.axaml.cs index 488220e5eb..2c011f8f75 100644 --- a/src/Views/Compare.axaml.cs +++ b/src/Views/Compare.axaml.cs @@ -346,7 +346,7 @@ private async void OnChangeCollectionViewKeyDown(object sender, KeyEventArgs e) await this.CopyTextAsync(builder.ToString()); e.Handled = true; } - else if (e.Key == Key.F && e.KeyModifiers == cmdKey) + else if (Models.Shortcuts.Search.Matches(e)) { ChangeSearchBox.Focus(); e.Handled = true; diff --git a/src/Views/DiffView.axaml b/src/Views/DiffView.axaml index ba889d09b7..6fa73ef401 100644 --- a/src/Views/DiffView.axaml +++ b/src/Views/DiffView.axaml @@ -66,7 +66,7 @@ - + @@ -81,7 +81,7 @@ - + @@ -104,7 +104,7 @@ - + @@ -119,7 +119,7 @@ - + @@ -215,7 +215,7 @@ - + diff --git a/src/Views/DiffView.axaml.cs b/src/Views/DiffView.axaml.cs index 22c16aca1d..feeee644f7 100644 --- a/src/Views/DiffView.axaml.cs +++ b/src/Views/DiffView.axaml.cs @@ -1,8 +1,6 @@ -using System; -using Avalonia; +using Avalonia; using Avalonia.Controls; using Avalonia.Controls.Primitives; -using Avalonia.Input; using Avalonia.Interactivity; using Avalonia.VisualTree; @@ -17,14 +15,15 @@ public DiffView() public void ToggleHotkeyBindings(bool enabled) { - var isMacOS = OperatingSystem.IsMacOS(); + _hotkeysEnabled = enabled; + if (enabled) { - BtnGotoFirstChange.HotKey = KeyGesture.Parse(isMacOS ? "Cmd+Alt+Home" : "Ctrl+Alt+Home"); - BtnGotoPrevChange.HotKey = KeyGesture.Parse(isMacOS ? "Cmd+Alt+Up" : "Ctrl+Alt+Up"); - BtnGotoNextChange.HotKey = KeyGesture.Parse(isMacOS ? "Cmd+Alt+Down" : "Ctrl+Alt+Down"); - BtnGotoLastChange.HotKey = KeyGesture.Parse(isMacOS ? "Cmd+Alt+End" : "Ctrl+Alt+End"); - BtnOpenExternalMergeTool.HotKey = KeyGesture.Parse(isMacOS ? "Cmd+Shift+D" : "Ctrl+Shift+D"); + BtnGotoFirstChange.HotKey = Models.Shortcuts.GotoFirstChange.Gesture; + BtnGotoPrevChange.HotKey = Models.Shortcuts.GotoPrevChange.Gesture; + BtnGotoNextChange.HotKey = Models.Shortcuts.GotoNextChange.Gesture; + BtnGotoLastChange.HotKey = Models.Shortcuts.GotoLastChange.Gesture; + BtnOpenExternalMergeTool.HotKey = Models.Shortcuts.OpenExternalMergeTool.Gesture; } else { @@ -44,14 +43,22 @@ protected override void OnLoaded(RoutedEventArgs e) vm.CheckSettings(); ToggleHotkeyBindings(IsEffectivelyVisible); + Models.Shortcuts.Changed += OnShortcutsChanged; } protected override void OnUnloaded(RoutedEventArgs e) { base.OnUnloaded(e); + Models.Shortcuts.Changed -= OnShortcutsChanged; ToggleHotkeyBindings(false); } + private void OnShortcutsChanged() + { + if (_hotkeysEnabled) + ToggleHotkeyBindings(true); + } + private void OnGotoFirstChange(object _, RoutedEventArgs e) { this.FindDescendantOfType()?.GotoChange(ViewModels.BlockNavigationDirection.First); @@ -99,5 +106,7 @@ private async void OnOpenBinaryFileViewer(object sender, RoutedEventArgs e) e.Handled = true; } } + + private bool _hotkeysEnabled = false; } } diff --git a/src/Views/GitHubRepositoryPicker.axaml b/src/Views/GitHubRepositoryPicker.axaml new file mode 100644 index 0000000000..2d9a320fc1 --- /dev/null +++ b/src/Views/GitHubRepositoryPicker.axaml @@ -0,0 +1,221 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - @@ -61,7 +61,7 @@ Width="32" ToolTip.Tip="{DynamicResource Text.MergeConflictEditor.NextConflict}" Click="OnGotoNextConflict" - HotKey="{OnPlatform Ctrl+Down, macOS=⌘+Down}" + HotKey="{Binding Source={x:Static m:Shortcuts.NextConflict}, Path=Gesture}" IsEnabled="{Binding UnsolvedCount, Converter={x:Static c:IntConverters.IsGreaterThanZero}, Mode=OneWay}"> @@ -328,7 +328,7 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - + + @@ -133,7 +134,7 @@ + Text="{Binding Source={x:Static m:Shortcuts.UnstageChunk}, Path=DisplayText}"/> @@ -144,7 +145,7 @@ + Text="{Binding Source={x:Static m:Shortcuts.DiscardChunk}, Path=DisplayText}"/> diff --git a/src/Views/TextDiffView.axaml.cs b/src/Views/TextDiffView.axaml.cs index 3d7d0eac3a..48a5e8236b 100644 --- a/src/Views/TextDiffView.axaml.cs +++ b/src/Views/TextDiffView.axaml.cs @@ -1550,7 +1550,6 @@ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs chang { if (SelectedChunk is { } chunk) { - var syscmd = OperatingSystem.IsMacOS() ? "Cmd" : "Ctrl"; var top = chunk.Y + 4; var right = 28.0; if (!chunk.Combined && chunk.IsOldSide) @@ -1561,9 +1560,9 @@ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs chang Popup.Margin = new Thickness(0, top, right, 0); Popup.IsVisible = true; - BtnStageChunk.HotKey = KeyGesture.Parse($"{syscmd}+S"); - BtnUnstageChunk.HotKey = KeyGesture.Parse($"{syscmd}+U"); - BtnDiscardChunk.HotKey = KeyGesture.Parse($"{syscmd}+D"); + BtnStageChunk.HotKey = Models.Shortcuts.StageChunk.Gesture; + BtnUnstageChunk.HotKey = Models.Shortcuts.UnstageChunk.Gesture; + BtnDiscardChunk.HotKey = Models.Shortcuts.DiscardChunk.Gesture; } else { diff --git a/src/Views/Welcome.axaml b/src/Views/Welcome.axaml index c777852982..4f157327ee 100644 --- a/src/Views/Welcome.axaml +++ b/src/Views/Welcome.axaml @@ -49,7 +49,7 @@