Skip to content

Commit d4e973e

Browse files
authored
cmd(git): Add Manager/Cmd pattern for git subcommands (#465)
Introduces typed Python objects for git subcommands instead of raw strings. New features: - Manager classes: GitBranchManager, GitRemoteManager, GitStashManager, GitTagManager, GitWorktreeManager, GitNotesManager, GitSubmoduleManager, GitReflogManager - Cmd classes for per-entity operations on branches, remotes, stashes, tags, worktrees, notes, submodules, and reflog entries - All ls() methods return QueryList for chainable filtering - Enhanced Git.init() with ref_format, make_parents, octal shared permissions Bug fixes: - Git.run(): Fix boolean config serialization, -C path iteration, add config_env - Git.clone(): Fix reference_if_able flag, separate_git_dir quoting - Git.fetch()/pull(): Remove clone-only params, add recurse_submodules, fix --signoff spelling - Git.rebase(): Fix --no-rerere-autoupdate typo, whitespace options - Git.init(): Remove invalid --default, fix shared=False behavior - Forward **kwargs in all Manager/Cmd run() methods - GitRemoteManager.ls(): Handle URLs with spaces - GitNoteCmd: Propagate custom ref to commands - GitNotesManager.merge(): Handle commit/abort forms - GitStashCmd.push(): Handle str paths - stash.pop(): Use stash@{N} format - branch.create(): Use git branch instead of checkout -b - remote.add(): Wire fetch, track, master params - remote.show(): Only add --verbose when explicitly True Documentation: - API docs for all new Manager/Cmd classes - Split git subcommand docs into separate pages - Usage examples in README and quickstart Tests: - Comprehensive coverage for all new Manager/Cmd classes
2 parents 23ddb7e + a402e4d commit d4e973e

19 files changed

Lines changed: 9566 additions & 413 deletions

File tree

CHANGES

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,59 @@ $ uv add libvcs --prerelease allow
2020

2121
_Upcoming changes will be written here._
2222

23+
### New features
24+
25+
#### cmd: Manager/Cmd pattern for git subcommands (#465)
26+
27+
New architecture for git subcommands that returns typed objects instead of raw strings:
28+
29+
- **Manager classes** handle collection-level operations (`ls()`, `get()`, `filter()`, `add()`/`create()`)
30+
- **Cmd classes** handle per-entity operations (`show()`, `remove()`, `rename()`)
31+
- All `ls()` methods return `QueryList` for chainable filtering
32+
33+
New subcommand managers accessible via `Git` instance:
34+
35+
- {attr}`Git.branches <libvcs.cmd.git.Git.branches>` -> {class}`~libvcs.cmd.git.GitBranchManager`
36+
- {attr}`Git.remotes <libvcs.cmd.git.Git.remotes>` -> {class}`~libvcs.cmd.git.GitRemoteManager`
37+
- {attr}`Git.stashes <libvcs.cmd.git.Git.stashes>` -> {class}`~libvcs.cmd.git.GitStashManager`
38+
- {attr}`Git.tags <libvcs.cmd.git.Git.tags>` -> {class}`~libvcs.cmd.git.GitTagManager`
39+
- {attr}`Git.worktrees <libvcs.cmd.git.Git.worktrees>` -> {class}`~libvcs.cmd.git.GitWorktreeManager`
40+
- {attr}`Git.notes <libvcs.cmd.git.Git.notes>` -> {class}`~libvcs.cmd.git.GitNotesManager`
41+
- {attr}`Git.submodules <libvcs.cmd.git.Git.submodules>` -> {class}`~libvcs.cmd.git.GitSubmoduleManager`
42+
- {attr}`Git.reflog <libvcs.cmd.git.Git.reflog>` -> {class}`~libvcs.cmd.git.GitReflogManager`
43+
44+
Example usage:
45+
46+
```python
47+
git = Git(path="/path/to/repo")
48+
49+
# List all branches, filter remote ones
50+
remote_branches = git.branches.ls(remotes=True)
51+
52+
# Get a specific tag
53+
tag = git.tags.get(tag_name="v1.0.0")
54+
tag.delete()
55+
56+
# Create a new branch and switch to it
57+
git.branches.create("feature-branch")
58+
```
59+
60+
#### cmd: Enhanced Git.init() (#465)
61+
62+
- Added `ref_format` parameter for `--ref-format` (files/reftable)
63+
- Added `make_parents` parameter to auto-create parent directories
64+
- Improved parameter validation with clear error messages
65+
- Extended `shared` parameter to support octal permissions (e.g., "0660")
66+
67+
### Documentation
68+
69+
- Add API documentation for all new Manager/Cmd classes (#465)
70+
- Split git subcommand documentation into separate pages: branch, tag, worktree, notes, reflog
71+
72+
### Tests
73+
74+
- Comprehensive test coverage for all new Manager/Cmd classes (#465)
75+
2376
## libvcs 0.37.0 (2025-11-01)
2477

2578
### Breaking changes

README.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,31 @@ git.clone(url='https://github.com/vcs-python/libvcs.git')
9191
Above: [`libvcs.cmd.git.Git`](https://libvcs.git-pull.com/cmd/git.html#libvcs.cmd.git.Git) using
9292
[`Git.clone()`](http://libvcs.git-pull.com/cmd/git.html#libvcs.cmd.git.Git.clone).
9393

94+
### Manage Branches, Tags, and More
95+
96+
Work with git subcommands using typed Python objects:
97+
98+
```python
99+
from libvcs.cmd.git import Git
100+
101+
git = Git(path='/path/to/repo')
102+
103+
# Branches
104+
branches = git.branches.ls() # List all branches
105+
git.branches.create('feature-branch') # Create a branch
106+
107+
# Tags
108+
git.tags.create(name='v1.0.0', message='Release')
109+
tags = git.tags.ls()
110+
111+
# Remotes
112+
remotes = git.remotes.ls()
113+
remote = git.remotes.get(remote_name='origin')
114+
remote.prune()
115+
```
116+
117+
See the [Manager/Cmd pattern documentation](https://libvcs.git-pull.com/cmd/git/index.html) for more.
118+
94119
## Repository Synchronization
95120

96121
Synchronize your repositories using the

docs/cmd/git/branch.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# `branch`
2+
3+
For `git-branch(1)`.
4+
5+
## Overview
6+
7+
Manage git branches using {class}`~libvcs.cmd.git.GitBranchManager` (collection-level)
8+
and {class}`~libvcs.cmd.git.GitBranchCmd` (per-branch operations).
9+
10+
### Example
11+
12+
```python
13+
from libvcs.cmd.git import Git
14+
15+
git = Git(path='/path/to/repo')
16+
17+
# List all branches
18+
branches = git.branches.ls()
19+
20+
# List remote branches only
21+
remote_branches = git.branches.ls(remotes=True)
22+
23+
# Create a new branch
24+
git.branches.create('feature-branch')
25+
26+
# Get a specific branch and operate on it
27+
branch = git.branches.get(branch_name='feature-branch')
28+
branch.rename('new-feature')
29+
branch.delete()
30+
```
31+
32+
## API Reference
33+
34+
```{eval-rst}
35+
.. autoclass:: libvcs.cmd.git.GitBranchManager
36+
:members:
37+
:show-inheritance:
38+
:undoc-members:
39+
40+
.. autoclass:: libvcs.cmd.git.GitBranchCmd
41+
:members:
42+
:show-inheritance:
43+
:undoc-members:
44+
```

docs/cmd/git/index.md

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,63 @@ _Compare to: [`fabtools.git`](https://fabtools.readthedocs.io/en/0.19.0/api/git.
66
[`salt.modules.git`](https://docs.saltproject.io/en/latest/ref/modules/all/salt.modules.git.html),
77
[`ansible.builtin.git`](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/git_module.html)_
88

9+
## Manager/Cmd Pattern
10+
11+
libvcs provides a **Manager/Cmd pattern** for git subcommands:
12+
13+
- **Manager** classes (`git.branches`, `git.tags`, etc.) handle collection-level operations
14+
- **Cmd** classes represent individual entities with mutation methods
15+
16+
```
17+
Git instance
18+
├── branches: GitBranchManager
19+
│ ├── ls() -> QueryList[GitBranchCmd]
20+
│ ├── get() -> GitBranchCmd
21+
│ └── create()
22+
├── tags: GitTagManager
23+
├── remotes: GitRemoteManager
24+
├── stashes: GitStashManager
25+
├── worktrees: GitWorktreeManager
26+
├── notes: GitNotesManager
27+
├── submodules: GitSubmoduleManager
28+
└── reflog: GitReflogManager
29+
```
30+
31+
### Quick Example
32+
33+
```python
34+
from libvcs.cmd.git import Git
35+
36+
git = Git(path='/path/to/repo')
37+
38+
# List all branches
39+
branches = git.branches.ls()
40+
41+
# Filter to remote branches only
42+
remote_branches = git.branches.ls(remotes=True)
43+
44+
# Get a specific branch and rename it
45+
branch = git.branches.get(branch_name='old-name')
46+
branch.rename('new-name')
47+
48+
# Create and manage tags
49+
git.tags.create(name='v1.0.0', message='Release 1.0')
50+
tag = git.tags.get(tag_name='v1.0.0')
51+
tag.delete()
52+
```
53+
954
```{toctree}
1055
:caption: Subcommands
1156
:maxdepth: 1
1257
1358
submodule
1459
remote
1560
stash
61+
branch
62+
tag
63+
worktree
64+
notes
65+
reflog
1666
```
1767

1868
```{eval-rst}
@@ -21,6 +71,23 @@ stash
2171
:show-inheritance:
2272
:undoc-members:
2373
:exclude-members: GitSubmoduleCmd,
74+
GitSubmoduleManager,
75+
GitSubmodule,
76+
GitSubmoduleEntryCmd,
2477
GitRemoteCmd,
25-
GitStashCmd
78+
GitRemoteManager,
79+
GitStashCmd,
80+
GitStashManager,
81+
GitStashEntryCmd,
82+
GitBranchCmd,
83+
GitBranchManager,
84+
GitTagCmd,
85+
GitTagManager,
86+
GitWorktreeCmd,
87+
GitWorktreeManager,
88+
GitNoteCmd,
89+
GitNotesManager,
90+
GitReflogEntry,
91+
GitReflogEntryCmd,
92+
GitReflogManager
2693
```

docs/cmd/git/notes.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# `notes`
2+
3+
For `git-notes(1)`.
4+
5+
## Overview
6+
7+
Manage git notes using {class}`~libvcs.cmd.git.GitNotesManager` (collection-level)
8+
and {class}`~libvcs.cmd.git.GitNoteCmd` (per-note operations).
9+
10+
### Example
11+
12+
```python
13+
from libvcs.cmd.git import Git
14+
15+
git = Git(path='/path/to/repo')
16+
17+
# Add a note to a commit
18+
git.notes.add(object='HEAD', message='This is a note')
19+
20+
# List all notes
21+
notes = git.notes.ls()
22+
23+
# Get a specific note and operate on it
24+
note = git.notes.get(object='HEAD')
25+
note.show()
26+
note.append(message='Additional info')
27+
note.remove()
28+
29+
# Prune notes for non-existent objects
30+
git.notes.prune()
31+
```
32+
33+
## API Reference
34+
35+
```{eval-rst}
36+
.. autoclass:: libvcs.cmd.git.GitNotesManager
37+
:members:
38+
:show-inheritance:
39+
:undoc-members:
40+
41+
.. autoclass:: libvcs.cmd.git.GitNoteCmd
42+
:members:
43+
:show-inheritance:
44+
:undoc-members:
45+
```

docs/cmd/git/reflog.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# `reflog`
2+
3+
For `git-reflog(1)`.
4+
5+
## Overview
6+
7+
Manage git reflog using {class}`~libvcs.cmd.git.GitReflogManager` (collection-level)
8+
and {class}`~libvcs.cmd.git.GitReflogEntryCmd` (per-entry operations).
9+
10+
### Example
11+
12+
```python
13+
from libvcs.cmd.git import Git
14+
15+
git = Git(path='/path/to/repo')
16+
17+
# List reflog entries
18+
entries = git.reflog.ls()
19+
20+
# List entries for a specific ref
21+
head_entries = git.reflog.ls(ref='HEAD')
22+
23+
# Check if reflog exists for a ref
24+
git.reflog.exists(ref='main')
25+
26+
# Expire old reflog entries
27+
git.reflog.expire(ref='HEAD', expire='90.days.ago')
28+
```
29+
30+
## API Reference
31+
32+
```{eval-rst}
33+
.. autoclass:: libvcs.cmd.git.GitReflogManager
34+
:members:
35+
:show-inheritance:
36+
:undoc-members:
37+
38+
.. autoclass:: libvcs.cmd.git.GitReflogEntryCmd
39+
:members:
40+
:show-inheritance:
41+
:undoc-members:
42+
43+
.. autoclass:: libvcs.cmd.git.GitReflogEntry
44+
:members:
45+
:show-inheritance:
46+
:undoc-members:
47+
```

docs/cmd/git/remote.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,39 @@
22

33
For `git-remote(1)`.
44

5+
## Overview
6+
7+
Manage git remotes using {class}`~libvcs.cmd.git.GitRemoteManager` (collection-level)
8+
and {class}`~libvcs.cmd.git.GitRemoteCmd` (per-remote operations).
9+
10+
### Example
11+
12+
```python
13+
from libvcs.cmd.git import Git
14+
15+
git = Git(path='/path/to/repo')
16+
17+
# List all remotes
18+
remotes = git.remotes.ls()
19+
20+
# Add a new remote
21+
git.remotes.add(name='upstream', url='https://github.com/org/repo.git')
22+
23+
# Get a specific remote and operate on it
24+
origin = git.remotes.get(remote_name='origin')
25+
origin.show()
26+
origin.prune()
27+
origin.set_url('https://new-url.git')
28+
```
29+
30+
## API Reference
31+
532
```{eval-rst}
33+
.. autoclass:: libvcs.cmd.git.GitRemoteManager
34+
:members:
35+
:show-inheritance:
36+
:undoc-members:
37+
638
.. autoclass:: libvcs.cmd.git.GitRemoteCmd
739
:members:
840
:show-inheritance:

0 commit comments

Comments
 (0)