From c0006db0de92bad00c84594f52dfa71704b1501e Mon Sep 17 00:00:00 2001 From: Anton Arnaudov Date: Sat, 17 Oct 2026 22:13:54 +0300 Subject: [PATCH] =?UTF-8?q?feat(graph):=20Compare=20With=E2=80=A6=20a=20br?= =?UTF-8?q?anch,=20a=20tag=20or=20a=20commit=20SHA=20(#123)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Right-click any commit in the Commit Graph (panel, editor tab or Commits rail) and choose Compare With…: a picker lists every local branch, remote branch (a remote's HEAD pointer left out) and tag, plus "Enter a commit SHA…". The choice opens the existing Compare panel from the commit to it, in "All differences" mode: the other side need not contain the commit, and "what an older tag adds" would be nothing. Files open through the existing diff routing, so gitstudio.diff.comparisonIn applies. Refs are picked and compared by their FULL names, so a tag and a branch of one name stay apart; a typed SHA is resolved with rev-parse --verify ^{commit} (an option-like text never reaches git) and asked again, with the reason, when it names no commit. The panel's own base/compare pickers and the palette entry use the same picker. The panel now names each side the way a person reads it: a short sha, a ref without refs/heads/ — the tab title, the pills, the summary and the diff titles used to show forty-character SHAs for Compare These Two Commits. Co-Authored-By: Claude Opus 5.5 --- apps/extension/CHANGELOG.md | 11 ++ apps/extension/README.md | 2 +- apps/extension/l10n/bundle.l10n.cs.json | 4 + apps/extension/l10n/bundle.l10n.de.json | 4 + apps/extension/l10n/bundle.l10n.es.json | 4 + apps/extension/l10n/bundle.l10n.fr.json | 4 + apps/extension/l10n/bundle.l10n.it.json | 4 + apps/extension/l10n/bundle.l10n.ja.json | 4 + apps/extension/l10n/bundle.l10n.json | 4 + apps/extension/l10n/bundle.l10n.ko.json | 4 + apps/extension/l10n/bundle.l10n.pl.json | 4 + apps/extension/l10n/bundle.l10n.pt-br.json | 4 + apps/extension/l10n/bundle.l10n.ru.json | 4 + apps/extension/l10n/bundle.l10n.tr.json | 4 + apps/extension/l10n/bundle.l10n.zh-cn.json | 4 + apps/extension/l10n/bundle.l10n.zh-tw.json | 4 + apps/extension/src/compare/comparePanel.ts | 64 ++++---- apps/extension/src/compare/refCompare.ts | 116 +++++++++++--- apps/extension/src/graph/commitActions.ts | 10 ++ apps/extension/src/graph/graphPanel.ts | 21 +++ .../test/comparePanelRepaint.test.ts | 6 +- apps/extension/test/compareSummary.test.ts | 22 ++- apps/extension/test/graphPanel.host.test.ts | 145 ++++++++++++++++++ l10n/cs.json | 4 + l10n/de.json | 4 + l10n/es.json | 4 + l10n/fr.json | 4 + l10n/it.json | 4 + l10n/ja.json | 4 + l10n/ko.json | 4 + l10n/pl.json | 4 + l10n/pt-br.json | 4 + l10n/ru.json | 4 + l10n/tr.json | 4 + l10n/zh-cn.json | 4 + l10n/zh-tw.json | 4 + 36 files changed, 457 insertions(+), 48 deletions(-) diff --git a/apps/extension/CHANGELOG.md b/apps/extension/CHANGELOG.md index 591a94ce..48676d88 100644 --- a/apps/extension/CHANGELOG.md +++ b/apps/extension/CHANGELOG.md @@ -20,6 +20,12 @@ All notable changes to **GitStudio** are documented here. This project adheres t `gitstudio.staging.codeLens` for the same links as a CodeLens above every change. A diff editor shows them only while VS Code's Diff Editor: Code Lens setting is on. +- **Compare a commit with a branch, a tag or another commit.** Right-click + any commit in the Commit Graph and choose Compare With…, then pick a local + branch, a remote branch or a tag, or enter a commit SHA. The Compare panel + opens on every difference between the two, with its changed files and + their diffs; the panel's own ref pickers offer the same choices + ([#123](https://github.com/GitStudioHQ/gitstudio/issues/123)). ### Changed - **The staging marks in the gutter are dots, not checkboxes.** VS Code lets @@ -27,6 +33,11 @@ All notable changes to **GitStudio** are documented here. This project adheres t marks only report: grey for unstaged, half amber for partly staged, green for staged ([#87](https://github.com/GitStudioHQ/gitstudio/issues/87)). +### Fixed +- **The Compare panel names commits by their short SHA.** Comparing two + commits used to show forty-character SHAs in the tab title, the ref + pickers and the summary. + ## [1.21.1] - 2026-10-15 ### Fixed diff --git a/apps/extension/README.md b/apps/extension/README.md index 4ffd7fe2..5f398e4a 100644 --- a/apps/extension/README.md +++ b/apps/extension/README.md @@ -120,7 +120,7 @@ The lanes, chips and avatars follow your theme — the same graph in Light Moder ## Branch compare -**A GitHub-style compare, locally, for any two refs.** *Compare Branches/Tags…* (or *Compare with Current* from any branch) opens a panel with ahead/behind counts, the exact commits between the two refs, and the changed files as native diffs. Answer "what would this merge actually bring in" *before* you merge it. +**A GitHub-style compare, locally, for any two refs.** *Compare Branches/Tags…* (or *Compare with Current* from any branch, or *Compare With…* on any commit in the Commit Graph, against a branch, a tag or a commit SHA) opens a panel with ahead/behind counts, the exact commits between the two refs, and the changed files as native diffs. Answer "what would this merge actually bring in" *before* you merge it. ## Optional AI, on your terms diff --git a/apps/extension/l10n/bundle.l10n.cs.json b/apps/extension/l10n/bundle.l10n.cs.json index 84df7d41..1c349d94 100644 --- a/apps/extension/l10n/bundle.l10n.cs.json +++ b/apps/extension/l10n/bundle.l10n.cs.json @@ -535,6 +535,7 @@ "Commit": "Commit", "Commit & Push": "Commit a push", "Commit Graph": "Graf commitů", + "Commit SHA": "SHA commitu", "Commit actions": "Akce commitu", "Commit all 1 changed file?": "Commitnout 1 změněný soubor?", "Commit all {0}": "Commitnout vše ({0})", @@ -559,6 +560,7 @@ "Commit…": "Commit…", "Compare": "Porovnat", "Compare These Two Commits": "Porovnat tyto dva commity", + "Compare With…": "Porovnat s…", "Compare from (base)…": "Porovnat od (základ)…", "Compare to (head)…": "Porovnat do (head)…", "Compare with {0}": "Porovnat s {0}", @@ -859,6 +861,7 @@ "Editing the message stopped and needs you — continue the rebase, or abort it to put the branch back as it was.": "Úprava zprávy se zastavila a potřebuje váš zásah — pokračujte v rebase, nebo ho zrušte, aby se větev vrátila tak, jak byla.", "Enable LM Studio's local server (Developer ▸ Start Server), then load a model.": "Zapněte místní server LM Studia (Developer ▸ Start Server) a potom načtěte model.", "Encrypted at rest in GitStudio's own store — not your OS keychain, so it never raises a password prompt. The key stays host-side and is never sent to a webview.": "Šifrováno v klidu ve vlastním úložišti GitStudia — ne v klíčence vašeho OS, takže se nikdy nezobrazí výzva k zadání hesla. Klíč zůstává na straně hostitele a nikdy se neodesílá do webview.", + "Enter a commit SHA…": "Zadat SHA commitu…", "Errored": "Chyba", "Every check on its latest commit": "Každá kontrola na jeho nejnovějším commitu", "Every conflict is resolved, and your stashed changes are in your files. git keeps the stash entry when applying it stops on conflicts, so it is still in your stash list — drop it once you are happy with the result.": "Všechny konflikty jsou vyřešeny a vaše změny ze stash jsou ve vašich souborech. Git ponechá položku stash, když se její použití zastaví na konfliktech, takže je stále v seznamu stashů — zahoďte ji, až budete s výsledkem spokojeni.", @@ -3113,6 +3116,7 @@ "{0} is no longer a worktree of this repository.": "{0} už není pracovním stromem tohoto repozitáře.", "{0} is no longer conflicted — nothing was changed.": "{0} už není v konfliktu — nic se nezměnilo.", "{0} is no longer conflicted — nothing was written, so a resolution made elsewhere stays as it is.": "{0} už není v konfliktu — nic se nezapsalo, takže řešení provedené jinde zůstává, jak je.", + "{0} is not a commit in this repository.": "{0} není commit v tomto repozitáři.", "{0} is not in an open Git repository, so it has no HEAD version.": "{0} není v otevřeném Git repozitáři, takže nemá verzi HEAD.", "{0} is open in another tab of this window, so it can't be removed — its folder would be deleted from under that tab. Close that tab first.": "{0} je otevřené v jiné záložce tohoto okna, takže to nelze odstranit — jeho složka by zmizela té záložce pod rukama. Nejdřív tu záložku zavřete.", "{0} is still conflicted — there is nothing to undo.": "{0} je stále v konfliktu — není co vracet zpět.", diff --git a/apps/extension/l10n/bundle.l10n.de.json b/apps/extension/l10n/bundle.l10n.de.json index 01fcc0a0..ef55e0e3 100644 --- a/apps/extension/l10n/bundle.l10n.de.json +++ b/apps/extension/l10n/bundle.l10n.de.json @@ -535,6 +535,7 @@ "Commit": "Commit", "Commit & Push": "Commit & Push", "Commit Graph": "Commit-Graph", + "Commit SHA": "Commit-SHA", "Commit actions": "Commit-Aktionen", "Commit all 1 changed file?": "Die 1 geänderte Datei committen?", "Commit all {0}": "Alle {0} committen", @@ -559,6 +560,7 @@ "Commit…": "Committen…", "Compare": "Vergleichen", "Compare These Two Commits": "Diese beiden Commits vergleichen", + "Compare With…": "Vergleichen mit…", "Compare from (base)…": "Vergleichen von (Basis)…", "Compare to (head)…": "Vergleichen mit (Head)…", "Compare with {0}": "Mit {0} vergleichen", @@ -859,6 +861,7 @@ "Editing the message stopped and needs you — continue the rebase, or abort it to put the branch back as it was.": "Das Ändern der Nachricht ist gestoppt und braucht Sie — den Rebase fortsetzen oder abbrechen, um den Branch wie zuvor zurückzusetzen.", "Enable LM Studio's local server (Developer ▸ Start Server), then load a model.": "Den lokalen Server von LM Studio aktivieren (Developer ▸ Start Server), dann ein Modell laden.", "Encrypted at rest in GitStudio's own store — not your OS keychain, so it never raises a password prompt. The key stays host-side and is never sent to a webview.": "Verschlüsselt im eigenen Speicher von GitStudio gespeichert — nicht im Schlüsselbund des Betriebssystems, daher erscheint nie eine Passwortabfrage. Der Schlüssel bleibt hostseitig und wird nie an eine Webview gesendet.", + "Enter a commit SHA…": "Commit-SHA eingeben…", "Errored": "Fehlgeschlagen", "Every check on its latest commit": "Jede Prüfung auf dessen letztem Commit", "Every conflict is resolved, and your stashed changes are in your files. git keeps the stash entry when applying it stops on conflicts, so it is still in your stash list — drop it once you are happy with the result.": "Jeder Konflikt ist gelöst, und Ihre gestashten Änderungen sind in Ihren Dateien. git behält den Stash-Eintrag, wenn das Anwenden bei Konflikten stoppt, daher ist er noch in Ihrer Stash-Liste — ihn verwerfen, sobald Sie mit dem Ergebnis zufrieden sind.", @@ -3113,6 +3116,7 @@ "{0} is no longer a worktree of this repository.": "{0} ist kein Worktree dieses Repositorys mehr.", "{0} is no longer conflicted — nothing was changed.": "{0} hat keinen Konflikt mehr — es wurde nichts geändert.", "{0} is no longer conflicted — nothing was written, so a resolution made elsewhere stays as it is.": "{0} hat keinen Konflikt mehr — es wurde nichts geschrieben, daher bleibt eine anderswo vorgenommene Lösung unverändert.", + "{0} is not a commit in this repository.": "{0} ist kein Commit in diesem Repository.", "{0} is not in an open Git repository, so it has no HEAD version.": "{0} befindet sich nicht in einem geöffneten Git-Repository, daher hat es keine HEAD-Version.", "{0} is open in another tab of this window, so it can't be removed — its folder would be deleted from under that tab. Close that tab first.": "{0} ist in einem anderen Tab dieses Fensters geöffnet, daher kann es nicht entfernt werden — sein Ordner würde unter diesem Tab gelöscht. Zuerst diesen Tab schließen.", "{0} is still conflicted — there is nothing to undo.": "{0} hat noch einen Konflikt — es gibt nichts rückgängig zu machen.", diff --git a/apps/extension/l10n/bundle.l10n.es.json b/apps/extension/l10n/bundle.l10n.es.json index 51c80541..e12be935 100644 --- a/apps/extension/l10n/bundle.l10n.es.json +++ b/apps/extension/l10n/bundle.l10n.es.json @@ -535,6 +535,7 @@ "Commit": "Commit", "Commit & Push": "Confirmar y publicar", "Commit Graph": "Grafo de commits", + "Commit SHA": "SHA del commit", "Commit actions": "Acciones del commit", "Commit all 1 changed file?": "¿Confirmar el único archivo cambiado?", "Commit all {0}": "Confirmar los {0}", @@ -559,6 +560,7 @@ "Commit…": "Commit…", "Compare": "Comparar", "Compare These Two Commits": "Comparar estos dos commits", + "Compare With…": "Comparar con…", "Compare from (base)…": "Comparar desde (base)…", "Compare to (head)…": "Comparar hasta (head)…", "Compare with {0}": "Comparar con {0}", @@ -859,6 +861,7 @@ "Editing the message stopped and needs you — continue the rebase, or abort it to put the branch back as it was.": "Reformular el mensaje se detuvo y necesita tu atención — continúa el rebase, o abórtalo para devolver la rama a como estaba.", "Enable LM Studio's local server (Developer ▸ Start Server), then load a model.": "Habilita el servidor local de LM Studio (Developer ▸ Start Server), y luego carga un modelo.", "Encrypted at rest in GitStudio's own store — not your OS keychain, so it never raises a password prompt. The key stays host-side and is never sent to a webview.": "Cifrado en reposo en el propio almacén de GitStudio — no en el llavero de tu sistema operativo, así que nunca muestra un aviso de contraseña. La clave permanece en el host y nunca se envía a una vista web.", + "Enter a commit SHA…": "Introducir el SHA de un commit…", "Errored": "Con error", "Every check on its latest commit": "Cada check en su commit más reciente", "Every conflict is resolved, and your stashed changes are in your files. git keeps the stash entry when applying it stops on conflicts, so it is still in your stash list — drop it once you are happy with the result.": "Todos los conflictos están resueltos, y tus cambios guardados en el stash están en tus archivos. git conserva la entrada del stash cuando al aplicarla se detiene por conflictos, así que sigue en tu lista de stashes — descártala cuando estés conforme con el resultado.", @@ -3113,6 +3116,7 @@ "{0} is no longer a worktree of this repository.": "{0} ya no es un worktree de este repositorio.", "{0} is no longer conflicted — nothing was changed.": "{0} ya no está en conflicto — no se cambió nada.", "{0} is no longer conflicted — nothing was written, so a resolution made elsewhere stays as it is.": "{0} ya no está en conflicto — no se escribió nada, así que una resolución hecha en otro lugar se mantiene como está.", + "{0} is not a commit in this repository.": "{0} no es un commit de este repositorio.", "{0} is not in an open Git repository, so it has no HEAD version.": "{0} no está en un repositorio Git abierto, así que no tiene versión de HEAD.", "{0} is open in another tab of this window, so it can't be removed — its folder would be deleted from under that tab. Close that tab first.": "{0} está abierto en otra pestaña de esta ventana, así que no se puede quitar — su carpeta se eliminaría debajo de esa pestaña. Cierra esa pestaña primero.", "{0} is still conflicted — there is nothing to undo.": "{0} todavía está en conflicto — no hay nada que deshacer.", diff --git a/apps/extension/l10n/bundle.l10n.fr.json b/apps/extension/l10n/bundle.l10n.fr.json index b374e71a..8f17d9d7 100644 --- a/apps/extension/l10n/bundle.l10n.fr.json +++ b/apps/extension/l10n/bundle.l10n.fr.json @@ -535,6 +535,7 @@ "Commit": "Valider", "Commit & Push": "Valider et pousser", "Commit Graph": "Graphe des commits", + "Commit SHA": "SHA du commit", "Commit actions": "Actions sur le commit", "Commit all 1 changed file?": "Valider le 1 fichier modifié ?", "Commit all {0}": "Valider tous les {0}", @@ -559,6 +560,7 @@ "Commit…": "Valider…", "Compare": "Comparer", "Compare These Two Commits": "Comparer ces deux commits", + "Compare With…": "Comparer avec…", "Compare from (base)…": "Comparer depuis (base)…", "Compare to (head)…": "Comparer à (head)…", "Compare with {0}": "Comparer avec {0}", @@ -859,6 +861,7 @@ "Editing the message stopped and needs you — continue the rebase, or abort it to put the branch back as it was.": "La reformulation du message s'est arrêtée et a besoin de vous — continuez le rebase, ou abandonnez-le pour remettre la branche comme avant.", "Enable LM Studio's local server (Developer ▸ Start Server), then load a model.": "Activez le serveur local de LM Studio (Developer ▸ Start Server), puis chargez un modèle.", "Encrypted at rest in GitStudio's own store — not your OS keychain, so it never raises a password prompt. The key stays host-side and is never sent to a webview.": "Chiffré au repos dans le propre stockage de GitStudio — pas votre porte-clés système, il ne déclenche donc jamais d'invite de mot de passe. La clé reste côté hôte et n'est jamais envoyée à une webview.", + "Enter a commit SHA…": "Saisir le SHA d’un commit…", "Errored": "En erreur", "Every check on its latest commit": "Toutes les vérifications sur son dernier commit", "Every conflict is resolved, and your stashed changes are in your files. git keeps the stash entry when applying it stops on conflicts, so it is still in your stash list — drop it once you are happy with the result.": "Tous les conflits sont résolus, et vos modifications remisées sont dans vos fichiers. git conserve l'entrée du stash quand son application s'arrête sur des conflits, elle est donc toujours dans votre liste de stashs — supprimez-la une fois satisfait du résultat.", @@ -3113,6 +3116,7 @@ "{0} is no longer a worktree of this repository.": "{0} n'est plus une arborescence de travail de ce dépôt.", "{0} is no longer conflicted — nothing was changed.": "{0} n'est plus en conflit — rien n'a changé.", "{0} is no longer conflicted — nothing was written, so a resolution made elsewhere stays as it is.": "{0} n'est plus en conflit — rien n'a été écrit, une résolution faite ailleurs reste donc telle qu'elle est.", + "{0} is not a commit in this repository.": "{0} n’est pas un commit de ce dépôt.", "{0} is not in an open Git repository, so it has no HEAD version.": "{0} n'est pas dans un dépôt Git ouvert, il n'a donc aucune version HEAD.", "{0} is open in another tab of this window, so it can't be removed — its folder would be deleted from under that tab. Close that tab first.": "{0} est ouvert dans un autre onglet de cette fenêtre, il ne peut donc pas être supprimé — son dossier serait supprimé sous cet onglet. Fermez d'abord cet onglet.", "{0} is still conflicted — there is nothing to undo.": "{0} est encore en conflit — il n'y a rien à annuler.", diff --git a/apps/extension/l10n/bundle.l10n.it.json b/apps/extension/l10n/bundle.l10n.it.json index 3383a770..533f42ab 100644 --- a/apps/extension/l10n/bundle.l10n.it.json +++ b/apps/extension/l10n/bundle.l10n.it.json @@ -535,6 +535,7 @@ "Commit": "Commit", "Commit & Push": "Commit e push", "Commit Graph": "Grafico dei commit", + "Commit SHA": "SHA del commit", "Commit actions": "Azioni del commit", "Commit all 1 changed file?": "Eseguire il commit dell'unico file modificato?", "Commit all {0}": "Esegui il commit di tutti i {0}", @@ -559,6 +560,7 @@ "Commit…": "Commit…", "Compare": "Confronta", "Compare These Two Commits": "Confronta questi due commit", + "Compare With…": "Confronta con…", "Compare from (base)…": "Confronta da (base)…", "Compare to (head)…": "Confronta con (head)…", "Compare with {0}": "Confronta con {0}", @@ -859,6 +861,7 @@ "Editing the message stopped and needs you — continue the rebase, or abort it to put the branch back as it was.": "La correzione del messaggio si è fermata e richiede il tuo intervento — continua il rebase, oppure interrompilo per riportare il ramo com'era.", "Enable LM Studio's local server (Developer ▸ Start Server), then load a model.": "Attiva il server locale di LM Studio (Developer ▸ Start Server), poi carica un modello.", "Encrypted at rest in GitStudio's own store — not your OS keychain, so it never raises a password prompt. The key stays host-side and is never sent to a webview.": "Cifrato a riposo nell'archivio proprio di GitStudio — non il keychain del tuo SO, quindi non chiede mai una password. La chiave resta lato host e non viene mai inviata a una webview.", + "Enter a commit SHA…": "Inserisci lo SHA di un commit…", "Errored": "Errore", "Every check on its latest commit": "Ogni controllo sul suo ultimo commit", "Every conflict is resolved, and your stashed changes are in your files. git keeps the stash entry when applying it stops on conflicts, so it is still in your stash list — drop it once you are happy with the result.": "Ogni conflitto è risolto, e le tue modifiche nello stash sono nei tuoi file. git conserva la voce dello stash quando la sua applicazione si ferma per conflitti, quindi è ancora nel tuo elenco di stash — eliminala quando sei soddisfatto del risultato.", @@ -3113,6 +3116,7 @@ "{0} is no longer a worktree of this repository.": "{0} non è più un worktree di questo repository.", "{0} is no longer conflicted — nothing was changed.": "{0} non è più in conflitto — nulla è stato modificato.", "{0} is no longer conflicted — nothing was written, so a resolution made elsewhere stays as it is.": "{0} non è più in conflitto — nulla è stato scritto, quindi una risoluzione fatta altrove resta com'è.", + "{0} is not a commit in this repository.": "{0} non è un commit di questo repository.", "{0} is not in an open Git repository, so it has no HEAD version.": "{0} non è in un repository Git aperto, quindi non ha una versione HEAD.", "{0} is open in another tab of this window, so it can't be removed — its folder would be deleted from under that tab. Close that tab first.": "{0} è aperto in un'altra scheda di questa finestra, quindi non può essere rimosso — la sua cartella verrebbe eliminata sotto quella scheda. Chiudi prima quella scheda.", "{0} is still conflicted — there is nothing to undo.": "{0} è ancora in conflitto — non c'è nulla da annullare.", diff --git a/apps/extension/l10n/bundle.l10n.ja.json b/apps/extension/l10n/bundle.l10n.ja.json index 502ab4d7..8db399b6 100644 --- a/apps/extension/l10n/bundle.l10n.ja.json +++ b/apps/extension/l10n/bundle.l10n.ja.json @@ -535,6 +535,7 @@ "Commit": "コミット", "Commit & Push": "コミット&プッシュ", "Commit Graph": "コミットグラフ", + "Commit SHA": "コミット SHA", "Commit actions": "コミットの操作", "Commit all 1 changed file?": "変更された 1 個のファイルをすべてコミットしますか?", "Commit all {0}": "{0} をすべてコミット", @@ -559,6 +560,7 @@ "Commit…": "コミット…", "Compare": "比較", "Compare These Two Commits": "これら 2 つのコミットを比較", + "Compare With…": "…と比較", "Compare from (base)…": "比較元(ベース)…", "Compare to (head)…": "比較先(ヘッド)…", "Compare with {0}": "{0} と比較", @@ -859,6 +861,7 @@ "Editing the message stopped and needs you — continue the rebase, or abort it to put the branch back as it was.": "メッセージの変更が停止し、あなたの対応が必要です — リベースを続行するか、中止してブランチを元の状態に戻してください。", "Enable LM Studio's local server (Developer ▸ Start Server), then load a model.": "LM Studio のローカルサーバーを有効にし(Developer ▸ Start Server)、モデルを読み込んでください。", "Encrypted at rest in GitStudio's own store — not your OS keychain, so it never raises a password prompt. The key stays host-side and is never sent to a webview.": "GitStudio 独自のストアに保存時暗号化されます — OS のキーチェーンではないため、パスワードの入力は求められません。キーはホスト側に保持され、Webview には送られません。", + "Enter a commit SHA…": "コミット SHA を入力…", "Errored": "エラー発生", "Every check on its latest commit": "最新コミットのすべてのチェック", "Every conflict is resolved, and your stashed changes are in your files. git keeps the stash entry when applying it stops on conflicts, so it is still in your stash list — drop it once you are happy with the result.": "すべてのコンフリクトが解決され、スタッシュした変更がファイルに反映されました。git はコンフリクトで適用が停止した場合、スタッシュエントリを残すため、まだスタッシュ一覧に残っています — 結果に問題がなければドロップしてください。", @@ -3113,6 +3116,7 @@ "{0} is no longer a worktree of this repository.": "{0} はこのリポジトリのワークツリーではなくなりました。", "{0} is no longer conflicted — nothing was changed.": "{0} はもうコンフリクトしていません — 何も変更されていません。", "{0} is no longer conflicted — nothing was written, so a resolution made elsewhere stays as it is.": "{0} はもうコンフリクトしていません — 何も書き込まれていないため、他で行われた解決内容はそのまま残ります。", + "{0} is not a commit in this repository.": "{0} はこのリポジトリのコミットではありません。", "{0} is not in an open Git repository, so it has no HEAD version.": "{0} は開いているGitリポジトリ内にないため、HEADバージョンがありません。", "{0} is open in another tab of this window, so it can't be removed — its folder would be deleted from under that tab. Close that tab first.": "{0} はこのウィンドウの別のタブで開かれているため削除できません — そのフォルダーがタブの下から削除されてしまいます。先にそのタブを閉じてください。", "{0} is still conflicted — there is nothing to undo.": "{0} はまだコンフリクトしています — 元に戻すものはありません。", diff --git a/apps/extension/l10n/bundle.l10n.json b/apps/extension/l10n/bundle.l10n.json index 7fb1a920..343d998c 100644 --- a/apps/extension/l10n/bundle.l10n.json +++ b/apps/extension/l10n/bundle.l10n.json @@ -535,6 +535,7 @@ "Commit": "Commit", "Commit & Push": "Commit & Push", "Commit Graph": "Commit Graph", + "Commit SHA": "Commit SHA", "Commit actions": "Commit actions", "Commit all 1 changed file?": "Commit all 1 changed file?", "Commit all {0}": "Commit all {0}", @@ -559,6 +560,7 @@ "Commit…": "Commit…", "Compare": "Compare", "Compare These Two Commits": "Compare These Two Commits", + "Compare With…": "Compare With…", "Compare from (base)…": "Compare from (base)…", "Compare to (head)…": "Compare to (head)…", "Compare with {0}": "Compare with {0}", @@ -859,6 +861,7 @@ "Editing the message stopped and needs you — continue the rebase, or abort it to put the branch back as it was.": "Editing the message stopped and needs you — continue the rebase, or abort it to put the branch back as it was.", "Enable LM Studio's local server (Developer ▸ Start Server), then load a model.": "Enable LM Studio's local server (Developer ▸ Start Server), then load a model.", "Encrypted at rest in GitStudio's own store — not your OS keychain, so it never raises a password prompt. The key stays host-side and is never sent to a webview.": "Encrypted at rest in GitStudio's own store — not your OS keychain, so it never raises a password prompt. The key stays host-side and is never sent to a webview.", + "Enter a commit SHA…": "Enter a commit SHA…", "Errored": "Errored", "Every check on its latest commit": "Every check on its latest commit", "Every conflict is resolved, and your stashed changes are in your files. git keeps the stash entry when applying it stops on conflicts, so it is still in your stash list — drop it once you are happy with the result.": "Every conflict is resolved, and your stashed changes are in your files. git keeps the stash entry when applying it stops on conflicts, so it is still in your stash list — drop it once you are happy with the result.", @@ -3113,6 +3116,7 @@ "{0} is no longer a worktree of this repository.": "{0} is no longer a worktree of this repository.", "{0} is no longer conflicted — nothing was changed.": "{0} is no longer conflicted — nothing was changed.", "{0} is no longer conflicted — nothing was written, so a resolution made elsewhere stays as it is.": "{0} is no longer conflicted — nothing was written, so a resolution made elsewhere stays as it is.", + "{0} is not a commit in this repository.": "{0} is not a commit in this repository.", "{0} is not in an open Git repository, so it has no HEAD version.": "{0} is not in an open Git repository, so it has no HEAD version.", "{0} is open in another tab of this window, so it can't be removed — its folder would be deleted from under that tab. Close that tab first.": "{0} is open in another tab of this window, so it can't be removed — its folder would be deleted from under that tab. Close that tab first.", "{0} is still conflicted — there is nothing to undo.": "{0} is still conflicted — there is nothing to undo.", diff --git a/apps/extension/l10n/bundle.l10n.ko.json b/apps/extension/l10n/bundle.l10n.ko.json index 9549c540..daba95fe 100644 --- a/apps/extension/l10n/bundle.l10n.ko.json +++ b/apps/extension/l10n/bundle.l10n.ko.json @@ -535,6 +535,7 @@ "Commit": "커밋", "Commit & Push": "커밋 및 푸시", "Commit Graph": "커밋 그래프", + "Commit SHA": "커밋 SHA", "Commit actions": "커밋 작업", "Commit all 1 changed file?": "변경된 파일 1개를 모두 커밋하시겠습니까?", "Commit all {0}": "{0} 모두 커밋", @@ -559,6 +560,7 @@ "Commit…": "커밋…", "Compare": "비교", "Compare These Two Commits": "이 두 커밋 비교", + "Compare With…": "다음과 비교…", "Compare from (base)…": "비교 시작(기준)…", "Compare to (head)…": "비교 대상(head)…", "Compare with {0}": "{0}과 비교", @@ -859,6 +861,7 @@ "Editing the message stopped and needs you — continue the rebase, or abort it to put the branch back as it was.": "메시지 수정이 중지되어 확인이 필요합니다 — 리베이스를 계속하거나, 중단하여 브랜치를 원래대로 되돌리세요.", "Enable LM Studio's local server (Developer ▸ Start Server), then load a model.": "LM Studio의 로컬 서버를 켠(개발자 ▸ 서버 시작) 후 모델을 로드하세요.", "Encrypted at rest in GitStudio's own store — not your OS keychain, so it never raises a password prompt. The key stays host-side and is never sent to a webview.": "GitStudio 자체 저장소에 암호화되어 저장됩니다 — OS 키체인이 아니므로 비밀번호 입력 창이 뜨지 않습니다. 키는 호스트 쪽에만 있으며 웹뷰로 전송되지 않습니다.", + "Enter a commit SHA…": "커밋 SHA 입력…", "Errored": "오류 발생", "Every check on its latest commit": "최신 커밋의 모든 검사", "Every conflict is resolved, and your stashed changes are in your files. git keeps the stash entry when applying it stops on conflicts, so it is still in your stash list — drop it once you are happy with the result.": "모든 충돌이 해결되었으며 스태시된 변경 내용이 파일에 반영되었습니다. 적용이 충돌로 중지되면 git이 스태시 항목을 유지하므로 여전히 스태시 목록에 있습니다 — 결과에 만족하면 삭제하세요.", @@ -3113,6 +3116,7 @@ "{0} is no longer a worktree of this repository.": "{0}은 더 이상 이 리포지토리의 작업 폴더가 아닙니다.", "{0} is no longer conflicted — nothing was changed.": "{0}은 더 이상 충돌하지 않습니다 — 아무것도 변경되지 않았습니다.", "{0} is no longer conflicted — nothing was written, so a resolution made elsewhere stays as it is.": "{0}은 더 이상 충돌하지 않습니다 — 아무것도 기록되지 않아 다른 곳에서 만든 해결 내용이 그대로 유지됩니다.", + "{0} is not a commit in this repository.": "{0}은(는) 이 리포지토리의 커밋이 아닙니다.", "{0} is not in an open Git repository, so it has no HEAD version.": "{0}은 열린 Git 리포지토리에 없어 HEAD 버전이 없습니다.", "{0} is open in another tab of this window, so it can't be removed — its folder would be deleted from under that tab. Close that tab first.": "{0}이 이 창의 다른 탭에서 열려 있어 제거할 수 없습니다 — 그 탭 아래의 폴더가 삭제됩니다. 먼저 그 탭을 닫으세요.", "{0} is still conflicted — there is nothing to undo.": "{0}은 여전히 충돌 상태입니다 — 실행 취소할 것이 없습니다.", diff --git a/apps/extension/l10n/bundle.l10n.pl.json b/apps/extension/l10n/bundle.l10n.pl.json index 3a5f6b92..4b161915 100644 --- a/apps/extension/l10n/bundle.l10n.pl.json +++ b/apps/extension/l10n/bundle.l10n.pl.json @@ -535,6 +535,7 @@ "Commit": "Commit", "Commit & Push": "Commit i push", "Commit Graph": "Graf commitów", + "Commit SHA": "SHA commita", "Commit actions": "Akcje commita", "Commit all 1 changed file?": "Zatwierdzić wszystkie zmiany w 1 pliku?", "Commit all {0}": "Zatwierdź wszystkie {0}", @@ -559,6 +560,7 @@ "Commit…": "Commit…", "Compare": "Porównaj", "Compare These Two Commits": "Porównaj te dwa commity", + "Compare With…": "Porównaj z…", "Compare from (base)…": "Porównaj od (baza)…", "Compare to (head)…": "Porównaj do (head)…", "Compare with {0}": "Porównaj z {0}", @@ -859,6 +861,7 @@ "Editing the message stopped and needs you — continue the rebase, or abort it to put the branch back as it was.": "Zmiana treści zatrzymała się i wymaga Twojej decyzji — kontynuuj rebase albo przerwij go, aby przywrócić branch do stanu poprzedniego.", "Enable LM Studio's local server (Developer ▸ Start Server), then load a model.": "Włącz lokalny serwer LM Studio (Developer ▸ Start Server), a potem wczytaj model.", "Encrypted at rest in GitStudio's own store — not your OS keychain, so it never raises a password prompt. The key stays host-side and is never sent to a webview.": "Szyfrowane w spoczynku we własnym magazynie GitStudio — nie w pęku kluczy systemu, więc nigdy nie pojawia się monit o hasło. Klucz pozostaje po stronie hosta i nigdy nie jest wysyłany do webview.", + "Enter a commit SHA…": "Wpisz SHA commita…", "Errored": "Błąd", "Every check on its latest commit": "Każda kontrola na jego najnowszym commicie", "Every conflict is resolved, and your stashed changes are in your files. git keeps the stash entry when applying it stops on conflicts, so it is still in your stash list — drop it once you are happy with the result.": "Każdy konflikt jest rozwiązany, a Twoje zmiany ze schowka są w Twoich plikach. git zachowuje wpis schowka, gdy jego stosowanie zatrzymuje się na konfliktach, więc wciąż jest na Twojej liście schowków — odrzuć go, gdy wynik Ci odpowiada.", @@ -3113,6 +3116,7 @@ "{0} is no longer a worktree of this repository.": "{0} nie jest już worktree tego repozytorium.", "{0} is no longer conflicted — nothing was changed.": "{0} nie jest już skonfliktowany — nic nie zostało zmienione.", "{0} is no longer conflicted — nothing was written, so a resolution made elsewhere stays as it is.": "{0} nie jest już skonfliktowany — nic nie zostało zapisane, więc rozwiązanie wykonane gdzie indziej zostaje bez zmian.", + "{0} is not a commit in this repository.": "{0} nie jest commitem w tym repozytorium.", "{0} is not in an open Git repository, so it has no HEAD version.": "{0} nie jest w otwartym repozytorium Git, więc nie ma wersji HEAD.", "{0} is open in another tab of this window, so it can't be removed — its folder would be deleted from under that tab. Close that tab first.": "{0} jest otwarty w innej karcie tego okna, więc nie można go usunąć — jego folder zostałby usunięty pod tą kartą. Najpierw zamknij tę kartę.", "{0} is still conflicted — there is nothing to undo.": "{0} jest wciąż skonfliktowany — nie ma nic do wycofania.", diff --git a/apps/extension/l10n/bundle.l10n.pt-br.json b/apps/extension/l10n/bundle.l10n.pt-br.json index fdd99b78..ccbd9072 100644 --- a/apps/extension/l10n/bundle.l10n.pt-br.json +++ b/apps/extension/l10n/bundle.l10n.pt-br.json @@ -535,6 +535,7 @@ "Commit": "Commit", "Commit & Push": "Commit e Push", "Commit Graph": "Grafo de Commits", + "Commit SHA": "SHA do commit", "Commit actions": "Ações do commit", "Commit all 1 changed file?": "Commitar o 1 arquivo alterado?", "Commit all {0}": "Commitar todos os {0}", @@ -559,6 +560,7 @@ "Commit…": "Commit…", "Compare": "Comparar", "Compare These Two Commits": "Comparar Estes Dois Commits", + "Compare With…": "Comparar Com…", "Compare from (base)…": "Comparar a partir de (base)…", "Compare to (head)…": "Comparar até (head)…", "Compare with {0}": "Comparar com {0}", @@ -859,6 +861,7 @@ "Editing the message stopped and needs you — continue the rebase, or abort it to put the branch back as it was.": "Reescrever a mensagem parou e precisa de você — continue o rebase, ou aborte-o para devolver o branch como estava.", "Enable LM Studio's local server (Developer ▸ Start Server), then load a model.": "Ative o servidor local do LM Studio (Developer ▸ Start Server) e depois carregue um modelo.", "Encrypted at rest in GitStudio's own store — not your OS keychain, so it never raises a password prompt. The key stays host-side and is never sent to a webview.": "Criptografado em repouso no próprio armazenamento do GitStudio — não no keychain do seu sistema, então nunca gera um pedido de senha. A chave fica no host e nunca é enviada a uma webview.", + "Enter a commit SHA…": "Inserir o SHA de um commit…", "Errored": "Com erro", "Every check on its latest commit": "Todas as verificações no seu commit mais recente", "Every conflict is resolved, and your stashed changes are in your files. git keeps the stash entry when applying it stops on conflicts, so it is still in your stash list — drop it once you are happy with the result.": "Todos os conflitos estão resolvidos, e suas alterações guardadas estão em seus arquivos. O git mantém a entrada do stash quando aplicá-lo para em conflitos, então ele ainda está na sua lista de stashes — descarte-o quando estiver satisfeito com o resultado.", @@ -3113,6 +3116,7 @@ "{0} is no longer a worktree of this repository.": "{0} não é mais um worktree deste repositório.", "{0} is no longer conflicted — nothing was changed.": "{0} não está mais em conflito — nada foi alterado.", "{0} is no longer conflicted — nothing was written, so a resolution made elsewhere stays as it is.": "{0} não está mais em conflito — nada foi gravado, então uma resolução feita em outro lugar permanece como está.", + "{0} is not a commit in this repository.": "{0} não é um commit deste repositório.", "{0} is not in an open Git repository, so it has no HEAD version.": "{0} não está em um repositório Git aberto, então não tem versão no HEAD.", "{0} is open in another tab of this window, so it can't be removed — its folder would be deleted from under that tab. Close that tab first.": "{0} está aberto em outra aba desta janela, então não pode ser removido — a pasta dele seria excluída debaixo daquela aba. Feche aquela aba primeiro.", "{0} is still conflicted — there is nothing to undo.": "{0} ainda está em conflito — não há nada para desfazer.", diff --git a/apps/extension/l10n/bundle.l10n.ru.json b/apps/extension/l10n/bundle.l10n.ru.json index 6e683865..c17f75ad 100644 --- a/apps/extension/l10n/bundle.l10n.ru.json +++ b/apps/extension/l10n/bundle.l10n.ru.json @@ -535,6 +535,7 @@ "Commit": "Коммит", "Commit & Push": "Закоммитить и отправить", "Commit Graph": "Граф коммитов", + "Commit SHA": "SHA коммита", "Commit actions": "Действия с коммитом", "Commit all 1 changed file?": "Закоммитить 1 изменённый файл?", "Commit all {0}": "Закоммитить все {0}", @@ -559,6 +560,7 @@ "Commit…": "Коммит…", "Compare": "Сравнить", "Compare These Two Commits": "Сравнить эти два коммита", + "Compare With…": "Сравнить с…", "Compare from (base)…": "Сравнить от (база)…", "Compare to (head)…": "Сравнить с (head)…", "Compare with {0}": "Сравнить с {0}", @@ -859,6 +861,7 @@ "Editing the message stopped and needs you — continue the rebase, or abort it to put the branch back as it was.": "Переформулирование сообщения остановилось и требует вашего решения — продолжите перебазирование или прервите его, чтобы вернуть ветку как было.", "Enable LM Studio's local server (Developer ▸ Start Server), then load a model.": "Включите локальный сервер LM Studio (Developer ▸ Start Server), затем загрузите модель.", "Encrypted at rest in GitStudio's own store — not your OS keychain, so it never raises a password prompt. The key stays host-side and is never sent to a webview.": "Зашифровано в собственном хранилище GitStudio — не в брелоке ключей ОС, поэтому запрос пароля никогда не появляется. Ключ остаётся на стороне хоста и никогда не отправляется в webview.", + "Enter a commit SHA…": "Ввести SHA коммита…", "Errored": "Ошибка", "Every check on its latest commit": "Каждая проверка на его последнем коммите", "Every conflict is resolved, and your stashed changes are in your files. git keeps the stash entry when applying it stops on conflicts, so it is still in your stash list — drop it once you are happy with the result.": "Все конфликты разрешены, и ваши спрятанные изменения теперь в файлах. git сохраняет запись тайника, когда его применение останавливается на конфликтах, поэтому он всё ещё в списке тайников — отбросьте его, когда будете довольны результатом.", @@ -3113,6 +3116,7 @@ "{0} is no longer a worktree of this repository.": "{0} больше не рабочий каталог этого репозитория.", "{0} is no longer conflicted — nothing was changed.": "{0} больше не конфликтует — ничего не изменено.", "{0} is no longer conflicted — nothing was written, so a resolution made elsewhere stays as it is.": "{0} больше не конфликтует — ничего не записано, поэтому разрешение, сделанное где-то ещё, остаётся как есть.", + "{0} is not a commit in this repository.": "{0} — не коммит в этом репозитории.", "{0} is not in an open Git repository, so it has no HEAD version.": "{0} не в открытом Git-репозитории, поэтому у него нет версии HEAD.", "{0} is open in another tab of this window, so it can't be removed — its folder would be deleted from under that tab. Close that tab first.": "{0} открыт в другой вкладке этого окна, поэтому его нельзя удалить — его папка была бы удалена из-под той вкладки. Сначала закройте эту вкладку.", "{0} is still conflicted — there is nothing to undo.": "{0} всё ещё конфликтует — нечего отменять.", diff --git a/apps/extension/l10n/bundle.l10n.tr.json b/apps/extension/l10n/bundle.l10n.tr.json index e729e5fc..b9543085 100644 --- a/apps/extension/l10n/bundle.l10n.tr.json +++ b/apps/extension/l10n/bundle.l10n.tr.json @@ -535,6 +535,7 @@ "Commit": "İşle", "Commit & Push": "İşle ve Gönder", "Commit Graph": "İşleme Grafiği", + "Commit SHA": "İşleme SHA'sı", "Commit actions": "İşleme eylemleri", "Commit all 1 changed file?": "1 değiştirilmiş dosyanın tümü işlensin mi?", "Commit all {0}": "{0} tümünü işle", @@ -559,6 +560,7 @@ "Commit…": "İşle…", "Compare": "Karşılaştır", "Compare These Two Commits": "Bu İki İşlemeyi Karşılaştır", + "Compare With…": "Şununla Karşılaştır…", "Compare from (base)…": "Karşılaştır (taban)…", "Compare to (head)…": "Karşılaştır (uç)…", "Compare with {0}": "{0} ile Karşılaştır", @@ -859,6 +861,7 @@ "Editing the message stopped and needs you — continue the rebase, or abort it to put the branch back as it was.": "Mesajı değiştirme durdu ve sizi gerektiriyor — yeniden temellendirmeyi sürdürün veya dalı olduğu haline geri koymak için iptal edin.", "Enable LM Studio's local server (Developer ▸ Start Server), then load a model.": "LM Studio'nun yerel sunucusunu etkinleştirin (Developer ▸ Start Server), sonra bir model yükleyin.", "Encrypted at rest in GitStudio's own store — not your OS keychain, so it never raises a password prompt. The key stays host-side and is never sent to a webview.": "GitStudio'nun kendi deposunda bekleme sırasında şifrelenir — işletim sisteminizin anahtarlığında değil, bu nedenle hiçbir zaman bir parola istemi çıkarmaz. Anahtar host tarafında kalır ve bir web görünümüne asla gönderilmez.", + "Enter a commit SHA…": "Bir işleme SHA'sı girin…", "Errored": "Hata oluştu", "Every check on its latest commit": "En son işlemesindeki her denetim", "Every conflict is resolved, and your stashed changes are in your files. git keeps the stash entry when applying it stops on conflicts, so it is still in your stash list — drop it once you are happy with the result.": "Her çakışma çözüldü ve zulalanmış değişiklikleriniz dosyalarınızda. git, uygularken çakışmalara durduğunda zula kaydını tutar, bu nedenle hâlâ zula listenizde — sonuçtan memnun olunca düşürün.", @@ -3113,6 +3116,7 @@ "{0} is no longer a worktree of this repository.": "{0} artık bu deponun bir çalışma alanı değil.", "{0} is no longer conflicted — nothing was changed.": "{0} artık çakışmalı değil — hiçbir şey değişmedi.", "{0} is no longer conflicted — nothing was written, so a resolution made elsewhere stays as it is.": "{0} artık çakışmalı değil — hiçbir şey yazılmadı, bu nedenle başka bir yerde yapılan bir çözüm olduğu gibi kalır.", + "{0} is not a commit in this repository.": "{0} bu depoda bir işleme değil.", "{0} is not in an open Git repository, so it has no HEAD version.": "{0} açık bir Git deposunda değil, bu nedenle bir HEAD sürümü yok.", "{0} is open in another tab of this window, so it can't be removed — its folder would be deleted from under that tab. Close that tab first.": "{0}, bu pencerenin başka bir sekmesinde açık, bu nedenle kaldırılamaz — klasörü o sekmenin altından silinmiş olur. Önce o sekmeyi kapatın.", "{0} is still conflicted — there is nothing to undo.": "{0} hâlâ çakışmalı — geri alınacak bir şey yok.", diff --git a/apps/extension/l10n/bundle.l10n.zh-cn.json b/apps/extension/l10n/bundle.l10n.zh-cn.json index 6dfe19dd..a5cbd3b1 100644 --- a/apps/extension/l10n/bundle.l10n.zh-cn.json +++ b/apps/extension/l10n/bundle.l10n.zh-cn.json @@ -535,6 +535,7 @@ "Commit": "提交", "Commit & Push": "提交并推送", "Commit Graph": "提交图", + "Commit SHA": "提交 SHA", "Commit actions": "提交操作", "Commit all 1 changed file?": "提交全部 1 个已更改文件?", "Commit all {0}": "提交全部 {0}", @@ -559,6 +560,7 @@ "Commit…": "提交…", "Compare": "比较", "Compare These Two Commits": "比较这两个提交", + "Compare With…": "与…比较", "Compare from (base)…": "比较起点(基准)…", "Compare to (head)…": "比较终点(目标)…", "Compare with {0}": "与 {0} 比较", @@ -859,6 +861,7 @@ "Editing the message stopped and needs you — continue the rebase, or abort it to put the branch back as it was.": "改写提交信息已停止,需要你处理 — 请继续变基,或中止以把分支恢复原样。", "Enable LM Studio's local server (Developer ▸ Start Server), then load a model.": "请启用 LM Studio 的本地服务器(Developer ▸ Start Server),然后加载模型。", "Encrypted at rest in GitStudio's own store — not your OS keychain, so it never raises a password prompt. The key stays host-side and is never sent to a webview.": "静态加密存储在 GitStudio 自己的存储中 — 不是你的操作系统钥匙串,因此绝不会弹出密码提示。密钥保留在宿主侧,绝不会发送到 webview。", + "Enter a commit SHA…": "输入提交 SHA…", "Errored": "出错", "Every check on its latest commit": "每项检查都在其最新提交上", "Every conflict is resolved, and your stashed changes are in your files. git keeps the stash entry when applying it stops on conflicts, so it is still in your stash list — drop it once you are happy with the result.": "每个冲突都已解决,你贮藏的更改已在文件中。在应用时遇到冲突而停下,git 会保留贮藏条目,所以它仍在贮藏列表中 — 满意后即可丢弃它。", @@ -3113,6 +3116,7 @@ "{0} is no longer a worktree of this repository.": "{0} 已不再是本仓库的工作树。", "{0} is no longer conflicted — nothing was changed.": "{0} 已不再有冲突 — 未做任何更改。", "{0} is no longer conflicted — nothing was written, so a resolution made elsewhere stays as it is.": "{0} 已不再有冲突 — 未写入任何内容,因此别处所做的解决保持不变。", + "{0} is not a commit in this repository.": "{0} 不是此仓库中的提交。", "{0} is not in an open Git repository, so it has no HEAD version.": "{0} 不在已打开的 Git 仓库中,因此没有 HEAD 版本。", "{0} is open in another tab of this window, so it can't be removed — its folder would be deleted from under that tab. Close that tab first.": "{0} 在此窗口的另一个标签页中打开,因此无法移除 — 它的文件夹会从该标签页下被删除。请先关闭该标签页。", "{0} is still conflicted — there is nothing to undo.": "{0} 仍有冲突 — 没有可撤销的内容。", diff --git a/apps/extension/l10n/bundle.l10n.zh-tw.json b/apps/extension/l10n/bundle.l10n.zh-tw.json index 5d51e3b1..e3dd1ab2 100644 --- a/apps/extension/l10n/bundle.l10n.zh-tw.json +++ b/apps/extension/l10n/bundle.l10n.zh-tw.json @@ -535,6 +535,7 @@ "Commit": "提交", "Commit & Push": "提交併推送", "Commit Graph": "提交圖", + "Commit SHA": "提交 SHA", "Commit actions": "提交操作", "Commit all 1 changed file?": "提交全部 1 個已更改檔案?", "Commit all {0}": "提交全部 {0}", @@ -559,6 +560,7 @@ "Commit…": "提交…", "Compare": "比較", "Compare These Two Commits": "比較這兩個提交", + "Compare With…": "與…比較", "Compare from (base)…": "比較起點(基準)…", "Compare to (head)…": "比較終點(目標)…", "Compare with {0}": "與 {0} 比較", @@ -859,6 +861,7 @@ "Editing the message stopped and needs you — continue the rebase, or abort it to put the branch back as it was.": "改寫提交資訊已停止,需要你處理 — 請繼續變基,或中止以把分支恢復原樣。", "Enable LM Studio's local server (Developer ▸ Start Server), then load a model.": "請啟用 LM Studio 的本地伺服器(Developer ▸ Start Server),然後載入模型。", "Encrypted at rest in GitStudio's own store — not your OS keychain, so it never raises a password prompt. The key stays host-side and is never sent to a webview.": "靜態加密儲存在 GitStudio 自己的儲存中 — 不是你的作業系統鑰匙串,因此絕不會彈出密碼提示。金鑰保留在宿主側,絕不會發送到 webview。", + "Enter a commit SHA…": "輸入提交 SHA…", "Errored": "出錯", "Every check on its latest commit": "每項檢查都在其最新提交上", "Every conflict is resolved, and your stashed changes are in your files. git keeps the stash entry when applying it stops on conflicts, so it is still in your stash list — drop it once you are happy with the result.": "每個衝突都已解決,你儲藏的更改已在檔案中。在應用時遇到衝突而停下,git 會保留儲藏條目,所以它仍在儲藏列表中 — 滿意後即可丟棄它。", @@ -3113,6 +3116,7 @@ "{0} is no longer a worktree of this repository.": "{0} 已不再是本儲存庫的工作樹。", "{0} is no longer conflicted — nothing was changed.": "{0} 已不再有衝突 — 未做任何更改。", "{0} is no longer conflicted — nothing was written, so a resolution made elsewhere stays as it is.": "{0} 已不再有衝突 — 未寫入任何內容,因此別處所做的解決保持不變。", + "{0} is not a commit in this repository.": "{0} 不是此儲存庫中的提交。", "{0} is not in an open Git repository, so it has no HEAD version.": "{0} 不在已開啟的 Git 儲存庫中,因此沒有 HEAD 版本。", "{0} is open in another tab of this window, so it can't be removed — its folder would be deleted from under that tab. Close that tab first.": "{0} 在此視窗的另一個標籤頁中開啟,因此無法移除 — 它的資料夾會從該標籤頁下被刪除。請先關閉該標籤頁。", "{0} is still conflicted — there is nothing to undo.": "{0} 仍有衝突 — 沒有可撤銷的內容。", diff --git a/apps/extension/src/compare/comparePanel.ts b/apps/extension/src/compare/comparePanel.ts index 7cece6a9..7c35174f 100644 --- a/apps/extension/src/compare/comparePanel.ts +++ b/apps/extension/src/compare/comparePanel.ts @@ -8,14 +8,14 @@ import { relativeTime } from "../util/relativeTime"; import tokensCss from "../../../../packages/webview-ui/src/styles/tokens.css"; import { SOLID_ACCENT_JS } from "../../../../packages/webview-ui/src/styles/solidAccent"; import { + compareRefLabel, compareRefsData, fileDiffPatch, openCompareFileDiff, - pickRef, + pickCompareTarget, type CompareResult, type RefKind, } from "./refCompare"; -import type { GitRef } from "@gitstudio/host-bridge/git"; import * as l10n from "@vscode/l10n"; import { l10nWebviewScript } from "@gitstudio/l10n/index"; @@ -54,6 +54,10 @@ export class ComparePanel { extensionUri: vscode.Uri, base?: string, head?: string, + /** Open in this mode: `threeDot: false` is "All differences" — the plain + * diff between two commits, for a comparison of one commit with another + * ref, where neither need contain the other. Omitted, the mode stays. */ + opts: { threeDot?: boolean } = {}, ): Promise { const active = repos.getActive(); if (!active) { @@ -61,27 +65,25 @@ export class ComparePanel { return; } const headRef = await active.ctx.refs.getHead(); - const current = headRef.detached ? headRef.sha : headRef.branch; + // By its full name: `branch` is git's shortest unambiguous one, which is + // "heads/release" beside a tag "release" — and the panel shows it short. + const current = headRef.detached ? headRef.sha : (headRef.fullName ?? headRef.branch); const b = base ?? current; let h = head; if (!h) { // Palette entry point — prompt for the ref to compare `b` against. - const refs = (await active.ctx.refs.listRefs()).filter( - (r: GitRef) => - r.type === "head" || r.type === "remote" || r.type === "tag", - ); - h = await pickRef(refs, l10n.t("Compare {0} with…", b ?? "")); + h = await pickCompareTarget(active, l10n.t("Compare {0} with…", compareRefLabel(b ?? ""))); } if (!b || !h) { return; } if (ComparePanel.current) { - ComparePanel.current.setRefs(b, h); + ComparePanel.current.setRefs(b, h, opts.threeDot); ComparePanel.current.panel.reveal(vscode.ViewColumn.Active); return; } - ComparePanel.current = new ComparePanel(repos, extensionUri, b, h); + ComparePanel.current = new ComparePanel(repos, extensionUri, b, h, opts.threeDot); } private readonly panel: vscode.WebviewPanel; @@ -109,9 +111,13 @@ export class ComparePanel { private readonly extensionUri: vscode.Uri, base: string, head: string, + threeDot?: boolean, ) { this.base = base; this.head = head; + if (threeDot !== undefined) { + this.threeDot = threeDot; + } this.panel = vscode.window.createWebviewPanel( "gitstudio.compare", l10n.t("Compare"), @@ -132,9 +138,12 @@ export class ComparePanel { void this.update(); } - private setRefs(base: string, head: string): void { + private setRefs(base: string, head: string, threeDot?: boolean): void { this.base = base; this.head = head; + if (threeDot !== undefined) { + this.threeDot = threeDot; + } void this.update(); } @@ -148,7 +157,7 @@ export class ComparePanel { const base = this.base; const head = this.head; const threeDot = this.threeDot; - this.panel.title = l10n.t("Compare: {0} ↔ {1}", base, head); + this.panel.title = l10n.t("Compare: {0} ↔ {1}", compareRefLabel(base), compareRefLabel(head)); const active = this.repos.getActive(); if (!active) { this.lastRenderKey = ""; @@ -169,7 +178,7 @@ export class ComparePanel { } this.lastRenderKey = ""; this.panel.webview.html = this.errorHtml( - l10n.t("Couldn't compare {0} with {1}.", this.base, this.head), + l10n.t("Couldn't compare {0} with {1}.", compareRefLabel(this.base), compareRefLabel(this.head)), ); return; } @@ -200,12 +209,8 @@ export class ComparePanel { if (!active) { return; } - const refs = (await active.ctx.refs.listRefs()).filter( - (r: GitRef) => - r.type === "head" || r.type === "remote" || r.type === "tag", - ); - const picked = await pickRef( - refs, + const picked = await pickCompareTarget( + active, m.type === "pickBase" ? l10n.t("Compare from (base)…") : l10n.t("Compare to (head)…"), ); if (picked) { @@ -289,6 +294,9 @@ export class ComparePanel { private render(result: CompareResult): string { this.filesLeftRef = result.filesLeftRef; + // What each side is CALLED; git is always handed this.base / this.head. + const baseName = compareRefLabel(this.base); + const headName = compareRefLabel(this.head); const nonce = getNonce(); const codiconUri = this.panel.webview.asWebviewUri( vscode.Uri.joinPath(this.extensionUri, "dist", "codicons", "codicon.css"), @@ -335,21 +343,21 @@ export class ComparePanel {
- + - +
- +
- ${esc(this.head)} + ${esc(headName)} ${l10n.t("compared with")} - ${esc(this.base)} + ${esc(baseName)}
${result.ahead} ${result.ahead === 1 ? l10n.t("commit") : l10n.t("commits")} @@ -359,7 +367,7 @@ export class ComparePanel { +${result.additions} −${result.deletions} - ${result.behind > 0 ? `${l10n.t("{0} behind", result.behind)}` : ""} + ${result.behind > 0 ? `${l10n.t("{0} behind", result.behind)}` : ""}
@@ -399,7 +407,7 @@ export class ComparePanel { ${l10nWebviewScript(nonce)} @@ -418,6 +426,10 @@ ${COMPARE_JS} } private dispose(): void { + // Once: disposing the panel fires its onDidDispose, which lands here again. + if (this.disposed) { + return; + } this.disposed = true; ComparePanel.current = undefined; this.panel.dispose(); diff --git a/apps/extension/src/compare/refCompare.ts b/apps/extension/src/compare/refCompare.ts index 62513e92..30e9c1ae 100644 --- a/apps/extension/src/compare/refCompare.ts +++ b/apps/extension/src/compare/refCompare.ts @@ -3,9 +3,10 @@ import type { CommitRecord, GitRef } from "@gitstudio/host-bridge/git"; import { mergeCommitFiles } from "@gitstudio/git-service/CommitDetailsProvider"; import type { RepoEntry } from "../git/repoManager"; import { toRevisionUri } from "../history/revisionContentProvider"; -import { promptPick } from "../ui/dialogs"; +import { promptInput, promptPick, type DialogChoice } from "../ui/dialogs"; import * as l10n from "@vscode/l10n"; import { openDiff } from "../merge/diffPlaces"; +import { refLabel } from "@gitstudio/host-bridge/graphRefFilter"; // The ref-comparison engine, lifted out of the retired Search & Compare view so // the branch-compare panel (and any future consumer) can reuse the same @@ -271,26 +272,105 @@ export async function openCompareFileDiff(arg: { await openDiff( left, right, - `${name} (${arg.refA} ↔ ${arg.refB})`, + `${name} (${compareRefLabel(arg.refA)} ↔ ${compareRefLabel(arg.refB)})`, undefined, "compare", ); } -/** A GitStudio dialog over the repo's branches/tags; returns the chosen name. */ -export async function pickRef( - refs: GitRef[], - title: string, -): Promise { - const icon = (r: GitRef) => - r.type === "tag" ? "tag" : r.type === "remote" ? "cloud" : "git-branch"; - return promptPick({ - title, - choices: refs.map((r) => ({ - id: r.name, - label: r.name, - icon: icon(r), - detail: r.sha.slice(0, 7), - })), - }); +/** + * A compared side as the panel names it: a commit by its short sha, a ref by + * its name with the namespace shorn ("refs/tags/v1" reads "v1", as the graph's + * chips say it). The panel compares by full names and full shas, so neither a + * tag and a branch of one name nor two abbreviations can be mistaken for each + * other; only what is SHOWN is short. Each pill's icon still says which kind. + */ +export function compareRefLabel(ref: string): string { + return /^[0-9a-f]{40}([0-9a-f]{24})?$/i.test(ref) ? ref.slice(0, 7) : refLabel(ref); +} + +/** The id of the "Enter a commit SHA…" row. Never a ref's: those start "refs/". */ +export const ENTER_COMMIT = "enter-commit"; + +/** + * What a commit can be compared with (issue #123): every local branch, then + * every remote branch (a remote's HEAD pointer left out — it is a copy of the + * default branch beside it), then every tag. Each is picked by its FULL name: + * `%(refname:short)` is "heads/release" beside a tag "release", and a short + * name handed on to git means whichever of the two git prefers. + */ +export function compareTargetChoices(refs: readonly GitRef[]): DialogChoice[] { + const of = (type: GitRef["type"], icon: string): DialogChoice[] => + refs + .filter((r) => r.type === type && !(type === "remote" && r.symref)) + .map((r) => ({ + id: r.fullName, + label: refLabel(r.fullName), + icon, + detail: r.sha.slice(0, 7), + })); + return [ + { id: ENTER_COMMIT, label: l10n.t("Enter a commit SHA…"), icon: "git-commit" }, + ...of("head", "git-branch"), + ...of("remote", "cloud"), + ...of("tag", "tag"), + ]; +} + +/** `rev` as a full commit sha, or undefined when it names no commit here. An + * option-like text never reaches git. */ +export async function resolveCommit(repo: RepoEntry, rev: string): Promise { + const text = rev.trim(); + if (!text || text.startsWith("-")) { + return undefined; + } + try { + const r = await repo.ctx.process.run(["rev-parse", "--verify", "--quiet", `${text}^{commit}`]); + const sha = r.code === 0 ? r.stdout.trim() : ""; + return /^[0-9a-f]{40}([0-9a-f]{24})?$/i.test(sha) ? sha : undefined; + } catch { + return undefined; + } +} + +/** + * Ask what to compare a commit with: a branch, a remote branch, a tag, or a + * commit typed by its SHA. Answers a ref's full name or a commit's full sha; + * undefined when the question was dismissed. A SHA that names no commit asks + * again, with what was typed still in the field and the reason under the title. + */ +export async function pickCompareTarget(repo: RepoEntry, title: string): Promise { + let refs: GitRef[] = []; + try { + refs = await repo.ctx.refs.listRefs(); + } catch { + // No refs to list still leaves the SHA row. + } + const picked = await promptPick({ title, choices: compareTargetChoices(refs) }); + if (picked !== ENTER_COMMIT) { + return picked; + } + let value = ""; + let hint: string | undefined; + for (;;) { + const typed = ( + await promptInput({ + title, + placeholder: l10n.t("Commit SHA"), + value, + hint, + confirmLabel: l10n.t("Compare"), + validate: "nonEmpty", + }) + )?.trim(); + if (!typed) { + return undefined; + } + const sha = await resolveCommit(repo, typed); + if (sha) { + return sha; + } + value = typed; + hint = l10n.t("{0} is not a commit in this repository.", typed); + } } diff --git a/apps/extension/src/graph/commitActions.ts b/apps/extension/src/graph/commitActions.ts index 61314a14..740ab7d1 100644 --- a/apps/extension/src/graph/commitActions.ts +++ b/apps/extension/src/graph/commitActions.ts @@ -64,11 +64,21 @@ export function commitMenuItems(opts: { drop?: boolean; reword?: boolean } = {}) { id: "reset", label: l10n.t("Reset Current Branch to Here…"), icon: "discard", danger: true }, { id: "interactiveRebase", label: l10n.t("Start Interactive Rebase Here…"), icon: "git-merge" }, { id: "", label: "", sep: true }, + // With a branch, a tag or another commit (issue #123) — the graph host + // asks which and opens the Compare panel; see COMPARE_WITH. + { id: COMPARE_WITH, label: l10n.t("Compare With…"), icon: "git-compare" }, { id: "copySha", label: l10n.t("Copy SHA"), icon: "copy" }, { id: "copyMessage", label: l10n.t("Copy Message"), icon: "copy" }, ]; } +/** + * "Compare With…": not a runCommitAction arm. It changes nothing in the + * repository and opens a panel, which only the graph host can (it owns the + * RepoManager and the extension's URI) — like Start Interactive Rebase Here. + */ +export const COMPARE_WITH = "compareWith"; + /** * The commit menu for `sha`, asking git whether it can be dropped. * diff --git a/apps/extension/src/graph/graphPanel.ts b/apps/extension/src/graph/graphPanel.ts index 37fdc284..1dcfb71c 100644 --- a/apps/extension/src/graph/graphPanel.ts +++ b/apps/extension/src/graph/graphPanel.ts @@ -36,6 +36,7 @@ import { gravatarAllowed, onGravatarSettingChange } from "./avatarPrefs"; import { getRefFilterStore } from "./refFilterStore"; import { getFilesLayoutStore } from "./filesLayoutStore"; import { + COMPARE_WITH, commitMenuItems, commitMenuItemsFor, multiCommitMenuItemsFor, @@ -47,6 +48,7 @@ import { import { menuTarget, selectedCommits } from "@gitstudio/host-bridge/graphSelection"; import { SettleLatest } from "@gitstudio/host-bridge/settleLatest"; import { ComparePanel } from "../compare/comparePanel"; +import { pickCompareTarget } from "../compare/refCompare"; import type { MenuRef } from "./checkoutTarget"; import { rowStatsReply } from "./rowStatsReply"; import { readRewritableChain } from "@gitstudio/git-service/rebaseChain"; @@ -1161,6 +1163,10 @@ export class CommitGraphPanel { await vscode.commands.executeCommand("gitstudio.startInteractiveRebase", sha); return; } + if (id === COMPARE_WITH) { + await this.compareWith(active, sha); + return; + } const record = this.records.get(sha); // Route destructive ops through the Undo envelope when it's available. const ledger = this.repos.getUndoLedger(); @@ -1180,6 +1186,21 @@ export class CommitGraphPanel { } } + /** + * "Compare With…" (issue #123): ask for a branch, a tag or a commit, then + * open the Compare panel from this commit to it. "All differences" — the + * plain diff between the two — because the other side need not contain this + * commit: "what it adds" of an older tag is nothing at all. The panel's own + * toggle offers the other mode, and its swap button the other direction. + */ + private async compareWith(active: RepoEntry, sha: string): Promise { + const target = await pickCompareTarget(active, l10n.t("Compare {0} with…", sha.slice(0, 7))); + if (!target) { + return; + } + await ComparePanel.show(this.repos, this.extensionUri, sha, target, { threeDot: false }); + } + // ── Commit details panel (docked under the graph) ────────────────────────── /** What this surface is currently showing (undefined until something is). */ diff --git a/apps/extension/test/comparePanelRepaint.test.ts b/apps/extension/test/comparePanelRepaint.test.ts index 895e9cdc..cb7e5543 100644 --- a/apps/extension/test/comparePanelRepaint.test.ts +++ b/apps/extension/test/comparePanelRepaint.test.ts @@ -58,11 +58,13 @@ function makeUpdate(resultFor: () => unknown): (self: Stub) => Promise { // new Function speaks JavaScript; the method is TypeScript. The one // annotation in it goes; if more appear the syntax error will say so. .replace(/let result: [A-Za-z]+;/, "let result;"); + // The title names each side through the module-scope compareRefLabel. const fn = new Function( "compareRefsData", + "compareRefLabel", `${body}\nreturn update;`, - ) as (c: () => unknown) => () => Promise; - return (self: Stub) => fn(() => resultFor()).call(self); + ) as (c: () => unknown, label: (r: string) => string) => () => Promise; + return (self: Stub) => fn(() => resultFor(), (r) => r).call(self); } function stub(): Stub { diff --git a/apps/extension/test/compareSummary.test.ts b/apps/extension/test/compareSummary.test.ts index 1623fc04..97417bef 100644 --- a/apps/extension/test/compareSummary.test.ts +++ b/apps/extension/test/compareSummary.test.ts @@ -27,7 +27,7 @@ loaders[".css"] = (m, f) => { /* eslint-disable @typescript-eslint/no-require-imports -- loaded after the stand-in is in place */ const { ComparePanel } = require("../src/compare/comparePanel") as typeof import("../src/compare/comparePanel"); -const { compareRefsData } = require("../src/compare/refCompare") as typeof import("../src/compare/refCompare"); +const { compareRefsData, compareRefLabel } = require("../src/compare/refCompare") as typeof import("../src/compare/refCompare"); const { GitContext } = require("@gitstudio/git-service/GitContext") as typeof import("@gitstudio/git-service/GitContext"); /* eslint-enable @typescript-eslint/no-require-imports */ import type { CompareResult } from "../src/compare/refCompare"; @@ -145,3 +145,23 @@ test("what each ref names, as git resolves it", async () => { const remote = await compareRefsData(repo, git("rev-parse", "--short", "v1.0"), "origin/main", false); assert.deepEqual([remote.baseKind, remote.headKind], ["commit", "remote"]); }); + +// Compare With… (issue #123) compares a commit by its full sha with a ref by +// its full name — so a tag and a branch of one name cannot be confused. What +// the panel SHOWS is what a person reads: a short sha, a ref's own name. +test("a side is named by its short sha or its ref's name, never forty characters or refs/…", () => { + const sha = "0123456789abcdef0123456789abcdef01234567"; + assert.equal(compareRefLabel(sha), "0123456"); + assert.equal(compareRefLabel("refs/heads/main"), "main"); + assert.equal(compareRefLabel("refs/remotes/origin/main"), "origin/main"); + assert.equal(compareRefLabel("refs/tags/v1.0"), "v1.0"); + assert.equal(compareRefLabel("feature/x"), "feature/x", "a short name is left alone"); + assert.equal(compareRefLabel("abc1234"), "abc1234", "so is a short sha"); + const html = render(sha, "refs/heads/main", result(1, { baseKind: "commit", headKind: "branch" })); + assert.match(html, /id="pick-base"[^>]*><\/i>0123456<\/span>/); + assert.match(html, /id="pick-head"[^>]*><\/i>main<\/span>/); + assert.match(html, />What main adds<\/button>/); + assert.match(html, /main<\/b>/); + assert.match(html, /0123456<\/b>/); + assert.doesNotMatch(html.slice(0, html.indexOf("const DATA")), /refs\/heads|0123456789/, "nowhere in the page's words"); +}); diff --git a/apps/extension/test/graphPanel.host.test.ts b/apps/extension/test/graphPanel.host.test.ts index 9642ebf7..c1247bf3 100644 --- a/apps/extension/test/graphPanel.host.test.ts +++ b/apps/extension/test/graphPanel.host.test.ts @@ -480,6 +480,151 @@ test("a several-commit rewrite runs and reloads: Drop 2 commits leaves the other void three; }); +// ── Compare With… (#123) ───────────────────────────────────────────────────── + +/** Compare panels opened since `from` (kit.panels' length before the test). */ +const comparePanels = (from: number) => kit.panels.slice(from).filter((x) => x.viewType === "gitstudio.compare"); + +/** The Compare panel opened since `from`, closed and forgotten when the test + * ends: it is one shared panel, the next test must open its own, and the + * editor-tab graph's test counts every panel there is. */ +async function comparePanel(from: number): Promise { + const p = await kit.until(() => comparePanels(from)[0], "the Compare panel"); + live.push({ + dispose: () => { + p.dispose(); + kit.panels.splice(kit.panels.indexOf(p), 1); + }, + }); + return p; +} + +/** What the panel's page was handed: its DATA, once a comparison has painted. */ +async function compared(p: kit.FakePanel): Promise<{ base: string; head: string; threeDot: boolean; files: { path: string }[] }> { + const html = await kit.until(() => p.webview.html.includes("const DATA = ") && p.webview.html, "a painted comparison"); + const json = html.slice(html.indexOf("const DATA = ") + "const DATA = ".length, html.indexOf(";\n", html.indexOf("const DATA = "))); + return JSON.parse(json); +} + +test("Compare With… is on one commit's menu, beside Copy SHA", async () => { + const { two, entry } = history(); + const g = track(open(entry)); + await g.nth("graphInit", 1); + g.w.send({ type: "contextMenu", sha: two, x: 1, y: 1 }); + const menu = await g.nth("commitMenu", 1); + const ids = menu.items.map((i: { id: string; sep?: boolean }) => (i.sep ? "—" : i.id)); + assert.deepEqual(ids.slice(-4), ["—", "compareWith", "copySha", "copyMessage"]); + const item = menu.items.find((i: { id: string }) => i.id === "compareWith"); + assert.equal(item.label, "Compare With…"); + assert.equal(item.icon, "git-compare"); +}); + +test("Compare With… offers every branch, remote branch and tag by full name, and a SHA row first", async () => { + const { r, one, entry } = history(); + r.git("update-ref", "refs/remotes/origin/main", "HEAD"); + r.git("symbolic-ref", "refs/remotes/origin/HEAD", "refs/remotes/origin/main"); + const g = track(open(entry)); + await g.nth("graphInit", 1); + const from = kit.panels.length; + kit.dialog.pick = undefined; // dismissed + g.w.send({ type: "commitMenuAction", sha: one, id: "compareWith" }); + await kit.until(() => kit.asked.length > 0, "the question"); + const q = kit.asked[0]; + assert.equal(q.kind, "pick"); + assert.equal(q.title, `Compare ${one.slice(0, 7)} with…`); + assert.deepEqual( + q.choices!.map((c) => [c.id, c.label]), + [ + ["enter-commit", "Enter a commit SHA…"], + ["refs/heads/feature", "feature"], + ["refs/heads/main", "main"], + // origin/HEAD is a pointer to origin/main, not a branch of its own. + ["refs/remotes/origin/main", "origin/main"], + ["refs/tags/v1", "v1"], + ], + ); + // Dismissed: nothing opens. + await new Promise((resolve) => setImmediate(resolve)); + assert.equal(comparePanels(from).length, 0); +}); + +test("picking a tag opens Compare from the commit to it, as the plain diff between the two", async () => { + const { two, entry } = history(); + const g = track(open(entry)); + await g.nth("graphInit", 1); + const from = kit.panels.length; + kit.dialog.pick = "refs/tags/v1"; + g.w.send({ type: "commitMenuAction", sha: two, id: "compareWith" }); + const p = await comparePanel(from); + const data = await compared(p); + assert.equal(data.base, two); + assert.equal(data.head, "refs/tags/v1"); + // v1 is older than `two`: "what v1 adds" would be nothing. The two-dot diff + // is what changed between them — two.txt, which v1 does not have. + assert.equal(data.threeDot, false); + assert.deepEqual(data.files.map((f) => f.path), ["two.txt"]); + // Named the way a person reads them: a short sha, a tag by its name. + assert.equal(p.title, `Compare: ${two.slice(0, 7)} ↔ v1`); + assert.match(p.webview.html, new RegExp(`id="pick-base"[^>]*>${two.slice(0, 7)}`)); + assert.match(p.webview.html, /id="pick-head"[^>]*><\/i>v1<\/span>/); +}); + +test("a tag and a branch of one name: the one picked is the one compared", async () => { + const { r, base, one, two, entry } = history(); + r.git("branch", "release", two); + r.git("tag", "release", base); + const g = track(open(entry)); + await g.nth("graphInit", 1); + const from = kit.panels.length; + kit.dialog.pick = (a) => { + const rows = a.choices!.filter((c) => c.label === "release").map((c) => c.id); + assert.deepEqual(rows, ["refs/heads/release", "refs/tags/release"], "both listed, each by its full name"); + return "refs/heads/release"; + }; + g.w.send({ type: "commitMenuAction", sha: one, id: "compareWith" }); + const data = await compared(await comparePanel(from)); + assert.equal(data.head, "refs/heads/release"); + // The branch is at `two`; the tag at `base` would have listed one.txt. + assert.deepEqual(data.files.map((f) => f.path), ["two.txt"]); +}); + +test("Enter a commit SHA…: a text that names no commit asks again, and a short sha compares by its full one", async () => { + const { base, two, entry } = history(); + const g = track(open(entry)); + await g.nth("graphInit", 1); + const from = kit.panels.length; + kit.dialog.pick = "enter-commit"; + const typed = ["nope", "--output=x", "deadbeef", ` ${base.slice(0, 8)} `]; + kit.dialog.input = () => typed.shift(); + g.w.send({ type: "commitMenuAction", sha: two, id: "compareWith" }); + const data = await compared(await comparePanel(from)); + assert.equal(data.base, two); + assert.equal(data.head, base, "the full sha, never the abbreviation typed"); + const inputs = kit.asked.filter((a) => a.kind === "input"); + assert.deepEqual( + inputs.map((a) => [a.value, a.text]), + [ + ["", ""], + ["nope", "nope is not a commit in this repository."], + ["--output=x", "--output=x is not a commit in this repository."], + ["deadbeef", "deadbeef is not a commit in this repository."], + ], + ); +}); + +test("Enter a commit SHA… dismissed opens nothing", async () => { + const { two, entry } = history(); + const g = track(open(entry)); + await g.nth("graphInit", 1); + const from = kit.panels.length; + kit.dialog.pick = "enter-commit"; + kit.dialog.input = undefined; + g.w.send({ type: "commitMenuAction", sha: two, id: "compareWith" }); + await kit.until(() => kit.asked.some((a) => a.kind === "input"), "the SHA field"); + await new Promise((resolve) => setImmediate(resolve)); + assert.equal(comparePanels(from).length, 0); +}); + // ── The details pane's toolbar ─────────────────────────────────────────────── test("details toolbar: Copy SHA, Tag and an unknown action", async () => { diff --git a/l10n/cs.json b/l10n/cs.json index d54dfaf0..8f0f3ff4 100644 --- a/l10n/cs.json +++ b/l10n/cs.json @@ -922,6 +922,7 @@ "Commit": "Commit", "Commit & Push": "Commit a push", "Commit Graph": "Graf commitů", + "Commit SHA": "SHA commitu", "Commit SHA copied": "SHA commitu zkopírováno", "Commit SHA copied.": "SHA commitu zkopírováno.", "Commit actions": "Akce commitu", @@ -962,6 +963,7 @@ "Compare": "Porovnat", "Compare (head)": "Porovnat (head)", "Compare These Two Commits": "Porovnat tyto dva commity", + "Compare With…": "Porovnat s…", "Compare from (base)…": "Porovnat od (základ)…", "Compare these two commits": "Porovnat tyto dva commity", "Compare to (head)…": "Porovnat do (head)…", @@ -1680,6 +1682,7 @@ "Empty repository": "Prázdný repozitář", "Enable LM Studio's local server (Developer ▸ Start Server), then load a model.": "Zapněte místní server LM Studia (Developer ▸ Start Server) a potom načtěte model.", "Encrypted at rest in GitStudio's own store — not your OS keychain, so it never raises a password prompt. The key stays host-side and is never sent to a webview.": "Šifrováno v klidu ve vlastním úložišti GitStudia — ne v klíčence vašeho OS, takže se nikdy nezobrazí výzva k zadání hesla. Klíč zůstává na straně hostitele a nikdy se neodesílá do webview.", + "Enter a commit SHA…": "Zadat SHA commitu…", "Enter a key first.": "Nejprve zadejte klíč.", "Enter a line number, or a range like 12-18.": "Zadejte číslo řádku, nebo rozsah jako 12-18.", "Enter a name and an email to save.": "Pro uložení zadejte jméno a e-mail.", @@ -5782,6 +5785,7 @@ "{0} is no longer a worktree of this repository.": "{0} už není pracovním stromem tohoto repozitáře.", "{0} is no longer conflicted — nothing was changed.": "{0} už není v konfliktu — nic se nezměnilo.", "{0} is no longer conflicted — nothing was written, so a resolution made elsewhere stays as it is.": "{0} už není v konfliktu — nic se nezapsalo, takže řešení provedené jinde zůstává, jak je.", + "{0} is not a commit in this repository.": "{0} není commit v tomto repozitáři.", "{0} is not in an open Git repository, so it has no HEAD version.": "{0} není v otevřeném Git repozitáři, takže nemá verzi HEAD.", "{0} is not in this repository's refs any more.": "{0} už není v referencích tohoto repozitáře.", "{0} is not inside a Git repository.": "{0} není uvnitř repozitáře Git.", diff --git a/l10n/de.json b/l10n/de.json index 6b074cd2..53aa4bdf 100644 --- a/l10n/de.json +++ b/l10n/de.json @@ -922,6 +922,7 @@ "Commit": "Commit", "Commit & Push": "Commit & Push", "Commit Graph": "Commit-Graph", + "Commit SHA": "Commit-SHA", "Commit SHA copied": "Commit-SHA kopiert", "Commit SHA copied.": "Commit-SHA kopiert.", "Commit actions": "Commit-Aktionen", @@ -962,6 +963,7 @@ "Compare": "Vergleichen", "Compare (head)": "Vergleich (Head)", "Compare These Two Commits": "Diese beiden Commits vergleichen", + "Compare With…": "Vergleichen mit…", "Compare from (base)…": "Vergleichen von (Basis)…", "Compare these two commits": "Diese beiden Commits vergleichen", "Compare to (head)…": "Vergleichen mit (Head)…", @@ -1680,6 +1682,7 @@ "Empty repository": "Leeres Repository", "Enable LM Studio's local server (Developer ▸ Start Server), then load a model.": "Den lokalen Server von LM Studio aktivieren (Developer ▸ Start Server), dann ein Modell laden.", "Encrypted at rest in GitStudio's own store — not your OS keychain, so it never raises a password prompt. The key stays host-side and is never sent to a webview.": "Verschlüsselt im eigenen Speicher von GitStudio gespeichert — nicht im Schlüsselbund des Betriebssystems, daher erscheint nie eine Passwortabfrage. Der Schlüssel bleibt hostseitig und wird nie an eine Webview gesendet.", + "Enter a commit SHA…": "Commit-SHA eingeben…", "Enter a key first.": "Zuerst einen Schlüssel eingeben.", "Enter a line number, or a range like 12-18.": "Eine Zeilennummer eingeben, oder einen Bereich wie 12-18.", "Enter a name and an email to save.": "Einen Namen und eine E-Mail-Adresse eingeben, um zu speichern.", @@ -5782,6 +5785,7 @@ "{0} is no longer a worktree of this repository.": "{0} ist kein Worktree dieses Repositorys mehr.", "{0} is no longer conflicted — nothing was changed.": "{0} hat keinen Konflikt mehr — es wurde nichts geändert.", "{0} is no longer conflicted — nothing was written, so a resolution made elsewhere stays as it is.": "{0} hat keinen Konflikt mehr — es wurde nichts geschrieben, daher bleibt eine anderswo vorgenommene Lösung unverändert.", + "{0} is not a commit in this repository.": "{0} ist kein Commit in diesem Repository.", "{0} is not in an open Git repository, so it has no HEAD version.": "{0} befindet sich nicht in einem geöffneten Git-Repository, daher hat es keine HEAD-Version.", "{0} is not in this repository's refs any more.": "{0} ist nicht mehr in den Referenzen dieses Repositorys.", "{0} is not inside a Git repository.": "{0} liegt nicht innerhalb eines Git-Repositorys.", diff --git a/l10n/es.json b/l10n/es.json index dbb6a710..ccd328ab 100644 --- a/l10n/es.json +++ b/l10n/es.json @@ -922,6 +922,7 @@ "Commit": "Commit", "Commit & Push": "Confirmar y publicar", "Commit Graph": "Grafo de commits", + "Commit SHA": "SHA del commit", "Commit SHA copied": "SHA del commit copiado", "Commit SHA copied.": "SHA del commit copiado.", "Commit actions": "Acciones del commit", @@ -962,6 +963,7 @@ "Compare": "Comparar", "Compare (head)": "Comparar (head)", "Compare These Two Commits": "Comparar estos dos commits", + "Compare With…": "Comparar con…", "Compare from (base)…": "Comparar desde (base)…", "Compare these two commits": "Comparar estos dos commits", "Compare to (head)…": "Comparar hasta (head)…", @@ -1680,6 +1682,7 @@ "Empty repository": "Repositorio vacío", "Enable LM Studio's local server (Developer ▸ Start Server), then load a model.": "Habilita el servidor local de LM Studio (Developer ▸ Start Server), y luego carga un modelo.", "Encrypted at rest in GitStudio's own store — not your OS keychain, so it never raises a password prompt. The key stays host-side and is never sent to a webview.": "Cifrado en reposo en el propio almacén de GitStudio — no en el llavero de tu sistema operativo, así que nunca muestra un aviso de contraseña. La clave permanece en el host y nunca se envía a una vista web.", + "Enter a commit SHA…": "Introducir el SHA de un commit…", "Enter a key first.": "Introduce una clave primero.", "Enter a line number, or a range like 12-18.": "Introduce un número de línea, o un rango como 12-18.", "Enter a name and an email to save.": "Introduce un nombre y un correo electrónico para guardar.", @@ -5782,6 +5785,7 @@ "{0} is no longer a worktree of this repository.": "{0} ya no es un worktree de este repositorio.", "{0} is no longer conflicted — nothing was changed.": "{0} ya no está en conflicto — no se cambió nada.", "{0} is no longer conflicted — nothing was written, so a resolution made elsewhere stays as it is.": "{0} ya no está en conflicto — no se escribió nada, así que una resolución hecha en otro lugar se mantiene como está.", + "{0} is not a commit in this repository.": "{0} no es un commit de este repositorio.", "{0} is not in an open Git repository, so it has no HEAD version.": "{0} no está en un repositorio Git abierto, así que no tiene versión de HEAD.", "{0} is not in this repository's refs any more.": "{0} ya no está en las refs de este repositorio.", "{0} is not inside a Git repository.": "{0} no está dentro de un repositorio Git.", diff --git a/l10n/fr.json b/l10n/fr.json index b17da7a2..4990f742 100644 --- a/l10n/fr.json +++ b/l10n/fr.json @@ -922,6 +922,7 @@ "Commit": "Valider", "Commit & Push": "Valider et pousser", "Commit Graph": "Graphe des commits", + "Commit SHA": "SHA du commit", "Commit SHA copied": "SHA du commit copié", "Commit SHA copied.": "SHA du commit copié.", "Commit actions": "Actions sur le commit", @@ -962,6 +963,7 @@ "Compare": "Comparer", "Compare (head)": "Comparer (head)", "Compare These Two Commits": "Comparer ces deux commits", + "Compare With…": "Comparer avec…", "Compare from (base)…": "Comparer depuis (base)…", "Compare these two commits": "Comparer ces deux commits", "Compare to (head)…": "Comparer à (head)…", @@ -1680,6 +1682,7 @@ "Empty repository": "Dépôt vide", "Enable LM Studio's local server (Developer ▸ Start Server), then load a model.": "Activez le serveur local de LM Studio (Developer ▸ Start Server), puis chargez un modèle.", "Encrypted at rest in GitStudio's own store — not your OS keychain, so it never raises a password prompt. The key stays host-side and is never sent to a webview.": "Chiffré au repos dans le propre stockage de GitStudio — pas votre porte-clés système, il ne déclenche donc jamais d'invite de mot de passe. La clé reste côté hôte et n'est jamais envoyée à une webview.", + "Enter a commit SHA…": "Saisir le SHA d’un commit…", "Enter a key first.": "Entrez d'abord une clé.", "Enter a line number, or a range like 12-18.": "Entrez un numéro de ligne, ou un intervalle comme 12-18.", "Enter a name and an email to save.": "Entrez un nom et un e-mail pour enregistrer.", @@ -5782,6 +5785,7 @@ "{0} is no longer a worktree of this repository.": "{0} n'est plus une arborescence de travail de ce dépôt.", "{0} is no longer conflicted — nothing was changed.": "{0} n'est plus en conflit — rien n'a changé.", "{0} is no longer conflicted — nothing was written, so a resolution made elsewhere stays as it is.": "{0} n'est plus en conflit — rien n'a été écrit, une résolution faite ailleurs reste donc telle qu'elle est.", + "{0} is not a commit in this repository.": "{0} n’est pas un commit de ce dépôt.", "{0} is not in an open Git repository, so it has no HEAD version.": "{0} n'est pas dans un dépôt Git ouvert, il n'a donc aucune version HEAD.", "{0} is not in this repository's refs any more.": "{0} n'est plus dans les références de ce dépôt.", "{0} is not inside a Git repository.": "{0} n'est pas à l'intérieur d'un dépôt Git.", diff --git a/l10n/it.json b/l10n/it.json index 650da755..b5cf5b26 100644 --- a/l10n/it.json +++ b/l10n/it.json @@ -922,6 +922,7 @@ "Commit": "Commit", "Commit & Push": "Commit e push", "Commit Graph": "Grafico dei commit", + "Commit SHA": "SHA del commit", "Commit SHA copied": "SHA del commit copiato", "Commit SHA copied.": "SHA del commit copiato.", "Commit actions": "Azioni del commit", @@ -962,6 +963,7 @@ "Compare": "Confronta", "Compare (head)": "Confronto (head)", "Compare These Two Commits": "Confronta questi due commit", + "Compare With…": "Confronta con…", "Compare from (base)…": "Confronta da (base)…", "Compare these two commits": "Confronta questi due commit", "Compare to (head)…": "Confronta con (head)…", @@ -1680,6 +1682,7 @@ "Empty repository": "Repository vuoto", "Enable LM Studio's local server (Developer ▸ Start Server), then load a model.": "Attiva il server locale di LM Studio (Developer ▸ Start Server), poi carica un modello.", "Encrypted at rest in GitStudio's own store — not your OS keychain, so it never raises a password prompt. The key stays host-side and is never sent to a webview.": "Cifrato a riposo nell'archivio proprio di GitStudio — non il keychain del tuo SO, quindi non chiede mai una password. La chiave resta lato host e non viene mai inviata a una webview.", + "Enter a commit SHA…": "Inserisci lo SHA di un commit…", "Enter a key first.": "Inserisci prima una chiave.", "Enter a line number, or a range like 12-18.": "Inserisci un numero di riga, o un intervallo come 12-18.", "Enter a name and an email to save.": "Inserisci un nome e un'email per salvare.", @@ -5782,6 +5785,7 @@ "{0} is no longer a worktree of this repository.": "{0} non è più un worktree di questo repository.", "{0} is no longer conflicted — nothing was changed.": "{0} non è più in conflitto — nulla è stato modificato.", "{0} is no longer conflicted — nothing was written, so a resolution made elsewhere stays as it is.": "{0} non è più in conflitto — nulla è stato scritto, quindi una risoluzione fatta altrove resta com'è.", + "{0} is not a commit in this repository.": "{0} non è un commit di questo repository.", "{0} is not in an open Git repository, so it has no HEAD version.": "{0} non è in un repository Git aperto, quindi non ha una versione HEAD.", "{0} is not in this repository's refs any more.": "{0} non è più nei ref di questo repository.", "{0} is not inside a Git repository.": "{0} non è all'interno di un repository Git.", diff --git a/l10n/ja.json b/l10n/ja.json index fb8cc27c..2123cb11 100644 --- a/l10n/ja.json +++ b/l10n/ja.json @@ -922,6 +922,7 @@ "Commit": "コミット", "Commit & Push": "コミット&プッシュ", "Commit Graph": "コミットグラフ", + "Commit SHA": "コミット SHA", "Commit SHA copied": "コミット SHA をコピーしました", "Commit SHA copied.": "コミット SHA をコピーしました。", "Commit actions": "コミットの操作", @@ -962,6 +963,7 @@ "Compare": "比較", "Compare (head)": "比較(ヘッド)", "Compare These Two Commits": "これら 2 つのコミットを比較", + "Compare With…": "…と比較", "Compare from (base)…": "比較元(ベース)…", "Compare these two commits": "これら 2 件のコミットを比較", "Compare to (head)…": "比較先(ヘッド)…", @@ -1680,6 +1682,7 @@ "Empty repository": "空のリポジトリ", "Enable LM Studio's local server (Developer ▸ Start Server), then load a model.": "LM Studio のローカルサーバーを有効にし(Developer ▸ Start Server)、モデルを読み込んでください。", "Encrypted at rest in GitStudio's own store — not your OS keychain, so it never raises a password prompt. The key stays host-side and is never sent to a webview.": "GitStudio 独自のストアに保存時暗号化されます — OS のキーチェーンではないため、パスワードの入力は求められません。キーはホスト側に保持され、Webview には送られません。", + "Enter a commit SHA…": "コミット SHA を入力…", "Enter a key first.": "まずキーを入力してください。", "Enter a line number, or a range like 12-18.": "行番号、または 12-18 のような範囲を入力してください。", "Enter a name and an email to save.": "保存するには名前とメールアドレスを入力してください。", @@ -5782,6 +5785,7 @@ "{0} is no longer a worktree of this repository.": "{0} はこのリポジトリのワークツリーではなくなりました。", "{0} is no longer conflicted — nothing was changed.": "{0} はもうコンフリクトしていません — 何も変更されていません。", "{0} is no longer conflicted — nothing was written, so a resolution made elsewhere stays as it is.": "{0} はもうコンフリクトしていません — 何も書き込まれていないため、他で行われた解決内容はそのまま残ります。", + "{0} is not a commit in this repository.": "{0} はこのリポジトリのコミットではありません。", "{0} is not in an open Git repository, so it has no HEAD version.": "{0} は開いているGitリポジトリ内にないため、HEADバージョンがありません。", "{0} is not in this repository's refs any more.": "{0} はもうこのリポジトリの参照にはありません。", "{0} is not inside a Git repository.": "{0} は Git リポジトリの中にありません。", diff --git a/l10n/ko.json b/l10n/ko.json index 3770dd1f..f3b3974b 100644 --- a/l10n/ko.json +++ b/l10n/ko.json @@ -922,6 +922,7 @@ "Commit": "커밋", "Commit & Push": "커밋 및 푸시", "Commit Graph": "커밋 그래프", + "Commit SHA": "커밋 SHA", "Commit SHA copied": "커밋 SHA를 복사했습니다", "Commit SHA copied.": "커밋 SHA를 복사했습니다.", "Commit actions": "커밋 작업", @@ -962,6 +963,7 @@ "Compare": "비교", "Compare (head)": "비교(head)", "Compare These Two Commits": "이 두 커밋 비교", + "Compare With…": "다음과 비교…", "Compare from (base)…": "비교 시작(기준)…", "Compare these two commits": "이 두 커밋 비교", "Compare to (head)…": "비교 대상(head)…", @@ -1680,6 +1682,7 @@ "Empty repository": "빈 리포지토리", "Enable LM Studio's local server (Developer ▸ Start Server), then load a model.": "LM Studio의 로컬 서버를 켠(개발자 ▸ 서버 시작) 후 모델을 로드하세요.", "Encrypted at rest in GitStudio's own store — not your OS keychain, so it never raises a password prompt. The key stays host-side and is never sent to a webview.": "GitStudio 자체 저장소에 암호화되어 저장됩니다 — OS 키체인이 아니므로 비밀번호 입력 창이 뜨지 않습니다. 키는 호스트 쪽에만 있으며 웹뷰로 전송되지 않습니다.", + "Enter a commit SHA…": "커밋 SHA 입력…", "Enter a key first.": "먼저 키를 입력하세요.", "Enter a line number, or a range like 12-18.": "줄 번호 또는 12-18과 같은 범위를 입력하세요.", "Enter a name and an email to save.": "저장하려면 이름과 이메일을 입력하세요.", @@ -5782,6 +5785,7 @@ "{0} is no longer a worktree of this repository.": "{0}은 더 이상 이 리포지토리의 작업 폴더가 아닙니다.", "{0} is no longer conflicted — nothing was changed.": "{0}은 더 이상 충돌하지 않습니다 — 아무것도 변경되지 않았습니다.", "{0} is no longer conflicted — nothing was written, so a resolution made elsewhere stays as it is.": "{0}은 더 이상 충돌하지 않습니다 — 아무것도 기록되지 않아 다른 곳에서 만든 해결 내용이 그대로 유지됩니다.", + "{0} is not a commit in this repository.": "{0}은(는) 이 리포지토리의 커밋이 아닙니다.", "{0} is not in an open Git repository, so it has no HEAD version.": "{0}은 열린 Git 리포지토리에 없어 HEAD 버전이 없습니다.", "{0} is not in this repository's refs any more.": "{0}은(는) 더 이상 이 리포지토리의 참조에 없습니다.", "{0} is not inside a Git repository.": "{0}은(는) Git 리포지토리 안에 있지 않습니다.", diff --git a/l10n/pl.json b/l10n/pl.json index bf9066fa..58778f19 100644 --- a/l10n/pl.json +++ b/l10n/pl.json @@ -922,6 +922,7 @@ "Commit": "Commit", "Commit & Push": "Commit i push", "Commit Graph": "Graf commitów", + "Commit SHA": "SHA commita", "Commit SHA copied": "SHA commita skopiowane", "Commit SHA copied.": "SHA commita skopiowane.", "Commit actions": "Akcje commita", @@ -962,6 +963,7 @@ "Compare": "Porównaj", "Compare (head)": "Porównanie (head)", "Compare These Two Commits": "Porównaj te dwa commity", + "Compare With…": "Porównaj z…", "Compare from (base)…": "Porównaj od (baza)…", "Compare these two commits": "Porównaj te dwa commity", "Compare to (head)…": "Porównaj do (head)…", @@ -1680,6 +1682,7 @@ "Empty repository": "Puste repozytorium", "Enable LM Studio's local server (Developer ▸ Start Server), then load a model.": "Włącz lokalny serwer LM Studio (Developer ▸ Start Server), a potem wczytaj model.", "Encrypted at rest in GitStudio's own store — not your OS keychain, so it never raises a password prompt. The key stays host-side and is never sent to a webview.": "Szyfrowane w spoczynku we własnym magazynie GitStudio — nie w pęku kluczy systemu, więc nigdy nie pojawia się monit o hasło. Klucz pozostaje po stronie hosta i nigdy nie jest wysyłany do webview.", + "Enter a commit SHA…": "Wpisz SHA commita…", "Enter a key first.": "Najpierw podaj klucz.", "Enter a line number, or a range like 12-18.": "Podaj numer linii albo zakres, np. 12-18.", "Enter a name and an email to save.": "Podaj imię i e-mail, aby zapisać.", @@ -5782,6 +5785,7 @@ "{0} is no longer a worktree of this repository.": "{0} nie jest już worktree tego repozytorium.", "{0} is no longer conflicted — nothing was changed.": "{0} nie jest już skonfliktowany — nic nie zostało zmienione.", "{0} is no longer conflicted — nothing was written, so a resolution made elsewhere stays as it is.": "{0} nie jest już skonfliktowany — nic nie zostało zapisane, więc rozwiązanie wykonane gdzie indziej zostaje bez zmian.", + "{0} is not a commit in this repository.": "{0} nie jest commitem w tym repozytorium.", "{0} is not in an open Git repository, so it has no HEAD version.": "{0} nie jest w otwartym repozytorium Git, więc nie ma wersji HEAD.", "{0} is not in this repository's refs any more.": "{0} już nie jest w refach tego repozytorium.", "{0} is not inside a Git repository.": "{0} nie jest wewnątrz repozytorium Git.", diff --git a/l10n/pt-br.json b/l10n/pt-br.json index 5e92e9be..76fb631f 100644 --- a/l10n/pt-br.json +++ b/l10n/pt-br.json @@ -922,6 +922,7 @@ "Commit": "Commit", "Commit & Push": "Commit e Push", "Commit Graph": "Grafo de Commits", + "Commit SHA": "SHA do commit", "Commit SHA copied": "SHA do commit copiado", "Commit SHA copied.": "SHA do commit copiado.", "Commit actions": "Ações do commit", @@ -962,6 +963,7 @@ "Compare": "Comparar", "Compare (head)": "Comparar (head)", "Compare These Two Commits": "Comparar Estes Dois Commits", + "Compare With…": "Comparar Com…", "Compare from (base)…": "Comparar a partir de (base)…", "Compare these two commits": "Comparar estes dois commits", "Compare to (head)…": "Comparar até (head)…", @@ -1680,6 +1682,7 @@ "Empty repository": "Repositório vazio", "Enable LM Studio's local server (Developer ▸ Start Server), then load a model.": "Ative o servidor local do LM Studio (Developer ▸ Start Server) e depois carregue um modelo.", "Encrypted at rest in GitStudio's own store — not your OS keychain, so it never raises a password prompt. The key stays host-side and is never sent to a webview.": "Criptografado em repouso no próprio armazenamento do GitStudio — não no keychain do seu sistema, então nunca gera um pedido de senha. A chave fica no host e nunca é enviada a uma webview.", + "Enter a commit SHA…": "Inserir o SHA de um commit…", "Enter a key first.": "Insira uma chave primeiro.", "Enter a line number, or a range like 12-18.": "Insira um número de linha, ou um intervalo como 12-18.", "Enter a name and an email to save.": "Insira um nome e um e-mail para salvar.", @@ -5782,6 +5785,7 @@ "{0} is no longer a worktree of this repository.": "{0} não é mais um worktree deste repositório.", "{0} is no longer conflicted — nothing was changed.": "{0} não está mais em conflito — nada foi alterado.", "{0} is no longer conflicted — nothing was written, so a resolution made elsewhere stays as it is.": "{0} não está mais em conflito — nada foi gravado, então uma resolução feita em outro lugar permanece como está.", + "{0} is not a commit in this repository.": "{0} não é um commit deste repositório.", "{0} is not in an open Git repository, so it has no HEAD version.": "{0} não está em um repositório Git aberto, então não tem versão no HEAD.", "{0} is not in this repository's refs any more.": "{0} não está mais nas refs deste repositório.", "{0} is not inside a Git repository.": "{0} não está dentro de um repositório Git.", diff --git a/l10n/ru.json b/l10n/ru.json index 0a5f6206..81cc23b9 100644 --- a/l10n/ru.json +++ b/l10n/ru.json @@ -922,6 +922,7 @@ "Commit": "Коммит", "Commit & Push": "Закоммитить и отправить", "Commit Graph": "Граф коммитов", + "Commit SHA": "SHA коммита", "Commit SHA copied": "SHA коммита скопирован", "Commit SHA copied.": "SHA коммита скопирован.", "Commit actions": "Действия с коммитом", @@ -962,6 +963,7 @@ "Compare": "Сравнить", "Compare (head)": "Сравнить (head)", "Compare These Two Commits": "Сравнить эти два коммита", + "Compare With…": "Сравнить с…", "Compare from (base)…": "Сравнить от (база)…", "Compare these two commits": "Сравнить эти два коммита", "Compare to (head)…": "Сравнить с (head)…", @@ -1680,6 +1682,7 @@ "Empty repository": "Пустой репозиторий", "Enable LM Studio's local server (Developer ▸ Start Server), then load a model.": "Включите локальный сервер LM Studio (Developer ▸ Start Server), затем загрузите модель.", "Encrypted at rest in GitStudio's own store — not your OS keychain, so it never raises a password prompt. The key stays host-side and is never sent to a webview.": "Зашифровано в собственном хранилище GitStudio — не в брелоке ключей ОС, поэтому запрос пароля никогда не появляется. Ключ остаётся на стороне хоста и никогда не отправляется в webview.", + "Enter a commit SHA…": "Ввести SHA коммита…", "Enter a key first.": "Сначала введите ключ.", "Enter a line number, or a range like 12-18.": "Введите номер строки или диапазон, например 12-18.", "Enter a name and an email to save.": "Введите имя и email, чтобы сохранить.", @@ -5782,6 +5785,7 @@ "{0} is no longer a worktree of this repository.": "{0} больше не рабочий каталог этого репозитория.", "{0} is no longer conflicted — nothing was changed.": "{0} больше не конфликтует — ничего не изменено.", "{0} is no longer conflicted — nothing was written, so a resolution made elsewhere stays as it is.": "{0} больше не конфликтует — ничего не записано, поэтому разрешение, сделанное где-то ещё, остаётся как есть.", + "{0} is not a commit in this repository.": "{0} — не коммит в этом репозитории.", "{0} is not in an open Git repository, so it has no HEAD version.": "{0} не в открытом Git-репозитории, поэтому у него нет версии HEAD.", "{0} is not in this repository's refs any more.": "{0} больше нет среди ссылок этого репозитория.", "{0} is not inside a Git repository.": "{0} не внутри git-репозитория.", diff --git a/l10n/tr.json b/l10n/tr.json index 518429eb..af72d5ab 100644 --- a/l10n/tr.json +++ b/l10n/tr.json @@ -922,6 +922,7 @@ "Commit": "İşle", "Commit & Push": "İşle ve Gönder", "Commit Graph": "İşleme Grafiği", + "Commit SHA": "İşleme SHA'sı", "Commit SHA copied": "İşleme SHA'sı kopyalandı", "Commit SHA copied.": "İşleme SHA'sı kopyalandı.", "Commit actions": "İşleme eylemleri", @@ -962,6 +963,7 @@ "Compare": "Karşılaştır", "Compare (head)": "Karşılaştır (head)", "Compare These Two Commits": "Bu İki İşlemeyi Karşılaştır", + "Compare With…": "Şununla Karşılaştır…", "Compare from (base)…": "Karşılaştır (taban)…", "Compare these two commits": "Bu iki işlemeyi karşılaştır", "Compare to (head)…": "Karşılaştır (uç)…", @@ -1680,6 +1682,7 @@ "Empty repository": "Boş depo", "Enable LM Studio's local server (Developer ▸ Start Server), then load a model.": "LM Studio'nun yerel sunucusunu etkinleştirin (Developer ▸ Start Server), sonra bir model yükleyin.", "Encrypted at rest in GitStudio's own store — not your OS keychain, so it never raises a password prompt. The key stays host-side and is never sent to a webview.": "GitStudio'nun kendi deposunda bekleme sırasında şifrelenir — işletim sisteminizin anahtarlığında değil, bu nedenle hiçbir zaman bir parola istemi çıkarmaz. Anahtar host tarafında kalır ve bir web görünümüne asla gönderilmez.", + "Enter a commit SHA…": "Bir işleme SHA'sı girin…", "Enter a key first.": "Önce bir anahtar girin.", "Enter a line number, or a range like 12-18.": "Bir satır numarası veya 12-18 gibi bir aralık girin.", "Enter a name and an email to save.": "Kaydetmek için bir ad ve bir e-posta girin.", @@ -5782,6 +5785,7 @@ "{0} is no longer a worktree of this repository.": "{0} artık bu deponun bir çalışma alanı değil.", "{0} is no longer conflicted — nothing was changed.": "{0} artık çakışmalı değil — hiçbir şey değişmedi.", "{0} is no longer conflicted — nothing was written, so a resolution made elsewhere stays as it is.": "{0} artık çakışmalı değil — hiçbir şey yazılmadı, bu nedenle başka bir yerde yapılan bir çözüm olduğu gibi kalır.", + "{0} is not a commit in this repository.": "{0} bu depoda bir işleme değil.", "{0} is not in an open Git repository, so it has no HEAD version.": "{0} açık bir Git deposunda değil, bu nedenle bir HEAD sürümü yok.", "{0} is not in this repository's refs any more.": "{0} artık bu deponun referanslarında değil.", "{0} is not inside a Git repository.": "{0} bir Git deposunun içinde değil.", diff --git a/l10n/zh-cn.json b/l10n/zh-cn.json index eab95f38..b825aad1 100644 --- a/l10n/zh-cn.json +++ b/l10n/zh-cn.json @@ -922,6 +922,7 @@ "Commit": "提交", "Commit & Push": "提交并推送", "Commit Graph": "提交图", + "Commit SHA": "提交 SHA", "Commit SHA copied": "提交 SHA 已复制", "Commit SHA copied.": "提交 SHA 已复制。", "Commit actions": "提交操作", @@ -962,6 +963,7 @@ "Compare": "比较", "Compare (head)": "比较(头部)", "Compare These Two Commits": "比较这两个提交", + "Compare With…": "与…比较", "Compare from (base)…": "比较起点(基准)…", "Compare these two commits": "比较这两个提交", "Compare to (head)…": "比较终点(目标)…", @@ -1680,6 +1682,7 @@ "Empty repository": "空仓库", "Enable LM Studio's local server (Developer ▸ Start Server), then load a model.": "请启用 LM Studio 的本地服务器(Developer ▸ Start Server),然后加载模型。", "Encrypted at rest in GitStudio's own store — not your OS keychain, so it never raises a password prompt. The key stays host-side and is never sent to a webview.": "静态加密存储在 GitStudio 自己的存储中 — 不是你的操作系统钥匙串,因此绝不会弹出密码提示。密钥保留在宿主侧,绝不会发送到 webview。", + "Enter a commit SHA…": "输入提交 SHA…", "Enter a key first.": "请先输入密钥。", "Enter a line number, or a range like 12-18.": "请输入行号,或类似 12-18 的范围。", "Enter a name and an email to save.": "请输入姓名和电子邮件以保存。", @@ -5782,6 +5785,7 @@ "{0} is no longer a worktree of this repository.": "{0} 已不再是本仓库的工作树。", "{0} is no longer conflicted — nothing was changed.": "{0} 已不再有冲突 — 未做任何更改。", "{0} is no longer conflicted — nothing was written, so a resolution made elsewhere stays as it is.": "{0} 已不再有冲突 — 未写入任何内容,因此别处所做的解决保持不变。", + "{0} is not a commit in this repository.": "{0} 不是此仓库中的提交。", "{0} is not in an open Git repository, so it has no HEAD version.": "{0} 不在已打开的 Git 仓库中,因此没有 HEAD 版本。", "{0} is not in this repository's refs any more.": "{0} 已不在此仓库的引用中。", "{0} is not inside a Git repository.": "{0} 不在任何 Git 仓库内。", diff --git a/l10n/zh-tw.json b/l10n/zh-tw.json index b7b27067..d013e50c 100644 --- a/l10n/zh-tw.json +++ b/l10n/zh-tw.json @@ -922,6 +922,7 @@ "Commit": "提交", "Commit & Push": "提交併推送", "Commit Graph": "提交圖", + "Commit SHA": "提交 SHA", "Commit SHA copied": "提交 SHA 已複製", "Commit SHA copied.": "提交 SHA 已複製。", "Commit actions": "提交操作", @@ -962,6 +963,7 @@ "Compare": "比較", "Compare (head)": "比較(頭部)", "Compare These Two Commits": "比較這兩個提交", + "Compare With…": "與…比較", "Compare from (base)…": "比較起點(基準)…", "Compare these two commits": "比較這兩個提交", "Compare to (head)…": "比較終點(目標)…", @@ -1680,6 +1682,7 @@ "Empty repository": "空儲存庫", "Enable LM Studio's local server (Developer ▸ Start Server), then load a model.": "請啟用 LM Studio 的本地伺服器(Developer ▸ Start Server),然後載入模型。", "Encrypted at rest in GitStudio's own store — not your OS keychain, so it never raises a password prompt. The key stays host-side and is never sent to a webview.": "靜態加密儲存在 GitStudio 自己的儲存中 — 不是你的作業系統鑰匙串,因此絕不會彈出密碼提示。金鑰保留在宿主側,絕不會發送到 webview。", + "Enter a commit SHA…": "輸入提交 SHA…", "Enter a key first.": "請先輸入金鑰。", "Enter a line number, or a range like 12-18.": "請輸入行號,或類似 12-18 的範圍。", "Enter a name and an email to save.": "請輸入姓名和電子郵件以儲存。", @@ -5782,6 +5785,7 @@ "{0} is no longer a worktree of this repository.": "{0} 已不再是本儲存庫的工作樹。", "{0} is no longer conflicted — nothing was changed.": "{0} 已不再有衝突 — 未做任何更改。", "{0} is no longer conflicted — nothing was written, so a resolution made elsewhere stays as it is.": "{0} 已不再有衝突 — 未寫入任何內容,因此別處所做的解決保持不變。", + "{0} is not a commit in this repository.": "{0} 不是此儲存庫中的提交。", "{0} is not in an open Git repository, so it has no HEAD version.": "{0} 不在已開啟的 Git 儲存庫中,因此沒有 HEAD 版本。", "{0} is not in this repository's refs any more.": "{0} 已不在此儲存庫的引用中。", "{0} is not inside a Git repository.": "{0} 不在任何 Git 儲存庫內。",