feat(vendor): select command — manage include/exclude selection after initial add

vendor select <name> --add/--remove/--mode all changes what a source
contributes without advancing the pinned rev: ids are validated against
the pinned upstream (typos abort listing available ids), collisions
re-run, renames from the lockfile are honored, and the external area is
rewritten via the same staging-swap as update. include mode grows and
shrinks the include list; all mode --remove moves ids onto exclude;
--mode all resets to everything. Failed selects mutate nothing.

Closes beads: agent-lib-cd3
This commit is contained in:
2026-08-23 15:13:50 +02:00
parent 7070d8cc25
commit 876ff1c6b9
5 changed files with 624 additions and 1 deletions
+22
View File
@@ -93,6 +93,28 @@ func resolveHead(repo *git.Repository, requestedRef string) (*Repo, error) {
return r, nil
}
// Pin returns a copy of the repo resolved to an explicit revision, so a
// selection can be re-materialized at the pinned rev without advancing it.
func (r *Repo) Pin(rev string) (*Repo, error) {
if _, err := r.Repository.CommitObject(plumbing.NewHash(rev)); err != nil {
return nil, fmt.Errorf("pinned revision %s not found in %s: %w", rev, r.URL(), err)
}
pinned := *r
pinned.Rev = rev
return &pinned, nil
}
func (r *Repo) URL() string {
if r.Repository == nil {
return ""
}
remote, err := r.Repository.Remote(git.DefaultRemoteName)
if err != nil || len(remote.Config().URLs) == 0 {
return ""
}
return remote.Config().URLs[0]
}
// Tree returns the commit tree of the pinned revision as a discovery.Tree.
func (r *Repo) Tree() (discovery.Tree, error) {
commit, err := r.Repository.CommitObject(plumbing.NewHash(r.Rev))