dsh-ide-git 0.19.12 → 0.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dsh.plugin.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "id": "dsh-external/dsh-ide-git",
3
- "version": "0.19.12",
3
+ "version": "0.20.0",
4
4
  "main": "./src/index.js",
5
5
  "description": "IDE 级 Git 操作面板:分支树 + 提交图谱 + 变更/暂存/提交 + 提交详情。装了 dsh-better-sidebar 时挂成它的原生 tab(右侧栏 + 底部工作台);没装时直接挂 DSH 原生右侧栏,单独安装即可用。JetBrains 风格 Git 工具窗口 for DeepSeek Harness.",
6
6
  "engines": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-ide-git",
3
- "version": "0.19.12",
3
+ "version": "0.20.0",
4
4
  "description": "DSH plugin: an IDE-grade Git tool window as a native dsh-better-sidebar tab — branch tree, commit graph, changes, commit details, JetBrains-style actions, in the right sidebar and the bottom panel. | DSH 插件:IDE 级 Git 工具窗口,以 dsh-better-sidebar 原生 Tab 挂载——分支树 / 提交图谱 / 变更与提交详情 / JetBrains 风格操作,右侧栏与底部面板双布局自适应。",
5
5
  "type": "module",
6
6
  "repository": {
package/src/client.js CHANGED
@@ -164,6 +164,9 @@ window.__ModuleLoader__.load({
164
164
  'action.fullscreen': '全屏',
165
165
  'action.exitFullscreen': '退出全屏',
166
166
  'action.newBranchFrom': '从该分支新建分支...',
167
+ 'action.setUpstream': '设置上游…',
168
+ 'action.unsetUpstream': '取消上游',
169
+ 'action.createLocalBranch': '创建本地分支…',
167
170
  'action.newBranchHere': '在此新建分支...',
168
171
  'action.rename': '重命名...',
169
172
  'action.delete': '删除',
@@ -235,6 +238,8 @@ window.__ModuleLoader__.load({
235
238
  'more.fetchAll': '从所有远程抓取',
236
239
  'more.deleteRemoteBranch': '删除远程分支...',
237
240
  'more.publish': '发布分支...',
241
+ 'more.setUpstreamHead': '设置当前分支上游…',
242
+ 'more.unsetUpstreamHead': '取消当前分支上游',
238
243
  'more.addRemote': '添加远程...',
239
244
  'more.removeRemote': '删除远程...',
240
245
  'more.stashTracked': '贮藏(仅已跟踪)',
@@ -392,6 +397,7 @@ window.__ModuleLoader__.load({
392
397
  'confirm.cancel': '取消',
393
398
  'confirm.ok': '确定',
394
399
  'prompt.newBranch': '新分支名(将创建并签出)',
400
+ 'prompt.createTracking': '从远程分支创建本地分支',
395
401
  'prompt.renameBranch': '重命名分支',
396
402
  'prompt.newTag': '新标签名',
397
403
  'prompt.fromHead': '当前 HEAD',
@@ -494,6 +500,9 @@ window.__ModuleLoader__.load({
494
500
  'action.fullscreen': 'Full screen',
495
501
  'action.exitFullscreen': 'Exit full screen',
496
502
  'action.newBranchFrom': 'New branch from here...',
503
+ 'action.setUpstream': 'Set Upstream…',
504
+ 'action.unsetUpstream': 'Unset Upstream',
505
+ 'action.createLocalBranch': 'Create Local Branch…',
497
506
  'action.newBranchHere': 'New branch here...',
498
507
  'action.rename': 'Rename...',
499
508
  'action.delete': 'Delete',
@@ -565,6 +574,8 @@ window.__ModuleLoader__.load({
565
574
  'more.fetchAll': 'Fetch from All Remotes',
566
575
  'more.deleteRemoteBranch': 'Delete Remote Branch...',
567
576
  'more.publish': 'Publish Branch...',
577
+ 'more.setUpstreamHead': 'Set Upstream for Current Branch…',
578
+ 'more.unsetUpstreamHead': 'Unset Upstream of Current Branch',
568
579
  'more.addRemote': 'Add Remote...',
569
580
  'more.removeRemote': 'Remove Remote...',
570
581
  'more.stashTracked': 'Stash (Tracked Only)',
@@ -722,6 +733,7 @@ window.__ModuleLoader__.load({
722
733
  'confirm.cancel': 'Cancel',
723
734
  'confirm.ok': 'OK',
724
735
  'prompt.newBranch': 'New branch name (created and checked out)',
736
+ 'prompt.createTracking': 'Create a local branch from the remote one',
725
737
  'prompt.renameBranch': 'Rename branch',
726
738
  'prompt.newTag': 'New tag name',
727
739
  'prompt.fromHead': 'current HEAD',
@@ -832,6 +844,9 @@ window.__ModuleLoader__.load({
832
844
  'action.fullscreen': '全螢幕',
833
845
  'action.exitFullscreen': '結束全螢幕',
834
846
  'action.newBranchFrom': '由此新建分支...',
847
+ 'action.setUpstream': '設定上游…',
848
+ 'action.unsetUpstream': '取消上游',
849
+ 'action.createLocalBranch': '建立本地分支…',
835
850
  'action.newBranchHere': '喺呢度新建分支...',
836
851
  'action.rename': '重新命名...',
837
852
  'action.delete': '刪除',
@@ -903,6 +918,8 @@ window.__ModuleLoader__.load({
903
918
  'more.fetchAll': '從所有遠端抓取',
904
919
  'more.deleteRemoteBranch': '刪除遠端分支...',
905
920
  'more.publish': '發布分支...',
921
+ 'more.setUpstreamHead': '設定目前分支上游…',
922
+ 'more.unsetUpstreamHead': '取消目前分支上游',
906
923
  'more.addRemote': '新增遠端...',
907
924
  'more.removeRemote': '刪除遠端...',
908
925
  'more.stashTracked': '儲存(僅已追蹤)',
@@ -1060,6 +1077,7 @@ window.__ModuleLoader__.load({
1060
1077
  'confirm.cancel': '取消',
1061
1078
  'confirm.ok': '確定',
1062
1079
  'prompt.newBranch': '新分支名(建立並簽出)',
1080
+ 'prompt.createTracking': '從遠端分支建立本地分支',
1063
1081
  'prompt.renameBranch': '重新命名分支',
1064
1082
  'prompt.newTag': '新標籤名',
1065
1083
  'prompt.fromHead': '當前 HEAD',
@@ -1162,6 +1180,9 @@ window.__ModuleLoader__.load({
1162
1180
  'action.fullscreen': '全螢幕',
1163
1181
  'action.exitFullscreen': '結束全螢幕',
1164
1182
  'action.newBranchFrom': '由此新建分支...',
1183
+ 'action.setUpstream': '設定上游…',
1184
+ 'action.unsetUpstream': '取消上游',
1185
+ 'action.createLocalBranch': '建立本地分支…',
1165
1186
  'action.newBranchHere': '在此新建分支...',
1166
1187
  'action.rename': '重新命名...',
1167
1188
  'action.delete': '刪除',
@@ -1233,6 +1254,8 @@ window.__ModuleLoader__.load({
1233
1254
  'more.fetchAll': '從所有遠端擷取',
1234
1255
  'more.deleteRemoteBranch': '刪除遠端分支...',
1235
1256
  'more.publish': '發佈分支...',
1257
+ 'more.setUpstreamHead': '設定目前分支上游…',
1258
+ 'more.unsetUpstreamHead': '取消目前分支上游',
1236
1259
  'more.addRemote': '新增遠端...',
1237
1260
  'more.removeRemote': '移除遠端...',
1238
1261
  'more.stashTracked': '擱置(僅已追蹤)',
@@ -1390,6 +1413,7 @@ window.__ModuleLoader__.load({
1390
1413
  'confirm.cancel': '取消',
1391
1414
  'confirm.ok': '確定',
1392
1415
  'prompt.newBranch': '新分支名稱(建立並簽出)',
1416
+ 'prompt.createTracking': '從遠端分支建立本地分支',
1393
1417
  'prompt.renameBranch': '重新命名分支',
1394
1418
  'prompt.newTag': '新標籤名稱',
1395
1419
  'prompt.fromHead': '目前 HEAD',
@@ -1492,6 +1516,9 @@ window.__ModuleLoader__.load({
1492
1516
  'action.fullscreen': '全螢幕',
1493
1517
  'action.exitFullscreen': '結束全螢幕',
1494
1518
  'action.newBranchFrom': '由此新建分支...',
1519
+ 'action.setUpstream': '設定上游…',
1520
+ 'action.unsetUpstream': '取消上游',
1521
+ 'action.createLocalBranch': '建立本地分支…',
1495
1522
  'action.newBranchHere': '喺呢度新建分支...',
1496
1523
  'action.rename': '重新命名...',
1497
1524
  'action.delete': '刪除',
@@ -1563,6 +1590,8 @@ window.__ModuleLoader__.load({
1563
1590
  'more.fetchAll': '從所有遠端抓取',
1564
1591
  'more.deleteRemoteBranch': '刪除遠端分支...',
1565
1592
  'more.publish': '發布分支...',
1593
+ 'more.setUpstreamHead': '設定目前分支上游…',
1594
+ 'more.unsetUpstreamHead': '取消目前分支上游',
1566
1595
  'more.addRemote': '新增遠端...',
1567
1596
  'more.removeRemote': '刪除遠端...',
1568
1597
  'more.stashTracked': '儲存(僅已追蹤)',
@@ -1720,6 +1749,7 @@ window.__ModuleLoader__.load({
1720
1749
  'confirm.cancel': '取消',
1721
1750
  'confirm.ok': '確定',
1722
1751
  'prompt.newBranch': '新分支名(建立並簽出)',
1752
+ 'prompt.createTracking': '從遠端分支建立本地分支',
1723
1753
  'prompt.renameBranch': '重新命名分支',
1724
1754
  'prompt.newTag': '新標籤名',
1725
1755
  'prompt.fromHead': '當前 HEAD',
@@ -1822,6 +1852,9 @@ window.__ModuleLoader__.load({
1822
1852
  'action.fullscreen': '全画面',
1823
1853
  'action.exitFullscreen': '全画面を終了',
1824
1854
  'action.newBranchFrom': 'ここから新しいブランチ...',
1855
+ 'action.setUpstream': '上流を設定…',
1856
+ 'action.unsetUpstream': '上流を解除',
1857
+ 'action.createLocalBranch': 'ローカルブランチを作成…',
1825
1858
  'action.newBranchHere': 'ここに新しいブランチ...',
1826
1859
  'action.rename': '名前を変更...',
1827
1860
  'action.delete': '削除',
@@ -1893,6 +1926,8 @@ window.__ModuleLoader__.load({
1893
1926
  'more.fetchAll': '全リモートからフェッチ',
1894
1927
  'more.deleteRemoteBranch': 'リモートブランチを削除...',
1895
1928
  'more.publish': 'ブランチを公開...',
1929
+ 'more.setUpstreamHead': '現在のブランチの上流を設定…',
1930
+ 'more.unsetUpstreamHead': '現在のブランチの上流を解除',
1896
1931
  'more.addRemote': 'リモートを追加...',
1897
1932
  'more.removeRemote': 'リモートを削除...',
1898
1933
  'more.stashTracked': 'スタッシュ(追跡済みのみ)',
@@ -2050,6 +2085,7 @@ window.__ModuleLoader__.load({
2050
2085
  'confirm.cancel': 'キャンセル',
2051
2086
  'confirm.ok': 'OK',
2052
2087
  'prompt.newBranch': '新しいブランチ名(作成してチェックアウト)',
2088
+ 'prompt.createTracking': 'リモートブランチからローカルブランチを作成',
2053
2089
  'prompt.renameBranch': 'ブランチ名を変更',
2054
2090
  'prompt.newTag': '新しいタグ名',
2055
2091
  'prompt.fromHead': '現在の HEAD',
@@ -2152,6 +2188,9 @@ window.__ModuleLoader__.load({
2152
2188
  'action.fullscreen': '전체 화면',
2153
2189
  'action.exitFullscreen': '전체 화면 종료',
2154
2190
  'action.newBranchFrom': '여기서 새 브랜치...',
2191
+ 'action.setUpstream': '업스트림 설정…',
2192
+ 'action.unsetUpstream': '업스트림 해제',
2193
+ 'action.createLocalBranch': '로컬 브랜치 만들기…',
2155
2194
  'action.newBranchHere': '여기에 새 브랜치...',
2156
2195
  'action.rename': '이름 바꾸기...',
2157
2196
  'action.delete': '삭제',
@@ -2223,6 +2262,8 @@ window.__ModuleLoader__.load({
2223
2262
  'more.fetchAll': '모든 원격에서 페치',
2224
2263
  'more.deleteRemoteBranch': '원격 브랜치 삭제...',
2225
2264
  'more.publish': '브랜치 게시...',
2265
+ 'more.setUpstreamHead': '현재 브랜치 업스트림 설정…',
2266
+ 'more.unsetUpstreamHead': '현재 브랜치 업스트림 해제',
2226
2267
  'more.addRemote': '원격 추가...',
2227
2268
  'more.removeRemote': '원격 제거...',
2228
2269
  'more.stashTracked': '스태시(추적된 파일만)',
@@ -2380,6 +2421,7 @@ window.__ModuleLoader__.load({
2380
2421
  'confirm.cancel': '취소',
2381
2422
  'confirm.ok': '확인',
2382
2423
  'prompt.newBranch': '새 브랜치 이름(생성 후 체크아웃)',
2424
+ 'prompt.createTracking': '원격 브랜치에서 로컬 브랜치 만들기',
2383
2425
  'prompt.renameBranch': '브랜치 이름 바꾸기',
2384
2426
  'prompt.newTag': '새 태그 이름',
2385
2427
  'prompt.fromHead': '현재 HEAD',
@@ -2482,6 +2524,9 @@ window.__ModuleLoader__.load({
2482
2524
  'action.fullscreen': 'Vollbild',
2483
2525
  'action.exitFullscreen': 'Vollbild beenden',
2484
2526
  'action.newBranchFrom': 'Neuer Branch von hier...',
2527
+ 'action.setUpstream': 'Upstream festlegen …',
2528
+ 'action.unsetUpstream': 'Upstream entfernen',
2529
+ 'action.createLocalBranch': 'Lokalen Branch erstellen …',
2485
2530
  'action.newBranchHere': 'Neuer Branch hier...',
2486
2531
  'action.rename': 'Umbenennen...',
2487
2532
  'action.delete': 'Löschen',
@@ -2553,6 +2598,8 @@ window.__ModuleLoader__.load({
2553
2598
  'more.fetchAll': 'Von allen Remotes holen',
2554
2599
  'more.deleteRemoteBranch': 'Remote-Branch löschen...',
2555
2600
  'more.publish': 'Branch veröffentlichen...',
2601
+ 'more.setUpstreamHead': 'Upstream des aktuellen Branch festlegen …',
2602
+ 'more.unsetUpstreamHead': 'Upstream des aktuellen Branch entfernen',
2556
2603
  'more.addRemote': 'Remote hinzufügen...',
2557
2604
  'more.removeRemote': 'Remote entfernen...',
2558
2605
  'more.stashTracked': 'Stash (nur getrackt)',
@@ -2710,6 +2757,7 @@ window.__ModuleLoader__.load({
2710
2757
  'confirm.cancel': 'Abbrechen',
2711
2758
  'confirm.ok': 'OK',
2712
2759
  'prompt.newBranch': 'Name des neuen Branch (wird erstellt und ausgecheckt)',
2760
+ 'prompt.createTracking': 'Lokalen Branch aus dem Remote-Branch erstellen',
2713
2761
  'prompt.renameBranch': 'Branch umbenennen',
2714
2762
  'prompt.newTag': 'Name des neuen Tags',
2715
2763
  'prompt.fromHead': 'aktuelles HEAD',
@@ -2812,6 +2860,9 @@ window.__ModuleLoader__.load({
2812
2860
  'action.fullscreen': 'Plein écran',
2813
2861
  'action.exitFullscreen': 'Quitter le plein écran',
2814
2862
  'action.newBranchFrom': 'Nouvelle branche depuis ici...',
2863
+ 'action.setUpstream': 'Définir l\'upstream…',
2864
+ 'action.unsetUpstream': 'Retirer l\'upstream',
2865
+ 'action.createLocalBranch': 'Créer une branche locale…',
2815
2866
  'action.newBranchHere': 'Nouvelle branche ici...',
2816
2867
  'action.rename': 'Renommer...',
2817
2868
  'action.delete': 'Supprimer',
@@ -2883,6 +2934,8 @@ window.__ModuleLoader__.load({
2883
2934
  'more.fetchAll': 'Récupérer de tous les distants',
2884
2935
  'more.deleteRemoteBranch': 'Supprimer la branche distante...',
2885
2936
  'more.publish': 'Publier la branche...',
2937
+ 'more.setUpstreamHead': 'Définir l\'upstream de la branche courante…',
2938
+ 'more.unsetUpstreamHead': 'Retirer l\'upstream de la branche courante',
2886
2939
  'more.addRemote': 'Ajouter un distant...',
2887
2940
  'more.removeRemote': 'Supprimer le distant...',
2888
2941
  'more.stashTracked': 'Remisage (suivis seulement)',
@@ -3040,6 +3093,7 @@ window.__ModuleLoader__.load({
3040
3093
  'confirm.cancel': 'Annuler',
3041
3094
  'confirm.ok': 'OK',
3042
3095
  'prompt.newBranch': 'Nom de la nouvelle branche (créée et extraite)',
3096
+ 'prompt.createTracking': 'Créer une branche locale depuis la branche distante',
3043
3097
  'prompt.renameBranch': 'Renommer la branche',
3044
3098
  'prompt.newTag': 'Nom de la nouvelle étiquette',
3045
3099
  'prompt.fromHead': 'HEAD courant',
@@ -3142,6 +3196,9 @@ window.__ModuleLoader__.load({
3142
3196
  'action.fullscreen': 'Полный экран',
3143
3197
  'action.exitFullscreen': 'Выйти из полного экрана',
3144
3198
  'action.newBranchFrom': 'Новая ветка отсюда...',
3199
+ 'action.setUpstream': 'Задать upstream…',
3200
+ 'action.unsetUpstream': 'Убрать upstream',
3201
+ 'action.createLocalBranch': 'Создать локальную ветку…',
3145
3202
  'action.newBranchHere': 'Новая ветка здесь...',
3146
3203
  'action.rename': 'Переименовать...',
3147
3204
  'action.delete': 'Удалить',
@@ -3213,6 +3270,8 @@ window.__ModuleLoader__.load({
3213
3270
  'more.fetchAll': 'Изъять со всех серверов',
3214
3271
  'more.deleteRemoteBranch': 'Удалить ветвь на сервере...',
3215
3272
  'more.publish': 'Опубликовать ветвь...',
3273
+ 'more.setUpstreamHead': 'Задать upstream текущей ветки…',
3274
+ 'more.unsetUpstreamHead': 'Убрать upstream текущей ветки',
3216
3275
  'more.addRemote': 'Добавить сервер...',
3217
3276
  'more.removeRemote': 'Удалить сервер...',
3218
3277
  'more.stashTracked': 'Отложить (только отслеживаемое)',
@@ -3370,6 +3429,7 @@ window.__ModuleLoader__.load({
3370
3429
  'confirm.cancel': 'Отмена',
3371
3430
  'confirm.ok': 'OK',
3372
3431
  'prompt.newBranch': 'Имя новой ветки (будет создана и выбрана)',
3432
+ 'prompt.createTracking': 'Создать локальную ветку из удалённой',
3373
3433
  'prompt.renameBranch': 'Переименовать ветку',
3374
3434
  'prompt.newTag': 'Имя нового тега',
3375
3435
  'prompt.fromHead': 'текущий HEAD',
@@ -3472,6 +3532,9 @@ window.__ModuleLoader__.load({
3472
3532
  'action.fullscreen': 'Tela cheia',
3473
3533
  'action.exitFullscreen': 'Sair da tela cheia',
3474
3534
  'action.newBranchFrom': 'Nova branch a partir daqui...',
3535
+ 'action.setUpstream': 'Definir upstream…',
3536
+ 'action.unsetUpstream': 'Remover upstream',
3537
+ 'action.createLocalBranch': 'Criar branch local…',
3475
3538
  'action.newBranchHere': 'Nova branch aqui...',
3476
3539
  'action.rename': 'Renomear...',
3477
3540
  'action.delete': 'Excluir',
@@ -3543,6 +3606,8 @@ window.__ModuleLoader__.load({
3543
3606
  'more.fetchAll': 'Fetch de todos os remotos',
3544
3607
  'more.deleteRemoteBranch': 'Eliminar ramo remoto...',
3545
3608
  'more.publish': 'Publicar ramificação...',
3609
+ 'more.setUpstreamHead': 'Definir upstream da branch atual…',
3610
+ 'more.unsetUpstreamHead': 'Remover upstream da branch atual',
3546
3611
  'more.addRemote': 'Adicionar remoto...',
3547
3612
  'more.removeRemote': 'Remover remoto...',
3548
3613
  'more.stashTracked': 'Stash (apenas rastreados)',
@@ -3700,6 +3765,7 @@ window.__ModuleLoader__.load({
3700
3765
  'confirm.cancel': 'Cancelar',
3701
3766
  'confirm.ok': 'OK',
3702
3767
  'prompt.newBranch': 'Nome da nova branch (criada e com checkout)',
3768
+ 'prompt.createTracking': 'Criar branch local a partir da remota',
3703
3769
  'prompt.renameBranch': 'Renomear branch',
3704
3770
  'prompt.newTag': 'Nome da nova tag',
3705
3771
  'prompt.fromHead': 'HEAD atual',
@@ -3802,6 +3868,9 @@ window.__ModuleLoader__.load({
3802
3868
  'action.fullscreen': 'Schermo intero',
3803
3869
  'action.exitFullscreen': 'Esci da schermo intero',
3804
3870
  'action.newBranchFrom': 'Nuovo branch da qui...',
3871
+ 'action.setUpstream': 'Imposta upstream…',
3872
+ 'action.unsetUpstream': 'Rimuovi upstream',
3873
+ 'action.createLocalBranch': 'Crea branch locale…',
3805
3874
  'action.newBranchHere': 'Nuovo branch qui...',
3806
3875
  'action.rename': 'Rinomina...',
3807
3876
  'action.delete': 'Elimina',
@@ -3873,6 +3942,8 @@ window.__ModuleLoader__.load({
3873
3942
  'more.fetchAll': 'Fetch da tutti i remoti',
3874
3943
  'more.deleteRemoteBranch': 'Elimina branch remoto...',
3875
3944
  'more.publish': 'Pubblica branch...',
3945
+ 'more.setUpstreamHead': 'Imposta upstream del branch corrente…',
3946
+ 'more.unsetUpstreamHead': 'Rimuovi upstream del branch corrente',
3876
3947
  'more.addRemote': 'Aggiungi remoto...',
3877
3948
  'more.removeRemote': 'Rimuovi remoto...',
3878
3949
  'more.stashTracked': 'Stash (solo tracciati)',
@@ -4030,6 +4101,7 @@ window.__ModuleLoader__.load({
4030
4101
  'confirm.cancel': 'Annulla',
4031
4102
  'confirm.ok': 'OK',
4032
4103
  'prompt.newBranch': 'Nome del nuovo branch (creato e messo in checkout)',
4104
+ 'prompt.createTracking': 'Crea un branch locale dal branch remoto',
4033
4105
  'prompt.renameBranch': 'Rinomina il branch',
4034
4106
  'prompt.newTag': 'Nome del nuovo tag',
4035
4107
  'prompt.fromHead': 'HEAD corrente',
@@ -4132,6 +4204,9 @@ window.__ModuleLoader__.load({
4132
4204
  'action.fullscreen': 'Volledig scherm',
4133
4205
  'action.exitFullscreen': 'Volledig scherm sluiten',
4134
4206
  'action.newBranchFrom': 'Nieuwe branch vanaf hier...',
4207
+ 'action.setUpstream': 'Upstream instellen…',
4208
+ 'action.unsetUpstream': 'Upstream verwijderen',
4209
+ 'action.createLocalBranch': 'Lokale branch maken…',
4135
4210
  'action.newBranchHere': 'Nieuwe branch hier...',
4136
4211
  'action.rename': 'Hernoemen...',
4137
4212
  'action.delete': 'Verwijderen',
@@ -4203,6 +4278,8 @@ window.__ModuleLoader__.load({
4203
4278
  'more.fetchAll': 'Van alle remotes halen',
4204
4279
  'more.deleteRemoteBranch': 'Remote branch verwijderen...',
4205
4280
  'more.publish': 'Branch publiceren...',
4281
+ 'more.setUpstreamHead': 'Upstream instellen voor huidige branch…',
4282
+ 'more.unsetUpstreamHead': 'Upstream van huidige branch verwijderen',
4206
4283
  'more.addRemote': 'Remote toevoegen...',
4207
4284
  'more.removeRemote': 'Remote verwijderen...',
4208
4285
  'more.stashTracked': 'Stash (alleen gevolgd)',
@@ -4360,6 +4437,7 @@ window.__ModuleLoader__.load({
4360
4437
  'confirm.cancel': 'Annuleren',
4361
4438
  'confirm.ok': 'OK',
4362
4439
  'prompt.newBranch': 'Naam van de nieuwe branch (wordt aangemaakt en uitgecheckt)',
4440
+ 'prompt.createTracking': 'Lokale branch maken vanaf de remote branch',
4363
4441
  'prompt.renameBranch': 'Branch hernoemen',
4364
4442
  'prompt.newTag': 'Naam van de nieuwe tag',
4365
4443
  'prompt.fromHead': 'huidige HEAD',
@@ -4462,6 +4540,9 @@ window.__ModuleLoader__.load({
4462
4540
  'action.fullscreen': 'Pełny ekran',
4463
4541
  'action.exitFullscreen': 'Wyjdź z pełnego ekranu',
4464
4542
  'action.newBranchFrom': 'Nowa gałąź stąd...',
4543
+ 'action.setUpstream': 'Ustaw upstream…',
4544
+ 'action.unsetUpstream': 'Usuń upstream',
4545
+ 'action.createLocalBranch': 'Utwórz gałąź lokalną…',
4465
4546
  'action.newBranchHere': 'Nowa gałąź tutaj...',
4466
4547
  'action.rename': 'Zmień nazwę...',
4467
4548
  'action.delete': 'Usuń',
@@ -4533,6 +4614,8 @@ window.__ModuleLoader__.load({
4533
4614
  'more.fetchAll': 'Pobierz ze wszystkich zdalnych',
4534
4615
  'more.deleteRemoteBranch': 'Usuń zdalną gałąź...',
4535
4616
  'more.publish': 'Opublikuj gałąź...',
4617
+ 'more.setUpstreamHead': 'Ustaw upstream bieżącej gałęzi…',
4618
+ 'more.unsetUpstreamHead': 'Usuń upstream bieżącej gałęzi',
4536
4619
  'more.addRemote': 'Dodaj zdalne...',
4537
4620
  'more.removeRemote': 'Usuń zdalne...',
4538
4621
  'more.stashTracked': 'Schowaj (tylko śledzone)',
@@ -4690,6 +4773,7 @@ window.__ModuleLoader__.load({
4690
4773
  'confirm.cancel': 'Anuluj',
4691
4774
  'confirm.ok': 'OK',
4692
4775
  'prompt.newBranch': 'Nazwa nowej gałęzi (zostanie utworzona i wybrana)',
4776
+ 'prompt.createTracking': 'Utwórz gałąź lokalną z gałęzi zdalnej',
4693
4777
  'prompt.renameBranch': 'Zmień nazwę gałęzi',
4694
4778
  'prompt.newTag': 'Nazwa nowego tagu',
4695
4779
  'prompt.fromHead': 'bieżący HEAD',
@@ -4792,6 +4876,9 @@ window.__ModuleLoader__.load({
4792
4876
  'action.fullscreen': 'Helskärm',
4793
4877
  'action.exitFullscreen': 'Avsluta helskärm',
4794
4878
  'action.newBranchFrom': 'Ny gren härifrån...',
4879
+ 'action.setUpstream': 'Ange upstream…',
4880
+ 'action.unsetUpstream': 'Ta bort upstream',
4881
+ 'action.createLocalBranch': 'Skapa lokal gren…',
4795
4882
  'action.newBranchHere': 'Ny gren här...',
4796
4883
  'action.rename': 'Byt namn...',
4797
4884
  'action.delete': 'Ta bort',
@@ -4863,6 +4950,8 @@ window.__ModuleLoader__.load({
4863
4950
  'more.fetchAll': 'Hämta från alla fjärrar',
4864
4951
  'more.deleteRemoteBranch': 'Ta bort fjärrgren...',
4865
4952
  'more.publish': 'Publicera gren...',
4953
+ 'more.setUpstreamHead': 'Ange upstream för aktuell gren…',
4954
+ 'more.unsetUpstreamHead': 'Ta bort upstream för aktuell gren',
4866
4955
  'more.addRemote': 'Lägg till fjärr...',
4867
4956
  'more.removeRemote': 'Ta bort fjärr...',
4868
4957
  'more.stashTracked': 'Stash (endast spårade)',
@@ -5020,6 +5109,7 @@ window.__ModuleLoader__.load({
5020
5109
  'confirm.cancel': 'Avbryt',
5021
5110
  'confirm.ok': 'OK',
5022
5111
  'prompt.newBranch': 'Namn på ny gren (skapas och checkas ut)',
5112
+ 'prompt.createTracking': 'Skapa lokal gren från fjärrgrenen',
5023
5113
  'prompt.renameBranch': 'Byt namn på grenen',
5024
5114
  'prompt.newTag': 'Namn på ny tagg',
5025
5115
  'prompt.fromHead': 'aktuell HEAD',
@@ -5122,6 +5212,9 @@ window.__ModuleLoader__.load({
5122
5212
  'action.fullscreen': 'Tam ekran',
5123
5213
  'action.exitFullscreen': 'Tam ekrandan çık',
5124
5214
  'action.newBranchFrom': 'Buradan yeni dal...',
5215
+ 'action.setUpstream': 'Upstream ayarla…',
5216
+ 'action.unsetUpstream': 'Upstream kaldır',
5217
+ 'action.createLocalBranch': 'Yerel dal oluştur…',
5125
5218
  'action.newBranchHere': 'Burada yeni dal...',
5126
5219
  'action.rename': 'Yeniden adlandır...',
5127
5220
  'action.delete': 'Sil',
@@ -5193,6 +5286,8 @@ window.__ModuleLoader__.load({
5193
5286
  'more.fetchAll': 'Tüm uzaklardan al',
5194
5287
  'more.deleteRemoteBranch': 'Uzak dalı sil...',
5195
5288
  'more.publish': 'Dalı yayınla...',
5289
+ 'more.setUpstreamHead': 'Geçerli dalın upstream\'ini ayarla…',
5290
+ 'more.unsetUpstreamHead': 'Geçerli dalın upstream\'ini kaldır',
5196
5291
  'more.addRemote': 'Uzak ekle...',
5197
5292
  'more.removeRemote': 'Uzağı kaldır...',
5198
5293
  'more.stashTracked': 'Stash (yalnızca izlenen)',
@@ -5350,6 +5445,7 @@ window.__ModuleLoader__.load({
5350
5445
  'confirm.cancel': 'İptal',
5351
5446
  'confirm.ok': 'Tamam',
5352
5447
  'prompt.newBranch': 'Yeni dal adı (oluşturulur ve çıkarılır)',
5448
+ 'prompt.createTracking': 'Uzak daldan yerel dal oluştur',
5353
5449
  'prompt.renameBranch': 'Dalı yeniden adlandır',
5354
5450
  'prompt.newTag': 'Yeni etiket adı',
5355
5451
  'prompt.fromHead': 'geçerli HEAD',
@@ -5452,6 +5548,9 @@ window.__ModuleLoader__.load({
5452
5548
  'action.fullscreen': 'Layar penuh',
5453
5549
  'action.exitFullscreen': 'Keluar dari layar penuh',
5454
5550
  'action.newBranchFrom': 'Branch baru dari sini...',
5551
+ 'action.setUpstream': 'Atur upstream…',
5552
+ 'action.unsetUpstream': 'Hapus upstream',
5553
+ 'action.createLocalBranch': 'Buat branch lokal…',
5455
5554
  'action.newBranchHere': 'Branch baru di sini...',
5456
5555
  'action.rename': 'Ganti nama...',
5457
5556
  'action.delete': 'Hapus',
@@ -5523,6 +5622,8 @@ window.__ModuleLoader__.load({
5523
5622
  'more.fetchAll': 'Fetch dari semua remote',
5524
5623
  'more.deleteRemoteBranch': 'Hapus cabang remote...',
5525
5624
  'more.publish': 'Publikasikan cabang...',
5625
+ 'more.setUpstreamHead': 'Atur upstream cabang saat ini…',
5626
+ 'more.unsetUpstreamHead': 'Hapus upstream cabang saat ini',
5526
5627
  'more.addRemote': 'Tambah remote...',
5527
5628
  'more.removeRemote': 'Hapus remote...',
5528
5629
  'more.stashTracked': 'Stash (hanya yang dilacak)',
@@ -5680,6 +5781,7 @@ window.__ModuleLoader__.load({
5680
5781
  'confirm.cancel': 'Batal',
5681
5782
  'confirm.ok': 'OK',
5682
5783
  'prompt.newBranch': 'Nama branch baru (dibuat dan di-checkout)',
5784
+ 'prompt.createTracking': 'Buat branch lokal dari branch remote',
5683
5785
  'prompt.renameBranch': 'Ganti nama branch',
5684
5786
  'prompt.newTag': 'Nama tag baru',
5685
5787
  'prompt.fromHead': 'HEAD saat ini',
@@ -5782,6 +5884,9 @@ window.__ModuleLoader__.load({
5782
5884
  'action.fullscreen': 'Toàn màn hình',
5783
5885
  'action.exitFullscreen': 'Thoát toàn màn hình',
5784
5886
  'action.newBranchFrom': 'Nhánh mới từ đây...',
5887
+ 'action.setUpstream': 'Đặt upstream…',
5888
+ 'action.unsetUpstream': 'Bỏ upstream',
5889
+ 'action.createLocalBranch': 'Tạo nhánh cục bộ…',
5785
5890
  'action.newBranchHere': 'Nhánh mới tại đây...',
5786
5891
  'action.rename': 'Đổi tên...',
5787
5892
  'action.delete': 'Xoá',
@@ -5853,6 +5958,8 @@ window.__ModuleLoader__.load({
5853
5958
  'more.fetchAll': 'Fetch từ mọi remote',
5854
5959
  'more.deleteRemoteBranch': 'Xóa nhánh remote...',
5855
5960
  'more.publish': 'Công bố nhánh...',
5961
+ 'more.setUpstreamHead': 'Đặt upstream cho nhánh hiện tại…',
5962
+ 'more.unsetUpstreamHead': 'Bỏ upstream của nhánh hiện tại',
5856
5963
  'more.addRemote': 'Thêm remote...',
5857
5964
  'more.removeRemote': 'Xóa remote...',
5858
5965
  'more.stashTracked': 'Stash (chỉ theo dõi)',
@@ -6010,6 +6117,7 @@ window.__ModuleLoader__.load({
6010
6117
  'confirm.cancel': 'Huỷ',
6011
6118
  'confirm.ok': 'OK',
6012
6119
  'prompt.newBranch': 'Tên nhánh mới (được tạo và checkout)',
6120
+ 'prompt.createTracking': 'Tạo nhánh cục bộ từ nhánh từ xa',
6013
6121
  'prompt.renameBranch': 'Đổi tên nhánh',
6014
6122
  'prompt.newTag': 'Tên thẻ mới',
6015
6123
  'prompt.fromHead': 'HEAD hiện tại',
@@ -6112,6 +6220,9 @@ window.__ModuleLoader__.load({
6112
6220
  'action.fullscreen': 'ملء الشاشة',
6113
6221
  'action.exitFullscreen': 'إنهاء ملء الشاشة',
6114
6222
  'action.newBranchFrom': 'فرع جديد من هنا...',
6223
+ 'action.setUpstream': 'تعيين upstream…',
6224
+ 'action.unsetUpstream': 'إزالة upstream',
6225
+ 'action.createLocalBranch': 'إنشاء فرع محلي…',
6115
6226
  'action.newBranchHere': 'فرع جديد هنا...',
6116
6227
  'action.rename': 'إعادة التسمية...',
6117
6228
  'action.delete': 'حذف',
@@ -6183,6 +6294,8 @@ window.__ModuleLoader__.load({
6183
6294
  'more.fetchAll': 'جلب من كل الأجهزة البعيدة',
6184
6295
  'more.deleteRemoteBranch': 'حذف فرع بعيد...',
6185
6296
  'more.publish': 'نشر الفرع...',
6297
+ 'more.setUpstreamHead': 'تعيين upstream للفرع الحالي…',
6298
+ 'more.unsetUpstreamHead': 'إزالة upstream للفرع الحالي',
6186
6299
  'more.addRemote': 'إضافة جهاز بعيد...',
6187
6300
  'more.removeRemote': 'إزالة جهاز بعيد...',
6188
6301
  'more.stashTracked': 'خبئ (المتتبع فقط)',
@@ -6340,6 +6453,7 @@ window.__ModuleLoader__.load({
6340
6453
  'confirm.cancel': 'إلغاء',
6341
6454
  'confirm.ok': 'موافق',
6342
6455
  'prompt.newBranch': 'اسم الفرع الجديد (يُنشأ ويُبدَّل إليه)',
6456
+ 'prompt.createTracking': 'إنشاء فرع محلي من الفرع البعيد',
6343
6457
  'prompt.renameBranch': 'إعادة تسمية الفرع',
6344
6458
  'prompt.newTag': 'اسم الوسم الجديد',
6345
6459
  'prompt.fromHead': 'HEAD الحالي',
@@ -6442,6 +6556,9 @@ window.__ModuleLoader__.load({
6442
6556
  'action.fullscreen': 'पूर्ण स्क्रीन',
6443
6557
  'action.exitFullscreen': 'पूर्ण स्क्रीन से बाहर',
6444
6558
  'action.newBranchFrom': 'यहाँ से नई शाखा...',
6559
+ 'action.setUpstream': 'अपस्ट्रीम सेट करें…',
6560
+ 'action.unsetUpstream': 'अपस्ट्रीम हटाएँ',
6561
+ 'action.createLocalBranch': 'लोकल शाखा बनाएँ…',
6445
6562
  'action.newBranchHere': 'यहाँ नई शाखा...',
6446
6563
  'action.rename': 'नाम बदलें...',
6447
6564
  'action.delete': 'हटाएँ',
@@ -6513,6 +6630,8 @@ window.__ModuleLoader__.load({
6513
6630
  'more.fetchAll': 'सभी रिमोट से फ़ेच',
6514
6631
  'more.deleteRemoteBranch': 'रिमोट ब्रांच हटाएँ...',
6515
6632
  'more.publish': 'ब्रांच प्रकाशित करें...',
6633
+ 'more.setUpstreamHead': 'वर्तमान शाखा के लिए अपस्ट्रीम सेट करें…',
6634
+ 'more.unsetUpstreamHead': 'वर्तमान शाखा का अपस्ट्रीम हटाएँ',
6516
6635
  'more.addRemote': 'रिमोट जोड़ें...',
6517
6636
  'more.removeRemote': 'रिमोट हटाएँ...',
6518
6637
  'more.stashTracked': 'स्टैश (केवल ट्रैक की गई)',
@@ -6670,6 +6789,7 @@ window.__ModuleLoader__.load({
6670
6789
  'confirm.cancel': 'रद्द करें',
6671
6790
  'confirm.ok': 'ठीक',
6672
6791
  'prompt.newBranch': 'नई शाखा का नाम (बनाई और चेकआउट की जाएगी)',
6792
+ 'prompt.createTracking': 'रिमोट शाखा से लोकल शाखा बनाएँ',
6673
6793
  'prompt.renameBranch': 'शाखा का नाम बदलें',
6674
6794
  'prompt.newTag': 'नए टैग का नाम',
6675
6795
  'prompt.fromHead': 'वर्तमान HEAD',
@@ -6772,6 +6892,9 @@ window.__ModuleLoader__.load({
6772
6892
  'action.fullscreen': 'เต็มหน้าจอ',
6773
6893
  'action.exitFullscreen': 'ออกจากเต็มหน้าจอ',
6774
6894
  'action.newBranchFrom': 'แบรนช์ใหม่จากที่นี่...',
6895
+ 'action.setUpstream': 'ตั้งค่า upstream…',
6896
+ 'action.unsetUpstream': 'ยกเลิก upstream',
6897
+ 'action.createLocalBranch': 'สร้างแบรนช์ในเครื่อง…',
6775
6898
  'action.newBranchHere': 'แบรนช์ใหม่ที่นี่...',
6776
6899
  'action.rename': 'เปลี่ยนชื่อ...',
6777
6900
  'action.delete': 'ลบ',
@@ -6843,6 +6966,8 @@ window.__ModuleLoader__.load({
6843
6966
  'more.fetchAll': 'ฟีตช์จากทุกรีโมต',
6844
6967
  'more.deleteRemoteBranch': 'ลบบรานช์รีโมต...',
6845
6968
  'more.publish': 'เผยแพร่บรานช์...',
6969
+ 'more.setUpstreamHead': 'ตั้งค่า upstream ของแบรนช์ปัจจุบัน…',
6970
+ 'more.unsetUpstreamHead': 'ยกเลิก upstream ของแบรนช์ปัจจุบัน',
6846
6971
  'more.addRemote': 'เพิ่มรีโมต...',
6847
6972
  'more.removeRemote': 'ลบรีโมต...',
6848
6973
  'more.stashTracked': 'สแตช(เฉพาะไฟล์ที่ติดตาม)',
@@ -7000,6 +7125,7 @@ window.__ModuleLoader__.load({
7000
7125
  'confirm.cancel': 'ยกเลิก',
7001
7126
  'confirm.ok': 'ตกลง',
7002
7127
  'prompt.newBranch': 'ชื่อแบรนช์ใหม่ (สร้างและเช็กเอาต์ให้)',
7128
+ 'prompt.createTracking': 'สร้างแบรนช์ในเครื่องจากแบรนช์รีโมต',
7003
7129
  'prompt.renameBranch': 'เปลี่ยนชื่อแบรนช์',
7004
7130
  'prompt.newTag': 'ชื่อแท็กใหม่',
7005
7131
  'prompt.fromHead': 'HEAD ปัจจุบัน',
@@ -10541,6 +10667,10 @@ window.__ModuleLoader__.load({
10541
10667
  },
10542
10668
  E('span', { className: 'dig-row-icon dig-tone-' + tone + (starred === true ? ' dig-star-filled' : '') }, E(Icon, { name: glyph, size: 12 })),
10543
10669
  E('span', { className: 'dig-row-label' }, props.label === undefined ? entry.name : props.label),
10670
+ // Inline tracking target (issue #18): the title already said "name →
10671
+ // upstream", but nobody hovers a tree to learn a binding. Local rows
10672
+ // show it as muted small text; remote rows ARE the upstream.
10673
+ kind !== 'remote' && kind !== 'tag' && entry.upstream !== null && entry.upstream !== undefined ? E('span', { className: 'dig-row-upstream' }, '→ ' + entry.upstream) : null,
10544
10674
  // A bare 'W' told nobody anything (reported right after the section counts):
10545
10675
  // it means this branch is checked out in ANOTHER working tree, which is why
10546
10676
  // git refuses to check it out here. An icon plus a spelled-out tooltip says so.
@@ -13184,7 +13314,25 @@ window.__ModuleLoader__.load({
13184
13314
  { id: 'copy', icon: 'tag', tone: 'secondary', label: t('action.copyName'), run: () => copyValues([entry.name]) },
13185
13315
  null,
13186
13316
  { id: 'favorite', icon: 'star', tone: 'warn', label: t('action.favorite'), active: favorites.indexOf(entry.name) >= 0, run: () => toggleFavoriteBranch(entry.name) },
13187
- { id: 'newBranch', icon: 'plus', tone: 'success', label: t('action.newBranchFrom'), run: () => setDialog({ kind: 'newBranch', from: entry.name }) },
13317
+ /* Upstream management (issue #18). The remote-picker submenu is
13318
+ built INSIDE run() — branches.remote is read at click time, not
13319
+ render time, so branchMenu's useCallback deps stay untouched
13320
+ (remoteBranches is defined AFTER this callback; a render-time
13321
+ reference would be the classic hooks TDZ trap). */
13322
+ isLocal ? { id: 'setUpstream', icon: 'fetch', tone: 'cyan', label: t('action.setUpstream'), disabled: branches === null || branches.remote.length === 0, reason: reason, run: (event) => openMenuAt(event, branches.remote.map((remoteEntry) => ({
13323
+ id: 'upstream:' + remoteEntry.name,
13324
+ icon: 'fetch', tone: 'cyan',
13325
+ label: remoteEntry.name,
13326
+ active: entry.upstream === remoteEntry.name,
13327
+ run: () => { void run('branch-upstream', { branch: entry.name, upstream: remoteEntry.name }) },
13328
+ }))) } : null,
13329
+ isLocal && entry.upstream !== null && entry.upstream !== undefined ? { id: 'unsetUpstream', icon: 'undo', tone: 'secondary', label: t('action.unsetUpstream'), run: () => { void run('branch-upstream', { branch: entry.name, unset: true }) } } : null,
13330
+ /* Remote rows get the tracking form: the local branch is created
13331
+ FROM the remote ref with --track in one step (issue #18 item 5),
13332
+ replacing the plain "new branch from" which could not bind. */
13333
+ entry.remote === true
13334
+ ? { id: 'createTracking', icon: 'branchCreate', tone: 'success', label: t('action.createLocalBranch'), run: () => setDialog({ kind: 'createTracking', from: entry.name, name: entry.name.slice(entry.name.indexOf('/') + 1) }) }
13335
+ : { id: 'newBranch', icon: 'plus', tone: 'success', label: t('action.newBranchFrom'), run: () => setDialog({ kind: 'newBranch', from: entry.name }) },
13188
13336
  isLocal ? { id: 'rename', icon: 'file', tone: 'primary', label: t('action.rename'), run: () => setDialog({ kind: 'renameBranch', from: entry.name }) } : null,
13189
13337
  isLocal ? { id: 'delete', icon: 'trash', tone: 'danger', label: t('action.delete'), danger: true, disabled: entry.head === true, reason: reason, run: () => setDialog({ kind: 'deleteBranch', name: entry.name }) } : null,
13190
13338
  entry.tag === true
@@ -13360,6 +13508,9 @@ window.__ModuleLoader__.load({
13360
13508
  const submitDialog = useCallback(async (state, value) => {
13361
13509
  setDialog(null)
13362
13510
  if (state.kind === 'newBranch') { await run('checkout', { branch: value, create: true, startPoint: state.from }); return }
13511
+ /* From a remote ref (issue #18): --track binds the upstream in the
13512
+ same checkout -b, so "create" and "set upstream" are one motion. */
13513
+ if (state.kind === 'createTracking') { await run('checkout', { branch: value, create: true, startPoint: state.from, track: true }); return }
13363
13514
  if (state.kind === 'renameBranch') { await run('branchRename', { from: state.from, to: value }); return }
13364
13515
  if (state.kind === 'newTag') { await run('tagCreate', { name: value, hash: state.hash }); return }
13365
13516
  if (state.kind === 'deleteTag') { await run('tagDelete', { name: value }); return }
@@ -13784,6 +13935,17 @@ window.__ModuleLoader__.load({
13784
13935
  { id: 'br-delete-remote', label: t('more.deleteRemoteBranch'), danger: true, disabled: remoteBranches.length === 0 || blocked, reason, run: (ev) => pickRemoteBranchMenu(ev) },
13785
13936
  null,
13786
13937
  { id: 'br-publish', label: t('more.publish'), disabled: remoteReady !== true || tracked === true || blocked, reason, run: () => { void run('push', { setUpstream: true, confirm: true }) } },
13938
+ /* Upstream management for the CURRENT branch (issue #18): same
13939
+ verbs as the branch-row menu, reachable without selecting a
13940
+ branch first. Submenu built inside run() like rm-remove. */
13941
+ { id: 'br-upstream', label: t('more.setUpstreamHead'), icon: 'fetch', tone: 'cyan', disabled: headBranch === '' || remoteBranches.length === 0 || blocked, reason, run: (ev) => openMenuAt(ev, remoteBranches.map((remoteEntry) => ({
13942
+ id: 'head-upstream:' + remoteEntry.name,
13943
+ icon: 'fetch', tone: 'cyan',
13944
+ label: remoteEntry.name,
13945
+ active: summary.upstream === remoteEntry.name,
13946
+ run: () => { void run('branch-upstream', { branch: headBranch, upstream: remoteEntry.name }) },
13947
+ }))) },
13948
+ { id: 'br-unset-upstream', label: t('more.unsetUpstreamHead'), icon: 'undo', tone: 'secondary', disabled: headBranch === '' || tracked !== true || blocked, reason, run: () => { void run('branch-upstream', { branch: headBranch, unset: true }) } },
13787
13949
  ] },
13788
13950
  /* —— SCM ▸ Remote ▸ —— */
13789
13951
  { id: 'sub-remote', icon: 'fetch', tone: 'violet', label: t('more.remoteGroup'), items: [
@@ -14175,13 +14337,13 @@ window.__ModuleLoader__.load({
14175
14337
  onClose: () => setRailSettings(false),
14176
14338
  }))
14177
14339
  }
14178
- if (dialog !== null && (dialog.kind === 'newBranch' || dialog.kind === 'renameBranch' || dialog.kind === 'newTag' || dialog.kind === 'deleteTag' || dialog.kind === 'commitMsg')) {
14179
- const titles = { newBranch: t('prompt.newBranch'), renameBranch: t('prompt.renameBranch'), newTag: t('prompt.newTag'), deleteTag: t('prompt.deleteTag'), commitMsg: t('prompt.commitMessage') }
14340
+ if (dialog !== null && (dialog.kind === 'newBranch' || dialog.kind === 'createTracking' || dialog.kind === 'renameBranch' || dialog.kind === 'newTag' || dialog.kind === 'deleteTag' || dialog.kind === 'commitMsg')) {
14341
+ const titles = { newBranch: t('prompt.newBranch'), createTracking: t('prompt.createTracking'), renameBranch: t('prompt.renameBranch'), newTag: t('prompt.newTag'), deleteTag: t('prompt.deleteTag'), commitMsg: t('prompt.commitMessage') }
14180
14342
  overlays.push(E(PromptDialog, {
14181
14343
  key: 'prompt',
14182
14344
  title: titles[dialog.kind],
14183
14345
  placeholder: dialog.from === undefined ? t('prompt.fromHead') : dialog.from,
14184
- initialValue: dialog.kind === 'renameBranch' ? dialog.from : '',
14346
+ initialValue: dialog.kind === 'renameBranch' ? dialog.from : (dialog.kind === 'createTracking' ? dialog.name : ''),
14185
14347
  okLabel: t('confirm.ok'), cancelLabel: t('confirm.cancel'),
14186
14348
  onCancel: () => setDialog(null),
14187
14349
  onSubmit: (value) => { void submitDialog(dialog, value) },
@@ -14710,6 +14872,9 @@ window.__ModuleLoader__.load({
14710
14872
  '.dig-row-head .dig-row-label{font-weight:600}',
14711
14873
  '.dig-row-icon{display:inline-flex;flex:none;opacity:.9}',
14712
14874
  '.dig-row-label{overflow:hidden;text-overflow:ellipsis;flex:1;min-width:0;font-weight:600}',
14875
+ // Inline tracking target (issue #18): flex:none so it never starves the
14876
+ // label, capped and ellipsised so a long origin/… cannot push the badges.
14877
+ '.dig-row-upstream{flex:none;max-width:180px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:11px;font-weight:400;color:var(--dsw-alias-label-tertiary,var(--dsw-alias-label-secondary))}',
14713
14878
  '.dig-row-sub{color:var(--dsw-alias-label-tertiary);font-size:11px;flex:none;max-width:45%;overflow:hidden;text-overflow:ellipsis}',
14714
14879
  '.dig-row-dir{margin-left:auto;opacity:.75}',
14715
14880
  '.dig-badge{font-size:10px;padding:0 5px;border-radius:999px;corner-shape:round;background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary);flex:none}',
@@ -14991,7 +15156,12 @@ window.__ModuleLoader__.load({
14991
15156
  '.dig-cs-pill{display:inline-flex;align-items:center;gap:5px;height:28px;padding:0 8px;border:none;border-radius:var(--dsw-radius-sm,8px);background:transparent;color:var(--dsw-alias-label-secondary);font-family:inherit;font-size:var(--dsh-content-font-size-secondary,13px);line-height:20px;white-space:nowrap;cursor:pointer}',
14992
15157
  '.dig-cs-pill:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}',
14993
15158
  '.dig-cs-pill:disabled{cursor:default}',
14994
- '.dig-cs-name{overflow:hidden;text-overflow:ellipsis;max-width:150px}',
15159
+ '.dig-cs-name{overflow:hidden;text-overflow:ellipsis;max-width:260px;white-space:nowrap;display:inline-block;vertical-align:bottom}',
15160
+ '.dig-cs-mrun{display:inline-flex;text-overflow:clip;-webkit-mask-image:linear-gradient(90deg,#000 0,#000 calc(100% - 14px),transparent);mask-image:linear-gradient(90deg,#000 0,#000 calc(100% - 14px),transparent)}',
15161
+ '.dig-cs-mrun .dig-cs-run{display:inline-flex;flex:none;will-change:transform}',
15162
+ '.dig-cs-mrun .dig-cs-chunk{flex:none;white-space:nowrap;padding-right:28px}',
15163
+ '.dig-cs-mrun:hover .dig-cs-run{animation:dig-cs-marquee var(--dig-cs-marquee-dur,10s) linear infinite}',
15164
+ '@keyframes dig-cs-marquee{from{transform:translateX(0)}to{transform:translateX(-50%)}}',
14995
15165
  '.dig-cs-pill svg{flex:none}',
14996
15166
  '.dig-cs-badge{display:inline-flex;align-items:center;font-size:12px;line-height:20px;font-variant-numeric:tabular-nums;white-space:nowrap;padding:0 3px;font-weight:500}',
14997
15167
  '.dig-cs-changes{color:var(--dsw-alias-state-warn-primary)}',
@@ -15214,6 +15384,51 @@ window.__ModuleLoader__.load({
15214
15384
  return null
15215
15385
  }
15216
15386
 
15387
+ /* Long repository/branch names: widen the label cap and, past it, run a
15388
+ hover-only seamless marquee (the official sidebar rows scroll hovered
15389
+ titles via useTitleMarquee, which this surface cannot require — this is
15390
+ the CSS twin). The label is measured after paint; only overflowing text
15391
+ switches to the duplicated-chunk structure, so short names keep the
15392
+ plain ellipsis and never animate. Duration follows the text width so a
15393
+ slightly-long name does not crawl. */
15394
+ const COMPOSER_NAME_MAX_PX = 260
15395
+ const MARQUEE_PX_PER_S = 28
15396
+
15397
+ function ComposerMarqueeName(props) {
15398
+ const text = typeof props.text === 'string' ? props.text : ''
15399
+ const boxRef = useRef(null)
15400
+ const [run, setRun] = useState(false)
15401
+ const [dur, setDur] = useState('')
15402
+ useEffect(() => {
15403
+ const box = boxRef.current
15404
+ if (box === null) return undefined
15405
+ const measure = () => {
15406
+ if (boxRef.current !== box) return /* replaced or unmounted */
15407
+ const overflow = box.scrollWidth > box.clientWidth + 1
15408
+ setRun(overflow)
15409
+ /* In the running structure scrollWidth covers BOTH chunks, so one
15410
+ chunk is half of it; the plain structure measures the text alone. */
15411
+ const unit = overflow === true && run === true ? box.scrollWidth / 2 : box.scrollWidth
15412
+ setDur(overflow === true ? (unit / MARQUEE_PX_PER_S).toFixed(2) + 's' : '')
15413
+ }
15414
+ measure()
15415
+ /* Webfonts land after paint and change text metrics — re-measure once. */
15416
+ let frame = 0
15417
+ const fonts = document.fonts
15418
+ if (fonts !== undefined && fonts !== null && fonts.ready !== undefined && typeof fonts.ready.then === 'function') {
15419
+ fonts.ready.then(() => { frame = requestAnimationFrame(measure) }, () => {})
15420
+ }
15421
+ return () => { if (frame !== 0) cancelAnimationFrame(frame) }
15422
+ }, [text, run])
15423
+ if (run !== true) {
15424
+ return E('span', { ref: boxRef, className: 'dig-cs-name' }, text)
15425
+ }
15426
+ return E('span', { ref: boxRef, className: 'dig-cs-name dig-cs-mrun', style: dur !== '' ? { '--dig-cs-marquee-dur': dur } : undefined },
15427
+ E('span', { className: 'dig-cs-run' },
15428
+ E('span', { className: 'dig-cs-chunk' }, text),
15429
+ E('span', { className: 'dig-cs-chunk', 'aria-hidden': 'true' }, text)))
15430
+ }
15431
+
15217
15432
  function ComposerGitStatus(props) {
15218
15433
  const ctx = props.ctx
15219
15434
  const t = props.t
@@ -15476,7 +15691,7 @@ window.__ModuleLoader__.load({
15476
15691
  onClick: singleRepo === true ? undefined : () => { setMenu(menu === 'repo' ? null : 'repo') },
15477
15692
  },
15478
15693
  E(Icon, { name: 'commit', size: 13 }),
15479
- E('span', { className: 'dig-cs-name' }, repoName),
15694
+ E(ComposerMarqueeName, { text: repoName }),
15480
15695
  singleRepo === true ? null : E(Icon, { name: 'chevron', size: 10 })),
15481
15696
  branchName !== null ? E('button', {
15482
15697
  type: 'button',
@@ -15485,7 +15700,7 @@ window.__ModuleLoader__.load({
15485
15700
  onClick: () => { if (menu !== 'branch') void openBranchMenu(); else setMenu(null) },
15486
15701
  },
15487
15702
  E(Icon, { name: 'branch', size: 13 }),
15488
- E('span', { className: 'dig-cs-name' }, detached === true ? t('composer.detached') : branchName),
15703
+ E(ComposerMarqueeName, { text: detached === true ? t('composer.detached') : branchName }),
15489
15704
  E(Icon, { name: 'chevron', size: 10 })) : null,
15490
15705
  changesCount !== null && changesCount > 0
15491
15706
  ? E('span', { className: 'dig-cs-badge dig-cs-changes', title: changesTitle }, '±' + String(changesCount),
package/src/index.js CHANGED
@@ -470,7 +470,7 @@ function withRepoLock(key, work) {
470
470
  }
471
471
 
472
472
  const WRITE_METHODS = new Set([
473
- 'stage', 'unstage', 'discard', 'commit', 'checkout', 'branchCreate', 'branchRename',
473
+ 'stage', 'unstage', 'discard', 'commit', 'checkout', 'branchCreate', 'branchRename', 'branch-upstream',
474
474
  'branchDelete', 'merge', 'rebase', 'cherryPick', 'revert', 'reset', 'fetch', 'pull',
475
475
  'push', 'stashPush', 'stashApply', 'stashDrop', 'stashClear', 'tagCreate', 'tagDelete', 'tagDeleteRemote', 'pushTags', 'clone', 'remoteAdd', 'remoteRemove', 'branchDeleteRemote', 'undoApply',
476
476
  ])
@@ -1003,6 +1003,9 @@ async function checkout(payload) {
1003
1003
  const name = requireRef(payload.branch, 'branch')
1004
1004
  const start = typeof payload.startPoint === 'string' && payload.startPoint.trim() !== '' ? requireRef(payload.startPoint, 'startPoint') : undefined
1005
1005
  const args = ['checkout', '-b', name]
1006
+ /* track (issue #18): "create a local branch from a remote one" must bind
1007
+ the upstream in the same breath — checkout -b alone never does. */
1008
+ if (payload.track === true && start !== undefined) args.push('--track')
1006
1009
  if (start !== undefined) args.push(start)
1007
1010
  await git(root, args)
1008
1011
  return { branch: name, created: true }
@@ -1022,6 +1025,25 @@ async function branchCreate(payload) {
1022
1025
  return { branch: name }
1023
1026
  }
1024
1027
 
1028
+ /* Upstream management (issue #18): rebind or drop a branch's tracking remote.
1029
+ git refuses --set-upstream-to with a ref it cannot resolve, so a typo dies
1030
+ here instead of silently writing branch.<name>.merge. */
1031
+ async function branchUpstream(payload) {
1032
+ const cwd = cwdOf(payload)
1033
+ const root = await repoRootOf(cwd, payload)
1034
+ const branch = requireRef(payload.branch, 'branch')
1035
+ if (payload.unset === true) {
1036
+ /* --unset-upstream errors on a branch that has none; the client only
1037
+ offers the verb when the row shows an upstream, and git's own message
1038
+ is the right one to surface if they raced. */
1039
+ await git(root, ['branch', '--unset-upstream', branch])
1040
+ return { branch, upstream: null }
1041
+ }
1042
+ const upstream = requireRef(payload.upstream, 'upstream')
1043
+ await git(root, ['branch', '--set-upstream-to=' + upstream, branch])
1044
+ return { branch, upstream }
1045
+ }
1046
+
1025
1047
  async function branchRename(payload) {
1026
1048
  const cwd = cwdOf(payload)
1027
1049
  const root = await repoRootOf(cwd, payload)
@@ -1999,6 +2021,7 @@ const METHODS = {
1999
2021
  checkout,
2000
2022
  branchCreate,
2001
2023
  branchRename,
2024
+ 'branch-upstream': branchUpstream,
2002
2025
  branchDelete,
2003
2026
  merge,
2004
2027
  rebase,