easy-worktree 0.0.1__py3-none-any.whl → 0.0.3__py3-none-any.whl
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.
- easy_worktree/__init__.py +431 -19
- {easy_worktree-0.0.1.dist-info → easy_worktree-0.0.3.dist-info}/METADATA +47 -1
- easy_worktree-0.0.3.dist-info/RECORD +6 -0
- easy_worktree-0.0.1.dist-info/RECORD +0 -6
- {easy_worktree-0.0.1.dist-info → easy_worktree-0.0.3.dist-info}/WHEEL +0 -0
- {easy_worktree-0.0.1.dist-info → easy_worktree-0.0.3.dist-info}/entry_points.txt +0 -0
- {easy_worktree-0.0.1.dist-info → easy_worktree-0.0.3.dist-info}/licenses/LICENSE +0 -0
easy_worktree/__init__.py
CHANGED
|
@@ -7,6 +7,8 @@ import subprocess
|
|
|
7
7
|
import sys
|
|
8
8
|
from pathlib import Path
|
|
9
9
|
import re
|
|
10
|
+
from datetime import datetime
|
|
11
|
+
import json
|
|
10
12
|
|
|
11
13
|
|
|
12
14
|
# 言語判定
|
|
@@ -27,8 +29,8 @@ MESSAGES = {
|
|
|
27
29
|
'ja': '使用方法: wt clone <repository_url>'
|
|
28
30
|
},
|
|
29
31
|
'usage_add': {
|
|
30
|
-
'en': 'Usage: wt add <work_name> [<base_branch>]',
|
|
31
|
-
'ja': '使用方法: wt add <作業名> [<base_branch>]'
|
|
32
|
+
'en': 'Usage: wt add <work_name> [<base_branch>] [--alias <name>]',
|
|
33
|
+
'ja': '使用方法: wt add <作業名> [<base_branch>] [--alias <名前>]'
|
|
32
34
|
},
|
|
33
35
|
'usage_rm': {
|
|
34
36
|
'en': 'Usage: wt rm <work_name>',
|
|
@@ -117,6 +119,62 @@ MESSAGES = {
|
|
|
117
119
|
'hook_failed': {
|
|
118
120
|
'en': 'Warning: hook exited with code {}',
|
|
119
121
|
'ja': '警告: hook が終了コード {} で終了しました'
|
|
122
|
+
},
|
|
123
|
+
'usage_clean': {
|
|
124
|
+
'en': 'Usage: wt clean [--dry-run] [--days N] [--all]',
|
|
125
|
+
'ja': '使用方法: wt clean [--dry-run] [--days N] [--all]'
|
|
126
|
+
},
|
|
127
|
+
'usage_alias': {
|
|
128
|
+
'en': 'Usage: wt alias <name> <worktree> | wt alias --list | wt alias --remove <name>',
|
|
129
|
+
'ja': '使用方法: wt alias <名前> <worktree> | wt alias --list | wt alias --remove <名前>'
|
|
130
|
+
},
|
|
131
|
+
'alias_exists_suggestion': {
|
|
132
|
+
'en': 'To override, use: wt alias --override {} {}',
|
|
133
|
+
'ja': '上書きするには次を実行してください: wt alias --override {} {}'
|
|
134
|
+
},
|
|
135
|
+
'no_clean_targets': {
|
|
136
|
+
'en': 'No worktrees to clean',
|
|
137
|
+
'ja': 'クリーンアップ対象の worktree がありません'
|
|
138
|
+
},
|
|
139
|
+
'clean_target': {
|
|
140
|
+
'en': 'Will remove: {} (created: {}, clean)',
|
|
141
|
+
'ja': '削除対象: {} (作成日時: {}, 変更なし)'
|
|
142
|
+
},
|
|
143
|
+
'clean_confirm': {
|
|
144
|
+
'en': 'Remove {} worktree(s)? [y/N]: ',
|
|
145
|
+
'ja': '{} 個の worktree を削除しますか? [y/N]: '
|
|
146
|
+
},
|
|
147
|
+
'alias_created': {
|
|
148
|
+
'en': 'Created alias: {} -> {}',
|
|
149
|
+
'ja': 'エイリアスを作成しました: {} -> {}'
|
|
150
|
+
},
|
|
151
|
+
'alias_removed': {
|
|
152
|
+
'en': 'Removed alias: {}',
|
|
153
|
+
'ja': 'エイリアスを削除しました: {}'
|
|
154
|
+
},
|
|
155
|
+
'alias_not_found': {
|
|
156
|
+
'en': 'Alias not found: {}',
|
|
157
|
+
'ja': 'エイリアスが見つかりません: {}'
|
|
158
|
+
},
|
|
159
|
+
'worktree_name': {
|
|
160
|
+
'en': 'Worktree',
|
|
161
|
+
'ja': 'Worktree'
|
|
162
|
+
},
|
|
163
|
+
'branch_name': {
|
|
164
|
+
'en': 'Branch',
|
|
165
|
+
'ja': 'ブランチ'
|
|
166
|
+
},
|
|
167
|
+
'created_at': {
|
|
168
|
+
'en': 'Created',
|
|
169
|
+
'ja': '作成日時'
|
|
170
|
+
},
|
|
171
|
+
'last_commit': {
|
|
172
|
+
'en': 'Last Commit',
|
|
173
|
+
'ja': '最終コミット'
|
|
174
|
+
},
|
|
175
|
+
'status_label': {
|
|
176
|
+
'en': 'Status',
|
|
177
|
+
'ja': '状態'
|
|
120
178
|
}
|
|
121
179
|
}
|
|
122
180
|
|
|
@@ -357,6 +415,19 @@ def cmd_add(args: list[str]):
|
|
|
357
415
|
print(msg('run_in_wt_dir'), file=sys.stderr)
|
|
358
416
|
sys.exit(1)
|
|
359
417
|
|
|
418
|
+
# --alias オプションをチェック
|
|
419
|
+
alias_name = None
|
|
420
|
+
if '--alias' in args:
|
|
421
|
+
alias_index = args.index('--alias')
|
|
422
|
+
if alias_index + 1 < len(args):
|
|
423
|
+
alias_name = args[alias_index + 1]
|
|
424
|
+
# --alias とその値を削除
|
|
425
|
+
args.pop(alias_index)
|
|
426
|
+
args.pop(alias_index)
|
|
427
|
+
else:
|
|
428
|
+
print(msg('error', 'Missing alias name after --alias'), file=sys.stderr)
|
|
429
|
+
sys.exit(1)
|
|
430
|
+
|
|
360
431
|
work_name = args[0]
|
|
361
432
|
|
|
362
433
|
# worktree のパスを決定(_base の親ディレクトリに作成)
|
|
@@ -424,6 +495,17 @@ def cmd_add(args: list[str]):
|
|
|
424
495
|
|
|
425
496
|
if result.returncode == 0:
|
|
426
497
|
print(msg('completed_worktree', worktree_path))
|
|
498
|
+
|
|
499
|
+
# エイリアスを作成
|
|
500
|
+
if alias_name:
|
|
501
|
+
alias_path = base_dir.parent / alias_name
|
|
502
|
+
if alias_path.exists():
|
|
503
|
+
print(msg('error', msg('already_exists', alias_name)), file=sys.stderr)
|
|
504
|
+
print(msg('alias_exists_suggestion', alias_name, work_name), file=sys.stderr)
|
|
505
|
+
else:
|
|
506
|
+
alias_path.symlink_to(worktree_path, target_is_directory=True)
|
|
507
|
+
print(msg('alias_created', alias_name, work_name))
|
|
508
|
+
|
|
427
509
|
# post-add hook を実行
|
|
428
510
|
run_post_add_hook(worktree_path, work_name, base_dir, branch_name)
|
|
429
511
|
else:
|
|
@@ -433,6 +515,64 @@ def cmd_add(args: list[str]):
|
|
|
433
515
|
sys.exit(1)
|
|
434
516
|
|
|
435
517
|
|
|
518
|
+
def get_worktree_info(base_dir: Path) -> list[dict]:
|
|
519
|
+
"""worktree の詳細情報を取得"""
|
|
520
|
+
result = run_command(
|
|
521
|
+
["git", "worktree", "list", "--porcelain"],
|
|
522
|
+
cwd=base_dir
|
|
523
|
+
)
|
|
524
|
+
|
|
525
|
+
worktrees = []
|
|
526
|
+
current = {}
|
|
527
|
+
|
|
528
|
+
for line in result.stdout.strip().split('\n'):
|
|
529
|
+
if not line:
|
|
530
|
+
if current:
|
|
531
|
+
worktrees.append(current)
|
|
532
|
+
current = {}
|
|
533
|
+
continue
|
|
534
|
+
|
|
535
|
+
if line.startswith('worktree '):
|
|
536
|
+
current['path'] = line.split(' ', 1)[1]
|
|
537
|
+
elif line.startswith('HEAD '):
|
|
538
|
+
current['head'] = line.split(' ', 1)[1]
|
|
539
|
+
elif line.startswith('branch '):
|
|
540
|
+
current['branch'] = line.split(' ', 1)[1].replace('refs/heads/', '')
|
|
541
|
+
elif line.startswith('detached'):
|
|
542
|
+
current['branch'] = 'DETACHED'
|
|
543
|
+
|
|
544
|
+
if current:
|
|
545
|
+
worktrees.append(current)
|
|
546
|
+
|
|
547
|
+
# 各 worktree の詳細情報を取得
|
|
548
|
+
for wt in worktrees:
|
|
549
|
+
path = Path(wt['path'])
|
|
550
|
+
|
|
551
|
+
# 作成日時(ディレクトリの作成時刻)
|
|
552
|
+
if path.exists():
|
|
553
|
+
stat_info = path.stat()
|
|
554
|
+
wt['created'] = datetime.fromtimestamp(stat_info.st_ctime)
|
|
555
|
+
|
|
556
|
+
# 最終コミット日時
|
|
557
|
+
result = run_command(
|
|
558
|
+
["git", "log", "-1", "--format=%ct", wt.get('head', 'HEAD')],
|
|
559
|
+
cwd=base_dir,
|
|
560
|
+
check=False
|
|
561
|
+
)
|
|
562
|
+
if result.returncode == 0 and result.stdout.strip():
|
|
563
|
+
wt['last_commit'] = datetime.fromtimestamp(int(result.stdout.strip()))
|
|
564
|
+
|
|
565
|
+
# git status(変更があるか)
|
|
566
|
+
result = run_command(
|
|
567
|
+
["git", "status", "--porcelain"],
|
|
568
|
+
cwd=path,
|
|
569
|
+
check=False
|
|
570
|
+
)
|
|
571
|
+
wt['is_clean'] = result.returncode == 0 and not result.stdout.strip()
|
|
572
|
+
|
|
573
|
+
return worktrees
|
|
574
|
+
|
|
575
|
+
|
|
436
576
|
def cmd_list(args: list[str]):
|
|
437
577
|
"""wt list - List worktrees"""
|
|
438
578
|
base_dir = find_base_dir()
|
|
@@ -440,8 +580,48 @@ def cmd_list(args: list[str]):
|
|
|
440
580
|
print(msg('error', msg('base_not_found')), file=sys.stderr)
|
|
441
581
|
sys.exit(1)
|
|
442
582
|
|
|
443
|
-
|
|
444
|
-
|
|
583
|
+
# --verbose または --sort オプションがある場合は詳細表示
|
|
584
|
+
verbose = '--verbose' in args or '-v' in args
|
|
585
|
+
sort_by = None
|
|
586
|
+
|
|
587
|
+
# ソートオプションを取得
|
|
588
|
+
for i, arg in enumerate(args):
|
|
589
|
+
if arg == '--sort' and i + 1 < len(args):
|
|
590
|
+
sort_by = args[i + 1]
|
|
591
|
+
|
|
592
|
+
if not verbose and not sort_by:
|
|
593
|
+
# 通常の git worktree list を実行
|
|
594
|
+
result = run_command(["git", "worktree", "list"] + args, cwd=base_dir)
|
|
595
|
+
print(result.stdout, end='')
|
|
596
|
+
return
|
|
597
|
+
|
|
598
|
+
# 詳細情報を取得
|
|
599
|
+
worktrees = get_worktree_info(base_dir)
|
|
600
|
+
|
|
601
|
+
# ソート
|
|
602
|
+
if sort_by == 'age' or sort_by == 'created':
|
|
603
|
+
worktrees.sort(key=lambda x: x.get('created', datetime.min))
|
|
604
|
+
elif sort_by == 'name':
|
|
605
|
+
worktrees.sort(key=lambda x: Path(x['path']).name)
|
|
606
|
+
|
|
607
|
+
# 表示
|
|
608
|
+
if verbose:
|
|
609
|
+
# ヘッダー
|
|
610
|
+
print(f"{msg('worktree_name'):<30} {msg('branch_name'):<25} {msg('created_at'):<20} {msg('last_commit'):<20} {msg('status_label')}")
|
|
611
|
+
print("-" * 110)
|
|
612
|
+
|
|
613
|
+
for wt in worktrees:
|
|
614
|
+
name = Path(wt['path']).name
|
|
615
|
+
branch = wt.get('branch', 'N/A')
|
|
616
|
+
created = wt.get('created').strftime('%Y-%m-%d %H:%M') if wt.get('created') else 'N/A'
|
|
617
|
+
last_commit = wt.get('last_commit').strftime('%Y-%m-%d %H:%M') if wt.get('last_commit') else 'N/A'
|
|
618
|
+
status = 'clean' if wt.get('is_clean') else 'modified'
|
|
619
|
+
|
|
620
|
+
print(f"{name:<30} {branch:<25} {created:<20} {last_commit:<20} {status}")
|
|
621
|
+
else:
|
|
622
|
+
# 通常表示(ソートのみ)
|
|
623
|
+
for wt in worktrees:
|
|
624
|
+
print(wt['path'])
|
|
445
625
|
|
|
446
626
|
|
|
447
627
|
def cmd_remove(args: list[str]):
|
|
@@ -473,6 +653,220 @@ def cmd_remove(args: list[str]):
|
|
|
473
653
|
sys.exit(1)
|
|
474
654
|
|
|
475
655
|
|
|
656
|
+
def cmd_clean(args: list[str]):
|
|
657
|
+
"""wt clean - Remove old/unused worktrees"""
|
|
658
|
+
base_dir = find_base_dir()
|
|
659
|
+
if not base_dir:
|
|
660
|
+
print(msg('error', msg('base_not_found')), file=sys.stderr)
|
|
661
|
+
sys.exit(1)
|
|
662
|
+
|
|
663
|
+
# オプションを解析
|
|
664
|
+
dry_run = '--dry-run' in args
|
|
665
|
+
clean_all = '--all' in args
|
|
666
|
+
days = None
|
|
667
|
+
|
|
668
|
+
for i, arg in enumerate(args):
|
|
669
|
+
if arg == '--days' and i + 1 < len(args):
|
|
670
|
+
try:
|
|
671
|
+
days = int(args[i + 1])
|
|
672
|
+
except ValueError:
|
|
673
|
+
print(msg('error', 'Invalid days value'), file=sys.stderr)
|
|
674
|
+
sys.exit(1)
|
|
675
|
+
|
|
676
|
+
# worktree 情報を取得
|
|
677
|
+
worktrees = get_worktree_info(base_dir)
|
|
678
|
+
|
|
679
|
+
# 削除対象を抽出(_baseは除外)
|
|
680
|
+
targets = []
|
|
681
|
+
now = datetime.now()
|
|
682
|
+
|
|
683
|
+
for wt in worktrees:
|
|
684
|
+
path = Path(wt['path'])
|
|
685
|
+
|
|
686
|
+
# _base は除外
|
|
687
|
+
if path.name == '_base':
|
|
688
|
+
continue
|
|
689
|
+
|
|
690
|
+
# clean状態のものだけが対象
|
|
691
|
+
if not wt.get('is_clean'):
|
|
692
|
+
continue
|
|
693
|
+
|
|
694
|
+
# 日数指定がある場合はチェック
|
|
695
|
+
if days is not None:
|
|
696
|
+
created = wt.get('created')
|
|
697
|
+
if created:
|
|
698
|
+
age_days = (now - created).days
|
|
699
|
+
if age_days < days:
|
|
700
|
+
continue
|
|
701
|
+
|
|
702
|
+
targets.append(wt)
|
|
703
|
+
|
|
704
|
+
if not targets:
|
|
705
|
+
print(msg('no_clean_targets'))
|
|
706
|
+
return
|
|
707
|
+
|
|
708
|
+
# 削除対象を表示
|
|
709
|
+
for wt in targets:
|
|
710
|
+
path = Path(wt['path'])
|
|
711
|
+
created = wt.get('created').strftime('%Y-%m-%d %H:%M') if wt.get('created') else 'N/A'
|
|
712
|
+
print(msg('clean_target', path.name, created))
|
|
713
|
+
|
|
714
|
+
if dry_run:
|
|
715
|
+
print(f"\n(--dry-run mode, no changes made)")
|
|
716
|
+
return
|
|
717
|
+
|
|
718
|
+
# 確認
|
|
719
|
+
if not clean_all:
|
|
720
|
+
try:
|
|
721
|
+
response = input(msg('clean_confirm', len(targets)))
|
|
722
|
+
if response.lower() not in ['y', 'yes']:
|
|
723
|
+
print("Cancelled.")
|
|
724
|
+
return
|
|
725
|
+
except (EOFError, KeyboardInterrupt):
|
|
726
|
+
print("\nCancelled.")
|
|
727
|
+
return
|
|
728
|
+
|
|
729
|
+
# 削除実行
|
|
730
|
+
for wt in targets:
|
|
731
|
+
path = Path(wt['path'])
|
|
732
|
+
print(msg('removing_worktree', path.name))
|
|
733
|
+
result = run_command(
|
|
734
|
+
["git", "worktree", "remove", str(path)],
|
|
735
|
+
cwd=base_dir,
|
|
736
|
+
check=False
|
|
737
|
+
)
|
|
738
|
+
|
|
739
|
+
if result.returncode == 0:
|
|
740
|
+
print(msg('completed_remove', path.name))
|
|
741
|
+
else:
|
|
742
|
+
if result.stderr:
|
|
743
|
+
print(result.stderr, file=sys.stderr)
|
|
744
|
+
|
|
745
|
+
|
|
746
|
+
def cmd_alias(args: list[str]):
|
|
747
|
+
"""wt alias - Manage worktree aliases"""
|
|
748
|
+
base_dir = find_base_dir()
|
|
749
|
+
if not base_dir:
|
|
750
|
+
print(msg('error', msg('base_not_found')), file=sys.stderr)
|
|
751
|
+
sys.exit(1)
|
|
752
|
+
|
|
753
|
+
parent_dir = base_dir.parent
|
|
754
|
+
|
|
755
|
+
# --list オプション
|
|
756
|
+
if '--list' in args or len(args) == 0:
|
|
757
|
+
# エイリアス一覧を表示(シンボリックリンクを探す)
|
|
758
|
+
aliases = []
|
|
759
|
+
for item in parent_dir.iterdir():
|
|
760
|
+
if item.is_symlink() and item.name != '_base':
|
|
761
|
+
target = item.resolve()
|
|
762
|
+
aliases.append((item.name, target.name))
|
|
763
|
+
|
|
764
|
+
if aliases:
|
|
765
|
+
for alias, target in sorted(aliases):
|
|
766
|
+
print(f"{alias} -> {target}")
|
|
767
|
+
else:
|
|
768
|
+
print("No aliases found.")
|
|
769
|
+
return
|
|
770
|
+
|
|
771
|
+
# --remove オプション
|
|
772
|
+
if '--remove' in args:
|
|
773
|
+
if len(args) < 2:
|
|
774
|
+
print(msg('usage_alias'), file=sys.stderr)
|
|
775
|
+
sys.exit(1)
|
|
776
|
+
|
|
777
|
+
alias_name = args[args.index('--remove') + 1]
|
|
778
|
+
alias_path = parent_dir / alias_name
|
|
779
|
+
|
|
780
|
+
if not alias_path.exists():
|
|
781
|
+
print(msg('error', msg('alias_not_found', alias_name)), file=sys.stderr)
|
|
782
|
+
sys.exit(1)
|
|
783
|
+
|
|
784
|
+
if not alias_path.is_symlink():
|
|
785
|
+
print(msg('error', f'{alias_name} is not an alias'), file=sys.stderr)
|
|
786
|
+
sys.exit(1)
|
|
787
|
+
|
|
788
|
+
alias_path.unlink()
|
|
789
|
+
print(msg('alias_removed', alias_name))
|
|
790
|
+
return
|
|
791
|
+
|
|
792
|
+
# --override オプションをチェック
|
|
793
|
+
override = '--override' in args
|
|
794
|
+
if override:
|
|
795
|
+
args.remove('--override')
|
|
796
|
+
|
|
797
|
+
# エイリアス作成
|
|
798
|
+
if len(args) < 2:
|
|
799
|
+
print(msg('usage_alias'), file=sys.stderr)
|
|
800
|
+
sys.exit(1)
|
|
801
|
+
|
|
802
|
+
alias_name = args[0]
|
|
803
|
+
worktree_name = args[1]
|
|
804
|
+
|
|
805
|
+
alias_path = parent_dir / alias_name
|
|
806
|
+
worktree_path = parent_dir / worktree_name
|
|
807
|
+
|
|
808
|
+
# worktree が存在するかチェック
|
|
809
|
+
if not worktree_path.exists():
|
|
810
|
+
print(msg('error', f'Worktree not found: {worktree_name}'), file=sys.stderr)
|
|
811
|
+
sys.exit(1)
|
|
812
|
+
|
|
813
|
+
# エイリアスがすでに存在するかチェック
|
|
814
|
+
if alias_path.exists():
|
|
815
|
+
if not override:
|
|
816
|
+
print(msg('error', msg('already_exists', alias_name)), file=sys.stderr)
|
|
817
|
+
print(msg('alias_exists_suggestion', alias_name, worktree_name), file=sys.stderr)
|
|
818
|
+
sys.exit(1)
|
|
819
|
+
# --override が指定されている場合は既存のエイリアスを削除
|
|
820
|
+
if alias_path.is_symlink():
|
|
821
|
+
alias_path.unlink()
|
|
822
|
+
|
|
823
|
+
# シンボリックリンクを作成
|
|
824
|
+
alias_path.symlink_to(worktree_path, target_is_directory=True)
|
|
825
|
+
print(msg('alias_created', alias_name, worktree_name))
|
|
826
|
+
|
|
827
|
+
|
|
828
|
+
def cmd_status(args: list[str]):
|
|
829
|
+
"""wt status - Show status of all worktrees"""
|
|
830
|
+
base_dir = find_base_dir()
|
|
831
|
+
if not base_dir:
|
|
832
|
+
print(msg('error', msg('base_not_found')), file=sys.stderr)
|
|
833
|
+
sys.exit(1)
|
|
834
|
+
|
|
835
|
+
# オプション
|
|
836
|
+
show_dirty_only = '--dirty' in args
|
|
837
|
+
short = '--short' in args
|
|
838
|
+
|
|
839
|
+
worktrees = get_worktree_info(base_dir)
|
|
840
|
+
|
|
841
|
+
for wt in worktrees:
|
|
842
|
+
path = Path(wt['path'])
|
|
843
|
+
|
|
844
|
+
# dirty only モードの場合、clean なものはスキップ
|
|
845
|
+
if show_dirty_only and wt.get('is_clean'):
|
|
846
|
+
continue
|
|
847
|
+
|
|
848
|
+
# git status を取得
|
|
849
|
+
result = run_command(
|
|
850
|
+
["git", "status", "--short" if short else "--short"],
|
|
851
|
+
cwd=path,
|
|
852
|
+
check=False
|
|
853
|
+
)
|
|
854
|
+
|
|
855
|
+
status_output = result.stdout.strip()
|
|
856
|
+
|
|
857
|
+
# ヘッダー
|
|
858
|
+
print(f"\n{'='*60}")
|
|
859
|
+
print(f"Worktree: {path.name}")
|
|
860
|
+
print(f"Branch: {wt.get('branch', 'N/A')}")
|
|
861
|
+
print(f"Path: {path}")
|
|
862
|
+
print(f"{'='*60}")
|
|
863
|
+
|
|
864
|
+
if status_output:
|
|
865
|
+
print(status_output)
|
|
866
|
+
else:
|
|
867
|
+
print("(clean - no changes)")
|
|
868
|
+
|
|
869
|
+
|
|
476
870
|
def cmd_passthrough(args: list[str]):
|
|
477
871
|
"""Passthrough other git worktree commands"""
|
|
478
872
|
base_dir = find_base_dir()
|
|
@@ -496,13 +890,19 @@ def show_help():
|
|
|
496
890
|
print(" wt <command> [options]")
|
|
497
891
|
print()
|
|
498
892
|
print("コマンド:")
|
|
499
|
-
print(" clone <repository_url>
|
|
500
|
-
print(" init
|
|
501
|
-
print(" add <作業名> [<base_branch>]
|
|
502
|
-
print(" list
|
|
503
|
-
print(" rm <作業名>
|
|
504
|
-
print(" remove <作業名>
|
|
505
|
-
print("
|
|
893
|
+
print(" clone <repository_url> - リポジトリをクローン")
|
|
894
|
+
print(" init - 既存リポジトリを WT_<repo>/_base/ に移動")
|
|
895
|
+
print(" add <作業名> [<base_branch>] [--alias <名前>] - worktree を追加(デフォルト: 新規ブランチ作成)")
|
|
896
|
+
print(" list [--verbose] [--sort age|name] - worktree 一覧を表示")
|
|
897
|
+
print(" rm <作業名> - worktree を削除")
|
|
898
|
+
print(" remove <作業名> - worktree を削除")
|
|
899
|
+
print(" clean [--dry-run] [--days N] - 未使用の worktree を削除")
|
|
900
|
+
print(" alias <名前> <worktree> - worktree のエイリアスを作成")
|
|
901
|
+
print(" alias --override <名前> <worktree> - エイリアスを上書き")
|
|
902
|
+
print(" alias --list - エイリアス一覧を表示")
|
|
903
|
+
print(" alias --remove <名前> - エイリアスを削除")
|
|
904
|
+
print(" status [--dirty] [--short] - 全 worktree の状態を表示")
|
|
905
|
+
print(" <git-worktree-command> - その他の git worktree コマンド")
|
|
506
906
|
print()
|
|
507
907
|
print("オプション:")
|
|
508
908
|
print(" -h, --help - このヘルプメッセージを表示")
|
|
@@ -514,13 +914,19 @@ def show_help():
|
|
|
514
914
|
print(" wt <command> [options]")
|
|
515
915
|
print()
|
|
516
916
|
print("Commands:")
|
|
517
|
-
print(" clone <repository_url>
|
|
518
|
-
print(" init
|
|
519
|
-
print(" add <work_name> [<base_branch>]
|
|
520
|
-
print(" list
|
|
521
|
-
print(" rm <work_name>
|
|
522
|
-
print(" remove <work_name>
|
|
523
|
-
print("
|
|
917
|
+
print(" clone <repository_url> - Clone a repository")
|
|
918
|
+
print(" init - Move existing repo to WT_<repo>/_base/")
|
|
919
|
+
print(" add <work_name> [<base_branch>] [--alias <name>] - Add a worktree (default: create new branch)")
|
|
920
|
+
print(" list [--verbose] [--sort age|name] - List worktrees")
|
|
921
|
+
print(" rm <work_name> - Remove a worktree")
|
|
922
|
+
print(" remove <work_name> - Remove a worktree")
|
|
923
|
+
print(" clean [--dry-run] [--days N] - Remove unused worktrees")
|
|
924
|
+
print(" alias <name> <worktree> - Create an alias for a worktree")
|
|
925
|
+
print(" alias --override <name> <worktree> - Override an existing alias")
|
|
926
|
+
print(" alias --list - List aliases")
|
|
927
|
+
print(" alias --remove <name> - Remove an alias")
|
|
928
|
+
print(" status [--dirty] [--short] - Show status of all worktrees")
|
|
929
|
+
print(" <git-worktree-command> - Other git worktree commands")
|
|
524
930
|
print()
|
|
525
931
|
print("Options:")
|
|
526
932
|
print(" -h, --help - Show this help message")
|
|
@@ -529,7 +935,7 @@ def show_help():
|
|
|
529
935
|
|
|
530
936
|
def show_version():
|
|
531
937
|
"""Show version information"""
|
|
532
|
-
print("easy-worktree version 0.0.
|
|
938
|
+
print("easy-worktree version 0.0.3")
|
|
533
939
|
|
|
534
940
|
|
|
535
941
|
def main():
|
|
@@ -562,6 +968,12 @@ def main():
|
|
|
562
968
|
cmd_list(args)
|
|
563
969
|
elif command in ["rm", "remove"]:
|
|
564
970
|
cmd_remove(args)
|
|
971
|
+
elif command == "clean":
|
|
972
|
+
cmd_clean(args)
|
|
973
|
+
elif command == "alias":
|
|
974
|
+
cmd_alias(args)
|
|
975
|
+
elif command == "status":
|
|
976
|
+
cmd_status(args)
|
|
565
977
|
else:
|
|
566
978
|
# その他のコマンドは git worktree にパススルー
|
|
567
979
|
cmd_passthrough([command] + args)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: easy-worktree
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.3
|
|
4
4
|
Summary: Git worktree を簡単に管理するための CLI ツール
|
|
5
5
|
Project-URL: Homepage, https://github.com/igtm/easy-worktree
|
|
6
6
|
Project-URL: Repository, https://github.com/igtm/easy-worktree
|
|
@@ -94,6 +94,12 @@ You can also specify a branch name:
|
|
|
94
94
|
wt add feature-1 main
|
|
95
95
|
```
|
|
96
96
|
|
|
97
|
+
Create a worktree and set an alias at the same time:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
wt add feature-123 --alias current # Create feature-123 and set 'current' alias
|
|
101
|
+
```
|
|
102
|
+
|
|
97
103
|
### List worktrees
|
|
98
104
|
|
|
99
105
|
```bash
|
|
@@ -155,6 +161,46 @@ chmod +x WT_repo/_base/.wt/post-add
|
|
|
155
161
|
|
|
156
162
|
The hook runs within the newly created worktree directory.
|
|
157
163
|
|
|
164
|
+
### List worktrees with details
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
wt list --verbose # Show creation time, last commit, status
|
|
168
|
+
wt list --sort age # Sort by creation time
|
|
169
|
+
wt list --sort name # Sort by name
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Clean up unused worktrees
|
|
173
|
+
|
|
174
|
+
Remove clean (no changes) worktrees in batch.
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
wt clean --dry-run # Preview what will be removed
|
|
178
|
+
wt clean --days 30 # Remove clean worktrees older than 30 days
|
|
179
|
+
wt clean --all # Remove all clean worktrees without confirmation
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### Create worktree aliases
|
|
183
|
+
|
|
184
|
+
Create symbolic link shortcuts to frequently used worktrees.
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
wt alias current feature-123 # Create alias named 'current'
|
|
188
|
+
wt alias dev feature-xyz # Create alias named 'dev'
|
|
189
|
+
wt alias --override current hoge3 # Override existing alias
|
|
190
|
+
wt alias --list # List all aliases
|
|
191
|
+
wt alias --remove current # Remove an alias
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### Check status of all worktrees
|
|
195
|
+
|
|
196
|
+
View git status of all worktrees at once.
|
|
197
|
+
|
|
198
|
+
```bash
|
|
199
|
+
wt status # Show status of all worktrees
|
|
200
|
+
wt status --dirty # Show only worktrees with changes
|
|
201
|
+
wt status --short # Concise display
|
|
202
|
+
```
|
|
203
|
+
|
|
158
204
|
### Other git worktree commands
|
|
159
205
|
|
|
160
206
|
`wt` also supports other git worktree commands:
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
easy_worktree/__init__.py,sha256=ycVq8MY0nsWqE51e9aqH-sgL5wIR5p51kxAkeObH6uc,31911
|
|
2
|
+
easy_worktree-0.0.3.dist-info/METADATA,sha256=_Iuo358hcbxjuqYfz78xYGUz1K3RNYzqEtBr4oJ7Z4E,5360
|
|
3
|
+
easy_worktree-0.0.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
4
|
+
easy_worktree-0.0.3.dist-info/entry_points.txt,sha256=Mf6MYDS2obZLvIJJFl-BbU8-SL0QGu5UWcC0FWnqtbg,42
|
|
5
|
+
easy_worktree-0.0.3.dist-info/licenses/LICENSE,sha256=7MGvWFDxXPqW2nrr9D7KHT0vWFiGwIUL5SQCj0IiAPc,1061
|
|
6
|
+
easy_worktree-0.0.3.dist-info/RECORD,,
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
easy_worktree/__init__.py,sha256=TcW_V6eZesS-brvH3G7oxaGYrKkSKWwnk0NK0zux5rg,18175
|
|
2
|
-
easy_worktree-0.0.1.dist-info/METADATA,sha256=uBUl869lSTaY6hHoTibVf10UZNupqXogLGAEH11CGLM,4020
|
|
3
|
-
easy_worktree-0.0.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
4
|
-
easy_worktree-0.0.1.dist-info/entry_points.txt,sha256=Mf6MYDS2obZLvIJJFl-BbU8-SL0QGu5UWcC0FWnqtbg,42
|
|
5
|
-
easy_worktree-0.0.1.dist-info/licenses/LICENSE,sha256=7MGvWFDxXPqW2nrr9D7KHT0vWFiGwIUL5SQCj0IiAPc,1061
|
|
6
|
-
easy_worktree-0.0.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|